From 5c38c17353077d7c498c667650971dae501f010f Mon Sep 17 00:00:00 2001 From: skylarbarrera Date: Tue, 30 Jan 2024 12:25:48 -0500 Subject: [PATCH 01/38] save --- src/hooks/useAccountTransactions.ts | 35 +-- src/parsers/transactions.ts | 2 +- src/react-query/index.ts | 1 + src/react-query/types.ts | 20 ++ .../transactions/consolidatedTransactions.ts | 176 +++++++++++++ src/resources/transactions/types.ts | 248 ++++++++++++++++++ 6 files changed, 466 insertions(+), 16 deletions(-) create mode 100644 src/resources/transactions/consolidatedTransactions.ts create mode 100644 src/resources/transactions/types.ts diff --git a/src/hooks/useAccountTransactions.ts b/src/hooks/useAccountTransactions.ts index cb8580a3f48..362c6380a0d 100644 --- a/src/hooks/useAccountTransactions.ts +++ b/src/hooks/useAccountTransactions.ts @@ -1,4 +1,4 @@ -import { useCallback, useMemo, useState } from 'react'; +import { useMemo } from 'react'; import { useSelector } from 'react-redux'; import { buildTransactionsSectionsSelector } from '../helpers/buildTransactionsSectionsSelector'; import NetworkTypes from '../helpers/networkTypes'; @@ -10,6 +10,8 @@ import { AppState } from '@/redux/store'; import { useTheme } from '@/theme'; import { getCachedProviderForNetwork, isHardHat } from '@/handlers/web3'; import { useUserAssets } from '@/resources/assets/UserAssetsQuery'; +import { useConsolidatedTransactions } from '@/resources/transactions/consolidatedTransactions'; +import { RainbowTransaction } from '@/entities'; export const NOE_PAGE = 30; @@ -31,12 +33,7 @@ export default function useAccountTransactions( connectedToHardhat, }); - const { - isLoadingTransactions, - network, - pendingTransactions, - transactions, - } = useSelector( + const { isLoadingTransactions, network, pendingTransactions } = useSelector( ({ data: { isLoadingTransactions, pendingTransactions, transactions }, settings: { network }, @@ -48,18 +45,26 @@ export default function useAccountTransactions( }) ); + const { data, fetchNextPage } = useConsolidatedTransactions({ + address: accountAddress, + currency: nativeCurrency, + }); + const pages = data?.pages; + + const transactions: RainbowTransaction[] = useMemo( + () => pages?.flatMap(p => p.transactions) || [], + [pages] + ); + console.log({ transactions }); + const allTransactions = useMemo( () => pendingTransactions.concat(transactions), [pendingTransactions, transactions] ); - const [page, setPage] = useState(1); - const nextPage = useCallback(() => setPage(page => page + 1), []); - - const slicedTransaction: any[] = useMemo( - () => allTransactions.slice(0, page * NOE_PAGE), - [allTransactions, page] - ); + const slicedTransaction: any[] = useMemo(() => allTransactions, [ + allTransactions, + ]); const mainnetAddresses = useMemo( () => @@ -107,7 +112,7 @@ export default function useAccountTransactions( return { isLoadingTransactions: network === NetworkTypes.mainnet ? isLoadingTransactions : false, - nextPage, + nextPage: fetchNextPage, remainingItemsLabel, sections, transactions: ios ? allTransactions : slicedTransaction, diff --git a/src/parsers/transactions.ts b/src/parsers/transactions.ts index 44be5ddfb9e..35e3ec5347b 100644 --- a/src/parsers/transactions.ts +++ b/src/parsers/transactions.ts @@ -329,7 +329,7 @@ const parseTransactionWithEmptyChanges = async ( ]; }; -const parseTransaction = async ( +export const parseTransaction = async ( transaction: ZerionTransaction, nativeCurrency: NativeCurrencyKey, purchaseTransactionsHashes: string[], diff --git a/src/react-query/index.ts b/src/react-query/index.ts index 96acdcbcfdb..2bee8eebc71 100644 --- a/src/react-query/index.ts +++ b/src/react-query/index.ts @@ -7,6 +7,7 @@ export { persistOptions, queryClient } from './queryClient'; export type { MutationConfig, MutationFunctionResult, + InfiniteQueryConfig, QueryConfig, QueryConfigDeprecated, QueryConfigWithSelect, diff --git a/src/react-query/types.ts b/src/react-query/types.ts index bd41924620b..822898a7f48 100644 --- a/src/react-query/types.ts +++ b/src/react-query/types.ts @@ -1,6 +1,7 @@ import { QueryFunctionContext, QueryKey, + UseInfiniteQueryOptions, UseMutationOptions, UseQueryOptions, } from '@tanstack/react-query'; @@ -37,6 +38,25 @@ export type QueryConfigWithSelect< | 'onSuccess' >; +export type InfiniteQueryConfig = Pick< + UseInfiniteQueryOptions< + TQueryFnData, + TError, + TData, + TQueryFnData, + Array + >, + | 'cacheTime' + | 'enabled' + | 'refetchInterval' + | 'retry' + | 'staleTime' + | 'select' + | 'onError' + | 'onSettled' + | 'onSuccess' +>; + // Note: we probably want to restrict the amount of configuration // to the React Query hook. So we are picking out the only the // configuration the consumer needs. I think these options are diff --git a/src/resources/transactions/consolidatedTransactions.ts b/src/resources/transactions/consolidatedTransactions.ts new file mode 100644 index 00000000000..457e381db5f --- /dev/null +++ b/src/resources/transactions/consolidatedTransactions.ts @@ -0,0 +1,176 @@ +import { useInfiniteQuery } from '@tanstack/react-query'; +import { + InfiniteQueryConfig, + QueryConfig, + QueryFunctionArgs, + createQueryKey, + queryClient, +} from '@/react-query'; +import { NativeCurrencyKey, RainbowTransaction } from '@/entities'; +import { Network } from '@/networks/types'; +import { TransactionsReceivedMessage } from './types'; +import { RainbowError, logger } from '@/logger'; +import { rainbowFetch } from '@/rainbow-fetch'; +import { ADDYS_API_KEY } from 'react-native-dotenv'; +import { RainbowNetworks } from '@/networks'; +import { parseTransaction } from '@/parsers/transactions'; + +const CONSOLIDATED_TRANSACTIONS_INTERVAL = 3000; +const CONSOLIDATED_TRANSACTIONS_TIMEOUT = 20000; + +// /////////////////////////////////////////////// +// Query Types + +export type ConsolidatedTransactionsArgs = { + address: string; + currency: NativeCurrencyKey; + chainIds: number[]; +}; + +// /////////////////////////////////////////////// +// Query Key + +export const consolidatedTransactionsQueryKey = ({ + address, + currency, + chainIds, +}: ConsolidatedTransactionsArgs) => + createQueryKey( + 'consolidatedTransactions', + { address, currency, chainIds }, + { persisterVersion: 1 } + ); + +type ConsolidatedTransactionsQueryKey = ReturnType< + typeof consolidatedTransactionsQueryKey +>; + +// /////////////////////////////////////////////// +// Query Fetcher + +export async function fetchConsolidatedTransactions< + ConsolidatedTransactionsResult +>( + { address, currency, chainIds }: ConsolidatedTransactionsArgs, + config: QueryConfig< + ConsolidatedTransactionsResult, + Error, + ConsolidatedTransactionsQueryKey + > +) { + return await queryClient.fetchQuery( + consolidatedTransactionsQueryKey({ + address, + currency, + chainIds, + }), + consolidatedTransactionsQueryFunction, + config + ); +} + +// /////////////////////////////////////////////// +// Query Function + +type _QueryResult = { + cutoff?: number; + nextPage?: string; + transactions: RainbowTransaction[] | []; +}; + +export async function consolidatedTransactionsQueryFunction({ + queryKey: [{ address, currency, chainIds }], + pageParam, +}: QueryFunctionArgs< + typeof consolidatedTransactionsQueryKey +>): Promise<_QueryResult> { + try { + const chainIdsString = chainIds.join(','); + const url = `https://addys.p.rainbow.me/v3/${chainIdsString}/${address}/transactions`; + const response = await rainbowFetch(url, { + method: 'get', + params: { + currency: currency.toLowerCase(), + ...(pageParam ? { pageCursor: pageParam } : {}), + }, + timeout: CONSOLIDATED_TRANSACTIONS_TIMEOUT, + headers: { + Authorization: `Bearer ${ADDYS_API_KEY}`, + }, + }); + + const consolidatedTransactions = await parseConsolidatedTransactions( + response?.data, + currency + ); + + return { + cutoff: response?.data?.meta?.cut_off, + nextPage: response?.data?.meta?.next_page_cursor, + transactions: consolidatedTransactions, + }; + } catch (e) { + logger.error(new RainbowError('consolidatedTransactionsQueryFunction: '), { + message: e, + }); + return { transactions: [] }; + } +} + +type ConsolidatedTransactionsResult = { + cutoff?: number; + nextPage?: string; + transactions: RainbowTransaction[]; +}; + +async function parseConsolidatedTransactions( + message: TransactionsReceivedMessage, + currency: NativeCurrencyKey +) { + const data = message?.payload?.transactions || []; + const parsedTransactionPromises = data + .map((tx: any) => + parseTransaction(tx, currency, [], tx?.network ?? Network.mainnet) + ) + .filter(Boolean); + + const parsedConsolidatedTransactions = ( + await Promise.all(parsedTransactionPromises) + ).flat(); + return parsedConsolidatedTransactions; +} + +// /////////////////////////////////////////////// +// Query Hook + +export function useConsolidatedTransactions( + { + address, + currency, + }: Pick, + config: InfiniteQueryConfig< + ConsolidatedTransactionsResult, + Error, + ConsolidatedTransactionsResult + > = {} +) { + const chainIds = RainbowNetworks.filter( + network => network.enabled && network.networkType !== 'testnet' + ).map(network => network.id); + + return useInfiniteQuery( + consolidatedTransactionsQueryKey({ + address, + currency, + chainIds, + }), + consolidatedTransactionsQueryFunction, + { + ...config, + keepPreviousData: true, + getNextPageParam: lastPage => lastPage?.nextPage, + refetchInterval: CONSOLIDATED_TRANSACTIONS_INTERVAL, + retry: 3, + } + ); +} diff --git a/src/resources/transactions/types.ts b/src/resources/transactions/types.ts new file mode 100644 index 00000000000..88baf90607f --- /dev/null +++ b/src/resources/transactions/types.ts @@ -0,0 +1,248 @@ +import { TransactionResponse } from '@ethersproject/providers'; + +import { ZerionAsset } from '@/entities/tokens'; +import { + LegacyTransactionGasParams, + TransactionGasParams, +} from '@/entities/gas'; +import { Network } from '@/networks/types'; +import { AddysAsset, ParsedAsset } from '../assets/types'; + +type ChainId = number; +/** + * Metadata for a message from the Zerion API. + */ +export interface MessageMeta { + address?: string; + currency?: string; + cut_off?: number; + status?: string; + chain_id?: Network; // L2 + chain_ids?: ChainId[]; // v3 consolidated + chain_ids_with_errors?: ChainId[]; // v3 consolidated + asset_codes?: string; + next_page_cursor?: string; +} + +/** + * A message from the Zerion API indicating that assets were received. + */ +export interface AddressAssetsReceivedMessage { + payload?: { + assets?: { + asset: ZerionAsset; + quantity: string; + small_balances?: boolean; + }[]; + }; + meta?: MessageMeta; +} + +/** + * A message from the Zerion API indicating that transaction data was received. + */ +export interface TransactionsReceivedMessage { + payload?: { + transactions?: PaginatedTransactionsApiResponse[]; + }; + meta?: MessageMeta; +} + +/** + * A message from the Zerion API indicating that asset price data was received + */ +export interface AssetPricesReceivedMessage { + payload?: { + prices?: { + [id: string]: ZerionAsset; + }; + }; + meta?: MessageMeta; +} + +export type TransactionStatus = 'pending' | 'confirmed' | 'failed'; + +export type TxHash = `0x${string}`; + +type BaseTransaction = { + hash: TxHash; + nonce: number; // -2 when not from the wallet user + chainId: ChainId; + from: string; + to?: string; // it may not have a to if it's a contract deployment (covalent) + data?: string; + + changes?: Array< + | { + asset: ParsedAsset; + direction: TransactionDirection; + address_from?: string; + address_to?: string; + value?: number | string; + price?: number | string; + } + | undefined + >; + direction?: TransactionDirection; + flashbots?: boolean; + + value?: string; // network asset amount sent with the tx (like eth or matic) + fee?: string; + native?: { + // fee and value but in the user prefered currency terms (USD, EUR, etc) + value?: string; + fee?: string; + }; + + type: TransactionType; + protocol?: string; + title: string; + description?: string; + + asset?: AddysAsset; // this is the relevant tx asset, like the asset being sold/approved/withdrawn etc + approvalAmount?: 'UNLIMITED' | (string & object); + contract?: { + name: string; + iconUrl?: string; + }; + + feeType?: 'legacy' | 'eip-1559'; + gasPrice?: string; + gasLimit?: string; + baseFee?: string; +} & Partial; + +export type PendingTransaction = BaseTransaction & { + status: 'pending'; +}; + +export type MinedTransaction = BaseTransaction & { + status: 'confirmed' | 'failed'; + flashbotsStatus?: 'CANCELLED' | 'FAILED' | 'INCLUDED'; + blockNumber: number; + minedAt: number; + confirmations: number; + gasUsed: string; +}; + +export type NewTransaction = Omit & { + changes?: Array< + | { + direction: TransactionDirection; + asset: AddysAsset; // becomes a user asset when the transaction is parsed + value?: number | string; + price?: number | string; + } + | undefined + >; +}; + +const transactionTypes = { + withoutChanges: [ + 'cancel', + 'contract_interaction', + 'deployment', + 'approve', + 'revoke', + 'speed_up', + ], + withChanges: [ + 'sale', + 'bridge', + 'airdrop', + 'wrap', + 'unwrap', + 'bid', + 'burn', + 'send', + 'receive', + 'withdraw', + 'deposit', + 'mint', + 'swap', + 'borrow', + 'claim', + 'repay', + 'stake', + 'unstake', + 'purchase', + ], +} as const; + +type TransactionWithChangesType = typeof transactionTypes.withChanges[number]; +type TransactionWithoutChangesType = typeof transactionTypes.withoutChanges[number]; + +export type TransactionType = + | TransactionWithChangesType + | TransactionWithoutChangesType; + +export type TransactionDirection = 'in' | 'out' | 'self'; + +export interface ExecuteRapResponse extends TransactionResponse { + errorMessage?: string; +} + +export type TransactionApiResponse = { + status: TransactionStatus; + id: TxHash; + hash: TxHash; + network: number; + protocol?: string; + direction?: TransactionDirection; + address_from?: string; + address_to?: string; + // nonce will ALWAYS be -2 when the transaction is *not* from the wallet user + nonce: number; + changes: Array< + | { + asset: AddysAsset; + value: number | null; + direction: TransactionDirection; + address_from: string; + address_to: string; + price: number; + } + | undefined + >; + fee: { + value: number; + price: number; + + // Fee Details are only available on the tx by hash endpoint + // (won't be available on the consolidated txs list) + details?: { + type: 0 | 2; + type_label: 'legacy' | 'eip-1559'; + gas_price: number; + gas_limit: number; + gas_used: number; + max_fee: number; + max_priority_fee: number; + base_fee: number; + max_base_fee: number; + rollup_fee_details: { + l1_fee: number; + l1_fee_scalar: number; + l1_gas_price: number; + l1_gas_used: number; + l2_fee: number; + }; + }; + }; + block_confirmations?: number; // also only available on the tx by hash endpoint + meta: { + contract_name?: string; + contract_icon_url?: string; + type?: TransactionType; + action?: string; + asset?: AddysAsset; + quantity?: 'UNLIMITED' | string; + }; + block_number?: number; + mined_at?: number; +}; + +export type PaginatedTransactionsApiResponse = Omit< + TransactionApiResponse, + 'fee' +> & { fee: Omit }; From dbe39a3b79e7b15181d03b972396605e68137cda Mon Sep 17 00:00:00 2001 From: skylarbarrera Date: Tue, 30 Jan 2024 14:30:04 -0500 Subject: [PATCH 02/38] remove selectors and add types --- .../buildTransactionsSectionsSelector.tsx | 143 +++++++++++------- src/hooks/useAccountTransactions.ts | 22 +-- 2 files changed, 102 insertions(+), 63 deletions(-) diff --git a/src/helpers/buildTransactionsSectionsSelector.tsx b/src/helpers/buildTransactionsSectionsSelector.tsx index f8a02de2059..e96b14f6971 100644 --- a/src/helpers/buildTransactionsSectionsSelector.tsx +++ b/src/helpers/buildTransactionsSectionsSelector.tsx @@ -9,21 +9,28 @@ import { todayTimestamp, yesterdayTimestamp, } from './transactions'; -import { TransactionStatusTypes } from '@/entities'; +import { RainbowTransaction, TransactionStatusTypes } from '@/entities'; import * as i18n from '@/languages'; +import { RequestData } from '@/redux/requests'; +import { ThemeContextProps } from '@/theme'; +import { Contact } from '@/redux/contacts'; -const mainnetAddressesSelector = (state: any) => state.mainnetAddresses; -const accountAddressSelector = (state: any) => state.accountAddress; -const contactsSelector = (state: any) => state.contacts; -const requestsSelector = (state: any) => state.requests; -const themeSelector = (state: any) => state.theme; -const transactionsSelector = (state: any) => state.transactions; -const focusedSelector = (state: any) => state.isFocused; -const initializedSelector = (state: any) => state.initialized; -const navigateSelector = (state: any) => state.navigate; +type RainbowTransactionWithContact = RainbowTransaction & { + contact: Contact | null; +}; +type RainbowTransactionWithContactAndMainnetAddress = RainbowTransactionWithContact & { + mainnetAddress: string; + accountAddress: string; +}; // bad news -const groupTransactionByDate = ({ pending, minedAt }: any) => { +const groupTransactionByDate = ({ + pending, + minedAt, +}: { + pending: boolean; + minedAt: string; +}) => { if (pending) return i18n.t(i18n.l.transactions.pending_title); const ts = parseInt(minedAt, 10) * 1000; @@ -38,15 +45,18 @@ const groupTransactionByDate = ({ pending, minedAt }: any) => { }) ); } catch (e) { - console.log(e); return i18n.t(i18n.l.transactions.dropped_title); } }; -const addContactInfo = (contacts: any) => (txn: any) => { +const addContactInfo = (contacts: { [address: string]: Contact }) => ( + txn: RainbowTransaction +): RainbowTransaction & { + contact: Contact | null; +} => { const { from, to, status } = txn; const isSent = status === TransactionStatusTypes.sent; - const contactAddress = isSent ? to : from; + const contactAddress = (isSent ? to : from) || ''; const contact = contacts?.[contactAddress?.toLowerCase()] ?? null; return { ...txn, @@ -54,21 +64,39 @@ const addContactInfo = (contacts: any) => (txn: any) => { }; }; -const buildTransactionsSections = ( - accountAddress: any, - mainnetAddresses: any, - contacts: any, - requests: any, - theme: any, - transactions: any, - isFocused: any, - initialized: any -) => { - if (!isFocused && !initialized) { +export const buildTransactionsSections = ({ + accountAddress, + mainnetAddresses, + contacts, + requests, + theme, + isFocused, + initialized, + transactions, +}: { + accountAddress: string; + mainnetAddresses: { [uniqueId: string]: string }; + contacts: { [address: string]: Contact }; + requests: RequestData[]; + theme: ThemeContextProps; + isFocused: boolean; + initialized: boolean; + navigate: (...args: any[]) => void; + transactions: RainbowTransaction[]; +}) => { + if ((!isFocused && !initialized) || !transactions) { return { sections: [] }; } - let sectionedTransactions: any = []; + let sectionedTransactions: { + title: string; + data: RainbowTransactionWithContactAndMainnetAddress[]; + renderItem: ({ + item, + }: { + item: RainbowTransactionWithContactAndMainnetAddress; + }) => JSX.Element; + }[] = []; const transactionsWithContacts = transactions?.map(addContactInfo(contacts)); @@ -78,22 +106,46 @@ const buildTransactionsSections = ( groupTransactionByDate ); - sectionedTransactions = Object.keys(transactionsByDate) - .filter(section => section !== 'Dropped') - .map(section => ({ - data: transactionsByDate[section].map(txn => ({ - ...txn, + const test = Object.keys(transactionsByDate); + const filter = test.filter(key => key !== 'Dropped'); + const sectioned: { + title: string; + data: RainbowTransactionWithContactAndMainnetAddress[]; + renderItem: ({ + item, + }: { + item: RainbowTransactionWithContactAndMainnetAddress; + }) => JSX.Element; + }[] = filter.map((section: string) => { + const sectionData: RainbowTransactionWithContactAndMainnetAddress[] = transactionsByDate[ + section + ].map(txn => { + const typeTxn = txn as RainbowTransactionWithContact; + const res = { + ...typeTxn, + to: typeTxn.to || '', + from: typeTxn.from || '', accountAddress, - mainnetAddress: mainnetAddresses[`${txn.address}_${txn.network}`], - })), - renderItem: ({ item }: any) => ( - - ), + mainnetAddress: + mainnetAddresses[`${typeTxn.address}_${typeTxn.network}`], + }; + + return res; + }); + + return { + data: sectionData, + renderItem: ({ + item, + }: { + item: RainbowTransactionWithContactAndMainnetAddress; + }) => , title: section, - })); + }; + }); + sectionedTransactions = sectioned; const pendingSectionIndex = sectionedTransactions.findIndex( - // @ts-expect-error ts-migrate(7031) FIXME: Binding element 'title' implicitly has an 'any' ty... Remove this comment to see the full error message ({ title }) => title === 'Pending' ); if (pendingSectionIndex > 0) { @@ -122,18 +174,3 @@ const buildTransactionsSections = ( sections: requestsToApprove.concat(sectionedTransactions), }; }; - -export const buildTransactionsSectionsSelector = createSelector( - [ - accountAddressSelector, - mainnetAddressesSelector, - contactsSelector, - requestsSelector, - themeSelector, - transactionsSelector, - focusedSelector, - initializedSelector, - navigateSelector, - ], - buildTransactionsSections -); diff --git a/src/hooks/useAccountTransactions.ts b/src/hooks/useAccountTransactions.ts index 362c6380a0d..10917c84f74 100644 --- a/src/hooks/useAccountTransactions.ts +++ b/src/hooks/useAccountTransactions.ts @@ -1,6 +1,6 @@ import { useMemo } from 'react'; import { useSelector } from 'react-redux'; -import { buildTransactionsSectionsSelector } from '../helpers/buildTransactionsSectionsSelector'; +import { buildTransactionsSections } from '../helpers/buildTransactionsSectionsSelector'; import NetworkTypes from '../helpers/networkTypes'; import useAccountSettings from './useAccountSettings'; import useContacts from './useContacts'; @@ -55,27 +55,29 @@ export default function useAccountTransactions( () => pages?.flatMap(p => p.transactions) || [], [pages] ); - console.log({ transactions }); const allTransactions = useMemo( () => pendingTransactions.concat(transactions), [pendingTransactions, transactions] ); - const slicedTransaction: any[] = useMemo(() => allTransactions, [ - allTransactions, - ]); + const slicedTransaction = useMemo(() => allTransactions, [allTransactions]); const mainnetAddresses = useMemo( () => userAssets - ? slicedTransaction.reduce((acc, txn) => { - acc[`${txn.address}_${txn.network}`] = - userAssets[`${txn.address}_${txn.network}`]?.mainnet_address; + ? slicedTransaction.reduce((acc: { [key: string]: string }, txn) => { + if (txn?.network && txn?.address) { + const asset = + userAssets[`${txn.address}_${txn.network}`]?.mainnet_address; + if (asset) { + acc[`${txn.address}_${txn.network}`] = asset; + } + } return acc; }, {}) - : [], + : {}, [userAssets, slicedTransaction] ); @@ -96,7 +98,7 @@ export default function useAccountTransactions( transactions: slicedTransaction, }; - const { sections } = buildTransactionsSectionsSelector(accountState); + const { sections } = buildTransactionsSections(accountState); const remainingItemsLabel = useMemo(() => { const remainingLength = allTransactions.length - slicedTransaction.length; From ae7a07e32981c62582fcccd8e49501d1e3ff81e1 Mon Sep 17 00:00:00 2001 From: skylarbarrera Date: Wed, 31 Jan 2024 11:25:25 -0500 Subject: [PATCH 03/38] single query, type refactor, pipe it up --- src/components/activity-list/ActivityList.js | 2 +- .../coin-row/FastTransactionCoinRow.tsx | 31 +- .../coin-row/FastTransactionStatusBadge.tsx | 27 +- src/entities/index.ts | 5 +- src/entities/protocolTypes.ts | 78 +-- src/entities/transactions/index.ts | 6 +- src/entities/transactions/transaction.ts | 38 +- src/entities/transactions/transactionType.ts | 68 +- .../transactions/zerionTransaction.ts | 4 +- src/hooks/useWalletsWithBalancesAndNames.ts | 1 - src/notifications/NotificationsHandler.tsx | 3 +- src/notifications/mapTransactionsType.ts | 29 +- src/parsers/index.ts | 7 +- src/parsers/newTransaction.ts | 8 +- src/parsers/transactions.ts | 647 ++++-------------- src/redux/data.ts | 47 +- src/resources/assets/assets.ts | 4 +- .../transactions/consolidatedTransactions.ts | 22 +- src/resources/transactions/transaction.ts | 147 ++++ src/resources/transactions/types.ts | 22 +- .../TransactionDetails.tsx | 9 +- .../TransactionDetailsValueAndFeeSection.tsx | 39 +- 22 files changed, 473 insertions(+), 771 deletions(-) create mode 100644 src/resources/transactions/transaction.ts diff --git a/src/components/activity-list/ActivityList.js b/src/components/activity-list/ActivityList.js index 6de7f11be3a..24986dc5bfc 100644 --- a/src/components/activity-list/ActivityList.js +++ b/src/components/activity-list/ActivityList.js @@ -127,7 +127,7 @@ const ActivityList = ({ return ( - remainingItemsLabel && ( + true && ( { + console.log('changes: ', item?.changes?.[0]?.asset); + console.log('asset: ', item?.asset); navigation.navigate(Routes.TRANSACTION_DETAILS, { transaction: item, }); @@ -104,7 +106,7 @@ export default React.memo(function TransactionCoinRow({ testID={`${item.title}-${item.description}-${item.balance?.display}`} > - {item.nft ? ( + {item.asset?.type === 'nft' ? ( @@ -153,10 +152,10 @@ export default React.memo(function TransactionCoinRow({ ) : ( )} @@ -165,8 +164,8 @@ export default React.memo(function TransactionCoinRow({ diff --git a/src/components/coin-row/FastTransactionStatusBadge.tsx b/src/components/coin-row/FastTransactionStatusBadge.tsx index d8359c01e2b..489c7effd34 100644 --- a/src/components/coin-row/FastTransactionStatusBadge.tsx +++ b/src/components/coin-row/FastTransactionStatusBadge.tsx @@ -7,6 +7,8 @@ import { TransactionStatus, TransactionStatusTypes } from '@/entities'; import { position } from '@/styles'; import { ThemeContextProps } from '@/theme'; import * as lang from '@/languages'; +import { TransactionType } from '@/resources/transactions/types'; +import { transactionTypes } from '@/entities/transactions/transactionType'; const StatusProps = { [TransactionStatusTypes.approved]: { @@ -161,35 +163,23 @@ const sx = StyleSheet.create({ export default React.memo(function FastTransactionStatusBadge({ pending, - status, + type, style, title, colors, }: { colors: ThemeContextProps['colors']; pending: boolean; - status: keyof typeof TransactionStatusTypes; + type: TransactionType; title: string; style?: StyleProp; }) { - const isSwapping = status === TransactionStatusTypes.swapping; - const isBridging = status === TransactionStatusTypes.bridging; - let statusColor = colors.alpha(colors.blueGreyDark, 0.7); if (pending) { - if (isSwapping || isBridging) { - statusColor = colors.swapPurple; - } else { - statusColor = colors.appleBlue; - } - } else if ( - status === TransactionStatusTypes.swapped || - status === TransactionStatusTypes.bridged - ) { - statusColor = colors.swapPurple; + statusColor = colors.appleBlue; } - const showIcon = !!StatusProps[status]; + const showIcon = !!StatusProps[type]; return ( @@ -201,15 +191,14 @@ export default React.memo(function FastTransactionStatusBadge({ /> )} {showIcon && ( - + )} - {/* @ts-expect-error cant get keys*/} - {lang.t(lang.l.transactions.type[status])} + {title} ); diff --git a/src/entities/index.ts b/src/entities/index.ts index fc3f5b8f394..0b656637fdf 100644 --- a/src/entities/index.ts +++ b/src/entities/index.ts @@ -29,7 +29,7 @@ export { NativeCurrencyKeys } from './nativeCurrencyTypes'; export type { NativeCurrencyKey } from './nativeCurrencyTypes'; export type Numberish = string | number; export type { NonceManager } from './nonce'; -export { default as ProtocolTypeNames, ProtocolType } from './protocolTypes'; +export type { ProtocolType } from './protocolTypes'; export type { UniqueAsset } from './uniqueAssets'; export type { Asset, @@ -55,9 +55,6 @@ export { TransactionDirections, TransactionStatus, TransactionStatusTypes, - TransactionType, - TransactionTypes, - ZerionTransactionStatus, } from './transactions'; export type { EthereumAddress } from './wallet'; export type { diff --git a/src/entities/protocolTypes.ts b/src/entities/protocolTypes.ts index 1ab56cb3c06..509cf55fa08 100644 --- a/src/entities/protocolTypes.ts +++ b/src/entities/protocolTypes.ts @@ -1,49 +1,29 @@ -export enum ProtocolType { - aave = 'aave', - bancor = 'bancor', - compound = 'compound', - curve = 'curve', - disperse_app = 'disperse_app', - dsr = 'dsr', - dydx = 'dydx', - fulcrum = 'fulcrum', - iearn = 'iearn', - kyber = 'kyber', - maker = 'maker', - maker_dss = 'maker_dss', - one_inch = 'one_inch', - pool_together = 'pool_together', - ray = 'ray', - rainbow = 'rainbow', - set = 'set', - socket = 'socket', - synthetix = 'synthetix', - uniswap = 'uniswap', - zrx_stacking = 'zrx_stacking', - zrx_staking = 'zrx_staking', -} - -export default { - [ProtocolType.aave]: 'Aave', - [ProtocolType.bancor]: 'Bancor', - [ProtocolType.compound]: 'Compound', - [ProtocolType.curve]: 'Curve', - [ProtocolType.disperse_app]: 'Disperse', - [ProtocolType.dsr]: 'DSR', - [ProtocolType.dydx]: 'dYdX', - [ProtocolType.fulcrum]: 'Fulcrum', - [ProtocolType.iearn]: 'iEarn Finance', - [ProtocolType.kyber]: 'Kyber', - [ProtocolType.maker]: 'Maker', // old maker - [ProtocolType.maker_dss]: 'Maker', - [ProtocolType.one_inch]: '1inch', - [ProtocolType.pool_together]: 'Pool Together', - [ProtocolType.ray]: 'Ray', - [ProtocolType.rainbow]: 'Rainbow', - [ProtocolType.set]: 'Set Protocol', - [ProtocolType.socket]: 'Socket', - [ProtocolType.synthetix]: 'Synthetix', - [ProtocolType.uniswap]: 'Uniswap', - [ProtocolType.zrx_stacking]: '0x Staking', // this is here for now due to a typo from Zerion field - [ProtocolType.zrx_staking]: '0x Staking', -}; +// protocols https://github.com/rainbow-me/go-utils-lib/blob/master/pkg/enums/token_type.go#L44 +export type ProtocolType = + | 'aave-v2' + | 'balancer' + | 'curve' + | 'compound' + | 'compound-v3' + | 'maker' + | 'one-inch' + | 'piedao-pool' + | 'yearn' + | 'yearn-v2' + | 'uniswap-v2' + | 'aave-v3' + | 'harvest' + | 'lido' + | 'uniswap-v3' + | 'convex' + | 'convex-frax' + | 'pancake-swap' + | 'balancer-v2' + | 'frax' + | 'gmx' + | 'aura' + | 'pickle' + | 'yearn-v3' + | 'venus' + | 'sushiswap' + | 'socket'; diff --git a/src/entities/transactions/index.ts b/src/entities/transactions/index.ts index 89cb70a895d..22aec9abbe6 100644 --- a/src/entities/transactions/index.ts +++ b/src/entities/transactions/index.ts @@ -7,15 +7,11 @@ export { default as TransactionStatusTypes, TransactionStatus, } from './transactionStatus'; -export { - default as TransactionTypes, - TransactionType, -} from './transactionType'; + export type { ZerionTransaction, ZerionTransactionChange, } from './zerionTransaction'; -export { ZerionTransactionStatus } from './zerionTransaction'; export { default as TransactionDirections, TransactionDirection, diff --git a/src/entities/transactions/transaction.ts b/src/entities/transactions/transaction.ts index ca2c0fc344e..66003daf168 100644 --- a/src/entities/transactions/transaction.ts +++ b/src/entities/transactions/transaction.ts @@ -2,24 +2,41 @@ import { BigNumberish } from '@ethersproject/bignumber'; import { ProtocolType } from '../protocolTypes'; import { ParsedAddressAsset } from '../tokens'; import { EthereumAddress } from '../wallet'; -import { TransactionStatus } from './transactionStatus'; -import { TransactionType } from './transactionType'; import { Network } from '@/helpers/networkTypes'; import { AddCashCurrencyAsset } from '@/references'; import { ChainId, SwapType } from '@rainbow-me/swaps'; import { SwapMetadata } from '@/raps/common'; import { FiatProviderName } from '@/entities/f2c'; import { UniqueAsset } from '../uniqueAssets'; +import { ParsedAsset } from '@/resources/assets/types'; +import { + TransactionStatus, + TransactionType, +} from '@/resources/transactions/types'; + +export type TransactionDirection = 'in' | 'out' | 'self'; export interface RainbowTransaction { address?: string; + asset?: ParsedAsset | null; balance?: { amount: string; display: string; } | null; - dappName?: string; // for walletconnect + changes?: Array< + | { + asset: ParsedAddressAsset; + direction: TransactionDirection; + address_from?: string; + address_to?: string; + value?: number | string; + price?: number | string; + } + | undefined + >; + direction?: TransactionDirection; + description: string; data?: string; // for pending tx - description?: string | null; from: EthereumAddress | null; gasLimit?: BigNumberish; gasPrice?: BigNumberish; @@ -32,12 +49,13 @@ export interface RainbowTransaction { amount: string; display: string; }; - network?: Network; + network: Network; nft?: UniqueAsset; nonce?: number | null; pending?: boolean; protocol?: ProtocolType | null; flashbots?: boolean; + approvalAmount?: 'UNLIMITED' | (string & object); ensCommitRegistrationName?: string; ensRegistration?: boolean; sourceAmount?: string; // for purchases @@ -50,11 +68,11 @@ export interface RainbowTransaction { }; symbol?: string | null; timestamp?: number; // for purchases - title?: string; + title: string; to: EthereumAddress | null; transferId?: string; // for purchases txTo?: EthereumAddress | null; - type?: TransactionType; + type: TransactionType; value?: BigNumberish; // for pending tx fee?: RainbowTransactionFee; fiatProvider?: { @@ -84,6 +102,10 @@ export interface NewTransaction { amount: string | null; asset: ParsedAddressAsset | null; dappName?: string; // for walletconnect + contract?: { + name: string; + iconUrl?: string; + }; data?: string; from: EthereumAddress | null; gasLimit?: BigNumberish; @@ -99,7 +121,7 @@ export interface NewTransaction { ensCommitRegistrationName?: string; ensRegistration?: boolean; sourceAmount?: string; // for purchases - status?: TransactionStatus; + status?: 'pending'; timestamp?: number; // for purchases to: EthereumAddress | null; transferId?: string; // for purchases diff --git a/src/entities/transactions/transactionType.ts b/src/entities/transactions/transactionType.ts index b64f2275ad5..9aed150286e 100644 --- a/src/entities/transactions/transactionType.ts +++ b/src/entities/transactions/transactionType.ts @@ -1,37 +1,31 @@ -export enum TransactionType { - authorize = 'authorize', - borrow = 'borrow', - cancel = 'cancel', - contract_interaction = 'contract interaction', - deployment = 'deployment', - deposit = 'deposit', - dropped = 'dropped', - execution = 'execution', - mint = 'mint', - purchase = 'purchase', // Rainbow-specific type - receive = 'receive', - repay = 'repay', - sell = 'sell', - send = 'send', - trade = 'trade', - withdraw = 'withdraw', -} - -export default { - authorize: 'authorize', - borrow: 'borrow', - cancel: 'cancel', - contract_interaction: 'contract interaction', - deployment: 'deployment', - deposit: 'deposit', - dropped: 'dropped', - execution: 'execution', - mint: 'mint', - purchase: 'purchase', - receive: 'receive', - repay: 'repay', - sell: 'sell', - send: 'send', - trade: 'trade', - withdraw: 'withdraw', -}; +export const transactionTypes = { + withoutChanges: [ + 'cancel', + 'contract_interaction', + 'deployment', + 'approve', + 'revoke', + 'speed_up', + ], + withChanges: [ + 'sale', + 'bridge', + 'airdrop', + 'wrap', + 'unwrap', + 'bid', + 'burn', + 'send', + 'receive', + 'withdraw', + 'deposit', + 'mint', + 'swap', + 'borrow', + 'claim', + 'repay', + 'stake', + 'unstake', + 'purchase', + ], +} as const; diff --git a/src/entities/transactions/zerionTransaction.ts b/src/entities/transactions/zerionTransaction.ts index 4e61e465956..1bd60d78b8d 100644 --- a/src/entities/transactions/zerionTransaction.ts +++ b/src/entities/transactions/zerionTransaction.ts @@ -1,7 +1,7 @@ +import { TransactionType } from '@/resources/transactions/types'; import { ProtocolType } from '../protocolTypes'; import { ZerionAsset } from '../tokens'; import { TransactionDirection } from './transactionDirection'; -import { TransactionType } from './transactionType'; interface ZerionTransactionFee { price: number; @@ -14,7 +14,7 @@ interface ZerionTransactionMeta { asset?: ZerionAsset; } -export enum ZerionTransactionStatus { +enum ZerionTransactionStatus { confirmed = 'confirmed', failed = 'failed', pending = 'pending', diff --git a/src/hooks/useWalletsWithBalancesAndNames.ts b/src/hooks/useWalletsWithBalancesAndNames.ts index 85aefbc7b75..d44a9793942 100644 --- a/src/hooks/useWalletsWithBalancesAndNames.ts +++ b/src/hooks/useWalletsWithBalancesAndNames.ts @@ -12,7 +12,6 @@ export default function useWalletsWithBalancesAndNames() { mapValues(wallets, wallet => { const updatedAccounts = (wallet.addresses ?? []).map(account => ({ ...account, - // @ts-expect-error ts-migrate(2571) FIXME: Object is of type 'unknown'. balance: walletBalances[account.address], ens: walletNames[account.address], })); diff --git a/src/notifications/NotificationsHandler.tsx b/src/notifications/NotificationsHandler.tsx index a557e48d7de..985abb03e69 100644 --- a/src/notifications/NotificationsHandler.tsx +++ b/src/notifications/NotificationsHandler.tsx @@ -218,7 +218,6 @@ export const NotificationsHandler = ({ walletReady }: Props) => { type: mapNotificationTransactionType(data.transaction_type), network, hash: rpcTransaction.hash, - status: TransactionStatus.unknown, amount: rpcTransaction.value.toString(), nonce: rpcTransaction.nonce, from: rpcTransaction.from, @@ -230,7 +229,7 @@ export const NotificationsHandler = ({ walletReady }: Props) => { gasPrice: rpcTransaction.gasPrice, data: rpcTransaction.data, }; - + return; const parsedTransaction = await parseNewTransaction( newTransactionDetails, nativeCurrency diff --git a/src/notifications/mapTransactionsType.ts b/src/notifications/mapTransactionsType.ts index e16be669bcc..353194543ac 100644 --- a/src/notifications/mapTransactionsType.ts +++ b/src/notifications/mapTransactionsType.ts @@ -1,8 +1,5 @@ -import { - NotificationTransactionTypes, - NotificationTransactionTypesType, -} from '@/notifications/types'; -import { TransactionType } from '@/entities'; +import { NotificationTransactionTypesType } from '@/notifications/types'; +import { TransactionType } from '@/resources/transactions/types'; /** * Mapping of notification backend transaction types sent in notification @@ -11,25 +8,5 @@ import { TransactionType } from '@/entities'; export function mapNotificationTransactionType( notificationTransactionType: NotificationTransactionTypesType ): TransactionType { - switch (notificationTransactionType) { - case NotificationTransactionTypes.approve: - return TransactionType.authorize; - case NotificationTransactionTypes.cancel: - return TransactionType.cancel; - case NotificationTransactionTypes.deposit: - return TransactionType.deposit; - case NotificationTransactionTypes.purchase: - return TransactionType.purchase; - case NotificationTransactionTypes.receive: - return TransactionType.receive; - case NotificationTransactionTypes.send: - case NotificationTransactionTypes.burn: - return TransactionType.send; - case NotificationTransactionTypes.swap: - return TransactionType.trade; - case NotificationTransactionTypes.withdraw: - return TransactionType.withdraw; - default: - return TransactionType.contract_interaction; - } + return notificationTransactionType; } diff --git a/src/parsers/index.ts b/src/parsers/index.ts index ba147824cea..dd1a0a99b86 100644 --- a/src/parsers/index.ts +++ b/src/parsers/index.ts @@ -21,9 +21,4 @@ export { } from './gas'; export { parseNewTransaction } from './newTransaction'; export { getRequestDisplayDetails } from './requests'; -export { - parseTransactions, - getTitle, - getDescription, - getTransactionLabel, -} from './transactions'; +export { getDescription } from './transactions'; diff --git a/src/parsers/newTransaction.ts b/src/parsers/newTransaction.ts index bf2d52a9dd4..f7af679e8f9 100644 --- a/src/parsers/newTransaction.ts +++ b/src/parsers/newTransaction.ts @@ -86,18 +86,12 @@ export const parseNewTransaction = async ( const nftName = type === TransactionType.authorize ? nft?.collection.name : nft?.name; - const description = getDescription({ - name: nftName ?? asset?.name ?? null, - status, - type, - }); + const description = 'yo it me'; return { address: asset?.address ?? ETH_ADDRESS, balance, - dappName, data, - description, ensCommitRegistrationName, ensRegistration, flashbots, diff --git a/src/parsers/transactions.ts b/src/parsers/transactions.ts index 35e3ec5347b..ca7c0282888 100644 --- a/src/parsers/transactions.ts +++ b/src/parsers/transactions.ts @@ -1,6 +1,7 @@ import { compact, isEmpty, + isObject, orderBy, partition, reverse, @@ -14,24 +15,22 @@ import { AssetType, EthereumAddress, NativeCurrencyKey, - ProtocolType, - ProtocolTypeNames, RainbowTransaction, TransactionDirection, TransactionStatus, - TransactionType, ZerionAsset, ZerionTransaction, ZerionTransactionChange, - ZerionTransactionStatus, } from '@/entities'; import { getTransactionMethodName } from '@/handlers/transactions'; import { isL2Network } from '@/handlers/web3'; import { Network } from '@/helpers/networkTypes'; import { ETH_ADDRESS } from '@/references'; import { + convertAmountAndPriceToNativeDisplay, convertRawAmountToBalance, convertRawAmountToNativeDisplay, + toFixedDecimals, } from '@/helpers/utilities'; import { ethereumUtils, getTokenMetadata } from '@/utils'; import { @@ -40,9 +39,42 @@ import { } from '@rainbow-me/swaps'; import { RainbowTransactionFee } from '@/entities/transactions/transaction'; import * as i18n from '@/languages'; +import { parseAddressAsset, parseAsset } from '@/resources/assets/assets'; +import { AddysAsset, ParsedAsset } from '@/resources/assets/types'; +import { transactionTypes } from '@/entities/transactions/transactionType'; +import { + PaginatedTransactionsApiResponse, + TransactionApiResponse, + TransactionChange, + TransactionChanges, + TransactionType, + TransactionWithChangesType, +} from '@/resources/transactions/types'; +import BigNumber from 'bignumber.js'; const LAST_TXN_HASH_BUFFER = 20; +const TransactionOutTypes = [ + 'burn', + 'send', + 'deposit', + 'repay', + 'stake', + 'sale', + 'bridge', + 'bid', + 'speed_up', + 'revoke', + 'deployment', + 'contract_interaction', +] as const; + +export const getDirection = (type: TransactionType) => { + //@ts-expect-error - Ts doesnt like the weird type structure here + if (TransactionOutTypes.includes(type as TransactionType)) return 'out'; + return 'in'; +}; + const dataFromLastTxHash = ( transactionData: ZerionTransaction[], transactions: RainbowTransaction[] @@ -63,379 +95,108 @@ const dataFromLastTxHash = ( return transactionData; }; -export const parseTransactions = async ( - transactionData: ZerionTransaction[], - accountAddress: EthereumAddress, - nativeCurrency: NativeCurrencyKey, - existingTransactions: RainbowTransaction[], - pendingTransactions: RainbowTransaction[], - purchaseTransactions: any, - network: Network, - appended = false +export const getAssetFromChanges = ( + changes: TransactionChanges, + type: TransactionType ) => { - /** - * This is empty because it previously pulled in data from our `addCash` - * reducer, which was deprecated and removed. - */ - const purchaseTransactionHashes: RainbowTransaction[] = []; - - // pending crosschain swaps transactions now depends on bridge status API - // so we need to persist pending txs until bridge is done even tho the tx - // on chain was confirmed https://github.com/rainbow-me/rainbow/pull/4189 - const pendingCrosschainSwapsTransactionHashes = pendingTransactions - .filter(txn => txn.protocol === ProtocolType.socket) - .map(txn => ethereumUtils.getHash(txn)); - const filteredExistingTransactions = existingTransactions.filter( - txn => - !pendingCrosschainSwapsTransactionHashes.includes( - ethereumUtils.getHash(txn) - ) - ); - const [ - allL2Transactions, - existingWithoutL2, - ] = partition(filteredExistingTransactions, tx => - isL2Network(tx.network || '') - ); - - const data = appended - ? transactionData - : dataFromLastTxHash(transactionData, existingWithoutL2); - - const newTransactionPromises = data.map(txn => - parseTransaction( - txn, - nativeCurrency, - // @ts-expect-error ts-migrate(100002) FIXME - purchaseTransactionHashes, - network - ) - ); - - const newTransactions = await Promise.all(newTransactionPromises); - const parsedNewTransactions = newTransactions.flat(); - - const updatedResults = parsedNewTransactions.concat( - existingTransactions, - allL2Transactions - ); - - const potentialNftTransaction = appended - ? parsedNewTransactions.find(txn => { - return ( - !txn.protocol && - (txn.type === TransactionType.send || - txn.type === TransactionType.receive) && - txn.symbol !== 'ETH' - ); - }) - : null; - - const dedupedResults = uniqBy(updatedResults, txn => txn.hash); - - const orderedDedupedResults = orderBy( - dedupedResults, - ['minedAt', 'nonce'], - ['desc', 'desc'] - ); - - return { - parsedTransactions: orderedDedupedResults, - potentialNftTransaction, - }; + if (type === 'sale') return changes?.find(c => c?.direction === 'out')?.asset; + return changes?.[0]?.asset; }; -const transformTradeRefund = ( - internalTransactions: ZerionTransactionChange[] -) => { - const [txnsOut, txnsIn] = partition( - internalTransactions, - txn => txn?.direction === TransactionDirection.out - ); - const isSuccessfulSwap = - txnsOut.length === 1 && (txnsIn.length === 1 || txnsIn.length === 2); - if (!isSuccessfulSwap) return internalTransactions; - - const txnOut = txnsOut[0]; - const txnIn = txnsIn.find( - txn => txn?.asset?.asset_code !== txnOut?.asset?.asset_code - ); - const refund = txnsIn.find( - txn => txn?.asset?.asset_code === txnOut?.asset?.asset_code - ); - let updatedOut = txnOut; - if (refund?.value && txnOut?.value) { - updatedOut = { - ...txnOut, - value: txnOut.value - refund.value, - }; - } - return compact([updatedOut, txnIn]); -}; - -const overrideFailedExecution = (txn: ZerionTransaction): ZerionTransaction => { - const isFailedExecution = - isEmpty(txn?.changes) && - txn.status === ZerionTransactionStatus.failed && - txn.type === TransactionType.execution && - txn.direction === TransactionDirection.out; - if (!isFailedExecution) return txn; +export const parseTransaction = async ( + transaction: TransactionApiResponse, + nativeCurrency: NativeCurrencyKey +): Promise => { + const { status, hash, meta, nonce, protocol } = transaction; - const newTxn = { - ...txn, - }; - const assetInternalTransaction = { - address_from: txn.address_from, - address_to: txn.address_to, - asset: { - asset_code: ETH_ADDRESS, - decimals: 18, - name: 'Ethereum', - symbol: 'ETH', - type: AssetType.eth, - }, - direction: TransactionDirection.out, - value: 0, + let txn = { + ...transaction, }; - newTxn.changes = [assetInternalTransaction]; - return newTxn; -}; + const changes: TransactionChanges = txn.changes.map(change => { + if (change) { + return { + ...change, + asset: parseAddressAsset({ + assetData: { + asset: change.asset, + quantity: change.value?.toString() || '0', + }, + }), + value: change.value || undefined, + }; + } + }); -const overrideAuthorizations = (txn: ZerionTransaction): ZerionTransaction => { - const isEmptyAuth = - isEmpty(txn?.changes) && txn.type === TransactionType.authorize; - if (!isEmptyAuth) return txn; + const type = isValidTransactionType(meta.type) + ? meta.type + : 'contract_interaction'; - const newTxn = { - ...txn, - }; - const approveInternalTransaction = { - address_from: txn.address_from, - address_to: txn.address_to, - asset: txn?.meta?.asset as ZerionAsset, - direction: TransactionDirection.out, - value: 0, - }; - newTxn.changes = [approveInternalTransaction]; - return newTxn; -}; + if (type === 'mint') { + console.log('MINT'); + changes?.map(change => { + console.log(change?.asset); + }); + } + const asset: RainbowTransaction['asset'] = meta.asset?.asset_code + ? parseAsset({ asset: meta.asset, address: meta.asset.asset_code }) + : getAssetFromChanges(changes, type); -const overrideSelfWalletConnect = ( - txn: ZerionTransaction -): ZerionTransaction => { - // logic below: prevent sending a WalletConnect 0 amount to be ignored - const isSelfWalletConnect = - isEmpty(txn?.changes) && - txn.type === TransactionType.execution && - txn.direction === TransactionDirection.self; - if (!isSelfWalletConnect) return txn; + const direction = txn.direction || getDirection(type); - const newTxn = { - ...txn, - }; - const ethInternalTransaction = { - address_from: txn.address_from, - address_to: txn.address_to, - asset: { - asset_code: ETH_ADDRESS, - decimals: 18, - name: 'Ethereum', - symbol: 'ETH', - type: AssetType.eth, - }, - direction: TransactionDirection.out, - value: 0, - }; - newTxn.changes = [ethInternalTransaction]; - return newTxn; -}; + const description = getDescription(asset, type, meta); -const overrideTradeRefund = (txn: ZerionTransaction): ZerionTransaction => { - if (txn.type !== TransactionType.trade) return txn; - return { - ...txn, - changes: transformTradeRefund(txn?.changes), - }; -}; + const nativeAsset = changes.find(change => change?.asset.isNativeAsset); + const nativeAssetPrice = nativeAsset?.price?.toString() || '0'; -const swapAddresses = ((): Set => { - const contractAddresses = new Set( - Array.from(SOCKET_REGISTRY_CONTRACT_ADDRESSESS.values()).map(addr => - addr.toLowerCase() - ) + const value = toFixedDecimals( + nativeAsset?.value || '', + nativeAsset?.asset?.decimals || 18 ); - contractAddresses.add(RAINBOW_ROUTER_CONTRACT_ADDRESS.toLowerCase()); - - return contractAddresses; -})(); - -const overrideSwap = (tx: ZerionTransaction): ZerionTransaction => { - const to = tx.address_to?.toLowerCase() || ''; - - if (swapAddresses.has(to)) { - return { ...tx, type: TransactionType.trade }; - } - return tx; -}; - -const parseTransactionWithEmptyChanges = async ( - txn: ZerionTransaction, - nativeCurrency: NativeCurrencyKey, - network: Network -) => { - const methodName = await getTransactionMethodName(txn); - const updatedAsset = { - address: ETH_ADDRESS, - decimals: 18, - name: 'ethereum', - symbol: 'ETH', - }; - const priceUnit = 0; - const valueUnit = 0; - const nativeDisplay = convertRawAmountToNativeDisplay( - 0, - 18, - priceUnit, + // this is probably wrong, need to revisit + const native = convertAmountAndPriceToNativeDisplay( + value, + nativeAssetPrice, nativeCurrency ); - const fee = - network === Network.mainnet - ? getTransactionFee(txn, nativeCurrency) - : undefined; - return [ - { - address: ETH_ADDRESS, - balance: isL2Network(network) - ? { amount: '', display: '-' } - : convertRawAmountToBalance(valueUnit, updatedAsset), - description: methodName || i18n.t(i18n.l.transactions.signed), - from: txn.address_from, - hash: `${txn.hash}-${0}`, - minedAt: txn.mined_at, - name: methodName || i18n.t(i18n.l.transactions.signed), - native: nativeDisplay, - network, - nonce: txn.nonce, - pending: false, - protocol: txn.protocol, - status: TransactionStatus.contract_interaction, - symbol: 'contract', - title: i18n.t(i18n.l.transactions.contract_interaction), - to: txn.address_to, - type: TransactionType.contract_interaction, - fee, - }, - ]; -}; - -export const parseTransaction = async ( - transaction: ZerionTransaction, - nativeCurrency: NativeCurrencyKey, - purchaseTransactionsHashes: string[], - network: Network -): Promise => { - let txn = { - ...transaction, - }; - txn = overrideFailedExecution(txn); - txn = overrideAuthorizations(txn); - txn = overrideSelfWalletConnect(txn); - txn = overrideTradeRefund(txn); - txn = overrideSwap(txn); - - if (txn.changes.length) { - const fee = - network === Network.mainnet - ? getTransactionFee(txn, nativeCurrency) - : undefined; - const internalTransactions = txn.changes.map( - (internalTxn, index): RainbowTransaction => { - const address = internalTxn?.asset?.asset_code?.toLowerCase() ?? ''; - const metadata = getTokenMetadata(address); - const updatedAsset = { - address, - decimals: internalTxn?.asset?.decimals, - name: internalTxn?.asset?.name, - symbol: toUpper(internalTxn?.asset?.symbol ?? ''), - ...metadata, - }; - const priceUnit = - internalTxn.price ?? internalTxn?.asset?.price?.value ?? 0; - const valueUnit = internalTxn.value || 0; - const nativeDisplay = convertRawAmountToNativeDisplay( - valueUnit, - updatedAsset.decimals, - priceUnit, - nativeCurrency - ); - if (purchaseTransactionsHashes.includes(txn.hash.toLowerCase())) { - txn.type = TransactionType.purchase; - } + const fee = getTransactionFee(txn, nativeCurrency); - const status = getTransactionLabel({ - direction: internalTxn.direction || txn.direction, - pending: false, - protocol: txn.protocol, - status: txn.status, - type: txn.type, - }); - - const title = getTitle({ - protocol: txn.protocol, - status, - type: txn.type, - }); - - const description = getDescription({ - name: updatedAsset.name, - status, - type: txn.type, - }); + const contract = meta.contract_name && { + name: meta.contract_name, + iconUrl: meta.contract_icon_url, + }; - return { - address: - updatedAsset.address.toLowerCase() === ETH_ADDRESS - ? ETH_ADDRESS - : updatedAsset.address, - balance: convertRawAmountToBalance(valueUnit, updatedAsset), - description, - from: internalTxn.address_from ?? txn.address_from, - hash: `${txn.hash}-${index}`, - minedAt: txn.mined_at, - name: updatedAsset.name, - native: isL2Network(network) - ? { amount: '', display: '' } - : nativeDisplay, - network, - nonce: txn.nonce, - pending: false, - protocol: txn.protocol, - status, - symbol: updatedAsset.symbol, - title, - to: internalTxn.address_to ?? txn.address_to, - type: txn.type, - fee, - }; - } - ); - return reverse(internalTransactions); - } - const parsedTransaction = await parseTransactionWithEmptyChanges( - txn, - nativeCurrency, - network - ); - return parsedTransaction; + return { + from: txn.address_from, + to: txn.address_to, + title: `${type}.${status}`, + description, + hash, + network: txn.network, + status, + nonce, + protocol, + type, + direction, + value, + changes, + asset, + approvalAmount: meta.quantity, + minedAt: txn.mined_at, + blockNumber: txn.block_number, + confirmations: txn.block_confirmations, + contract, + native, + fee, + } as RainbowTransaction; }; /** * Helper for retrieving tx fee sent by zerion, works only for mainnet only */ const getTransactionFee = ( - txn: ZerionTransaction, + txn: TransactionApiResponse, nativeCurrency: NativeCurrencyKey ): RainbowTransactionFee | undefined => { if (txn.fee === null || txn.fee === undefined) { @@ -462,163 +223,29 @@ const getTransactionFee = ( }; }; -export const getTitle = ({ - protocol, - status, - type, -}: { - protocol: ProtocolType | null | undefined; - status: TransactionStatus; - type?: TransactionType; -}) => { - if ( - protocol && - (type === TransactionType.deposit || type === TransactionType.withdraw) - ) { - if ( - status === TransactionStatus.deposited || - status === TransactionStatus.withdrew || - status === TransactionStatus.sent || - status === TransactionStatus.received - ) { - return ProtocolTypeNames?.[protocol]; - } - } - return upperFirst(status); -}; +export const getDescription = ( + asset: ParsedAsset | undefined, + type: TransactionType, + meta: PaginatedTransactionsApiResponse['meta'] +) => { + if (asset?.type === 'nft') return asset.symbol || asset.name; + if (type === 'cancel') return i18n.t('transactions.cancelled'); -export const getDescription = ({ - name, - status, - type, -}: { - name: string | null; - status: TransactionStatus; - type: TransactionType; -}) => { - switch (type) { - case TransactionType.deposit: - return status === TransactionStatus.depositing || - status === TransactionStatus.sending - ? name - : i18n.t(i18n.l.transactions.deposited_with_token, { name: name! }); - case TransactionType.withdraw: - return status === TransactionStatus.withdrawing || - status === TransactionStatus.receiving - ? name - : i18n.t(i18n.l.transactions.withdrew_with_token, { name: name! }); - default: - return name; - } + return asset?.name || meta.action; }; -export const getTransactionLabel = ({ - direction, - pending, - protocol, - status, - type, -}: { - direction: TransactionDirection | null; - pending: boolean; - protocol: ProtocolType | null | undefined; - status: ZerionTransactionStatus | TransactionStatus; - type?: TransactionType; -}) => { - if (status === TransactionStatus.cancelling) - return TransactionStatus.cancelling; - - if (status === TransactionStatus.cancelled) - return TransactionStatus.cancelled; - - if ( - status === TransactionStatus.selling || - (type === TransactionType.sell && pending) - ) { - return TransactionStatus.selling; - } - - if ( - status === TransactionStatus.sold || - (type === TransactionType.sell && !pending) - ) - return TransactionStatus.sold; - - if ( - status === TransactionStatus.minting || - (type === TransactionType.mint && pending) - ) { - return TransactionStatus.minting; - } - - if ( - status === TransactionStatus.minted || - (type === TransactionType.mint && !pending) - ) - return TransactionStatus.minted; - - if (status === TransactionStatus.speeding_up) - return TransactionStatus.speeding_up; - - if (pending && type === TransactionType.purchase) - return TransactionStatus.purchasing; - - const isFromAccount = direction === TransactionDirection.out; - const isToAccount = direction === TransactionDirection.in; - const isSelf = direction === TransactionDirection.self; - - if (pending && type === TransactionType.authorize) - return TransactionStatus.approving; - - if (pending && type === TransactionType.deposit) { - if (protocol === ProtocolType.compound) { - return TransactionStatus.depositing; - } else { - return TransactionStatus.sending; - } - } - - if (pending && type === TransactionType.withdraw) { - if (protocol === ProtocolType.compound) { - return TransactionStatus.withdrawing; - } else { - return TransactionStatus.receiving; - } - } - - if (pending && isFromAccount) return TransactionStatus.sending; - if (pending && isToAccount) return TransactionStatus.receiving; - - if (status === TransactionStatus.failed) return TransactionStatus.failed; - if (status === TransactionStatus.dropped) return TransactionStatus.dropped; - - if (type === TransactionType.trade && isFromAccount) - return TransactionStatus.swapped; - - if (type === TransactionType.authorize) return TransactionStatus.approved; - if (type === TransactionType.purchase) return TransactionStatus.purchased; - if (type === TransactionType.cancel) return TransactionStatus.cancelled; - - if (type === TransactionType.deposit) { - if (protocol === ProtocolType.compound) { - return TransactionStatus.deposited; - } else { - return TransactionStatus.sent; - } - } - - if (type === TransactionType.withdraw) { - if (protocol === ProtocolType.compound) { - return TransactionStatus.withdrew; - } else { - return TransactionStatus.received; - } - } - - if (isSelf) return TransactionStatus.self; - - if (isFromAccount) return TransactionStatus.sent; - if (isToAccount) return TransactionStatus.received; - - return TransactionStatus.unknown; -}; +export const isValidTransactionType = ( + type: string | undefined +): type is TransactionType => + !!type && + //@ts-expect-error - Ts doesnt like the weird type structure here + (transactionTypes.withChanges.includes(type as TransactionType) || + //@ts-expect-error - Ts doesnt like the weird type structure here + transactionTypes.withoutChanges.includes(type as TransactionType) || + type === ('sale' as TransactionType)); + +export const transactionTypeShouldHaveChanges = ( + type: TransactionType +): type is TransactionWithChangesType => + //@ts-expect-error - Ts doesnt like the weird type structure here + transactionTypes.withChanges.includes(type); diff --git a/src/redux/data.ts b/src/redux/data.ts index 6b4f9da73f4..0b0d164eae6 100644 --- a/src/redux/data.ts +++ b/src/redux/data.ts @@ -32,7 +32,7 @@ import WalletTypes from '@/helpers/walletTypes'; import { Navigation } from '@/navigation'; import { triggerOnSwipeLayout } from '@/navigation/onNavigationStateChange'; import { Network } from '@/helpers/networkTypes'; -import { parseAsset, parseNewTransaction, parseTransactions } from '@/parsers'; +import { parseAsset, parseNewTransaction } from '@/parsers'; import { ETH_ADDRESS } from '@/references'; import Routes from '@/navigation/routesNames'; import { ethereumUtils, isLowerCaseMatch } from '@/utils'; @@ -453,6 +453,7 @@ export const transactionsReceived = ( >, getState: AppGetState ) => { + return; loggr.debug('transactionsReceived', { message: { ...message, @@ -704,6 +705,7 @@ export const dataAddNewTransaction = ( >, getState: AppGetState ) => { + return; loggr.debug('dataAddNewTransaction', {}, loggr.DebugContext.f2c); const { pendingTransactions } = getState().data; @@ -854,6 +856,7 @@ export const dataWatchPendingTransactions = ( minedAt: null, pending: true, }; + return; try { logger.log('Checking pending tx with hash', txHash); const p = @@ -880,20 +883,8 @@ export const dataWatchPendingTransactions = ( if (tx?.ensRegistration) { fetchWalletENSDataAfterRegistration(); } - const transactionStatus = await getTransactionReceiptStatus( - updatedPendingTransaction, - nonceAlreadyIncluded, - txObj - ); - // approvals are not via socket so we dont want to check their status with them. - const isApproveTx = - transactionStatus === TransactionStatus.approved || - transactionStatus === TransactionStatus.approving; - if ( - updatedPendingTransaction?.swap?.type === SwapType.crossChain && - !isApproveTx - ) { + if (updatedPendingTransaction?.swap?.type === SwapType.crossChain) { pendingTransactionData = await getTransactionSocketStatus( updatedPendingTransaction ); @@ -936,31 +927,6 @@ export const dataWatchPendingTransactions = ( }) ); - if (txStatusesDidChange) { - const { accountAddress, network } = getState().settings; - const [newDataTransactions, pendingTransactions] = partition( - updatedPendingTransactions.filter( - ({ status }) => status !== TransactionStatus.unknown - ), - tx => !tx.pending - ); - dispatch({ - payload: pendingTransactions, - type: DATA_UPDATE_PENDING_TRANSACTIONS_SUCCESS, - }); - saveLocalPendingTransactions(pendingTransactions, accountAddress, network); - - const { transactions } = getState().data; - const updatedTransactions = newDataTransactions.concat(transactions); - dispatch({ - payload: updatedTransactions, - type: DATA_LOAD_TRANSACTIONS_SUCCESS, - }); - saveLocalTransactions(updatedTransactions, accountAddress, network); - if (!pendingTransactions?.length) { - return true; - } - } return false; }; @@ -987,6 +953,7 @@ export const dataUpdateTransaction = ( >, getState: AppGetState ) => { + return; const { pendingTransactions } = getState().data; const allOtherTx = pendingTransactions.filter(tx => tx.hash !== txHash); @@ -1026,6 +993,7 @@ export const checkPendingTransactionsOnInitialize = ( dispatch: ThunkDispatch, getState: AppGetState ) => { + return; const { accountAddress: currentAccountAddress, network, @@ -1068,6 +1036,7 @@ export const watchPendingTransactions = ( dispatch: ThunkDispatch, getState: AppGetState ) => { + return; pendingTransactionsHandle && clearTimeout(pendingTransactionsHandle); if (remainingTries === 0) return; diff --git a/src/resources/assets/assets.ts b/src/resources/assets/assets.ts index cde10c8470b..5ab35149319 100644 --- a/src/resources/assets/assets.ts +++ b/src/resources/assets/assets.ts @@ -84,7 +84,7 @@ export function parseAsset({ // networks: asset?.networks, price: asset?.price, symbol: asset?.symbol, - type: assetType, + type: asset.type || 'token', uniqueId, }; @@ -106,7 +106,7 @@ export function parseAddressAsset({ return { ...parsedAsset, balance: convertRawAmountToBalance(quantity, asset), - type: asset.network === Network.mainnet ? AssetType.token : asset.network, + type: asset.type, }; } diff --git a/src/resources/transactions/consolidatedTransactions.ts b/src/resources/transactions/consolidatedTransactions.ts index 457e381db5f..5e733458ca0 100644 --- a/src/resources/transactions/consolidatedTransactions.ts +++ b/src/resources/transactions/consolidatedTransactions.ts @@ -7,15 +7,14 @@ import { queryClient, } from '@/react-query'; import { NativeCurrencyKey, RainbowTransaction } from '@/entities'; -import { Network } from '@/networks/types'; -import { TransactionsReceivedMessage } from './types'; +import { TransactionApiResponse, TransactionsReceivedMessage } from './types'; import { RainbowError, logger } from '@/logger'; import { rainbowFetch } from '@/rainbow-fetch'; import { ADDYS_API_KEY } from 'react-native-dotenv'; import { RainbowNetworks } from '@/networks'; import { parseTransaction } from '@/parsers/transactions'; -const CONSOLIDATED_TRANSACTIONS_INTERVAL = 3000; +const CONSOLIDATED_TRANSACTIONS_INTERVAL = 30000; const CONSOLIDATED_TRANSACTIONS_TIMEOUT = 20000; // /////////////////////////////////////////////// @@ -36,7 +35,7 @@ export const consolidatedTransactionsQueryKey = ({ chainIds, }: ConsolidatedTransactionsArgs) => createQueryKey( - 'consolidatedTransactions', + 'consolidatedTransactionss', { address, currency, chainIds }, { persisterVersion: 1 } ); @@ -126,17 +125,18 @@ type ConsolidatedTransactionsResult = { async function parseConsolidatedTransactions( message: TransactionsReceivedMessage, currency: NativeCurrencyKey -) { +): Promise { const data = message?.payload?.transactions || []; - const parsedTransactionPromises = data - .map((tx: any) => - parseTransaction(tx, currency, [], tx?.network ?? Network.mainnet) - ) - .filter(Boolean); + + const parsedTransactionPromises = data.map((tx: TransactionApiResponse) => + parseTransaction(tx, currency) + ); + // Filter out undefined values immediately const parsedConsolidatedTransactions = ( await Promise.all(parsedTransactionPromises) - ).flat(); + ).flat(); // Filter out any remaining undefined values + return parsedConsolidatedTransactions; } diff --git a/src/resources/transactions/transaction.ts b/src/resources/transactions/transaction.ts new file mode 100644 index 00000000000..226dd061935 --- /dev/null +++ b/src/resources/transactions/transaction.ts @@ -0,0 +1,147 @@ +import { NativeCurrencyKey, RainbowTransaction } from '@/entities'; +import { + createQueryKey, + queryClient, + QueryConfig, + QueryFunctionArgs, + QueryFunctionResult, +} from '@/react-query'; +import { useQuery } from '@tanstack/react-query'; +import { + consolidatedTransactionsQueryFunction, + consolidatedTransactionsQueryKey, +} from './consolidatedTransactions'; +import { useAccountSettings } from '@/hooks'; +import { RainbowNetworks, getNetworkObj } from '@/networks'; +import { rainbowFetch } from '@/rainbow-fetch'; +import { ADDYS_API_KEY } from 'react-native-dotenv'; +import { parseTransaction } from '@/parsers/transactions'; +import { Network } from '@/networks/types'; +import { RainbowError, logger } from '@/logger'; + +type ConsolidatedTransactionsResult = QueryFunctionResult< + typeof consolidatedTransactionsQueryFunction +>; + +export type TransactionArgs = { + hash: string; + address: string; + currency: NativeCurrencyKey; + network: Network; +}; + +type TransactionQueryKey = ReturnType; + +export type BackendTransactionArgs = { + hash: string; + network: Network; + enabled: boolean; +}; + +export const transactionQueryKey = ({ + hash, + address, + currency, + network, +}: TransactionArgs) => + createQueryKey( + 'transactions', + { address, currency, network, hash }, + { persisterVersion: 1 } + ); + +export const fetchTransaction = async ({ + queryKey: [{ address, currency, network, hash }], +}: QueryFunctionArgs) => { + try { + const chainId = getNetworkObj(network).id; + const url = `https://addys.p.rainbow.me/v3/${chainId}/${address}/transactions/${hash}`; + const response = await rainbowFetch(url, { + method: 'get', + params: { + currency: currency.toLowerCase(), + }, + timeout: 20000, + headers: { + Authorization: `Bearer ${ADDYS_API_KEY}`, + }, + }); + const tx = response?.data?.payload?.transaction || []; + + const parsedTx = await parseTransaction(tx, currency); + if (!parsedTx) throw new Error('Failed to parse transaction'); + return parsedTx; + } catch (e) { + logger.error(new RainbowError('fetchTransaction: '), { + message: (e as Error)?.message, + }); + } +}; + +type PaginatedTransactions = { pages: ConsolidatedTransactionsResult[] }; + +export function useBackendTransaction({ + hash, + network, +}: BackendTransactionArgs) { + const { accountAddress, nativeCurrency } = useAccountSettings(); + + const chainIds = RainbowNetworks.filter( + network => network.enabled && network.networkType !== 'testnet' + ).map(network => network.id); + + const paginatedTransactionsKey = consolidatedTransactionsQueryKey({ + address: accountAddress, + currency: nativeCurrency, + chainIds, + }); + + const params: TransactionArgs = { + hash: hash, + address: accountAddress, + currency: nativeCurrency, + network: network, + }; + + return useQuery(transactionQueryKey(params), fetchTransaction, { + enabled: !!hash && !!accountAddress && !!network, + initialData: () => { + const queryData = queryClient.getQueryData( + paginatedTransactionsKey + ); + const pages = queryData?.pages || []; + for (const page of pages) { + const tx = page.transactions.find(tx => tx.hash === hash); + if (tx) { + return tx; + } + } + }, + initialDataUpdatedAt: () => + queryClient.getQueryState(paginatedTransactionsKey)?.dataUpdatedAt, + }); +} + +export const useTransaction = ({ + network, + hash, +}: { + network: Network; + hash: string; +}) => { + const { + data: backendTransaction, + isLoading: backendTransactionIsLoading, + isFetched: backendTransactionIsFetched, + } = useBackendTransaction({ + hash, + network, + enabled: !!hash && !!network, + }); + + return { + data: backendTransaction, + isLoading: backendTransactionIsLoading, + isFetched: backendTransactionIsFetched, + }; +}; diff --git a/src/resources/transactions/types.ts b/src/resources/transactions/types.ts index 88baf90607f..dd4c636d716 100644 --- a/src/resources/transactions/types.ts +++ b/src/resources/transactions/types.ts @@ -9,6 +9,20 @@ import { Network } from '@/networks/types'; import { AddysAsset, ParsedAsset } from '../assets/types'; type ChainId = number; + +export type TransactionStatus = 'pending' | 'confirmed' | 'failed'; + +export type TransactionChanges = ( + | { + asset: ParsedAsset; + value: number | undefined; + direction: TransactionDirection; + address_from: string; + address_to: string; + price: number; + } + | undefined +)[]; /** * Metadata for a message from the Zerion API. */ @@ -60,8 +74,6 @@ export interface AssetPricesReceivedMessage { meta?: MessageMeta; } -export type TransactionStatus = 'pending' | 'confirmed' | 'failed'; - export type TxHash = `0x${string}`; type BaseTransaction = { @@ -169,8 +181,8 @@ const transactionTypes = { ], } as const; -type TransactionWithChangesType = typeof transactionTypes.withChanges[number]; -type TransactionWithoutChangesType = typeof transactionTypes.withoutChanges[number]; +export type TransactionWithChangesType = typeof transactionTypes.withChanges[number]; +export type TransactionWithoutChangesType = typeof transactionTypes.withoutChanges[number]; export type TransactionType = | TransactionWithChangesType @@ -186,7 +198,7 @@ export type TransactionApiResponse = { status: TransactionStatus; id: TxHash; hash: TxHash; - network: number; + network: Network; protocol?: string; direction?: TransactionDirection; address_from?: string; diff --git a/src/screens/transaction-details/TransactionDetails.tsx b/src/screens/transaction-details/TransactionDetails.tsx index f9713421630..04eabcb1c3c 100644 --- a/src/screens/transaction-details/TransactionDetails.tsx +++ b/src/screens/transaction-details/TransactionDetails.tsx @@ -15,6 +15,8 @@ import { TransactionDetailsStatusActionsAndTimestampSection } from '@/screens/tr import { useTransactionDetailsToasts } from '@/screens/transaction-details/hooks/useTransactionDetailsToasts'; import { LayoutChangeEvent } from 'react-native'; import { useDimensions } from '@/hooks'; +import { useTransaction } from '@/resources/transactions/transaction'; +import { Network } from '@/networks/types'; type RouteParams = { TransactionDetails: { @@ -27,7 +29,12 @@ export const TransactionDetails = () => { const navigation = useNavigation(); const route = useRoute>(); const { setParams } = navigation; - const { transaction } = route.params; + const { transaction: tx } = route.params; + const { data } = useTransaction({ + hash: tx.hash || '', + network: tx.network || Network.mainnet, + }); + const transaction = data; const [sheetHeight, setSheetHeight] = useState(0); const [statusIconHidden, setStatusIconHidden] = useState(false); const { presentedToast, presentToastFor } = useTransactionDetailsToasts(); diff --git a/src/screens/transaction-details/components/TransactionDetailsValueAndFeeSection.tsx b/src/screens/transaction-details/components/TransactionDetailsValueAndFeeSection.tsx index 5576a77e97e..b8fc1e883c3 100644 --- a/src/screens/transaction-details/components/TransactionDetailsValueAndFeeSection.tsx +++ b/src/screens/transaction-details/components/TransactionDetailsValueAndFeeSection.tsx @@ -9,10 +9,16 @@ import { CoinIcon } from '@/components/coin-icon'; import { Box, Stack } from '@/design-system'; import { TransactionDetailsDivider } from '@/screens/transaction-details/components/TransactionDetailsDivider'; import * as i18n from '@/languages'; -import { AssetTypes, TransactionType } from '@/entities'; +import { AssetTypes } from '@/entities'; import { ethereumUtils } from '@/utils'; import { Network } from '@/networks/types'; import { useUserAsset } from '@/resources/assets/useUserAsset'; +import { + convertAmountAndPriceToNativeDisplay, + convertAmountToBalanceDisplay, + convertAmountToNativeDisplay, +} from '@/helpers/utilities'; +import { useAccountSettings } from '@/hooks'; type Props = { transaction: RainbowTransaction; @@ -24,38 +30,31 @@ type Props = { export const TransactionDetailsValueAndFeeSection: React.FC = ({ transaction, }) => { + const { nativeCurrency } = useAccountSettings(); const { network, symbol, type, fee } = transaction; - const assetUniqueId = - transaction.network === Network.mainnet - ? `${transaction.address}` - : `${transaction.address}_${transaction.network}`; - const { data: assetData } = useUserAsset(assetUniqueId); + const assetData = transaction?.asset; + const change = transaction?.changes?.[0]; - const coinAddress = assetData?.address ?? transaction.address; + const coinAddress = assetData?.address; const mainnetCoinAddress = assetData?.mainnet_address; - const coinSymbol = - type === TransactionType.contract_interaction - ? ethereumUtils.getNetworkNativeAsset(network ?? Network.mainnet)?.symbol - : assetData?.symbol ?? symbol ?? undefined; + const coinSymbol = assetData?.symbol ?? symbol ?? undefined; const coinType = assetData?.type ?? network !== Network.mainnet ? network : AssetTypes.token; - const value = transaction.balance?.display; - const nativeCurrencyValue = transaction.native?.display; - + const value = change?.asset?.balance?.display || transaction.balance?.display; + const nativeCurrencyValue = convertAmountAndPriceToNativeDisplay( + change?.asset?.balance?.amount, + change?.asset?.price?.value, + nativeCurrency + ).display; const feeValue = fee?.value.display ?? ''; const feeNativeCurrencyValue = fee?.native?.display ?? ''; - - if (!fee && !value) { - return null; - } - return ( <> - {value && ( + {true && ( Date: Sat, 3 Feb 2024 22:37:12 -0500 Subject: [PATCH 04/38] pendingTx state & zustand --- package.json | 3 +- src/state/internal/createStore.ts | 27 +++++++ src/state/internal/persistStorage.ts | 16 ++++ src/state/pendingTransactionsStore.ts | 103 ++++++++++++++++++++++++++ src/storage/index.ts | 7 +- src/storage/legacy.ts | 1 + yarn.lock | 9 ++- 7 files changed, 163 insertions(+), 3 deletions(-) create mode 100644 src/state/internal/createStore.ts create mode 100644 src/state/internal/persistStorage.ts create mode 100644 src/state/pendingTransactionsStore.ts diff --git a/package.json b/package.json index 967e992c43e..3d89f9b8039 100644 --- a/package.json +++ b/package.json @@ -306,7 +306,8 @@ "util": "0.10.4", "viem": "1.6.0", "vm-browserify": "0.0.4", - "w2t": "3.0.2" + "w2t": "3.0.2", + "zustand": "4.1.5" }, "devDependencies": { "@babel/core": "7.22.0", diff --git a/src/state/internal/createStore.ts b/src/state/internal/createStore.ts new file mode 100644 index 00000000000..4e48af9b675 --- /dev/null +++ b/src/state/internal/createStore.ts @@ -0,0 +1,27 @@ +import { persist } from 'zustand/middleware'; +import create, { Mutate, StoreApi } from 'zustand/vanilla'; + +import { persistStorage } from './persistStorage'; + +type Initializer = Parameters>[0]; +export type StoreWithPersist = Mutate< + StoreApi, + [['zustand/persist', unknown]] +> & { + initializer: Initializer; +}; + +export function createStore( + initializer: Initializer +) { + const name = `rainbow.zustand`; + return Object.assign( + create( + persist(initializer, { + name, + getStorage: () => (persistStorage), + }), + ), + { initializer }, + ); +} diff --git a/src/state/internal/persistStorage.ts b/src/state/internal/persistStorage.ts new file mode 100644 index 00000000000..eb1fd35da97 --- /dev/null +++ b/src/state/internal/persistStorage.ts @@ -0,0 +1,16 @@ +// persistStorage.ts + +import { zustandStorage } from '@/storage/legacy'; +import { StateStorage } from 'zustand/middleware'; + +export const persistStorage: StateStorage = { + getItem: async (key: string): Promise => { + return zustandStorage.get([key]); + }, + setItem: async (key: string, value: string): Promise => { + await zustandStorage.set([key], value); + }, + removeItem: async (key: string): Promise => { + await zustandStorage.remove([key]); + }, +}; diff --git a/src/state/pendingTransactionsStore.ts b/src/state/pendingTransactionsStore.ts new file mode 100644 index 00000000000..1d968d4ba8d --- /dev/null +++ b/src/state/pendingTransactionsStore.ts @@ -0,0 +1,103 @@ +import { RainbowTransaction, NewTransaction } from '@/entities/transactions'; +import { createStore } from './internal/createStore'; +import { create } from 'zustand'; +import { parseNewTransaction } from '@/parsers/transactions'; +import { Network } from '@/networks/types'; + +export const addNewTransaction = ({ + address, + network, + transaction, +}: { + address: string; + network: Network; + transaction: NewTransaction; +}) => { + const parsedTransaction = parseNewTransaction(transaction); + pendingTransactionsStore + .getState() + .addPendingTransaction({ address, pendingTransaction: parsedTransaction }); +}; +export interface PendingTransactionsState { + pendingTransactions: Record; + addPendingTransaction: ({ + address, + pendingTransaction, + }: { + address: string; + pendingTransaction: RainbowTransaction; + }) => void; + updatePendingTransaction: ({ + address, + pendingTransaction, + }: { + address: string; + pendingTransaction: RainbowTransaction; + }) => void; + setPendingTransactions: ({ + address, + pendingTransactions, + }: { + address: string; + pendingTransactions: RainbowTransaction[]; + }) => void; + clearPendingTransactions: () => void; +} + +export const pendingTransactionsStore = createStore( + (set, get) => ({ + pendingTransactions: {}, + addPendingTransaction: ({ address, pendingTransaction }) => { + console.log('adding pending transaction'); + const { pendingTransactions: currentPendingTransactions } = get(); + const addressPendingTransactions = + currentPendingTransactions[address] || []; + set({ + pendingTransactions: { + ...currentPendingTransactions, + [address]: [...addressPendingTransactions, pendingTransaction], + }, + }); + }, + updatePendingTransaction: ({ address, pendingTransaction }) => { + const { pendingTransactions: currentPendingTransactions } = get(); + const addressPendingTransactions = + currentPendingTransactions[address] || []; + + set({ + pendingTransactions: { + ...currentPendingTransactions, + [address]: [ + ...addressPendingTransactions.filter(tx => { + if (tx.network === pendingTransaction.network) { + return tx.nonce !== pendingTransaction.nonce; + } + return true; + }), + pendingTransaction, + ], + }, + }); + }, + setPendingTransactions: ({ address, pendingTransactions }) => { + const { pendingTransactions: currentPendingTransactions } = get(); + set({ + pendingTransactions: { + ...currentPendingTransactions, + [address]: [...pendingTransactions], + }, + }); + }, + clearPendingTransactions: () => { + set({ pendingTransactions: {} }); + }, + }), + { + persist: { + name: 'pendingTransactions', + version: 1, + }, + } +); + +export const usePendingTransactionsStore = create(pendingTransactionsStore); diff --git a/src/storage/index.ts b/src/storage/index.ts index 85b4af72b85..c5989ceb90f 100644 --- a/src/storage/index.ts +++ b/src/storage/index.ts @@ -1,7 +1,7 @@ import { MMKV } from 'react-native-mmkv'; import { Account, Cards, Campaigns, Device, Review } from '@/storage/schema'; -import { EthereumAddress } from '@/entities'; +import { EthereumAddress, RainbowTransaction } from '@/entities'; import { Network } from '@/networks/types'; /** @@ -77,6 +77,11 @@ export const account = new Storage<[EthereumAddress, Network], Account>({ id: 'account', }); +export const pendingTransactions = new Storage< + [], + { pendingTransactions: Record } +>({ id: 'pendingTransactions' }); + export const review = new Storage<[], Review>({ id: 'review' }); export const campaigns = new Storage<[], Campaigns>({ id: 'campaigns' }); diff --git a/src/storage/legacy.ts b/src/storage/legacy.ts index 027fcc11d20..a63219a6ea1 100644 --- a/src/storage/legacy.ts +++ b/src/storage/legacy.ts @@ -58,3 +58,4 @@ class LegacyStorage extends Storage< * instance instead of this one. */ export const legacy = new LegacyStorage<[], Legacy>({ id: 'global' }); +export const zustandStorage = new LegacyStorage<[], Legacy>({ id: 'zustand' }); diff --git a/yarn.lock b/yarn.lock index da7c7bc5c92..ddafa87bc79 100644 --- a/yarn.lock +++ b/yarn.lock @@ -18256,7 +18256,7 @@ use-memo-one@1.1.1: resolved "https://registry.yarnpkg.com/use-memo-one/-/use-memo-one-1.1.1.tgz#39e6f08fe27e422a7d7b234b5f9056af313bd22c" integrity sha512-oFfsyun+bP7RX8X2AskHNTxu+R3QdE/RC5IefMbqptmACAA/gfol1KDD5KRzPsGMa62sWxGZw+Ui43u6x4ddoQ== -use-sync-external-store@^1.0.0, use-sync-external-store@^1.2.0: +use-sync-external-store@1.2.0, use-sync-external-store@^1.0.0, use-sync-external-store@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz#7dbefd6ef3fe4e767a0cf5d7287aacfb5846928a" integrity sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA== @@ -19164,3 +19164,10 @@ zod@^1.11.11: version "1.11.17" resolved "https://registry.yarnpkg.com/zod/-/zod-1.11.17.tgz#2aae9e91fc66128116ae9844e8f416a95f453f8e" integrity sha512-UzIwO92D0dSFwIRyyqAfRXICITLjF0IP8tRbEK/un7adirMssWZx8xF/1hZNE7t61knWZ+lhEuUvxlu2MO8qqA== + +zustand@4.1.5: + version "4.1.5" + resolved "https://registry.yarnpkg.com/zustand/-/zustand-4.1.5.tgz#7402b511f5b23ccb0f9ba6d20ae01ec817e16eb6" + integrity sha512-PsdRT8Bvq22Yyh1tvpgdHNE7OAeFKqJXUxtJvj1Ixw2B9O2YZ1M34ImQ+xyZah4wZrR4lENMoDUutKPpyXCQ/Q== + dependencies: + use-sync-external-store "1.2.0" From cdff8844b2d6ada13eab93bb115fb1d428c4bba4 Mon Sep 17 00:00:00 2001 From: skylarbarrera Date: Sat, 3 Feb 2024 22:39:14 -0500 Subject: [PATCH 05/38] useWatchPendingTxs --- src/hooks/useWatchPendingTxs.ts | 259 ++++++++++++++++++++++++++++++++ 1 file changed, 259 insertions(+) create mode 100644 src/hooks/useWatchPendingTxs.ts diff --git a/src/hooks/useWatchPendingTxs.ts b/src/hooks/useWatchPendingTxs.ts new file mode 100644 index 00000000000..32b0fbcc2ff --- /dev/null +++ b/src/hooks/useWatchPendingTxs.ts @@ -0,0 +1,259 @@ +import { useCallback, useMemo } from 'react'; +import useAccountSettings from './useAccountSettings'; +import { + RainbowTransaction, + MinedTransaction, +} from '@/entities/transactions/transaction'; +import { fetchUserAssets } from '@/resources/assets/UserAssetsQuery'; +import { transactionFetchQuery } from '@/resources/transactions/transaction'; +import { RainbowError, logger } from '@/logger'; +import { Network } from '@/networks/types'; +import { getProviderForNetwork } from '@/handlers/web3'; +import { consolidatedTransactionsQueryKey } from '@/resources/transactions/consolidatedTransactions'; +import { RainbowNetworks } from '@/networks'; +import { queryClient } from '@/react-query/queryClient'; +import { getTransactionFlashbotStatus } from '@/handlers/transactions'; +import { usePendingTransactionsStore } from '@/state/pendingTransactionsStore'; + +export const useWatchPendingTransactions = ({ + address, +}: { + address: string; +}) => { + //const { swapRefreshAssets } = useSwapRefreshAssets(); + + const { + pendingTransactions: storePendingTransactions, + setPendingTransactions, + } = usePendingTransactionsStore(); + + const pendingTransactions = useMemo( + () => storePendingTransactions[address] || [], + [address, storePendingTransactions] + ); + + const { nativeCurrency, accountAddress } = useAccountSettings(); + + const refreshAssets = useCallback( + (tx: RainbowTransaction) => { + if (tx.type === 'swap') { + // update swap assets + //swapRefreshAssets(tx.nonce); + } else { + // fetch assets again + fetchUserAssets({ + address: accountAddress, + currency: nativeCurrency, + connectedToHardhat: false, + }); + } + }, + [accountAddress, nativeCurrency] + ); + + const processFlashbotsTransaction = useCallback( + async (tx: RainbowTransaction): Promise => { + const flashbotsTxStatus = await getTransactionFlashbotStatus( + tx, + tx.hash! + ); + if (flashbotsTxStatus) { + const { flashbotsStatus, status, minedAt, title } = flashbotsTxStatus; + + return { + ...tx, + status, + minedAt, + title, + flashbotsStatus, + } as RainbowTransaction; + } + return tx; + }, + [] + ); + + const processSupportedNetworkTransaction = useCallback( + async (tx: RainbowTransaction) => { + const transaction = await transactionFetchQuery({ + hash: tx.hash!, + network: tx.network, + address, + currency: nativeCurrency, + }); + + return { + ...tx, + ...transaction, + }; + }, + [address, nativeCurrency] + ); + + const processPendingTransaction = useCallback( + async (tx: RainbowTransaction) => { + let updatedTransaction: RainbowTransaction = { ...tx }; + try { + if (tx.network && tx.hash && address) { + updatedTransaction = await processSupportedNetworkTransaction( + updatedTransaction + ); + // if flashbots tx and no blockNumber, check if it failed + if (!(tx as any).blockNumber && tx.flashbots) { + updatedTransaction = await processFlashbotsTransaction( + updatedTransaction + ); + } + } else { + throw new Error('Pending transaction missing chain id'); + } + // eslint-disable-next-line @typescript-eslint/no-explicit-any + } catch (e: any) { + logger.error( + new RainbowError( + `useWatchPendingTransaction: Failed to watch transaction` + ), + { + message: e.message, + } + ); + } + + if (updatedTransaction?.status !== 'pending') { + refreshAssets(tx); + } + return updatedTransaction; + }, + [ + address, + processSupportedNetworkTransaction, + processFlashbotsTransaction, + refreshAssets, + ] + ); + + const processNonces = useCallback( + (txs: RainbowTransaction[]) => { + const userTxs = txs.filter( + tx => address?.toLowerCase() === tx.from?.toLowerCase() + ); + const networks = [ + ...new Set( + userTxs.reduce((acc, tx) => { + acc.add(tx.network); + return acc; + }, new Set()) + ), + ]; + let flashbotsTxFailed = false; + const highestNoncePerChainId = userTxs.reduce((acc, tx) => { + // if tx is not on mainnet, we don't care about the nonce + if (tx.network !== Network.mainnet) { + acc.set(tx.network, tx.nonce); + return acc; + } + // if tx is flashbots and failed, we want to use the lowest nonce + if ( + tx.flashbots && + (tx as any)?.flashbotsStatus === 'FAILED' && + tx?.nonce + ) { + // if we already have a failed flashbots tx, we want to use the lowest nonce + if (flashbotsTxFailed && tx.nonce < acc.get(tx.network)) { + acc.set(tx.network, tx.nonce); + } else { + acc.set(tx.network, tx.nonce); + flashbotsTxFailed = true; + } + // if tx succeeded, we want to use the highest nonce + } else if ( + !flashbotsTxFailed && + tx?.nonce && + tx.nonce > acc.get(tx.network) + ) { + acc.set(tx.network, tx.nonce); + } + return acc; + }, new Map()); + + networks.map(async network => { + const provider = await getProviderForNetwork(network); + const providerTransactionCount = await provider.getTransactionCount( + address, + 'latest' + ); + const currentProviderNonce = providerTransactionCount - 1; + const currentNonceForChainId = highestNoncePerChainId.get(network) - 1; + }); + // need to set nonce + // setNonce({ + // address, + // chainId, + // currentNonce: + // currentProviderNonce > currentNonceForChainId + // ? currentProviderNonce + // : currentNonceForChainId, + // latestConfirmedNonce: currentProviderNonce, + // }); + // }); + }, + [address] + ); + + const watchPendingTransactions = useCallback(async () => { + if (!pendingTransactions?.length) return; + console.log('watching pending txs'); + const updatedPendingTransactions = await Promise.all( + pendingTransactions.map((tx: RainbowTransaction) => + processPendingTransaction(tx) + ) + ); + + processNonces(updatedPendingTransactions); + + const { + newPendingTransactions, + minedTransactions, + } = updatedPendingTransactions.reduce( + (acc, tx) => { + if (tx?.status === 'pending') { + acc.newPendingTransactions.push(tx); + } else { + acc.minedTransactions.push(tx as MinedTransaction); + } + return acc; + }, + { + newPendingTransactions: [] as RainbowTransaction[], + minedTransactions: [] as MinedTransaction[], + } + ); + + if (minedTransactions.length) { + console.log('we mined a transaction'); + const chainIds = RainbowNetworks.filter( + network => network.enabled && network.networkType !== 'testnet' + ).map(network => network.id); + await queryClient.refetchQueries({ + queryKey: consolidatedTransactionsQueryKey({ + address: accountAddress, + currency: nativeCurrency, + chainIds, + }), + }); + } + setPendingTransactions({ + address: accountAddress, + pendingTransactions: newPendingTransactions, + }); + }, [ + accountAddress, + nativeCurrency, + pendingTransactions, + processNonces, + processPendingTransaction, + setPendingTransactions, + ]); + + return { watchPendingTransactions }; +}; From 2090834da7040eff2501bb218544d41c7cf8c15e Mon Sep 17 00:00:00 2001 From: skylarbarrera Date: Sat, 3 Feb 2024 22:39:42 -0500 Subject: [PATCH 06/38] usePoll + usage --- src/hooks/usePendingTransactionWatcher.ts | 9 +++++++++ src/hooks/usePoll.ts | 18 ++++++++++++++++++ 2 files changed, 27 insertions(+) create mode 100644 src/hooks/usePendingTransactionWatcher.ts create mode 100644 src/hooks/usePoll.ts diff --git a/src/hooks/usePendingTransactionWatcher.ts b/src/hooks/usePendingTransactionWatcher.ts new file mode 100644 index 00000000000..0f3604b24aa --- /dev/null +++ b/src/hooks/usePendingTransactionWatcher.ts @@ -0,0 +1,9 @@ +import { usePoll } from './usePoll'; +import { useWatchPendingTransactions } from './useWatchPendingTxs'; + +const PENDING_TRANSACTION_POLLING_INTERVAL = 5000; + +export function usePendingTransactionWatcher({ address }: { address: string }) { + const { watchPendingTransactions } = useWatchPendingTransactions({ address }); + usePoll(watchPendingTransactions, PENDING_TRANSACTION_POLLING_INTERVAL); +} diff --git a/src/hooks/usePoll.ts b/src/hooks/usePoll.ts new file mode 100644 index 00000000000..505746bb598 --- /dev/null +++ b/src/hooks/usePoll.ts @@ -0,0 +1,18 @@ +import { useEffect, useLayoutEffect, useRef } from 'react'; + +export function usePoll(callback: () => void, delay: number) { + const cbRef = useRef<() => void>(); + + useLayoutEffect(() => { + cbRef.current = callback; + }, [callback]); + + useEffect(() => { + if (delay === null) return; + const cb = () => cbRef.current?.(); + const id = setInterval(cb, delay); + return () => { + clearInterval(id); + }; + }, [callback, delay]); +} From 73edda0d5f2d6b892ff2284ae0c1f798b92e00d9 Mon Sep 17 00:00:00 2001 From: skylarbarrera Date: Sat, 3 Feb 2024 22:40:31 -0500 Subject: [PATCH 07/38] queries --- .../transactions/consolidatedTransactions.ts | 8 +++++++- src/resources/transactions/transaction.ts | 19 +++++++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/src/resources/transactions/consolidatedTransactions.ts b/src/resources/transactions/consolidatedTransactions.ts index 5e733458ca0..25e6a15a7bf 100644 --- a/src/resources/transactions/consolidatedTransactions.ts +++ b/src/resources/transactions/consolidatedTransactions.ts @@ -121,7 +121,13 @@ type ConsolidatedTransactionsResult = { nextPage?: string; transactions: RainbowTransaction[]; }; - +/** + * + * should we? + * queryClient.invalidateQueries({ + queryKey: nftsQueryKey({ address: accountAddress }), + }); + */ async function parseConsolidatedTransactions( message: TransactionsReceivedMessage, currency: NativeCurrencyKey diff --git a/src/resources/transactions/transaction.ts b/src/resources/transactions/transaction.ts index 226dd061935..59c522bc243 100644 --- a/src/resources/transactions/transaction.ts +++ b/src/resources/transactions/transaction.ts @@ -78,6 +78,25 @@ export const fetchTransaction = async ({ } }; +// /////////////////////////////////////////////// +// Query Function + +export const transactionFetchQuery = async ({ + address, + currency, + network, + hash, +}: { + address: string; + currency: NativeCurrencyKey; + network: Network; + hash: string; +}) => + queryClient.fetchQuery( + transactionQueryKey({ address, currency, network, hash }), + fetchTransaction + ); + type PaginatedTransactions = { pages: ConsolidatedTransactionsResult[] }; export function useBackendTransaction({ From 43ea9f26f42d84a35d4ce1082cec47811c5bb675 Mon Sep 17 00:00:00 2001 From: skylarbarrera Date: Sat, 3 Feb 2024 22:41:46 -0500 Subject: [PATCH 08/38] use transactions --- .../buildTransactionsSectionsSelector.tsx | 8 +-- src/hooks/useAccountTransactions.ts | 52 +++++++++---------- src/hooks/useENSLocalTransactions.ts | 25 +++++---- src/screens/SendConfirmationSheet.tsx | 15 +++++- 4 files changed, 57 insertions(+), 43 deletions(-) diff --git a/src/helpers/buildTransactionsSectionsSelector.tsx b/src/helpers/buildTransactionsSectionsSelector.tsx index e96b14f6971..e656db21e52 100644 --- a/src/helpers/buildTransactionsSectionsSelector.tsx +++ b/src/helpers/buildTransactionsSectionsSelector.tsx @@ -31,7 +31,9 @@ const groupTransactionByDate = ({ pending: boolean; minedAt: string; }) => { - if (pending) return i18n.t(i18n.l.transactions.pending_title); + if (pending) { + return i18n.t(i18n.l.transactions.pending_title); + } const ts = parseInt(minedAt, 10) * 1000; @@ -70,8 +72,6 @@ export const buildTransactionsSections = ({ contacts, requests, theme, - isFocused, - initialized, transactions, }: { accountAddress: string; @@ -84,7 +84,7 @@ export const buildTransactionsSections = ({ navigate: (...args: any[]) => void; transactions: RainbowTransaction[]; }) => { - if ((!isFocused && !initialized) || !transactions) { + if (!transactions) { return { sections: [] }; } diff --git a/src/hooks/useAccountTransactions.ts b/src/hooks/useAccountTransactions.ts index 10917c84f74..2405565cbf9 100644 --- a/src/hooks/useAccountTransactions.ts +++ b/src/hooks/useAccountTransactions.ts @@ -12,13 +12,11 @@ import { getCachedProviderForNetwork, isHardHat } from '@/handlers/web3'; import { useUserAssets } from '@/resources/assets/UserAssetsQuery'; import { useConsolidatedTransactions } from '@/resources/transactions/consolidatedTransactions'; import { RainbowTransaction } from '@/entities'; +import { usePendingTransactionsStore } from '@/state/pendingTransactionsStore'; export const NOE_PAGE = 30; -export default function useAccountTransactions( - initialized: boolean, - isFocused: boolean -) { +export default function useAccountTransactions() { const { network: currentNetwork, accountAddress, @@ -33,17 +31,15 @@ export default function useAccountTransactions( connectedToHardhat, }); - const { isLoadingTransactions, network, pendingTransactions } = useSelector( - ({ - data: { isLoadingTransactions, pendingTransactions, transactions }, - settings: { network }, - }: AppState) => ({ - isLoadingTransactions, - network, - pendingTransactions, - transactions, - }) - ); + const { + pendingTransactions: storePendingTransactions, + } = usePendingTransactionsStore(); + + const pendingTransactions = useMemo(() => { + const txs = storePendingTransactions[accountAddress] || []; + console.log('PENDING: ', txs); + return txs; + }, [accountAddress, storePendingTransactions]); const { data, fetchNextPage } = useConsolidatedTransactions({ address: accountAddress, @@ -66,17 +62,20 @@ export default function useAccountTransactions( const mainnetAddresses = useMemo( () => userAssets - ? slicedTransaction.reduce((acc: { [key: string]: string }, txn) => { - if (txn?.network && txn?.address) { - const asset = - userAssets[`${txn.address}_${txn.network}`]?.mainnet_address; - if (asset) { - acc[`${txn.address}_${txn.network}`] = asset; + ? slicedTransaction.reduce( + (acc: { [key: string]: string }, txn: RainbowTransaction) => { + if (txn?.network && txn?.address) { + const asset = + userAssets[`${txn.address}_${txn.network}`]?.mainnet_address; + if (asset) { + acc[`${txn.address}_${txn.network}`] = asset; + } } - } - return acc; - }, {}) + return acc; + }, + {} + ) : {}, [userAssets, slicedTransaction] ); @@ -89,8 +88,6 @@ export default function useAccountTransactions( const accountState = { accountAddress, contacts, - initialized, - isFocused, mainnetAddresses, navigate, requests, @@ -112,8 +109,7 @@ export default function useAccountTransactions( }, [slicedTransaction.length, allTransactions.length]); return { - isLoadingTransactions: - network === NetworkTypes.mainnet ? isLoadingTransactions : false, + isLoadingTransactions: !!allTransactions, nextPage: fetchNextPage, remainingItemsLabel, sections, diff --git a/src/hooks/useENSLocalTransactions.ts b/src/hooks/useENSLocalTransactions.ts index 777fab9c097..2ff5a874f11 100644 --- a/src/hooks/useENSLocalTransactions.ts +++ b/src/hooks/useENSLocalTransactions.ts @@ -1,21 +1,28 @@ import { useSelector } from 'react-redux'; -import { - useAccountSettings, - useAccountTransactions, - usePendingTransactions, -} from '.'; -import { ENSRegistrationState } from '@/entities'; +import { useMemo } from 'react'; +import { useAccountSettings, usePendingTransactions } from '.'; +import { ENSRegistrationState, RainbowTransaction } from '@/entities'; import { AppState } from '@/redux/store'; import { ethereumUtils } from '@/utils'; +import { useConsolidatedTransactions } from '@/resources/transactions/consolidatedTransactions'; /** * @description Returns the local ENS transactions for a given name. * */ export default function useENSLocalTransactions({ name }: { name: string }) { - const { accountAddress } = useAccountSettings(); + const { accountAddress, nativeCurrency } = useAccountSettings(); const { getPendingTransactionByHash } = usePendingTransactions(); - const { transactions } = useAccountTransactions(true, true); + const { data } = useConsolidatedTransactions({ + address: accountAddress, + currency: nativeCurrency, + }); + + const pages = data?.pages; + const transactions: RainbowTransaction[] = useMemo( + () => pages?.flatMap(p => p.transactions) || [], + [pages] + ); const registration = useSelector(({ ensRegistration }: AppState) => { const { registrations } = ensRegistration as ENSRegistrationState; const accountRegistrations = @@ -28,7 +35,7 @@ export default function useENSLocalTransactions({ name }: { name: string }) { const pendingRegistrationTransaction = getPendingTransactionByHash( registration?.registerTransactionHash?.toString() || '' ); - const confirmedRegistrationTransaction = transactions.find( + const confirmedRegistrationTransaction = transactions?.find( (txn: any) => ethereumUtils.getHash(txn) === registration?.registerTransactionHash && !txn.pending diff --git a/src/screens/SendConfirmationSheet.tsx b/src/screens/SendConfirmationSheet.tsx index f0e5ec5d71e..1cf13ecb129 100644 --- a/src/screens/SendConfirmationSheet.tsx +++ b/src/screens/SendConfirmationSheet.tsx @@ -55,7 +55,6 @@ import { add, convertAmountToNativeDisplay } from '@/helpers/utilities'; import { isENSAddressFormat, isValidDomainFormat } from '@/helpers/validators'; import { useAccountSettings, - useAccountTransactions, useColorForAsset, useContacts, useDimensions, @@ -72,6 +71,7 @@ import { useTheme } from '@/theme'; import { ethereumUtils, getUniqueTokenType, promiseUtils } from '@/utils'; import logger from '@/utils/logger'; import { getNetworkObj } from '@/networks'; +import { useConsolidatedTransactions } from '@/resources/transactions/consolidatedTransactions'; const Container = styled(Centered).attrs({ direction: 'column', @@ -260,7 +260,18 @@ export const SendConfirmationSheet = () => { setAlreadySentTransactionsCurrentNetwork, ] = useState(0); - const { transactions } = useAccountTransactions(true, true); + const { data } = useConsolidatedTransactions({ + address: accountAddress, + currency: nativeCurrency, + }); + + const pages = data?.pages; + + const transactions = useMemo( + () => pages?.flatMap(p => p.transactions) || [], + [pages] + ); + const { userAccounts, watchedAccounts } = useUserAccounts(); const { walletNames } = useWallets(); const isSendingToUserAccount = useMemo(() => { From 1fb037ec0da7b9b27a95024de952c409045b92d2 Mon Sep 17 00:00:00 2001 From: skylarbarrera Date: Sat, 3 Feb 2024 22:44:58 -0500 Subject: [PATCH 09/38] messy types and structure --- src/entities/transactions/transaction.ts | 80 +++++++------ src/handlers/transactions.ts | 138 ++++------------------- src/parsers/transactions.ts | 70 ++++++------ src/resources/transactions/types.ts | 6 +- 4 files changed, 96 insertions(+), 198 deletions(-) diff --git a/src/entities/transactions/transaction.ts b/src/entities/transactions/transaction.ts index 66003daf168..5084fb05b9a 100644 --- a/src/entities/transactions/transaction.ts +++ b/src/entities/transactions/transaction.ts @@ -34,15 +34,19 @@ export interface RainbowTransaction { } | undefined >; + contract?: { + name: string; + iconUrl?: string; + }; direction?: TransactionDirection; - description: string; + description?: string; data?: string; // for pending tx from: EthereumAddress | null; gasLimit?: BigNumberish; gasPrice?: BigNumberish; maxFeePerGas?: BigNumberish; maxPriorityFeePerGas?: BigNumberish; - hash?: string | null; + hash: string; minedAt?: number | null; name?: string | null; native?: { @@ -87,47 +91,29 @@ export interface RainbowTransaction { }; // etc { name: FiatProviderName.Ramp, orderId: string } } -export interface RainbowTransactionFee { - value: { - amount: string; - display: string; - }; - native?: { - amount: string; - display: string; - }; -} +export type MinedTransaction = RainbowTransaction & { + status: 'confirmed' | 'failed'; + flashbotsStatus?: 'CANCELLED' | 'FAILED' | 'INCLUDED'; + blockNumber: number; + minedAt: number; + confirmations: number; + gasUsed: string; +}; -export interface NewTransaction { - amount: string | null; - asset: ParsedAddressAsset | null; - dappName?: string; // for walletconnect - contract?: { - name: string; - iconUrl?: string; - }; - data?: string; - from: EthereumAddress | null; +export type NewTransaction = Omit & { gasLimit?: BigNumberish; - gasPrice?: BigNumberish; - maxFeePerGas?: BigNumberish; - maxPriorityFeePerGas?: BigNumberish; - hash: string | null; - network?: Network; - nft?: UniqueAsset; - nonce: number | null; - protocol?: ProtocolType | null; - flashbots?: boolean; - ensCommitRegistrationName?: string; - ensRegistration?: boolean; - sourceAmount?: string; // for purchases - status?: 'pending'; - timestamp?: number; // for purchases - to: EthereumAddress | null; - transferId?: string; // for purchases - type?: TransactionType; - value?: BigNumberish; - txTo?: EthereumAddress | null; + changes?: Array< + | { + asset: ParsedAddressAsset; + direction: TransactionDirection; + address_from?: string; + address_to?: string; + value?: number | string; + price?: number | string; + } + | undefined + >; + swap?: { type: SwapType; fromChainId: ChainId; @@ -135,7 +121,17 @@ export interface NewTransaction { isBridge: boolean; }; meta?: SwapMetadata; - fiatProvider?: RainbowTransaction['fiatProvider']; +}; + +export interface RainbowTransactionFee { + value: { + amount: string; + display: string; + }; + native?: { + amount: string; + display: string; + }; } export interface NewTransactionOrAddCashTransaction diff --git a/src/handlers/transactions.ts b/src/handlers/transactions.ts index 10507372fe4..d5ccc4f5912 100644 --- a/src/handlers/transactions.ts +++ b/src/handlers/transactions.ts @@ -6,18 +6,12 @@ import { CONTRACT_FUNCTION } from '@/apollo/queries'; import { RainbowTransaction, TransactionStatus, - TransactionDirection, - TransactionTypes, - TransactionType, ZerionTransaction, } from '@/entities'; import store from '@/redux/store'; import { transactionSignaturesDataAddNewSignature } from '@/redux/transactionSignatures'; import { SIGNATURE_REGISTRY_ADDRESS, signatureRegistryABI } from '@/references'; -import { ethereumUtils, isLowerCaseMatch } from '@/utils'; -import { TransactionResponse } from '@ethersproject/abstract-provider'; -import { getTitle, getTransactionLabel } from '@/parsers'; -import { isZero } from '@/helpers/utilities'; +import { ethereumUtils } from '@/utils'; import { fetchWalletENSAvatars, fetchWalletNames } from '@/redux/wallets'; import { RainbowFetchClient } from '@/rainbow-fetch'; import { IS_TEST } from '@/env'; @@ -101,108 +95,39 @@ export const getTransactionMethodName = async ( } }; -/** - * Returns the `TransactionStatus` that represents completion for a given - * transaction type. - * - * @param type The transaction type. - * @returns The confirmed status. - */ -const getConfirmedState = (type?: TransactionType): TransactionStatus => { - switch (type) { - case TransactionTypes.authorize: - return TransactionStatus.approved; - case TransactionTypes.sell: - return TransactionStatus.sold; - case TransactionTypes.mint: - return TransactionStatus.minted; - case TransactionTypes.deposit: - return TransactionStatus.deposited; - case TransactionTypes.withdraw: - return TransactionStatus.withdrew; - case TransactionTypes.receive: - return TransactionStatus.received; - case TransactionTypes.purchase: - return TransactionStatus.purchased; - default: - return TransactionStatus.sent; - } -}; - -export const getTransactionReceiptStatus = async ( - transaction: RainbowTransaction, - nonceAlreadyIncluded: boolean, - txObj?: TransactionResponse -): Promise => { - let receipt; - let status; - try { - if (txObj) { - receipt = await txObj.wait(); - } - } catch (e: any) { - // https://docs.ethers.io/v5/api/providers/types/#providers-TransactionResponse - if (e.transaction) { - // if a transaction field exists, it was confirmed but failed - status = TransactionStatus.failed; - } else { - // cancelled or replaced - status = TransactionStatus.cancelled; - } - } - status = receipt?.status || 0; - - if (!isZero(status)) { - const isSelf = isLowerCaseMatch( - transaction?.from || '', - transaction?.to || '' - ); - const transactionDirection = isSelf - ? TransactionDirection.self - : TransactionDirection.out; - const transactionStatus = - transaction.status === TransactionStatus.cancelling - ? TransactionStatus.cancelled - : getConfirmedState(transaction?.type); - status = getTransactionLabel({ - direction: transactionDirection, - pending: false, - protocol: transaction?.protocol, - status: transactionStatus, - type: transaction?.type, - }); - } else if (nonceAlreadyIncluded) { - status = TransactionStatus.unknown; - } else { - status = TransactionStatus.failed; - } - return status; -}; +type FlashbotsStatus = + | 'PENDING' + | 'INCLUDED' + | 'FAILED' + | 'CANCELLED' + | 'UNKNOWN'; export const getTransactionFlashbotStatus = async ( transaction: RainbowTransaction, txHash: string -) => { +): Promise<{ + flashbotsStatus: 'FAILED' | 'CANCELLED'; + status: 'failed'; + minedAt: number; + title: string; +} | null> => { try { - const fbStatus = await flashbotsApi.get(`/tx/${txHash}`); - const flashbotStatus = fbStatus.data.status; + const fbStatus = await flashbotsApi.get<{ status: FlashbotsStatus }>( + `/tx/${txHash}` + ); + const flashbotsStatus = fbStatus.data.status; // Make sure it wasn't dropped after 25 blocks or never made it - if (flashbotStatus === 'FAILED' || flashbotStatus === 'CANCELLED') { - const transactionStatus = TransactionStatus.dropped; + if (flashbotsStatus === 'FAILED' || flashbotsStatus === 'CANCELLED') { + const status = 'failed'; const minedAt = Math.floor(Date.now() / 1000); - const title = getTitle({ - protocol: transaction.protocol, - status: transactionStatus, - type: transaction.type, - }); - return { status: transactionStatus, minedAt, pending: false, title }; + const title = `transactions.${transaction.type}.failed`; + return { flashbotsStatus, status, minedAt, title }; } } catch (e) { // } return null; }; - export const getTransactionSocketStatus = async ( pendingTransaction: RainbowTransaction ) => { @@ -261,26 +186,7 @@ export const getTransactionSocketStatus = async ( } } - const title = getTitle({ - protocol: pendingTransaction.protocol, - status, - type: pendingTransaction.type, - }); - - return { status, minedAt, pending, title }; -}; - -export const getPendingTransactionData = ( - transaction: RainbowTransaction, - transactionStatus: TransactionStatus -) => { - const minedAt = Math.floor(Date.now() / 1000); - const title = getTitle({ - protocol: transaction.protocol, - status: transactionStatus, - type: transaction.type, - }); - return { title, minedAt, pending: false, status: transactionStatus }; + return { status, minedAt, pending }; }; export const fetchWalletENSDataAfterRegistration = async () => { diff --git a/src/parsers/transactions.ts b/src/parsers/transactions.ts index e4734c74e5d..20e75c69848 100644 --- a/src/parsers/transactions.ts +++ b/src/parsers/transactions.ts @@ -1,55 +1,32 @@ -import { - compact, - isEmpty, - isObject, - orderBy, - partition, - reverse, - slice, - toUpper, - uniqBy, - upperFirst, -} from 'lodash'; +import { slice } from 'lodash'; import { parseAllTxnsOnReceive } from '../config/debug'; import { - EthereumAddress, NativeCurrencyKey, RainbowTransaction, - TransactionDirection, - TransactionStatus, - ZerionAsset, ZerionTransaction, - ZerionTransactionChange, } from '@/entities'; -import { getTransactionMethodName } from '@/handlers/transactions'; -import { isL2Network } from '@/handlers/web3'; -import { Network } from '@/helpers/networkTypes'; -import { ETH_ADDRESS } from '@/references'; + import { convertAmountAndPriceToNativeDisplay, convertRawAmountToBalance, convertRawAmountToNativeDisplay, toFixedDecimals, } from '@/helpers/utilities'; -import { ethereumUtils, getTokenMetadata } from '@/utils'; + import { - RAINBOW_ROUTER_CONTRACT_ADDRESS, - SOCKET_REGISTRY_CONTRACT_ADDRESSESS, -} from '@rainbow-me/swaps'; -import { RainbowTransactionFee } from '@/entities/transactions/transaction'; -import * as i18n from '@/languages'; + NewTransaction, + RainbowTransactionFee, +} from '@/entities/transactions/transaction'; import { parseAddressAsset, parseAsset } from '@/resources/assets/assets'; -import { AddysAsset, ParsedAsset } from '@/resources/assets/types'; +import { ParsedAsset } from '@/resources/assets/types'; import { transactionTypes } from '@/entities/transactions/transactionType'; import { PaginatedTransactionsApiResponse, TransactionApiResponse, - TransactionChange, TransactionChanges, TransactionType, TransactionWithChangesType, } from '@/resources/transactions/types'; -import BigNumber from 'bignumber.js'; const LAST_TXN_HASH_BUFFER = 20; @@ -130,12 +107,6 @@ export const parseTransaction = async ( ? meta.type : 'contract_interaction'; - if (type === 'mint') { - console.log('MINT'); - changes?.map(change => { - console.log(change?.asset); - }); - } const asset: RainbowTransaction['asset'] = meta.asset?.asset_code ? parseAsset({ asset: meta.asset, address: meta.asset.asset_code }) : getAssetFromChanges(changes, type); @@ -191,6 +162,31 @@ export const parseTransaction = async ( } as RainbowTransaction; }; +export const parseNewTransaction = (tx: NewTransaction): RainbowTransaction => { + const asset = tx?.changes?.[0]?.asset || tx.asset; + const methodName = 'Unknown method'; + + return { + ...tx, + status: 'pending', + pending: true, + data: tx.data, + title: `transactions.${tx.type}.${tx.status}`, + description: asset?.name || methodName, + from: tx.from, + changes: tx.changes, + hash: tx.hash, + nonce: tx.nonce, + protocol: tx.protocol, + to: tx.to, + type: tx.type, + flashbots: tx.flashbots, + gasPrice: tx.gasPrice, + maxFeePerGas: tx.maxFeePerGas, + maxPriorityFeePerGas: tx.maxPriorityFeePerGas, + }; +}; + /** * Helper for retrieving tx fee sent by zerion, works only for mainnet only */ @@ -228,7 +224,7 @@ export const getDescription = ( meta: PaginatedTransactionsApiResponse['meta'] ) => { if (asset?.type === 'nft') return asset.symbol || asset.name; - if (type === 'cancel') return i18n.t('transactions.cancelled'); + if (type === 'cancel') return 'transactions.cancelled'; return asset?.name || meta.action; }; diff --git a/src/resources/transactions/types.ts b/src/resources/transactions/types.ts index dd4c636d716..e8219a0027c 100644 --- a/src/resources/transactions/types.ts +++ b/src/resources/transactions/types.ts @@ -79,10 +79,10 @@ export type TxHash = `0x${string}`; type BaseTransaction = { hash: TxHash; nonce: number; // -2 when not from the wallet user - chainId: ChainId; from: string; to?: string; // it may not have a to if it's a contract deployment (covalent) data?: string; + network: Network; changes?: Array< | { @@ -128,7 +128,7 @@ export type PendingTransaction = BaseTransaction & { status: 'pending'; }; -export type MinedTransaction = BaseTransaction & { +type MinedTransaction = BaseTransaction & { status: 'confirmed' | 'failed'; flashbotsStatus?: 'CANCELLED' | 'FAILED' | 'INCLUDED'; blockNumber: number; @@ -137,7 +137,7 @@ export type MinedTransaction = BaseTransaction & { gasUsed: string; }; -export type NewTransaction = Omit & { +type NewTransaction = Omit & { changes?: Array< | { direction: TransactionDirection; From f00741cb1ec56393539b217f34afe881282bedf5 Mon Sep 17 00:00:00 2001 From: skylarbarrera Date: Sun, 4 Feb 2024 17:56:35 -0500 Subject: [PATCH 10/38] addNewTransactions --- src/raps/actions/crosschainSwap.ts | 54 +-- src/raps/actions/ens.ts | 31 +- src/raps/actions/swap.ts | 61 ++-- src/raps/actions/unlock.ts | 23 +- src/screens/AddCash/index.tsx | 2 - src/screens/AddCash/providers/Ratio/index.tsx | 314 ------------------ src/screens/AddCash/providers/Ratio/utils.ts | 103 ------ src/screens/NFTSingleOfferSheet/index.tsx | 62 +++- src/screens/SendSheet.js | 15 +- src/screens/SignTransactionSheet.tsx | 35 +- src/screens/mints/MintSheet.tsx | 74 +++-- 11 files changed, 231 insertions(+), 543 deletions(-) delete mode 100644 src/screens/AddCash/providers/Ratio/index.tsx delete mode 100644 src/screens/AddCash/providers/Ratio/utils.ts diff --git a/src/raps/actions/crosschainSwap.ts b/src/raps/actions/crosschainSwap.ts index 2c7d193a7ed..a00e8882f2b 100644 --- a/src/raps/actions/crosschainSwap.ts +++ b/src/raps/actions/crosschainSwap.ts @@ -12,11 +12,10 @@ import { Rap, RapExchangeActionParameters, } from '../common'; -import { ProtocolType, TransactionStatus, TransactionType } from '@/entities'; +import { NewTransaction } from '@/entities'; import { toHex } from '@/handlers/web3'; import { parseGasParamAmounts } from '@/parsers'; -import { dataAddNewTransaction } from '@/redux/data'; import store from '@/redux/store'; import { ethereumUtils } from '@/utils'; import logger from '@/utils/logger'; @@ -24,6 +23,7 @@ import { estimateCrosschainSwapGasLimit } from '@/handlers/swap'; import { swapMetadataStorage } from './swap'; import { REFERRER } from '@/references'; import { overrideWithFastSpeedIfNeeded } from '../utils'; +import { addNewTransaction } from '@/state/pendingTransactionsStore'; const actionName = 'crosschainSwap'; @@ -145,29 +145,46 @@ const crosschainSwap = async ( logger.log(`[${actionName}] response`, swap); const isBridge = inputCurrency.symbol === outputCurrency.symbol; - const newTransaction = { - ...gasParams, - amount: inputAmount, - asset: inputCurrency, + + const newTransaction: NewTransaction = { data: swap?.data, - flashbots: parameters.flashbots, from: accountAddress, - gasLimit, + to: swap?.to ?? null, + value: tradeDetails?.value?.toString() || '', + asset: outputCurrency, + changes: [ + { + direction: 'out', + asset: inputCurrency, + value: tradeDetails.sellAmount.toString(), + }, + { + direction: 'in', + asset: outputCurrency, + value: tradeDetails.buyAmount.toString(), + }, + ], hash: swap?.hash, - network: ethereumUtils.getNetworkFromChainId(Number(chainId)), + network: inputCurrency.network, nonce: swap?.nonce, - protocol: ProtocolType.socket, - status: isBridge ? TransactionStatus.bridging : TransactionStatus.swapping, - to: swap?.to, - type: TransactionType.trade, - value: (swap && toHex(swap.value)) || undefined, + status: 'pending', + pending: true, + type: 'swap', + flashbots: parameters.flashbots, swap: { type: SwapType.crossChain, fromChainId: ethereumUtils.getChainIdFromNetwork(inputCurrency?.network), toChainId: ethereumUtils.getChainIdFromNetwork(outputCurrency?.network), isBridge, }, + ...gasParams, }; + + addNewTransaction({ + address: accountAddress, + transaction: newTransaction, + network: inputCurrency.network, + }); logger.log(`[${actionName}] adding new txn`, newTransaction); if (parameters.meta && swap?.hash) { @@ -177,15 +194,6 @@ const crosschainSwap = async ( ); } - dispatch( - dataAddNewTransaction( - // @ts-ignore - newTransaction, - accountAddress, - false, - wallet?.provider - ) - ); return swap?.nonce; }; diff --git a/src/raps/actions/ens.ts b/src/raps/actions/ens.ts index ba58d457737..fa66c1307d8 100644 --- a/src/raps/actions/ens.ts +++ b/src/raps/actions/ens.ts @@ -6,7 +6,11 @@ import { } from 'react-native-dotenv'; import { Rap, RapActionTypes, RapENSActionParameters } from '../common'; import { analytics } from '@/analytics'; -import { ENSRegistrationRecords, TransactionGasParamAmounts } from '@/entities'; +import { + ENSRegistrationRecords, + NewTransaction, + TransactionGasParamAmounts, +} from '@/entities'; import { estimateENSTransactionGasLimit, formatRecordsForTransaction, @@ -18,7 +22,7 @@ import { getENSExecutionDetails, REGISTRATION_MODES, } from '@/helpers/ens'; -import { dataAddNewTransaction } from '@/redux/data'; + import { saveCommitRegistrationParameters, updateTransactionRegistrationParameters, @@ -27,6 +31,8 @@ import store from '@/redux/store'; import { ethereumUtils } from '@/utils'; import logger from '@/utils/logger'; import { parseGasParamAmounts } from '@/parsers'; +import { addNewTransaction } from '@/state/pendingTransactionsStore'; +import { Network } from '@/networks/types'; const executeCommit = async ( name?: string, @@ -552,28 +558,35 @@ const ensAction = async ( const nativeAsset = await ethereumUtils.getNetworkNativeAsset( NetworkTypes.mainnet ); - const newTransaction = { - amount: 0, + const newTransaction: NewTransaction = { asset: nativeAsset, data: tx.data, ensCommitRegistrationName: type === ENSRegistrationTransactionType.COMMIT ? name : undefined, ensRegistration: true, from: ownerAddress, - gasLimit, hash: tx?.hash, maxFeePerGas, maxPriorityFeePerGas, nonce: tx?.nonce, + type: 'contract_interaction', + contract: { + name: 'ENS', + iconUrl: 'https://ens.domains/images/favicon-32x32.png', + }, to: tx?.to, value: toHex(tx.value), network: NetworkTypes.mainnet, + status: 'pending', + pending: true, }; logger.log(`[${actionName}] adding new txn`, newTransaction); - // @ts-expect-error Since src/redux/data.js is not typed yet, `accountAddress` - // being a string conflicts with the inferred type of "null" for the second - // parameter. - await dispatch(dataAddNewTransaction(newTransaction, ownerAddress)); + + addNewTransaction({ + address: ownerAddress, + transaction: newTransaction, + network: Network.mainnet, + }); return tx?.nonce; }; diff --git a/src/raps/actions/swap.ts b/src/raps/actions/swap.ts index 6977c4d84cd..fd5fadb5b54 100644 --- a/src/raps/actions/swap.ts +++ b/src/raps/actions/swap.ts @@ -15,19 +15,19 @@ import { RapExchangeActionParameters, SwapActionParameters, } from '../common'; -import { ProtocolType, TransactionStatus, TransactionType } from '@/entities'; +import { NewTransaction } from '@/entities'; import { toHex } from '@/handlers/web3'; import { parseGasParamAmounts } from '@/parsers'; -import { dataAddNewTransaction } from '@/redux/data'; import store from '@/redux/store'; -import { AllowancesCache, ethereumUtils } from '@/utils'; +import { AllowancesCache } from '@/utils'; import logger from '@/utils/logger'; import { estimateSwapGasLimit } from '@/handlers/swap'; import { MMKV } from 'react-native-mmkv'; import { STORAGE_IDS } from '@/model/mmkv'; import { REFERRER } from '@/references'; import { overrideWithFastSpeedIfNeeded } from '../utils'; +import { addNewTransaction } from '@/state/pendingTransactionsStore'; export const swapMetadataStorage = new MMKV({ id: STORAGE_IDS.SWAPS_METADATA_STORAGE, @@ -143,7 +143,7 @@ const swap = async ( } = parameters as SwapActionParameters; const { dispatch } = store; const { accountAddress } = store.getState().settings; - const { inputCurrency } = store.getState().swap; + const { inputCurrency, outputCurrency } = store.getState().swap; const { gasFeeParamsBySpeed, selectedGasFee } = store.getState().gas; let gasParams = parseGasParamAmounts(selectedGasFee); @@ -208,22 +208,34 @@ const swap = async ( logger.log(`[${actionName}] response`, swap); - const newTransaction = { - ...gasParams, - amount: inputAmount, - asset: inputCurrency, + if (!swap) throw Error; + + const newTransaction: NewTransaction = { data: swap?.data, - flashbots: parameters.flashbots, from: accountAddress, - gasLimit, - hash: swap?.hash ?? null, - network: ethereumUtils.getNetworkFromChainId(Number(chainId)), - nonce: swap?.nonce ?? null, - protocol: ProtocolType.uniswap, - status: TransactionStatus.swapping, to: swap?.to ?? null, - type: TransactionType.trade, - value: (swap && toHex(swap.value)) || undefined, + value: tradeDetails?.value?.toString() || '', + asset: outputCurrency, + changes: [ + { + direction: 'out', + asset: inputCurrency, + value: tradeDetails.sellAmount.toString(), + }, + { + direction: 'in', + asset: outputCurrency, + value: tradeDetails.buyAmount.toString(), + }, + ], + hash: swap.hash, + network: inputCurrency.network, + nonce: swap.nonce, + status: 'pending', + pending: true, + type: 'swap', + flashbots: parameters.flashbots, + ...gasParams, }; logger.log(`[${actionName}] adding new txn`, newTransaction); @@ -234,15 +246,12 @@ const swap = async ( ); } - dispatch( - dataAddNewTransaction( - newTransaction, - accountAddress, - false, - // @ts-ignore - wallet?.provider - ) - ); + addNewTransaction({ + address: accountAddress, + transaction: newTransaction, + network: inputCurrency.network, + }); + return swap?.nonce; }; diff --git a/src/raps/actions/unlock.ts b/src/raps/actions/unlock.ts index 1bf3887d23a..6b061b4b7ea 100644 --- a/src/raps/actions/unlock.ts +++ b/src/raps/actions/unlock.ts @@ -14,16 +14,18 @@ import { RapExchangeActionParameters, UnlockActionParameters, } from '../common'; -import { Asset, TransactionStatus, TransactionType } from '@/entities'; +import { Asset, NewTransaction } from '@/entities'; import { getProviderForNetwork, toHex } from '@/handlers/web3'; import { parseGasParamAmounts } from '@/parsers'; -import { dataAddNewTransaction } from '@/redux/data'; + import store from '@/redux/store'; import { erc20ABI, ETH_ADDRESS, ethUnits } from '@/references'; import { convertAmountToRawAmount, greaterThan } from '@/helpers/utilities'; import { AllowancesCache, ethereumUtils } from '@/utils'; import { overrideWithFastSpeedIfNeeded } from '../utils'; import logger from '@/utils/logger'; +import { ParsedAsset } from '@/resources/assets/types'; +import { addNewTransaction } from '@/state/pendingTransactionsStore'; export const estimateApprove = async ( owner: string, @@ -196,26 +198,25 @@ const unlock = async ( logger.log(`[${actionName}] response`, approval); - const newTransaction = { - amount: 0, - asset: assetToUnlock, + const newTransaction: NewTransaction = { + asset: assetToUnlock as ParsedAsset, data: approval.data, from: accountAddress, gasLimit, hash: approval?.hash, + type: 'approve', network: ethereumUtils.getNetworkFromChainId(Number(chainId)), nonce: approval?.nonce, - status: TransactionStatus.approving, to: approval?.to, - type: TransactionType.authorize, value: toHex(approval.value), ...gasParams, }; logger.log(`[${actionName}] adding new txn`, newTransaction); - // @ts-expect-error Since src/redux/data.js is not typed yet, `accountAddress` - // being a string conflicts with the inferred type of "null" for the second - // parameter. - await dispatch(dataAddNewTransaction(newTransaction, accountAddress)); + addNewTransaction({ + address: accountAddress, + transaction: newTransaction, + network: newTransaction.network, + }); return approval?.nonce; }; diff --git a/src/screens/AddCash/index.tsx b/src/screens/AddCash/index.tsx index 75b893b4f4a..4cd88867639 100644 --- a/src/screens/AddCash/index.tsx +++ b/src/screens/AddCash/index.tsx @@ -24,7 +24,6 @@ import Navigation from '@/navigation/Navigation'; import { WrappedAlert } from '@/helpers/alert'; import { logger, RainbowError } from '@/logger'; -import { Ratio } from '@/screens/AddCash/providers/Ratio'; import { Ramp } from '@/screens/AddCash/providers/Ramp'; import { Coinbase } from '@/screens/AddCash/providers/Coinbase'; import { Moonpay } from '@/screens/AddCash/providers/Moonpay'; @@ -35,7 +34,6 @@ const deviceHeight = deviceUtils.dimensions.height; const statusBarHeight = StatusBar.currentHeight || 0; const providerComponents = { - [FiatProviderName.Ratio]: Ratio, [FiatProviderName.Ramp]: Ramp, [FiatProviderName.Coinbase]: Coinbase, [FiatProviderName.Moonpay]: Moonpay, diff --git a/src/screens/AddCash/providers/Ratio/index.tsx b/src/screens/AddCash/providers/Ratio/index.tsx deleted file mode 100644 index ff96e85f328..00000000000 --- a/src/screens/AddCash/providers/Ratio/index.tsx +++ /dev/null @@ -1,314 +0,0 @@ -import React from 'react'; -import { - RatioComponent, - RatioOrderStatus, - OrderStatus, -} from '@ratio.me/ratio-react-native-library'; -import { nanoid } from 'nanoid/non-secure'; -import { useDispatch } from 'react-redux'; -import { useNavigation } from '@react-navigation/native'; -import { InteractionManager } from 'react-native'; -import upperFirst from 'lodash/upperFirst'; - -import { IS_IOS } from '@/env'; -import { WrappedAlert } from '@/helpers/alert'; -import { logger, RainbowError } from '@/logger'; -import * as lang from '@/languages'; -import { analyticsV2 } from '@/analytics'; -import { dataAddNewTransaction } from '@/redux/data'; -import { FiatProviderName } from '@/entities/f2c'; -import { Network as InternalNetwork } from '@/helpers'; -import { emailRainbow } from '@/utils/emailRainbow'; -import Routes from '@/navigation/routesNames'; -import { ProviderCard } from '@/screens/AddCash/components/ProviderCard'; -import { ProviderConfig } from '@/screens/AddCash/types'; -import { - getPublicKeyOfTheSigningWalletAndCreateWalletIfNeeded, - signWithSigningWallet, -} from '@/helpers/signingWallet'; -import { - ratioOrderToNewTransaction, - parseRatioNetworkToInternalNetwork, -} from './utils'; -import { isAuthenticated } from '@/utils/authentication'; -import { ratioGetClientSession } from '@/resources/f2c'; - -const ERROR_USER_FAILED_AUTH = 'user_failed_auth'; -const RATIO_SUPPORT_EMAIL = 'support@ratio.me'; - -export function Ratio({ - accountAddress, - config, -}: { - accountAddress: string; - config: ProviderConfig; -}) { - const [userId, setUserId] = React.useState(''); - const analyticsSessionId = React.useMemo(() => nanoid(), []); - const dispatch = useDispatch(); - const pendingTransactionSheetExplainerType = React.useRef(''); - const { navigate } = useNavigation(); - - const onTransactionComplete = React.useCallback( - async (order: RatioOrderStatus) => { - const success = order.status === OrderStatus.SUCCESS; - - logger.debug( - `Ratio: transaction complete`, - { success, order }, - logger.DebugContext.f2c - ); - - if (success) { - try { - analyticsV2.track(analyticsV2.event.f2cProviderFlowCompleted, { - provider: FiatProviderName.Ratio, - success: true, - sessionId: analyticsSessionId, - fiat_amount: order.data.activity.fiat.amount, - fiat_currency: order.data.activity.fiat.currency, - fiat_source: 'bank', - crypto_network: order.data.activity.crypto.wallet.network, - crypto_amount: order.data.activity.crypto.amount || undefined, - crypto_price: order.data.activity.crypto.price || undefined, - crypto_currency: order.data.activity.crypto.currency, - crypto_fee: order.data.activity.crypto.networkFee || undefined, - }); - } catch (e) { - // Just in case data changes during early stages of launch - logger.error( - new RainbowError( - `Ratio: error tracking f2cProviderFlowCompleted event` - ), - { message: (e as Error).message } - ); - } - - try { - const networkName = parseRatioNetworkToInternalNetwork( - order.data.activity.crypto.wallet.network - ); - const isMainnet = networkName === InternalNetwork.mainnet; - - /** - * Handle this check synchronously before we run - * ratioOrderToNewTransaction. THis ensures that the user hasn't - * closed the modal before that async function has returned. - */ - if (!isMainnet) { - logger.log( - `Ratio: transaction is not on mainnet, will not add to transaction list data`, - { - network: order.data.activity.crypto.wallet.network, - } - ); - - // set this to show the explainer sheet onClose of the modal - pendingTransactionSheetExplainerType.current = - 'f2cSemiSupportedAssetPurchased'; - } - - // OK now we can run this async function - const transaction = await ratioOrderToNewTransaction({ - userId: order.data.userId, - activity: order.data.activity, - analyticsSessionId, - }); - - logger.debug( - `Ratio: transaction parsed`, - { transaction }, - logger.DebugContext.f2c - ); - - // for now we only support L1 transaction data from our backend - if (isMainnet) { - logger.debug( - `Ratio: transaction is on mainnet, adding to transaction list data`, - {}, - logger.DebugContext.f2c - ); - - dispatch( - dataAddNewTransaction( - transaction, - order.data.activity.crypto.wallet.address, - true - ) - ); - } - } catch (e) { - if (e instanceof RainbowError) { - logger.error(e); - } else { - logger.error( - new RainbowError( - `Ratio: failed to parse an order into a transaction` - ), - { error: e } - ); - } - } - } else { - analyticsV2.track(analyticsV2.event.f2cProviderFlowCompleted, { - provider: FiatProviderName.Ratio, - success: false, - sessionId: analyticsSessionId, - }); - - logger.warn(`Ratio: order completed but success === false`, { - error: order.error, - }); - - WrappedAlert.alert( - lang.t(lang.l.wallet.add_cash_v2.generic_error.title), - order.error.message || - lang.t(lang.l.wallet.add_cash_v2.generic_error.message), - [ - { - text: lang.t(lang.l.wallet.add_cash_v2.generic_error.button), - }, - ] - ); - } - }, - [dispatch, userId, analyticsSessionId, pendingTransactionSheetExplainerType] - ); - - return ( - { - logger.debug(`Ratio: clicked`, {}, logger.DebugContext.f2c); - analyticsV2.track(analyticsV2.event.f2cProviderFlowStarted, { - provider: FiatProviderName.Ratio, - sessionId: analyticsSessionId, - }); - }} - onOpen={() => { - logger.debug(`Ratio: opened`, {}, logger.DebugContext.f2c); - }} - fetchSessionToken={async () => { - logger.debug(`Ratio: fetchSessionToken`, {}, logger.DebugContext.f2c); - - const isAuthed = await isAuthenticated(); - - if (!isAuthed) { - throw new Error(ERROR_USER_FAILED_AUTH); - } - - const signingAddress = await getPublicKeyOfTheSigningWalletAndCreateWalletIfNeeded(); - - const { data, error } = await ratioGetClientSession({ - signingAddress, - depositAddress: accountAddress, - }); - - if (!data || error) { - const [{ message }] = error.errors; - throw new Error(message); - } - - return data?.id; - }} - signingCallback={async challenge => { - logger.debug(`Ratio: signingCallback`, {}, logger.DebugContext.f2c); - - const signature = await signWithSigningWallet(challenge); - - return { signature }; - }} - onLogin={async user => { - logger.debug(`Ratio: onLogin`, {}, logger.DebugContext.f2c); - setUserId(user.id); - }} - onTransactionComplete={onTransactionComplete} - onError={error => { - let title = lang.t(lang.l.wallet.add_cash_v2.generic_error.title); - let message = lang.t(lang.l.wallet.add_cash_v2.generic_error.message); - - /** - * If this is thrown by the Ratio SDK, it's a known error. It's what we - * throw to fail authentication. - */ - if (error.includes(ERROR_USER_FAILED_AUTH)) { - title = lang.t( - lang.l.wallet.add_cash_v2.unauthenticated_ratio_error.title - ); - message = lang.t( - lang.l.wallet.add_cash_v2.unauthenticated_ratio_error.message - ); - } else { - logger.error( - new RainbowError(`Ratio component threw an error: ${error}`), - { error } - ); - - analyticsV2.track(analyticsV2.event.f2cProviderFlowErrored, { - provider: FiatProviderName.Ratio, - sessionId: analyticsSessionId, - }); - } - - WrappedAlert.alert(title, message, [ - { - text: lang.t(lang.l.wallet.add_cash_v2.generic_error.button), - }, - ]); - }} - onHelp={() => { - logger.debug(`Ratio: help clicked`, {}, logger.DebugContext.f2c); - emailRainbow({ - email: RATIO_SUPPORT_EMAIL, - hideRainbowBranding: true, - subject: lang.t(lang.l.wallet.add_cash_v2.support_emails.help, { - provider: upperFirst(FiatProviderName.Ratio), - }), - }); - }} - onAccountRecovery={() => { - logger.debug( - `Ratio: account recovery clicked`, - {}, - logger.DebugContext.f2c - ); - emailRainbow({ - email: RATIO_SUPPORT_EMAIL, - hideRainbowBranding: true, - subject: lang.t( - lang.l.wallet.add_cash_v2.support_emails.account_recovery - ), - }); - }} - onClose={() => { - logger.debug( - `Ratio: closed`, - { - showingL2Explainer: Boolean( - pendingTransactionSheetExplainerType.current - ), - }, - logger.DebugContext.f2c - ); - - // assign to variable to avoid ref updates before interactions finish - const explainerType = pendingTransactionSheetExplainerType.current; - - if (explainerType) { - InteractionManager.runAfterInteractions(() => { - setTimeout(() => { - navigate(Routes.EXPLAIN_SHEET, { - type: explainerType, - }); - }, 1000); - }); - } - - pendingTransactionSheetExplainerType.current = ''; - }} - > - - - ); -} diff --git a/src/screens/AddCash/providers/Ratio/utils.ts b/src/screens/AddCash/providers/Ratio/utils.ts deleted file mode 100644 index af8ab51edd6..00000000000 --- a/src/screens/AddCash/providers/Ratio/utils.ts +++ /dev/null @@ -1,103 +0,0 @@ -import { ActivityItem } from '@ratio.me/ratio-react-native-library'; - -import { - NewTransactionOrAddCashTransaction, - TransactionStatus, - TransactionType, -} from '@/entities'; -import { AddCashCurrencies } from '@/references'; -import { ethereumUtils } from '@/utils'; -import { logger, RainbowError } from '@/logger'; -import { FiatProviderName } from '@/entities/f2c'; -import { Network } from '@/helpers'; - -export function parseRatioNetworkToInternalNetwork(network: string) { - switch (network) { - case 'ETHEREUM': - return Network.mainnet; - case 'POLYGON': - return Network.polygon; - default: - return undefined; - } -} - -export function parseRatioCurrency(currency: string | `${string}_${string}`) { - const [token] = currency.split('_') as [string, string | undefined]; - return token; -} - -export async function ratioOrderToNewTransaction({ - userId, - activity, - analyticsSessionId, -}: { - userId: string; - activity: ActivityItem; - analyticsSessionId: string; -}): Promise { - const parsedCurrency = parseRatioCurrency(activity.crypto.currency); - const parsedNetwork = parseRatioNetworkToInternalNetwork( - activity.crypto.wallet.network - ); - - if (!parsedNetwork) { - logger.debug(`Ratio: could not determine network`, { - rawNetwork: activity.crypto.wallet.network, - parsedNetwork, - }); - - throw new RainbowError(`Ratio: could not determine network`); - } - - const destAssetAddress = AddCashCurrencies[parsedNetwork]?.[ - parsedCurrency - ]?.toLowerCase(); - - if (!destAssetAddress) { - logger.debug(`Ratio: could not determine asset address`, { - rawNetwork: activity.crypto.wallet.network, - parsedNetwork, - rawCurrency: activity.crypto.currency, - parsedCurrency, - }); - - throw new RainbowError(`Ratio: could not determine asset address`); - } - - const asset = await ethereumUtils.getNativeAssetForNetwork( - parsedNetwork, - destAssetAddress - ); - - if (!asset) { - logger.debug(`Ratio: could not get account asset`, { - rawNetwork: activity.crypto.wallet.network, - parsedNetwork, - rawCurrency: activity.crypto.currency, - parsedCurrency, - destAssetAddress, - }); - - throw new RainbowError(`Ratio: could not get account asset`); - } - - return { - amount: activity.crypto.amount, - asset, - from: null, - hash: null, - nonce: null, - sourceAmount: `${activity.fiat.amount} ${activity.fiat.currency}`, - status: TransactionStatus.purchasing, - timestamp: Date.now(), - to: activity.crypto.wallet.address, - type: TransactionType.purchase, - fiatProvider: { - name: FiatProviderName.Ratio, - orderId: activity.id, - userId: userId, - analyticsSessionId: analyticsSessionId, - }, - }; -} diff --git a/src/screens/NFTSingleOfferSheet/index.tsx b/src/screens/NFTSingleOfferSheet/index.tsx index 49f565b62a6..f3e7ea63234 100644 --- a/src/screens/NFTSingleOfferSheet/index.tsx +++ b/src/screens/NFTSingleOfferSheet/index.tsx @@ -32,7 +32,7 @@ import ConditionalWrap from 'conditional-wrap'; import Routes from '@/navigation/routesNames'; import { useLegacyNFTs } from '@/resources/nfts'; import { useAccountSettings, useGas, useWallets } from '@/hooks'; -import { TransactionStatus, TransactionType } from '@/entities'; +import { NewTransaction } from '@/entities'; import { analyticsV2 } from '@/analytics'; import { BigNumber } from '@ethersproject/bignumber'; import { HoldToAuthorizeButton } from '@/components/buttons'; @@ -42,7 +42,7 @@ import { Execute, getClient } from '@reservoir0x/reservoir-sdk'; import { privateKeyToAccount } from 'viem/accounts'; import { createWalletClient, http } from 'viem'; import { useDispatch } from 'react-redux'; -import { dataAddNewTransaction } from '@/redux/data'; + import { RainbowError, logger } from '@/logger'; import { estimateNFTOfferGas } from '@/handlers/nftOffers'; import { useTheme } from '@/theme'; @@ -52,6 +52,8 @@ import { CardSize } from '@/components/unique-token/CardSize'; import { queryClient } from '@/react-query'; import { nftOffersQueryKey } from '@/resources/reservoir/nftOffersQuery'; import { getRainbowFeeAddress } from '@/resources/reservoir/utils'; +import { addNewTransaction } from '@/state/pendingTransactionsStore'; +import { getUniqueId } from '@/utils/ethereumUtils'; const NFT_IMAGE_HEIGHT = 160; const TWO_HOURS_MS = 2 * 60 * 60 * 1000; @@ -350,37 +352,65 @@ export function NFTSingleOfferSheet() { !txsRef.current.includes(item.txHashes?.[0]) && item.status === 'incomplete' ) { - let tx; + let tx: NewTransaction | null = null; + const asset = { + ...nft, + address: nft.asset_contract.address || '', + symbol: 'NFT', + decimals: 18, + }; if (step.id === 'sale') { tx = { to: item.data?.to, from: item.data?.from, hash: item.txHashes[0], - network: offer.network, - amount: offer.netAmount.decimal, + network: offer.network as Network, asset: { - address: offer.paymentToken.address, - symbol: offer.paymentToken.symbol, + ...offer.paymentToken, + network: offer.network as Network, + uniqueId: getUniqueId( + offer.paymentToken.address, + offer.network as Network + ), }, - nft, - type: TransactionType.sell, - status: TransactionStatus.selling, + changes: [ + { + direction: 'out', + asset, + value: 1, + }, + { + direction: 'in', + asset: { + ...offer.paymentToken, + network: offer.network as Network, + uniqueId: getUniqueId( + offer.paymentToken.address, + offer.network as Network + ), + }, + value: offer.grossAmount.raw, + }, + ], + type: 'sale', }; } else if (step.id === 'nft-approval') { tx = { to: item.data?.to, from: item.data?.from, hash: item.txHashes[0], - network: offer.network, - nft, - type: TransactionType.authorize, - status: TransactionStatus.approving, + network: offer.network as Network, + asset, + type: 'approve', }; } if (tx) { + addNewTransaction({ + transaction: tx, + address: accountAddress, + network: offer.network as Network, + }); txsRef.current.push(tx.hash); - // @ts-ignore TODO: fix when we overhaul tx list, types are not good - dispatch(dataAddNewTransaction(tx)); } } else if ( item.status === 'complete' && diff --git a/src/screens/SendSheet.js b/src/screens/SendSheet.js index 97974d7856d..56c93295ef8 100644 --- a/src/screens/SendSheet.js +++ b/src/screens/SendSheet.js @@ -89,6 +89,7 @@ import { NoResultsType } from '@/components/list/NoResults'; import { setHardwareTXError } from '@/navigation/HardwareWalletTxNavigator'; import { Wallet } from '@ethersproject/wallet'; import { getNetworkObj } from '@/networks'; +import { addNewTransaction } from '@/state/pendingTransactionsStore'; const sheetHeight = deviceUtils.dimensions.height - (IS_ANDROID ? 30 : 10); const statusBarHeight = IS_IOS @@ -123,7 +124,6 @@ const validateRecipient = toAddress => { export default function SendSheet(props) { const dispatch = useDispatch(); const { goBack, navigate } = useNavigation(); - const { dataAddNewTransaction } = useTransactionConfirmation(); const { data: sortedAssets } = useSortedUserAssets(); const { gasFeeParamsBySpeed, @@ -581,9 +581,14 @@ export default function SendSheet(props) { txDetails.data = data; txDetails.value = value; txDetails.txTo = signableTransaction.to; - await dispatch( - dataAddNewTransaction(txDetails, null, false, currentProvider) - ); + txDetails.pending = true; + txDetails.type = 'send'; + txDetails.status = 'pending'; + addNewTransaction({ + address: accountAddress, + network: currentNetwork, + transaction: txDetails, + }); } } } catch (error) { @@ -607,8 +612,6 @@ export default function SendSheet(props) { amountDetails.isSufficientBalance, currentNetwork, currentProvider, - dataAddNewTransaction, - dispatch, ensName, ensProfile?.data?.coinAddresses, ensProfile?.data?.contenthash, diff --git a/src/screens/SignTransactionSheet.tsx b/src/screens/SignTransactionSheet.tsx index d906caab16b..e920e303850 100644 --- a/src/screens/SignTransactionSheet.tsx +++ b/src/screens/SignTransactionSheet.tsx @@ -53,7 +53,7 @@ import { useForegroundColor, } from '@/design-system'; import { TextColor } from '@/design-system/color/palettes'; -import { ParsedAddressAsset } from '@/entities'; +import { NewTransaction, ParsedAddressAsset } from '@/entities'; import { useNavigation } from '@/navigation'; import { useTheme } from '@/theme'; @@ -129,7 +129,6 @@ import { } from '@/model/wallet'; import { analytics } from '@/analytics'; -import { dataAddNewTransaction } from '@/redux/data'; import { handleSessionRequestResponse } from '@/walletConnect'; import { WalletconnectResultType, @@ -143,6 +142,8 @@ import { isAddress } from '@ethersproject/address'; import { methodRegistryLookupAndParse } from '@/utils/methodRegistry'; import { sanitizeTypedData } from '@/utils/signingUtils'; import { hexToNumber, isHex } from 'viem'; +import { addNewTransaction } from '@/state/pendingTransactionsStore'; +import { account } from '@/storage'; const COLLAPSED_CARD_HEIGHT = 56; const MAX_CARD_HEIGHT = 176; @@ -970,25 +971,33 @@ export const SignTransactionSheet = () => { callback({ result: sendInsteadOfSign ? sendResult.hash : signResult }); } let txSavedInCurrentWallet = false; - let txDetails: any = null; const displayDetails = transactionDetails.displayDetails; - if (sendInsteadOfSign) { - txDetails = { - amount: displayDetails?.request?.value ?? 0, + + if (sendInsteadOfSign && sendResult?.hash) { + const txDetails: NewTransaction = { asset: nativeAsset || displayDetails?.request?.asset, - dappName: displayDetails.dappName, + contract: { + name: displayDetails.dappName, + iconUrl: displayDetails.dappIcon, + }, data: sendResult.data, from: displayDetails?.request?.from, gasLimit, hash: sendResult.hash, - network: currentNetwork, + network: currentNetwork || Network.mainnet, nonce: sendResult.nonce, to: displayDetails?.request?.to, value: sendResult.value.toString(), + pending: true, + type: 'contract_interaction', ...gasParams, }; if (accountAddress?.toLowerCase() === txDetails.from?.toLowerCase()) { - dispatch(dataAddNewTransaction(txDetails, null, false, provider)); + addNewTransaction({ + transaction: txDetails, + network: currentNetwork || Network.mainnet, + address: accountAddress, + }); txSavedInCurrentWallet = true; } } @@ -1029,8 +1038,12 @@ export const SignTransactionSheet = () => { // we need to switch to that wallet before saving the tx if (!txSavedInCurrentWallet) { InteractionManager.runAfterInteractions(async () => { - await switchToWalletWithAddress(txDetails.from); - dispatch(dataAddNewTransaction(txDetails, null, false, provider)); + await switchToWalletWithAddress(txDetails.from!); + addNewTransaction({ + transaction: txDetails, + network: currentNetwork || Network.mainnet, + address: txDetails?.from!, + }); }); } } else { diff --git a/src/screens/mints/MintSheet.tsx b/src/screens/mints/MintSheet.tsx index 41140de2c4d..b623bc387cf 100644 --- a/src/screens/mints/MintSheet.tsx +++ b/src/screens/mints/MintSheet.tsx @@ -14,7 +14,6 @@ import { GasSpeedButton } from '@/components/gas'; import { Execute, getClient } from '@reservoir0x/reservoir-sdk'; import { privateKeyToAccount } from 'viem/accounts'; import { createWalletClient, http } from 'viem'; -import { dataAddNewTransaction } from '@/redux/data'; import { HoldToAuthorizeButton } from '@/components/buttons'; import Routes from '@/navigation/routesNames'; import ImgixImage from '../../components/images/ImgixImage'; @@ -51,7 +50,7 @@ import { ButtonPressAnimation } from '@/components/animations'; import { useFocusEffect, useRoute } from '@react-navigation/native'; import { ReservoirCollection } from '@/graphql/__generated__/arcDev'; import { format } from 'date-fns'; -import { TransactionStatus, TransactionType } from '@/entities'; +import { NewTransaction, RainbowTransaction } from '@/entities'; import * as i18n from '@/languages'; import { analyticsV2 } from '@/analytics'; import { event } from '@/analytics/event'; @@ -78,6 +77,8 @@ import { QuantityButton } from './components/QuantityButton'; import { estimateGas, getProviderForNetwork } from '@/handlers/web3'; import { getRainbowFeeAddress } from '@/resources/reservoir/utils'; import { IS_ANDROID, IS_IOS } from '@/env'; +import { addNewTransaction } from '@/state/pendingTransactionsStore'; +import { getUniqueId } from '@/utils/ethereumUtils'; const NFT_IMAGE_HEIGHT = 250; // inset * 2 -> 28 *2 @@ -353,7 +354,7 @@ const MintSheet = () => { // add l1Fee for OP Chains if (getNetworkObj(currentNetwork).gas.OptimismTxFee) { l1GasFeeOptimism = await ethereumUtils.calculateL1FeeOptimism( - tx, + tx as RainbowTransaction, provider ); } @@ -488,31 +489,60 @@ const MintSheet = () => { txRef.current !== item.txHashes?.[0] && item.status === 'incomplete' ) { - const tx = { + const asset = { + type: 'nft', + icon_url: imageUrl, + address: mintCollection.id || '', + network: currentNetwork, + name: mintCollection.name || '', + decimals: 18, + symbol: 'NFT', + uniqueId: `${mintCollection.id}-${item.txHashes[0]}`, + }; + + const paymentAsset = { + type: 'nft', + address: ETH_ADDRESS, + network: currentNetwork, + name: + mintCollection.publicMintInfo?.price?.currency?.name || + 'Ethereum', + decimals: + mintCollection.publicMintInfo?.price?.currency?.decimals || + 18, + symbol: ETH_SYMBOL, + uniqueId: getUniqueId(ETH_ADDRESS, currentNetwork), + }; + + const tx: NewTransaction = { to: item.data?.to, from: item.data?.from, hash: item.txHashes[0], network: currentNetwork, - amount: mintPriceAmount, - asset: { - address: ETH_ADDRESS, - symbol: ETH_SYMBOL, - }, - nft: { - predominantColor: imageColor, - collection: { - image: imageUrl, + + changes: [ + { + direction: 'out', + asset: paymentAsset, + value: mintPriceAmount, }, - lowResUrl: imageUrl, - name: mintCollection.name, - }, - type: TransactionType.mint, - status: TransactionStatus.minting, + ...Array(quantity).fill({ + direction: 'in', + asset, + }), + ], + description: asset.name, + asset, + type: 'mint', }; txRef.current = tx.hash; - // @ts-expect-error TODO: fix when we overhaul tx list, types are not good - dispatch(dataAddNewTransaction(tx)); + + addNewTransaction({ + transaction: tx, + address: accountAddress, + network: currentNetwork, + }); analyticsV2.track(event.mintsMintedNFT, { collectionName: mintCollection.name || '', contract: mintCollection.id || '', @@ -543,14 +573,14 @@ const MintSheet = () => { }, [ accountAddress, currentNetwork, - dispatch, - imageColor, imageUrl, isMintingAvailable, isReadOnlyWallet, mintCollection.chainId, mintCollection.id, mintCollection.name, + mintCollection.publicMintInfo?.price?.currency?.decimals, + mintCollection.publicMintInfo?.price?.currency?.name, mintPriceAmount, navigate, quantity, From 0ead5a0e866ccbb63cc93d8735107235be3f0926 Mon Sep 17 00:00:00 2001 From: Matthew Wall Date: Mon, 5 Feb 2024 09:45:31 -0700 Subject: [PATCH 11/38] fix prettier --- audit-ci.jsonc | 4 +- e2e/registerENSFlow.spec.js | 12 +- lint-staged.config.js | 3 + metro.transform.js | 3 +- package.json | 10 +- src/components/EdgeFade.js | 28 +- .../ButtonPressAnimation.android.tsx | 7 +- .../ButtonPressAnimation/NativeButton.tsx | 45 +- .../animations/ButtonPressAnimation/types.ts | 3 +- .../asset-list/RecyclerAssetList/index.tsx | 19 +- .../FastCurrencySelectionRow.tsx | 9 +- .../WrappedPositionsListHeader.tsx | 6 +- .../core/ExternalENSProfileScrollView.tsx | 10 +- .../core/RawRecyclerList.tsx | 19 +- .../asset-list/RecyclerAssetList2/index.tsx | 14 +- .../ProfileActionButtonsRow.tsx | 6 +- .../profile-header/ProfileAvatarRow.tsx | 7 +- .../backup/BackupConfirmPasswordStep.js | 7 +- src/components/buttons/MiniButton.js | 8 +- src/components/buttons/PasteAddressButton.js | 8 +- .../HoldToAuthorizeButtonContent.tsx | 4 +- .../rainbow-button/RainbowButtonBackground.js | 8 +- src/components/cards/ActionCard.tsx | 8 +- .../cards/MintsCard/CollectionCell.tsx | 5 +- .../cards/remote-cards/RemoteCard.tsx | 9 +- .../cards/remote-cards/RemoteCardCarousel.tsx | 8 +- src/components/cards/utils/constants.ts | 4 +- src/components/change-wallet/AddressRow.tsx | 7 +- src/components/coin-divider/CoinDivider.js | 13 +- src/components/coin-icon/CoinIcon.tsx | 7 +- src/components/coin-icon/CoinIconFallback.js | 12 +- .../coin-row/CollectiblesSendRow.tsx | 4 +- src/components/coin-row/SendCoinRow.js | 8 +- src/components/contacts/ContactAvatar.js | 8 +- src/components/contacts/ContactRow.js | 11 +- .../contacts/SwipeableContactRow.js | 8 +- .../copy-tooltip/CopyTooltip.ios.js | 7 +- .../ens-profile/ProfileCover/ProfileCover.tsx | 12 +- .../ens-profile/RecordTags/RecordTags.tsx | 2 +- .../IntroMarquee/IntroMarquee.tsx | 5 +- .../RegistrationAvatar/RegistrationAvatar.tsx | 82 +- .../RegistrationCover/RegistrationCover.tsx | 13 +- .../exchange/ConfirmExchangeButton.js | 22 +- src/components/exchange/ExchangeAssetList.tsx | 7 +- .../exchange/ExchangeNativeField.tsx | 5 +- src/components/exchange/ExchangeTokenRow.tsx | 3 +- .../expanded-state/SwapDetailsState.js | 32 +- .../UniqueTokenExpandedState.tsx | 20 +- .../asset/ChartExpandedState.js | 23 +- .../chart/ChartContextButton.js | 7 +- .../ChartChangeDirectionArrow.js | 4 +- .../chart/chart-data-labels/ChartDateLabel.js | 4 +- .../ChartPercentChangeLabel.js | 13 +- .../expanded-state/custom-gas/FeesPanel.tsx | 10 +- src/components/expanded-state/ens/InfoRow.tsx | 8 +- .../expanded-state/ens/ProfileInfoSection.tsx | 31 +- .../expanded-state/profile/ProfileModal.tsx | 7 +- .../swap-details/SwapDetailsContent.js | 5 +- .../swap-details/SwapDetailsContractRow.js | 12 +- .../swap-settings/MaxToleranceInput.tsx | 4 +- .../swap-settings/SwapSettingsState.js | 6 +- .../UniqueTokenExpandedStateHeader.tsx | 2 +- .../unique-token/ZoomableWrapper.android.js | 40 +- .../unique-token/ZoomableWrapper.js | 40 +- src/components/fields/BubbleField.js | 8 +- src/components/fields/SmallBubbleField.js | 12 +- .../floating-emojis/FloatingEmojis.js | 4 +- src/components/gas/GasSpeedButton.js | 26 +- src/components/images/ImagePreviewOverlay.tsx | 4 +- src/components/inputs/InlineField.tsx | 12 +- src/components/layout/LayoutWithDividers.js | 7 +- src/components/qrcode-scanner/CameraDimmer.js | 5 +- .../remote-promo-sheet/RemotePromoSheet.tsx | 5 +- .../remote-promo-sheet/checkForCampaign.ts | 11 +- .../notificationsPromoCampaign.ts | 47 +- src/components/secret-display/states.ts | 3 +- src/components/send/SendAssetFormField.js | 4 +- src/components/send/SendAssetFormToken.js | 6 +- src/components/send/SendButton.js | 4 +- src/components/send/SendHeader.js | 8 +- src/components/sheet/SlackSheet.js | 4 +- src/components/unique-token/Tag.js | 5 +- .../unique-token/UniqueTokenCard.js | 7 +- src/components/value-chart/Chart.js | 7 +- .../WalletConnectV2ListItem.tsx | 81 +- .../color/AccentColorContext.tsx | 2 +- src/design-system/color/palettes.docs.tsx | 20 +- src/design-system/color/palettes.ts | 8 +- src/design-system/components/Box/Box.tsx | 2 +- .../components/Box/polymorphic.ts | 7 +- .../components/Heading/Heading.examples.tsx | 6 +- .../components/Heading/useHeadingStyle.ts | 2 +- .../components/Inline/Inline.tsx | 7 +- .../components/MarkdownText/MarkdownText.tsx | 17 +- .../components/Text/useTextStyle.ts | 2 +- src/design-system/docs/.playroom/fonts.css | 30 +- src/design-system/docs/styles/fonts.css | 36 +- .../docs/system/typography.css.ts | 4 +- src/design-system/playground/Playground.tsx | 7 +- src/ens-avatar/src/index.ts | 5 +- .../unlockableAppIconCheck.ts | 9 +- src/graphql/utils/getFetchRequester.ts | 2 +- src/handlers/LedgerSigner.ts | 5 +- src/handlers/ens.ts | 16 +- src/handlers/nftOffers.ts | 6 +- src/handlers/swap.ts | 43 +- src/handlers/web3.ts | 8 +- .../buildTransactionsSectionsSelector.tsx | 64 +- src/helpers/buildWalletSections.tsx | 6 +- src/helpers/chartTypes.ts | 2 +- src/helpers/emojiHandler.ts | 3 +- src/helpers/ens.ts | 23 +- src/helpers/signingWallet.ts | 6 +- src/helpers/time.ts | 6 +- ...ansformUniqueAssetTraitsForPresentation.ts | 3 +- src/helpers/utilities.ts | 15 +- src/hooks/charts/useChartInfo.ts | 2 +- src/hooks/charts/useChartThrottledPoints.ts | 5 +- src/hooks/useAccountENSDomains.ts | 43 +- src/hooks/useAccountTransactions.ts | 5 +- src/hooks/useAnimatedPageScrollHandler.ts | 4 +- src/hooks/useCoinListEditOptions.ts | 7 +- src/hooks/useCoinListEdited.ts | 5 +- src/hooks/useDeleteWallet.ts | 22 +- src/hooks/useENSModifiedRegistration.ts | 6 +- src/hooks/useENSRegistrationActionHandler.ts | 6 +- src/hooks/useENSRegistrationCosts.ts | 7 +- src/hooks/useENSRegistrationForm.ts | 5 +- src/hooks/useENSRegistrationStepHandler.tsx | 20 +- src/hooks/useExpandedStateNavigation.ts | 2 +- src/hooks/useInteraction.ts | 2 +- src/hooks/useInterval.ts | 2 +- src/hooks/useInvalidPaste.ts | 7 +- src/hooks/useLatestCallback.ts | 4 +- src/hooks/useOnAvatarPress.ts | 22 +- src/hooks/useParamsForExchangeModal.ts | 7 +- src/hooks/usePortfolios.ts | 7 +- src/hooks/usePriceImpactDetails.ts | 5 +- src/hooks/useRouteExistsInNavigationState.ts | 8 +- src/hooks/useSearchCurrencyList.ts | 29 +- src/hooks/useSendSheetInputRefs.ts | 7 +- src/hooks/useSwapCurrencyHandlers.ts | 7 +- src/hooks/useSwapCurrencyList.ts | 29 +- src/hooks/useSwapDerivedOutputs.ts | 12 +- src/hooks/useSwapInputRefs.ts | 7 +- src/hooks/useSwapRefuel.ts | 49 +- src/hooks/useSwappableUserAssets.ts | 10 +- src/hooks/useTimeout.ts | 2 +- src/hooks/useWalletSectionsData.ts | 20 +- src/hooks/useWatchPendingTxs.ts | 40 +- src/hooks/useWatchWallet.ts | 11 +- src/keychain/index.ts | 2 +- src/model/backup.ts | 6 +- src/model/migrations.ts | 12 +- src/model/preferences.ts | 11 +- src/model/wallet.ts | 70 +- src/navigation/HardwareWalletTxNavigator.tsx | 5 +- .../PairHardwareWalletNavigator.tsx | 5 +- .../RecyclerListViewScrollToTopContext.tsx | 12 +- src/navigation/RegisterENSNavigator.tsx | 14 +- src/navigation/Routes.android.tsx | 2 +- src/navigation/Routes.ios.tsx | 2 +- .../bottom-sheet/contexts/internal.ts | 5 +- src/navigation/bottom-sheet/types.d.ts | 4 +- src/navigation/config.tsx | 55 +- src/navigation/effects.tsx | 100 +- src/navigation/onNavigationStateChange.js | 4 +- src/notifications/NotificationsHandler.tsx | 10 +- src/notifications/analytics.ts | 33 +- src/notifications/settings/hooks.ts | 24 +- src/notifications/settings/initialization.ts | 49 +- src/notifications/settings/types.ts | 9 +- src/notifications/types.ts | 6 +- src/parsers/accounts.js | 6 +- .../tracking/types/PerformanceMetrics.ts | 3 +- .../tracking/types/PerformanceTags.ts | 3 +- src/raps/actions/crosschainSwap.ts | 8 +- src/raps/actions/ens.ts | 11 +- src/raps/actions/swap.ts | 9 +- src/raps/actions/unlock.ts | 13 +- src/raps/registerENS.ts | 9 +- .../Example/src/BasicExample/index.js | 6 +- .../Example/src/GenericExample/index.js | 137 +- .../src/charts/linear/ChartLabels.tsx | 9 +- .../src/charts/linear/ChartPath.tsx | 97 +- .../src/helpers/d3Interpolate.js | 3 +- src/react-query/types.ts | 40 +- src/redux/appState.ts | 16 +- src/redux/charts.ts | 57 +- src/redux/contacts.ts | 102 +- src/redux/data.ts | 1185 ++++++++-------- src/redux/editOptions.ts | 16 +- src/redux/ensRegistration.ts | 613 ++++---- src/redux/explorer.ts | 441 +++--- src/redux/gas.ts | 691 ++++----- src/redux/hiddenTokens.ts | 178 +-- src/redux/imageMetadata.ts | 47 +- src/redux/keyboardHeight.ts | 59 +- src/redux/nonceManager.ts | 103 +- src/redux/requests.ts | 202 +-- src/redux/settings.ts | 339 ++--- src/redux/showcaseTokens.ts | 188 +-- src/redux/swap.ts | 242 ++-- src/redux/transactionSignatures.ts | 56 +- src/redux/walletconnect.ts | 1259 +++++++++-------- src/redux/wallets.ts | 872 ++++++------ src/references/rainbow-token-list/index.ts | 12 +- src/references/swap/bridges.ts | 3 +- src/resources/assets/UserAssetsQuery.ts | 6 +- src/resources/assets/assetSelectors.ts | 6 +- src/resources/assets/hardhatAssets.ts | 11 +- src/resources/cards/cardCollectionQuery.ts | 2 +- src/resources/nfts/index.ts | 15 +- src/resources/nfts/utils.ts | 3 +- .../transactions/consolidatedTransactions.ts | 2 +- src/resources/transactions/types.ts | 6 +- src/screens/AddCash/index.tsx | 6 +- src/screens/ChangeWalletSheet.tsx | 20 +- src/screens/CurrencySelectModal.tsx | 27 +- .../Diagnostics/DiagnosticsItemRow.tsx | 7 +- src/screens/Diagnostics/index.tsx | 5 +- src/screens/ENSAdditionalRecordsSheet.tsx | 7 +- src/screens/ENSConfirmRegisterSheet.tsx | 5 +- src/screens/ENSSearchSheet.tsx | 4 +- src/screens/ExchangeModal.tsx | 65 +- src/screens/ExplainSheet.js | 19 +- src/screens/ImportOrWatchWalletSheet.tsx | 9 +- src/screens/MintsSheet/MintsSheet.tsx | 8 +- src/screens/NFTOffersSheet/index.tsx | 8 +- src/screens/NotificationsPromoSheet/index.tsx | 6 +- src/screens/PinAuthenticationScreen.js | 4 +- src/screens/ProfileSheet.tsx | 22 +- src/screens/ReceiveModal.js | 7 +- src/screens/RestoreSheet.js | 5 +- src/screens/SelectENSSheet.tsx | 7 +- src/screens/SendConfirmationSheet.tsx | 6 +- src/screens/SendSheet.js | 25 +- .../components/BackupSection.android.tsx | 16 +- .../components/BackupSection.tsx | 16 +- .../components/DevSection.android.tsx | 15 +- .../SettingsSheet/components/DevSection.tsx | 15 +- .../SettingsSheet/components/MenuItem.tsx | 12 +- .../NotificationsSection.android.tsx | 19 +- .../components/NotificationsSection.tsx | 19 +- .../components/PrivacySection.android.tsx | 37 +- .../components/PrivacySection.tsx | 37 +- .../components/SettingsSection.tsx | 12 +- .../WalletNotificationsSettings.android.tsx | 17 +- .../WalletNotificationsSettings.tsx | 17 +- src/screens/ShowcaseSheet.js | 5 +- src/screens/SignTransactionSheet.tsx | 12 +- src/screens/TransactionConfirmationScreen.js | 11 +- .../discover/components/DiscoverHome.js | 15 +- .../components/DiscoverSearchContainer.js | 5 +- .../PairHardwareWalletAgainSheet.tsx | 8 +- .../PairHardwareWalletErrorSheet.tsx | 5 +- .../PairHardwareWalletSigningSheet.tsx | 12 +- src/screens/mints/MintSheet.tsx | 4 +- src/screens/mints/PoapSheet.tsx | 8 +- src/screens/points/PointsScreen.tsx | 14 +- .../points/components/AnimatedText.tsx | 19 +- .../points/components/LeaderboardRow.tsx | 7 +- .../NotificationToggleContextMenu.tsx | 16 +- src/screens/points/content/PointsContent.tsx | 20 +- .../points/content/console/calculate.tsx | 5 +- .../points/content/console/initialize.tsx | 8 +- src/screens/points/content/console/share.tsx | 15 +- .../points/contexts/PointsProfileContext.tsx | 42 +- src/screens/rewards/RewardsSheet.tsx | 6 +- .../TransactionDetails.tsx | 8 +- .../TransactionDetailsAddressRow.tsx | 7 +- ...etailsStatusActionsAndTimestampSection.tsx | 7 +- src/state/internal/createStore.ts | 10 +- src/styled-thing/hoist.ts | 12 +- src/theme/ThemeContext.tsx | 2 +- src/utils/__mocks__/delay.ts | 8 +- src/utils/ens.ts | 2 +- src/utils/ethereumUtils.ts | 6 +- src/utils/haptics.ts | 3 +- src/utils/profileUtils.ts | 7 +- src/utils/recompactAdapters.tsx | 6 +- src/walletConnect/index.tsx | 19 +- src/walletConnect/types.ts | 4 +- yarn.lock | 16 +- 284 files changed, 5005 insertions(+), 5225 deletions(-) create mode 100644 lint-staged.config.js diff --git a/audit-ci.jsonc b/audit-ci.jsonc index 3a1cd024405..2fcd75461f2 100644 --- a/audit-ci.jsonc +++ b/audit-ci.jsonc @@ -15,6 +15,6 @@ "GHSA-cchq-frgv-rjh5", // https://github.com/advisories/GHSA-cchq-frgv-rjh5 "GHSA-g644-9gfx-q4q4", // https://github.com/advisories/GHSA-g644-9gfx-q4q4 "GHSA-m95q-7qp3-xv42", // https://github.com/advisories/GHSA-m95q-7qp3-xv42 - "GHSA-gxpj-cx7g-858c" // https://github.com/advisories/GHSA-gxpj-cx7g-858c - ] + "GHSA-gxpj-cx7g-858c", // https://github.com/advisories/GHSA-gxpj-cx7g-858c + ], } diff --git a/e2e/registerENSFlow.spec.js b/e2e/registerENSFlow.spec.js index 77f755cbbaf..70118cf5773 100644 --- a/e2e/registerENSFlow.spec.js +++ b/e2e/registerENSFlow.spec.js @@ -133,14 +133,10 @@ const resolveName = async ensName => { }; const validatePrimaryName = async name => { - const { - address: rainbowAddress, - primaryName: rainbowPrimaryName, - } = await resolveName(RAINBOW_TEST_WALLET_NAME); - const { - address: randomAddress, - primaryName: randomPrimaryName, - } = await resolveName(RANDOM_NAME_ETH); + const { address: rainbowAddress, primaryName: rainbowPrimaryName } = + await resolveName(RAINBOW_TEST_WALLET_NAME); + const { address: randomAddress, primaryName: randomPrimaryName } = + await resolveName(RANDOM_NAME_ETH); if ( rainbowAddress !== randomAddress || diff --git a/lint-staged.config.js b/lint-staged.config.js new file mode 100644 index 00000000000..64148218a63 --- /dev/null +++ b/lint-staged.config.js @@ -0,0 +1,3 @@ +module.exports = { + '*.{js,jsx,ts,tsx,graphql}': ['prettier --write', 'eslint --cache'], +}; diff --git a/metro.transform.js b/metro.transform.js index cf91d9b9d3f..4eff389db94 100644 --- a/metro.transform.js +++ b/metro.transform.js @@ -10,7 +10,8 @@ module.exports.transform = function applyRainbowTransform({ const opts = merge(options, { customTransformOptions: { 'metro-plugin-anisotropic-transform': { - cyclicDependents: /.+\/node_modules\/react-native\/Libraries\/BatchedBridge\/NativeModules\.js$/, + cyclicDependents: + /.+\/node_modules\/react-native\/Libraries\/BatchedBridge\/NativeModules\.js$/, globalScopeFilter: { '@react-native-community/clipboard': {}, 'react-native-keychain': {}, diff --git a/package.json b/package.json index 3d89f9b8039..dc11d53a367 100644 --- a/package.json +++ b/package.json @@ -307,7 +307,7 @@ "viem": "1.6.0", "vm-browserify": "0.0.4", "w2t": "3.0.2", - "zustand": "4.1.5" + "zustand": "4.3.1" }, "devDependencies": { "@babel/core": "7.22.0", @@ -361,7 +361,7 @@ "metro-plugin-anisotropic-transform": "https://github.com/rainbow-me/metro-plugin-anisotropic-transform#eaf2a2db95eeedd2f63ce8032c102a12c5a88802", "metro-react-native-babel-preset": "0.76.7", "node-vibrant": "3.2.1-alpha.1", - "prettier": "2.2.1", + "prettier": "3.2.5", "react-test-renderer": "18.1.0", "resolve": "1.22.8", "rn-nodeify": "10.2.0", @@ -531,11 +531,5 @@ "react-native-storage": false, "react-native-storage>opencollective>babel-polyfill>core-js": false } - }, - "lint-staged": { - "*.{js,jsx,ts,tsx,graphql}": [ - "prettier --write", - "eslint --cache" - ] } } diff --git a/src/components/EdgeFade.js b/src/components/EdgeFade.js index f947c9b2797..374f80e61ec 100644 --- a/src/components/EdgeFade.js +++ b/src/components/EdgeFade.js @@ -20,19 +20,7 @@ const LeftFade = styled(LinearGradient).attrs(({ theme: { colors } }) => ({ ], end: { x: 1, y: 0.5 }, locations: [ - 0, - 0.19, - 0.34, - 0.47, - 0.565, - 0.65, - 0.73, - 0.802, - 0.861, - 0.91, - 0.952, - 0.982, - 1, + 0, 0.19, 0.34, 0.47, 0.565, 0.65, 0.73, 0.802, 0.861, 0.91, 0.952, 0.982, 1, ], pointerEvents: 'none', start: { x: 0, y: 0.5 }, @@ -61,19 +49,7 @@ const RightFade = styled(LinearGradient).attrs(({ theme: { colors } }) => ({ ], end: { x: 0, y: 0.5 }, locations: [ - 0, - 0.19, - 0.34, - 0.47, - 0.565, - 0.65, - 0.73, - 0.802, - 0.861, - 0.91, - 0.952, - 0.982, - 1, + 0, 0.19, 0.34, 0.47, 0.565, 0.65, 0.73, 0.802, 0.861, 0.91, 0.952, 0.982, 1, ], pointerEvents: 'none', start: { x: 1, y: 0.5 }, diff --git a/src/components/animations/ButtonPressAnimation/ButtonPressAnimation.android.tsx b/src/components/animations/ButtonPressAnimation/ButtonPressAnimation.android.tsx index c57e0724ff6..8762e1a84b2 100644 --- a/src/components/animations/ButtonPressAnimation/ButtonPressAnimation.android.tsx +++ b/src/components/animations/ButtonPressAnimation/ButtonPressAnimation.android.tsx @@ -126,8 +126,8 @@ const ScaleButton = ({ onPress, }); - const gestureHandler = useAnimatedGestureHandler( - { + const gestureHandler = + useAnimatedGestureHandler({ onActive: () => { runOnJS(handleStartPress)(); if (hasScaledDown.value === 0) { @@ -148,8 +148,7 @@ const ScaleButton = ({ onFail: () => { runOnJS(handleCancel)(); }, - } - ); + }); return ( diff --git a/src/components/animations/ButtonPressAnimation/NativeButton.tsx b/src/components/animations/ButtonPressAnimation/NativeButton.tsx index 672b3fc4234..96cf0772523 100644 --- a/src/components/animations/ButtonPressAnimation/NativeButton.tsx +++ b/src/components/animations/ButtonPressAnimation/NativeButton.tsx @@ -21,31 +21,32 @@ interface SpecificRawNativeButtonProps extends Props { transformOrigin?: TransformOrigin; } -const RawNativeButton = requireNativeComponent( - 'Button' -); - -const ButtonWithTransformOrigin = styled(RawNativeButton)( - ({ transformOrigin }: { transformOrigin: TransformOrigin }) => { - if (!transformOrigin) return {}; - const [x, y] = transformOrigin; - // 👇️ Here we want to set the button's top / left - // properties (relative to the parent wrapper view) to - // values opposite of the provided transformOrigin. - // This is necessary to do in order for the `transformOrigin` prop to - // work with NativeButton without effecting NativeButton's layout. - const styles: ViewStyle = {}; +const RawNativeButton = + requireNativeComponent('Button'); - if (x !== 0.5) { - styles.left = `${x + 0.5 * (x > 0.5 ? 100 : -100)}%`; - } - if (y !== 0.5) { - styles.top = `${y + 0.5 * (y > 0.5 ? 100 : -100)}%`; - } +const ButtonWithTransformOrigin = styled(RawNativeButton)(({ + transformOrigin, +}: { + transformOrigin: TransformOrigin; +}) => { + if (!transformOrigin) return {}; + const [x, y] = transformOrigin; + // 👇️ Here we want to set the button's top / left + // properties (relative to the parent wrapper view) to + // values opposite of the provided transformOrigin. + // This is necessary to do in order for the `transformOrigin` prop to + // work with NativeButton without effecting NativeButton's layout. + const styles: ViewStyle = {}; - return styles; + if (x !== 0.5) { + styles.left = `${x + 0.5 * (x > 0.5 ? 100 : -100)}%`; } -); + if (y !== 0.5) { + styles.top = `${y + 0.5 * (y > 0.5 ? 100 : -100)}%`; + } + + return styles; +}); export function normalizeTransformOrigin( transformOrigin: TransformOrigin | string | undefined diff --git a/src/components/animations/ButtonPressAnimation/types.ts b/src/components/animations/ButtonPressAnimation/types.ts index b4973c3786a..3963c393adc 100644 --- a/src/components/animations/ButtonPressAnimation/types.ts +++ b/src/components/animations/ButtonPressAnimation/types.ts @@ -7,7 +7,8 @@ import { export type TransformOrigin = [number, number]; export type Direction = 'bottom' | 'left' | 'right' | 'top'; -export type ButtonPressAnimationTouchEvent = NativeSyntheticEvent; +export type ButtonPressAnimationTouchEvent = + NativeSyntheticEvent; export interface BaseButtonAnimationProps extends Pick, diff --git a/src/components/asset-list/RecyclerAssetList/index.tsx b/src/components/asset-list/RecyclerAssetList/index.tsx index aabb4e9167f..009701115de 100644 --- a/src/components/asset-list/RecyclerAssetList/index.tsx +++ b/src/components/asset-list/RecyclerAssetList/index.tsx @@ -225,9 +225,8 @@ function RecyclerAssetList({ const { openFamilies: openFamilyTabs } = useOpenFamilies(); const { ref, handleRef } = useRecyclerListViewRef(); const stickyCoinDividerRef = React.useRef() as React.RefObject; - const [globalDeviceDimensions, setGlobalDeviceDimensions] = useState( - 0 - ); + const [globalDeviceDimensions, setGlobalDeviceDimensions] = + useState(0); const { areSmallCollectibles, items, @@ -353,9 +352,8 @@ function RecyclerAssetList({ } if (type.index === ViewTypes.HEADER.index) { - return (showcase - ? ViewTypes.SHOWCASE_HEADER - : ViewTypes.HEADER + return ( + showcase ? ViewTypes.SHOWCASE_HEADER : ViewTypes.HEADER ).renderComponent({ data, isCoinListEdited, @@ -524,7 +522,7 @@ function RecyclerAssetList({ }; }, (type, dim) => { - const element = (type as unknown) as { + const element = type as unknown as { readonly height: number; readonly visibleDuringCoinEdit: boolean; }; @@ -583,7 +581,8 @@ function RecyclerAssetList({ useEffect(() => { let collectibles: RecyclerAssetListSection = {} as RecyclerAssetListSection; - let prevCollectibles: RecyclerAssetListSection = {} as RecyclerAssetListSection; + let prevCollectibles: RecyclerAssetListSection = + {} as RecyclerAssetListSection; let balances: RecyclerAssetListSection = {} as RecyclerAssetListSection; let smallBalances: any = {}; @@ -687,8 +686,8 @@ function RecyclerAssetList({ disableStickyHeaders ? [] : isCoinListEdited - ? defaultIndices - : stickyComponentsIndices + ? defaultIndices + : stickyComponentsIndices } > {/* @ts-ignore */} diff --git a/src/components/asset-list/RecyclerAssetList2/FastComponents/FastCurrencySelectionRow.tsx b/src/components/asset-list/RecyclerAssetList2/FastComponents/FastCurrencySelectionRow.tsx index 06a2dd5a033..0a1d2d08458 100644 --- a/src/components/asset-list/RecyclerAssetList2/FastComponents/FastCurrencySelectionRow.tsx +++ b/src/components/asset-list/RecyclerAssetList2/FastComponents/FastCurrencySelectionRow.tsx @@ -19,9 +19,9 @@ import { useAccountAsset } from '@/hooks'; import { colors, fonts, fontWithWidth, getFontSize } from '@/styles'; import { deviceUtils } from '@/utils'; -const SafeRadialGradient = (IS_TESTING === 'true' - ? View - : RadialGradient) as typeof RadialGradient; +const SafeRadialGradient = ( + IS_TESTING === 'true' ? View : RadialGradient +) as typeof RadialGradient; interface FastCurrencySelectionRowProps { item: any; @@ -261,8 +261,7 @@ export default React.memo(function FastCurrencySelectionRow({ )} ); -}, -isEqual); +}, isEqual); const sx = StyleSheet.create({ addGradient: { diff --git a/src/components/asset-list/RecyclerAssetList2/WrappedPositionsListHeader.tsx b/src/components/asset-list/RecyclerAssetList2/WrappedPositionsListHeader.tsx index 6c8a3a3f6dc..05e3ca48626 100644 --- a/src/components/asset-list/RecyclerAssetList2/WrappedPositionsListHeader.tsx +++ b/src/components/asset-list/RecyclerAssetList2/WrappedPositionsListHeader.tsx @@ -14,10 +14,8 @@ const TokenFamilyHeaderHeight = 48; const PositionListHeader = ({ total, ...props }: { total: string }) => { const { colors } = useTheme(); - const { - isPositionCardsOpen, - toggleOpenPositionCards, - } = useOpenPositionCards(); + const { isPositionCardsOpen, toggleOpenPositionCards } = + useOpenPositionCards(); const toValue = Number(!!isPositionCardsOpen); diff --git a/src/components/asset-list/RecyclerAssetList2/core/ExternalENSProfileScrollView.tsx b/src/components/asset-list/RecyclerAssetList2/core/ExternalENSProfileScrollView.tsx index ff3b3d2da63..5d0f230b5f7 100644 --- a/src/components/asset-list/RecyclerAssetList2/core/ExternalENSProfileScrollView.tsx +++ b/src/components/asset-list/RecyclerAssetList2/core/ExternalENSProfileScrollView.tsx @@ -111,12 +111,10 @@ const ExternalENSProfileScrollViewWithRefFactory = (type: string) => ); }); -const ExternalENSProfileScrollViewWithRef = ExternalENSProfileScrollViewWithRefFactory( - 'ens-profile' -); -const ExternalSelectNFTScrollViewWithRef = ExternalENSProfileScrollViewWithRefFactory( - 'select-nft' -); +const ExternalENSProfileScrollViewWithRef = + ExternalENSProfileScrollViewWithRefFactory('ens-profile'); +const ExternalSelectNFTScrollViewWithRef = + ExternalENSProfileScrollViewWithRefFactory('select-nft'); export { ExternalSelectNFTScrollViewWithRef, ExternalENSProfileScrollViewWithRef, diff --git a/src/components/asset-list/RecyclerAssetList2/core/RawRecyclerList.tsx b/src/components/asset-list/RecyclerAssetList2/core/RawRecyclerList.tsx index 7a371de025d..b87abbc1087 100644 --- a/src/components/asset-list/RecyclerAssetList2/core/RawRecyclerList.tsx +++ b/src/components/asset-list/RecyclerAssetList2/core/RawRecyclerList.tsx @@ -79,10 +79,10 @@ const RawMemoRecyclerAssetList = React.memo(function RawRecyclerAssetList({ const { getCardsForPlacement } = useRemoteCardContext(); const { isReadOnlyWallet } = useWallets(); - const cards = useMemo(() => getCardsForPlacement(name as string), [ - getCardsForPlacement, - name, - ]); + const cards = useMemo( + () => getCardsForPlacement(name as string), + [getCardsForPlacement, name] + ); const layoutProvider = useMemo( () => @@ -134,9 +134,10 @@ const RawMemoRecyclerAssetList = React.memo(function RawRecyclerAssetList({ }, [ref, setScrollToTopRef]); const onLayout = useCallback( - () => ({ nativeEvent }: LayoutChangeEvent) => { - topMarginRef.current = nativeEvent.layout.y; - }, + () => + ({ nativeEvent }: LayoutChangeEvent) => { + topMarginRef.current = nativeEvent.layout.y; + }, [] ); @@ -188,8 +189,8 @@ const RawMemoRecyclerAssetList = React.memo(function RawRecyclerAssetList({ type === 'ens-profile' ? ExternalENSProfileScrollViewWithRef : type === 'select-nft' - ? ExternalSelectNFTScrollViewWithRef - : ExternalScrollViewWithRef + ? ExternalSelectNFTScrollViewWithRef + : ExternalScrollViewWithRef } itemAnimator={layoutItemAnimator} layoutProvider={layoutProvider} diff --git a/src/components/asset-list/RecyclerAssetList2/index.tsx b/src/components/asset-list/RecyclerAssetList2/index.tsx index 07eb44cc75e..389ed45fe99 100644 --- a/src/components/asset-list/RecyclerAssetList2/index.tsx +++ b/src/components/asset-list/RecyclerAssetList2/index.tsx @@ -39,14 +39,12 @@ function RecyclerAssetList({ type?: AssetListType; walletBriefSectionsData: any[]; }) { - const { - memoizedResult: briefSectionsData, - additionalData, - } = useMemoBriefSectionData({ - briefSectionsData: walletBriefSectionsData, - externalAddress, - type, - }); + const { memoizedResult: briefSectionsData, additionalData } = + useMemoBriefSectionData({ + briefSectionsData: walletBriefSectionsData, + externalAddress, + type, + }); const insets = useSafeAreaInsets(); diff --git a/src/components/asset-list/RecyclerAssetList2/profile-header/ProfileActionButtonsRow.tsx b/src/components/asset-list/RecyclerAssetList2/profile-header/ProfileActionButtonsRow.tsx index 38b6e148a05..356b750767f 100644 --- a/src/components/asset-list/RecyclerAssetList2/profile-header/ProfileActionButtonsRow.tsx +++ b/src/components/asset-list/RecyclerAssetList2/profile-header/ProfileActionButtonsRow.tsx @@ -58,10 +58,8 @@ export function ProfileActionButtonsRow() { ], })); - const { - f2c_enabled: addCashEnabled, - swagg_enabled: swapEnabled, - } = useRemoteConfig(); + const { f2c_enabled: addCashEnabled, swagg_enabled: swapEnabled } = + useRemoteConfig(); if (!accentColorLoaded) return null; diff --git a/src/components/asset-list/RecyclerAssetList2/profile-header/ProfileAvatarRow.tsx b/src/components/asset-list/RecyclerAssetList2/profile-header/ProfileAvatarRow.tsx index b69e75ecd70..e284edfe3cd 100644 --- a/src/components/asset-list/RecyclerAssetList2/profile-header/ProfileAvatarRow.tsx +++ b/src/components/asset-list/RecyclerAssetList2/profile-header/ProfileAvatarRow.tsx @@ -39,11 +39,8 @@ export function ProfileAvatarRow({ const { accountSymbol, accountColor, accountImage } = useAccountProfile(); - const { - avatarContextMenuConfig, - onAvatarPressProfile, - onSelectionCallback, - } = useOnAvatarPress({ screenType: 'wallet' }); + const { avatarContextMenuConfig, onAvatarPressProfile, onSelectionCallback } = + useOnAvatarPress({ screenType: 'wallet' }); const dominantColor = usePersistentDominantColorFromImage(accountImage); diff --git a/src/components/backup/BackupConfirmPasswordStep.js b/src/components/backup/BackupConfirmPasswordStep.js index 06e70f4daf7..3cf7e65318b 100644 --- a/src/components/backup/BackupConfirmPasswordStep.js +++ b/src/components/backup/BackupConfirmPasswordStep.js @@ -72,11 +72,8 @@ export default function BackupConfirmPasswordStep() { const walletCloudBackup = useWalletCloudBackup(); const [isKeyboardOpen, setIsKeyboardOpen] = useState(false); const [validPassword, setValidPassword] = useState(false); - const [ - passwordFocused, - setPasswordFocused, - setPasswordBlurred, - ] = useBooleanState(true); + const [passwordFocused, setPasswordFocused, setPasswordBlurred] = + useBooleanState(true); const [password, setPassword] = useState(''); const [label, setLabel] = useState( `􀎽 ${lang.t('back_up.confirm_password.confirm_backup')}` diff --git a/src/components/buttons/MiniButton.js b/src/components/buttons/MiniButton.js index e9707603cec..a1161a455c4 100644 --- a/src/components/buttons/MiniButton.js +++ b/src/components/buttons/MiniButton.js @@ -118,8 +118,8 @@ export default function MiniButton({ android ? 'none' : disabled - ? colors.lightGrey - : backgroundColor || colors.appleBlue + ? colors.lightGrey + : backgroundColor || colors.appleBlue } borderRadius={borderRadius} height={height} @@ -127,8 +127,8 @@ export default function MiniButton({ hideShadow ? shadows.none : disabled - ? shadows.disabled - : shadows.default + ? shadows.disabled + : shadows.default } width={width} /> diff --git a/src/components/buttons/PasteAddressButton.js b/src/components/buttons/PasteAddressButton.js index 103ef908e55..bbb59509a9a 100644 --- a/src/components/buttons/PasteAddressButton.js +++ b/src/components/buttons/PasteAddressButton.js @@ -10,12 +10,8 @@ export default function PasteAddressButton({ onPress }) { const [isValid, setIsValid] = useState(false); const { colors } = useTheme(); const { onInvalidPaste } = useInvalidPaste(); - const { - clipboard, - enablePaste, - getClipboard, - hasClipboardData, - } = useClipboard(); + const { clipboard, enablePaste, getClipboard, hasClipboardData } = + useClipboard(); useEffect(() => { async function validate() { diff --git a/src/components/buttons/hold-to-authorize/HoldToAuthorizeButtonContent.tsx b/src/components/buttons/hold-to-authorize/HoldToAuthorizeButtonContent.tsx index fb18aa23b38..1185b658c21 100644 --- a/src/components/buttons/hold-to-authorize/HoldToAuthorizeButtonContent.tsx +++ b/src/components/buttons/hold-to-authorize/HoldToAuthorizeButtonContent.tsx @@ -158,8 +158,8 @@ function HoldToAuthorizeButtonContent2({ const height = tinyButton ? TINY_BUTTON_HEIGHT : smallButton - ? SMALL_BUTTON_HEIGHT - : BUTTON_HEIGHT; + ? SMALL_BUTTON_HEIGHT + : BUTTON_HEIGHT; const width = deviceDimensions.width - parentHorizontalPadding * 2; diff --git a/src/components/buttons/rainbow-button/RainbowButtonBackground.js b/src/components/buttons/rainbow-button/RainbowButtonBackground.js index 6529fa5d599..d32e1a027b6 100644 --- a/src/components/buttons/rainbow-button/RainbowButtonBackground.js +++ b/src/components/buttons/rainbow-button/RainbowButtonBackground.js @@ -63,8 +63,8 @@ const InnerGradient = styled(RainbowButtonGradient).attrs( colors: disabled ? gradientColors.inner.disabled : type === RainbowButtonTypes.addCash - ? gradientColors.inner.addCash - : gradientColors.inner.default, + ? gradientColors.inner.addCash + : gradientColors.inner.default, }) )(({ width, height }) => ({ height: width, @@ -77,8 +77,8 @@ const OuterGradient = styled(RainbowButtonGradient).attrs( colors: disabled ? gradientColors.outer.disabled : type === RainbowButtonTypes.addCash - ? gradientColors.outer.addCash - : gradientColors.outer.default, + ? gradientColors.outer.addCash + : gradientColors.outer.default, }) )(({ width, height }) => ({ height: width * 2, diff --git a/src/components/cards/ActionCard.tsx b/src/components/cards/ActionCard.tsx index d31f28a0575..966b3c7fb99 100644 --- a/src/components/cards/ActionCard.tsx +++ b/src/components/cards/ActionCard.tsx @@ -21,12 +21,8 @@ export const ActionCard = ({ }: ActionCardProps) => { const { isDarkMode } = useTheme(); const cardColorways = getCardColorways(isDarkMode); - const { - gradient, - shadowColor, - orbColorDark, - primaryTextColor, - } = cardColorways[colorway]; + const { gradient, shadowColor, orbColorDark, primaryTextColor } = + cardColorways[colorway]; return ( = ({ const { width } = useDimensions(); const { dismissCard } = useRemoteCardContext(); - const { - cardKey, - accentColor, - backgroundColor, - primaryButton, - imageIcon, - } = card; + const { cardKey, accentColor, backgroundColor, primaryButton, imageIcon } = + card; const accent = useForegroundColor(getColorFromString(accentColor)); const border = useForegroundColor('separatorSecondary'); diff --git a/src/components/cards/remote-cards/RemoteCardCarousel.tsx b/src/components/cards/remote-cards/RemoteCardCarousel.tsx index b9059b46373..00011029ff5 100644 --- a/src/components/cards/remote-cards/RemoteCardCarousel.tsx +++ b/src/components/cards/remote-cards/RemoteCardCarousel.tsx @@ -37,10 +37,10 @@ export const RemoteCardCarousel = () => { const { getCardsForPlacement } = useRemoteCardContext(); const { width } = useDimensions(); - const data = useMemo(() => getCardsForPlacement(name as string), [ - getCardsForPlacement, - name, - ]); + const data = useMemo( + () => getCardsForPlacement(name as string), + [getCardsForPlacement, name] + ); const gutterSize = getGutterSizeForCardAmount(data.length); diff --git a/src/components/cards/utils/constants.ts b/src/components/cards/utils/constants.ts index d87524a14eb..ccbe94c5787 100644 --- a/src/components/cards/utils/constants.ts +++ b/src/components/cards/utils/constants.ts @@ -6,9 +6,7 @@ import { LearnCategory, } from './types'; -export const getCardColorways: ( - isDarkMode: boolean -) => { +export const getCardColorways: (isDarkMode: boolean) => { [key in CardColor]: CardColorway; } = (isDarkMode: boolean) => { return { diff --git a/src/components/change-wallet/AddressRow.tsx b/src/components/change-wallet/AddressRow.tsx index a5af90c724b..bcbf2c87f3f 100644 --- a/src/components/change-wallet/AddressRow.tsx +++ b/src/components/change-wallet/AddressRow.tsx @@ -151,9 +151,10 @@ export default function AddressRow({ cleanedUpBalance = '0'; } - const cleanedUpLabel = useMemo(() => removeFirstEmojiFromString(label), [ - label, - ]); + const cleanedUpLabel = useMemo( + () => removeFirstEmojiFromString(label), + [label] + ); const emoji = useMemo( () => diff --git a/src/components/coin-divider/CoinDivider.js b/src/components/coin-divider/CoinDivider.js index 4984df7b549..7ba4357e24f 100644 --- a/src/components/coin-divider/CoinDivider.js +++ b/src/components/coin-divider/CoinDivider.js @@ -106,16 +106,11 @@ export default function CoinDivider({ const { clearSelectedCoins } = useCoinListEditOptions(); - const { - currentAction, - setHiddenCoins, - setPinnedCoins, - } = useCoinListFinishEditingOptions(); + const { currentAction, setHiddenCoins, setPinnedCoins } = + useCoinListFinishEditingOptions(); - const { - isSmallBalancesOpen, - toggleOpenSmallBalances, - } = useOpenSmallBalances(); + const { isSmallBalancesOpen, toggleOpenSmallBalances } = + useOpenSmallBalances(); const handlePressEdit = useCallback(() => { setIsCoinListEdited(prev => !prev); diff --git a/src/components/coin-icon/CoinIcon.tsx b/src/components/coin-icon/CoinIcon.tsx index d7c083f6bd2..aa982f80fe4 100644 --- a/src/components/coin-icon/CoinIcon.tsx +++ b/src/components/coin-icon/CoinIcon.tsx @@ -61,9 +61,10 @@ const CoinIcon: React.FC = ({ }); const { colors, isDarkMode } = useTheme(); const forceFallback = !isETH(mainnet_address || address); - const isNotContractInteraction = useMemo(() => symbol !== 'contract', [ - symbol, - ]); + const isNotContractInteraction = useMemo( + () => symbol !== 'contract', + [symbol] + ); const theme = useTheme(); diff --git a/src/components/coin-icon/CoinIconFallback.js b/src/components/coin-icon/CoinIconFallback.js index 11fdcca5535..befb798c3a4 100644 --- a/src/components/coin-icon/CoinIconFallback.js +++ b/src/components/coin-icon/CoinIconFallback.js @@ -29,16 +29,8 @@ const fallbackIconStyle = size => { }; export const CoinIconFallback = fallbackProps => { - const { - address, - height, - network, - symbol, - shadowColor, - theme, - size, - width, - } = fallbackProps; + const { address, height, network, symbol, shadowColor, theme, size, width } = + fallbackProps; const { colors } = theme; const imageUrl = getUrlForTrustIconFallback(address, network); diff --git a/src/components/coin-row/CollectiblesSendRow.tsx b/src/components/coin-row/CollectiblesSendRow.tsx index 56d450cf73d..9e86c7110bc 100644 --- a/src/components/coin-row/CollectiblesSendRow.tsx +++ b/src/components/coin-row/CollectiblesSendRow.tsx @@ -24,8 +24,8 @@ const selectedStyles = { ...(isTinyPhone ? padding.object(10, 0, 0) : isSmallPhone - ? padding.object(12) - : padding.object(15)), + ? padding.object(12) + : padding.object(15)), }; const BottomRow = ({ diff --git a/src/components/coin-row/SendCoinRow.js b/src/components/coin-row/SendCoinRow.js index e2f53e26e9b..ed9f6c062bd 100644 --- a/src/components/coin-row/SendCoinRow.js +++ b/src/components/coin-row/SendCoinRow.js @@ -66,8 +66,8 @@ const BottomRow = ({ {showNativeValue ? `${fiatValue} available` : balance?.display - ? `${balance?.display}${selected ? ' available' : ''}` - : 'Fetching balances...'} + ? `${balance?.display}${selected ? ' available' : ''}` + : 'Fetching balances...'} ); }; @@ -130,8 +130,8 @@ const SendCoinRow = ({ ...(isTinyPhone ? padding.object(10, 0, 0) : isSmallPhone - ? padding.object(12, 12, 12, isL2 ? 17 : 12) - : padding.object(15, 15, 15, isL2 ? 19 : 15)), + ? padding.object(12, 12, 12, isL2 ? 17 : 12) + : padding.object(15, 15, 15, isL2 ? 19 : 15)), }; return ( diff --git a/src/components/contacts/ContactAvatar.js b/src/components/contacts/ContactAvatar.js index 7c7c33b77eb..d4691b88d73 100644 --- a/src/components/contacts/ContactAvatar.js +++ b/src/components/contacts/ContactAvatar.js @@ -129,10 +129,10 @@ const sizeConfigs = colors => ({ const ContactAvatar = ({ color, size = 'medium', value, ...props }) => { const { colors } = useTheme(); - const { dimensions, textSize } = useMemo(() => sizeConfigs(colors)[size], [ - colors, - size, - ]); + const { dimensions, textSize } = useMemo( + () => sizeConfigs(colors)[size], + [colors, size] + ); const { isDarkMode } = useTheme(); const shadows = useMemo( diff --git a/src/components/contacts/ContactRow.js b/src/components/contacts/ContactRow.js index 1e1d06c09d5..23936266ea9 100644 --- a/src/components/contacts/ContactRow.js +++ b/src/components/contacts/ContactRow.js @@ -97,8 +97,8 @@ const ContactRow = ( typeof ens === 'string' ? ens : nickname?.includes(ENS_DOMAIN) - ? nickname - : ''; + ? nickname + : ''; const [ensName, setENSName] = useState(initialENSName); @@ -154,9 +154,10 @@ const ContactRow = ( const imageAvatar = profilesEnabled ? ensAvatar?.imageUrl : image; - const emoji = useMemo(() => (address ? addressHashedEmoji(address) : ''), [ - address, - ]); + const emoji = useMemo( + () => (address ? addressHashedEmoji(address) : ''), + [address] + ); const emojiAvatar = avatar || emoji || nickname || label; const colorIndex = useMemo( diff --git a/src/components/contacts/SwipeableContactRow.js b/src/components/contacts/SwipeableContactRow.js index 2a6c5a55111..06328a68609 100644 --- a/src/components/contacts/SwipeableContactRow.js +++ b/src/components/contacts/SwipeableContactRow.js @@ -96,10 +96,10 @@ const SwipeableContactRow = ( [] ); - const handlePressStart = useCallback(() => onTouch(address), [ - address, - onTouch, - ]); + const handlePressStart = useCallback( + () => onTouch(address), + [address, onTouch] + ); const renderRightActions = useCallback( progress => ( diff --git a/src/components/copy-tooltip/CopyTooltip.ios.js b/src/components/copy-tooltip/CopyTooltip.ios.js index 9c83ca84b73..8e0bf6893ec 100644 --- a/src/components/copy-tooltip/CopyTooltip.ios.js +++ b/src/components/copy-tooltip/CopyTooltip.ios.js @@ -3,9 +3,10 @@ import React, { useCallback, useEffect, useRef } from 'react'; import ToolTip from 'react-native-tooltip'; function CopyTooltip({ textToCopy, activeOpacity, tooltipText, ...props }) { - const handleCopy = useCallback(() => Clipboard.setString(textToCopy), [ - textToCopy, - ]); + const handleCopy = useCallback( + () => Clipboard.setString(textToCopy), + [textToCopy] + ); const { colors } = useTheme(); const ref = useRef(); useEffect(() => ref.current.hideMenu, []); diff --git a/src/components/ens-profile/ProfileCover/ProfileCover.tsx b/src/components/ens-profile/ProfileCover/ProfileCover.tsx index 51e79f284f5..0d3e4199293 100644 --- a/src/components/ens-profile/ProfileCover/ProfileCover.tsx +++ b/src/components/ens-profile/ProfileCover/ProfileCover.tsx @@ -58,12 +58,12 @@ export default function ProfileCover({ ...(showSkeleton ? {} : coverUrl - ? { - background: 'body (Deprecated)', - } - : { - style: { backgroundColor: accentColor }, - }), + ? { + background: 'body (Deprecated)', + } + : { + style: { backgroundColor: accentColor }, + }), })} > { - onRemoveField({ key: ENS_RECORDS.avatar }); - onChangeAvatarUrl(''); - setAvatarMetadata(undefined); - setDisabled(false); - setTimeout(() => { + const { ContextMenu, handleSelectImage, handleSelectNFT } = + useSelectImageMenu({ + imagePickerOptions: { + cropperCircleOverlay: true, + cropping: true, + height: 400, + width: 400, + }, + menuItems: enableNFTs ? ['library', 'nft'] : ['library'], + onChangeImage, + onRemoveImage: () => { + onRemoveField({ key: ENS_RECORDS.avatar }); + onChangeAvatarUrl(''); + setAvatarMetadata(undefined); + setDisabled(false); + setTimeout(() => { + setAvatarUrl(''); + }, 100); + }, + onUploadError: () => { + onBlurField({ key: 'avatar', value: '' }); setAvatarUrl(''); - }, 100); - }, - onUploadError: () => { - onBlurField({ key: 'avatar', value: '' }); - setAvatarUrl(''); - }, - onUploading: () => setDisabled(true), - onUploadSuccess: ({ data }: { data: UploadImageReturnData }) => { - onBlurField({ key: 'avatar', value: data.url }); - setDisabled(false); - }, - showRemove: Boolean(avatarUrl), - testID: 'avatar', - uploadToIPFS: true, - }); + }, + onUploading: () => setDisabled(true), + onUploadSuccess: ({ data }: { data: UploadImageReturnData }) => { + onBlurField({ key: 'avatar', value: data.url }); + setDisabled(false); + }, + showRemove: Boolean(avatarUrl), + testID: 'avatar', + uploadToIPFS: true, + }); return ( @@ -185,10 +177,10 @@ const RegistrationAvatar = ({ !hasSeenExplainSheet ? onShowExplainSheet : isTesting - ? handleSelectNFT - : enableNFTs - ? undefined - : handleSelectImage + ? handleSelectNFT + : enableNFTs + ? undefined + : handleSelectImage } testID="use-select-image-avatar" > diff --git a/src/components/ens-registration/RegistrationCover/RegistrationCover.tsx b/src/components/ens-registration/RegistrationCover/RegistrationCover.tsx index f93c0f3fcb6..ba87fe76e22 100644 --- a/src/components/ens-registration/RegistrationCover/RegistrationCover.tsx +++ b/src/components/ens-registration/RegistrationCover/RegistrationCover.tsx @@ -37,13 +37,8 @@ const RegistrationCover = ({ const { images: { coverUrl: initialCoverUrl }, } = useENSModifiedRegistration(); - const { - isLoading, - onBlurField, - onRemoveField, - setDisabled, - values, - } = useENSRegistrationForm(); + const { isLoading, onBlurField, onRemoveField, setDisabled, values } = + useENSRegistrationForm(); const { name } = useENSRegistration(); const [coverUpdateAllowed, setCoverUpdateAllowed] = useState(true); const [coverUrl, setCoverUrl] = useState(initialCoverUrl || values?.header); @@ -161,8 +156,8 @@ const RegistrationCover = ({ !hasSeenExplainSheet ? onShowExplainSheet : enableNFTs - ? undefined - : handleSelectImage + ? undefined + : handleSelectImage } scaleTo={1} > diff --git a/src/components/exchange/ConfirmExchangeButton.js b/src/components/exchange/ConfirmExchangeButton.js index 17ed7c4a579..edf79735be8 100644 --- a/src/components/exchange/ConfirmExchangeButton.js +++ b/src/components/exchange/ConfirmExchangeButton.js @@ -80,13 +80,13 @@ export default function ConfirmExchangeButton({ const color = quoteError ? disabledButtonColor : asset.address === ETH_ADDRESS - ? colors.appleBlue - : isSwapDetailsRoute - ? colorForAsset - : makeColorMoreChill( - colorForAsset, - (isSwapDetailsRoute ? colors : darkModeThemeColors).light - ); + ? colors.appleBlue + : isSwapDetailsRoute + ? colorForAsset + : makeColorMoreChill( + colorForAsset, + (isSwapDetailsRoute ? colors : darkModeThemeColors).light + ); return { buttonColor: color, @@ -193,10 +193,10 @@ export default function ConfirmExchangeButton({ loading || isSwapSubmitting ? NOOP : explainerType - ? handleExplainer - : shouldOpenSwapDetails - ? onPressViewDetails - : onSwap + ? handleExplainer + : shouldOpenSwapDetails + ? onPressViewDetails + : onSwap } shadows={ isSwapDetailsRoute diff --git a/src/components/exchange/ExchangeAssetList.tsx b/src/components/exchange/ExchangeAssetList.tsx index 8cf58bf89d5..ea4e51fb598 100644 --- a/src/components/exchange/ExchangeAssetList.tsx +++ b/src/components/exchange/ExchangeAssetList.tsx @@ -144,11 +144,8 @@ const ExchangeAssetList: ForwardRefRenderFunction< useImperativeHandle(ref, () => sectionListRef.current as SectionList); const prevQuery = usePrevious(query); const { getParent: dangerouslyGetParent, navigate } = useNavigation(); - const { - copiedText, - copyCount, - onCopySwapDetailsText, - } = useSwapDetailsClipboardState(); + const { copiedText, copyCount, onCopySwapDetailsText } = + useSwapDetailsClipboardState(); // Scroll to top once the query is cleared if (prevQuery && prevQuery.length && !query.length) { diff --git a/src/components/exchange/ExchangeNativeField.tsx b/src/components/exchange/ExchangeNativeField.tsx index 19f06bb978f..139931f3bf1 100644 --- a/src/components/exchange/ExchangeNativeField.tsx +++ b/src/components/exchange/ExchangeNativeField.tsx @@ -59,9 +59,8 @@ const ExchangeNativeField: ForwardRefRenderFunction< const [value, setValue] = useState(nativeAmount); - const { mask, placeholder, symbol } = supportedNativeCurrencies[ - nativeCurrency as NativeCurrencyKey - ]; + const { mask, placeholder, symbol } = + supportedNativeCurrencies[nativeCurrency as NativeCurrencyKey]; const handleFocusNativeField = useCallback( () => nativeFieldRef?.current?.focus(), diff --git a/src/components/exchange/ExchangeTokenRow.tsx b/src/components/exchange/ExchangeTokenRow.tsx index 5857561c64a..4b29e31edaa 100644 --- a/src/components/exchange/ExchangeTokenRow.tsx +++ b/src/components/exchange/ExchangeTokenRow.tsx @@ -174,5 +174,4 @@ export default React.memo(function ExchangeTokenRow({ ); -}, -isEqual); +}, isEqual); diff --git a/src/components/expanded-state/SwapDetailsState.js b/src/components/expanded-state/SwapDetailsState.js index 6ca404aa4bc..2b451d3f3a6 100644 --- a/src/components/expanded-state/SwapDetailsState.js +++ b/src/components/expanded-state/SwapDetailsState.js @@ -104,22 +104,16 @@ export default function SwapDetailsState({ tradeDetails, } = useSelector(state => state.swap); - const { - priceImpact, - inputNativeAmount, - outputNativeAmount, - } = usePriceImpactDetails( - inputCurrency, - outputCurrency, - tradeDetails, - currentNetwork - ); + const { priceImpact, inputNativeAmount, outputNativeAmount } = + usePriceImpactDetails( + inputCurrency, + outputCurrency, + tradeDetails, + currentNetwork + ); - const { - copiedText, - copyCount, - onCopySwapDetailsText, - } = useSwapDetailsClipboardState(); + const { copiedText, copyCount, onCopySwapDetailsText } = + useSwapDetailsClipboardState(); const [footerHeight, setFooterHeight] = useHeight(FOOTER_MIN_HEIGHT); const [slippageMessageHeight, setSlippageMessageHeight] = useHeight(); @@ -127,12 +121,8 @@ export default function SwapDetailsState({ FOOTER_CONTENT_MIN_HEIGHT ); - const { - onHeightChange, - wrapperStyle, - onPressMore, - onWrapperLayout, - } = useSwapDetailsButtonPosition({ contentHeight }); + const { onHeightChange, wrapperStyle, onPressMore, onWrapperLayout } = + useSwapDetailsButtonPosition({ contentHeight }); const onContentHeightChange = useCallback( event => { diff --git a/src/components/expanded-state/UniqueTokenExpandedState.tsx b/src/components/expanded-state/UniqueTokenExpandedState.tsx index ecb80b27d3a..67111383f57 100644 --- a/src/components/expanded-state/UniqueTokenExpandedState.tsx +++ b/src/components/expanded-state/UniqueTokenExpandedState.tsx @@ -253,10 +253,8 @@ const UniqueTokenExpandedState = ({ const { colors, isDarkMode } = useTheme(); const { isReadOnlyWallet } = useWallets(); - const [ - isRefreshMetadataToastActive, - setIsRefreshMetadataToastActive, - ] = useState(false); + const [isRefreshMetadataToastActive, setIsRefreshMetadataToastActive] = + useState(false); const activateRefreshMetadataToast = useCallback(() => { if (!isRefreshMetadataToastActive) { @@ -325,18 +323,12 @@ const UniqueTokenExpandedState = ({ return available; }, [ensData?.records]); - const { - addShowcaseToken, - removeShowcaseToken, - showcaseTokens, - } = useShowcaseTokens(); + const { addShowcaseToken, removeShowcaseToken, showcaseTokens } = + useShowcaseTokens(); const { hiddenTokens, removeHiddenToken } = useHiddenTokens(); - const [ - contentFocused, - handleContentFocus, - handleContentBlur, - ] = useBooleanState(); + const [contentFocused, handleContentFocus, handleContentBlur] = + useBooleanState(); const animationProgress = useSharedValue(0); const ensCoverAnimationProgress = useSharedValue(0); // TODO(jxom): This is temporary until `ZoomableWrapper` refactor diff --git a/src/components/expanded-state/asset/ChartExpandedState.js b/src/components/expanded-state/asset/ChartExpandedState.js index 3199f4aaa57..345e6cd9fc6 100644 --- a/src/components/expanded-state/asset/ChartExpandedState.js +++ b/src/components/expanded-state/asset/ChartExpandedState.js @@ -199,14 +199,14 @@ export default function ChartExpandedState({ asset }) { return hasBalance ? { ...asset } : genericAsset - ? asset?.networks - ? { - ...ethereumUtils.formatGenericAsset(genericAsset, nativeCurrency), - network: asset.network, - colors: asset?.colors, - } - : ethereumUtils.formatGenericAsset(genericAsset, nativeCurrency) - : { ...asset }; + ? asset?.networks + ? { + ...ethereumUtils.formatGenericAsset(genericAsset, nativeCurrency), + network: asset.network, + colors: asset?.colors, + } + : ethereumUtils.formatGenericAsset(genericAsset, nativeCurrency) + : { ...asset }; }, [asset, genericAsset, hasBalance, nativeCurrency]); if (assetWithPrice?.mainnet_address) { @@ -214,9 +214,10 @@ export default function ChartExpandedState({ asset }) { assetWithPrice.address = assetWithPrice.mainnet_address; } - const isL2 = useMemo(() => isL2Network(assetWithPrice.network), [ - assetWithPrice.network, - ]); + const isL2 = useMemo( + () => isL2Network(assetWithPrice.network), + [assetWithPrice.network] + ); const isTestnet = isTestnetNetwork(currentNetwork); const { diff --git a/src/components/expanded-state/chart/ChartContextButton.js b/src/components/expanded-state/chart/ChartContextButton.js index 5a3c420aa9c..33f10003303 100644 --- a/src/components/expanded-state/chart/ChartContextButton.js +++ b/src/components/expanded-state/chart/ChartContextButton.js @@ -14,11 +14,8 @@ const emojiSpacing = ios ? '' : ' '; export default function ChartContextButton({ asset, color }) { const { clearSelectedCoins, pushSelectedCoin } = useCoinListEditOptions(); - const { - currentAction, - setHiddenCoins, - setPinnedCoins, - } = useCoinListFinishEditingOptions(); + const { currentAction, setHiddenCoins, setPinnedCoins } = + useCoinListFinishEditingOptions(); useEffect(() => { // Ensure this expanded state's asset is always actively inside diff --git a/src/components/expanded-state/chart/chart-data-labels/ChartChangeDirectionArrow.js b/src/components/expanded-state/chart/chart-data-labels/ChartChangeDirectionArrow.js index ea40c175772..c605d9fea25 100644 --- a/src/components/expanded-state/chart/chart-data-labels/ChartChangeDirectionArrow.js +++ b/src/components/expanded-state/chart/chart-data-labels/ChartChangeDirectionArrow.js @@ -31,8 +31,8 @@ export default function ChartChangeDirectionArrow({ ratio, sharedRatio }) { realRatio === 1 ? colors.blueGreyDark : realRatio < 1 - ? colors.red - : colors.green, + ? colors.red + : colors.green, }; }, [ratio]); diff --git a/src/components/expanded-state/chart/chart-data-labels/ChartDateLabel.js b/src/components/expanded-state/chart/chart-data-labels/ChartDateLabel.js index e3d9d7fba94..5eb2d2a7ee9 100644 --- a/src/components/expanded-state/chart/chart-data-labels/ChartDateLabel.js +++ b/src/components/expanded-state/chart/chart-data-labels/ChartDateLabel.js @@ -94,8 +94,8 @@ export default function ChartDateLabel({ chartTimeDefaultValue, ratio }) { realRatio === 1 ? colors.blueGreyDark : realRatio < 1 - ? colors.red - : colors.green, + ? colors.red + : colors.green, }; }, [ratio]); diff --git a/src/components/expanded-state/chart/chart-data-labels/ChartPercentChangeLabel.js b/src/components/expanded-state/chart/chart-data-labels/ChartPercentChangeLabel.js index bf653eb45af..ac1d1d5314b 100644 --- a/src/components/expanded-state/chart/chart-data-labels/ChartPercentChangeLabel.js +++ b/src/components/expanded-state/chart/chart-data-labels/ChartPercentChangeLabel.js @@ -63,11 +63,10 @@ export default function ChartPercentChangeLabel({ ratio, latestChange }) { const { colors } = useTheme(); // we don't need to format on latestChange changes - const defaultValue = useMemo(() => format(originalY, data, latestChange), [ - originalY, - data, - latestChange, - ]); + const defaultValue = useMemo( + () => format(originalY, data, latestChange), + [originalY, data, latestChange] + ); const textProps = useAnimatedStyle( () => ({ @@ -87,8 +86,8 @@ export default function ChartPercentChangeLabel({ ratio, latestChange }) { realRatio === 1 ? colors.blueGreyDark : realRatio < 1 - ? colors.red - : colors.green, + ? colors.red + : colors.green, }; }, [ratio]); diff --git a/src/components/expanded-state/custom-gas/FeesPanel.tsx b/src/components/expanded-state/custom-gas/FeesPanel.tsx index 5847a109c20..9d8dff51918 100644 --- a/src/components/expanded-state/custom-gas/FeesPanel.tsx +++ b/src/components/expanded-state/custom-gas/FeesPanel.tsx @@ -120,12 +120,10 @@ export default function FeesPanel({ const isL2 = getNetworkObj(txNetwork)?.networkType === 'layer2'; - const [maxPriorityFeeWarning, setMaxPriorityFeeWarning] = useState( - null - ); - const [maxPriorityFeeError, setMaxPriorityFeeError] = useState( - null - ); + const [maxPriorityFeeWarning, setMaxPriorityFeeWarning] = + useState(null); + const [maxPriorityFeeError, setMaxPriorityFeeError] = + useState(null); const [maxBaseFeeWarning, setMaxBaseFeeWarning] = useState(null); const [maxBaseFeeError, setMaxBaseFeeError] = useState(null); diff --git a/src/components/expanded-state/ens/InfoRow.tsx b/src/components/expanded-state/ens/InfoRow.tsx index 8896912f262..13e94e258bc 100644 --- a/src/components/expanded-state/ens/InfoRow.tsx +++ b/src/components/expanded-state/ens/InfoRow.tsx @@ -148,15 +148,15 @@ export default function InfoRow({ isSwitch ? undefined : isMultiline - ? ('15px (Deprecated)' as const) - : ('10px' as const) + ? ('15px (Deprecated)' as const) + : ('10px' as const) } style={{ backgroundColor: isSwitch ? 'transparent' : useAccentColor - ? accentColor + '10' - : 'rgba(255, 255, 255, 0.08)', + ? accentColor + '10' + : 'rgba(255, 255, 255, 0.08)', maxWidth: android ? 250 : undefined, opacity: show ? 1 : 0, }} diff --git a/src/components/expanded-state/ens/ProfileInfoSection.tsx b/src/components/expanded-state/ens/ProfileInfoSection.tsx index 77e10e261be..8bb15f5bd5a 100644 --- a/src/components/expanded-state/ens/ProfileInfoSection.tsx +++ b/src/components/expanded-state/ens/ProfileInfoSection.tsx @@ -57,9 +57,10 @@ export default function ProfileInfoSection({ .filter(Boolean) as [ENS_RECORDS, string][]; return [orderedTopRecords, otherRecords as [ENS_RECORDS, string][]]; }, [recordsArray]); - const coinAddresses = useMemo(() => Object.entries(coinAddressMap || {}), [ - coinAddressMap, - ]); + const coinAddresses = useMemo( + () => Object.entries(coinAddressMap || {}), + [coinAddressMap] + ); return ( @@ -130,21 +131,15 @@ function ProfileInfoRow({ recordValue: string; type: 'address' | 'record'; }) { - const { - ContextMenuButton, - icon, - isImageValue, - label, - url, - value, - } = useENSRecordDisplayProperties({ - allowEdit, - ensName, - images, - key: recordKey, - type, - value: recordValue, - }); + const { ContextMenuButton, icon, isImageValue, label, url, value } = + useENSRecordDisplayProperties({ + allowEdit, + ensName, + images, + key: recordKey, + type, + value: recordValue, + }); return ( (null); - const handleTriggerFocusInput = useCallback(() => inputRef.current?.focus(), [ - inputRef, - ]); + const handleTriggerFocusInput = useCallback( + () => inputRef.current?.focus(), + [inputRef] + ); return ( diff --git a/src/components/expanded-state/swap-details/SwapDetailsContent.js b/src/components/expanded-state/swap-details/SwapDetailsContent.js index 503e85452b6..8eb8d0f8a71 100644 --- a/src/components/expanded-state/swap-details/SwapDetailsContent.js +++ b/src/components/expanded-state/swap-details/SwapDetailsContent.js @@ -42,9 +42,8 @@ export default function SwapDetailsContent({ ...props }) { const { inputCurrency, outputCurrency } = useSwapCurrencies(); - const { amountReceivedSold, receivedSoldLabel } = useSwapAdjustedAmounts( - tradeDetails - ); + const { amountReceivedSold, receivedSoldLabel } = + useSwapAdjustedAmounts(tradeDetails); const { navigate } = useNavigation(); const { flashbotsEnabled } = useAccountSettings(); const inputAsExact = useSelector( diff --git a/src/components/expanded-state/swap-details/SwapDetailsContractRow.js b/src/components/expanded-state/swap-details/SwapDetailsContractRow.js index 1aaaf224b0d..82176ef34c6 100644 --- a/src/components/expanded-state/swap-details/SwapDetailsContractRow.js +++ b/src/components/expanded-state/swap-details/SwapDetailsContractRow.js @@ -31,9 +31,8 @@ export const SwapDetailsValue = styled(SwapDetailsText).attrs( }) )(fontWithWidth(fonts.weight.bold)); -const AnimatedTruncatedAddress = Animated.createAnimatedComponent( - TruncatedAddress -); +const AnimatedTruncatedAddress = + Animated.createAnimatedComponent(TruncatedAddress); const AnimatedText = Animated.createAnimatedComponent(Text); const ContractActionsEnum = { @@ -75,9 +74,10 @@ function SwapDetailsContractRowContent({ const { colors } = useTheme(); const colorForAsset = useColorForAsset(asset); const animation = useSharedValue(menuVisible ? 1 : 0); - const startingColor = useMemo(() => colors.alpha(colors.blueGreyDark, 0.8), [ - colors, - ]); + const startingColor = useMemo( + () => colors.alpha(colors.blueGreyDark, 0.8), + [colors] + ); useLayoutEffect(() => { animation.value = withTiming(menuVisible ? 1 : 0, { duration: 150 }); diff --git a/src/components/expanded-state/swap-settings/MaxToleranceInput.tsx b/src/components/expanded-state/swap-settings/MaxToleranceInput.tsx index 4f83fbfc2a7..6d5af12b506 100644 --- a/src/components/expanded-state/swap-settings/MaxToleranceInput.tsx +++ b/src/components/expanded-state/swap-settings/MaxToleranceInput.tsx @@ -64,9 +64,9 @@ export const MaxToleranceInput = forwardRef( slippageRef?.current?.blur(); }, reset: () => { - const slippage = (getDefaultSlippageFromConfig( + const slippage = getDefaultSlippageFromConfig( currentNetwork - ) as unknown) as number; + ) as unknown as number; onSlippageChange(convertBipsToPercent(slippage)); }, })); diff --git a/src/components/expanded-state/swap-settings/SwapSettingsState.js b/src/components/expanded-state/swap-settings/SwapSettingsState.js index a7766e9d4f1..74ceac98d28 100644 --- a/src/components/expanded-state/swap-settings/SwapSettingsState.js +++ b/src/components/expanded-state/swap-settings/SwapSettingsState.js @@ -44,10 +44,8 @@ function useAndroidDisableGesturesOnFocus() { } export default function SwapSettingsState({ asset }) { - const { - flashbotsEnabled, - settingsChangeFlashbotsEnabled, - } = useAccountSettings(); + const { flashbotsEnabled, settingsChangeFlashbotsEnabled } = + useAccountSettings(); const { params: { swapSupportsFlashbots = false, network }, } = useRoute(); diff --git a/src/components/expanded-state/unique-token/UniqueTokenExpandedStateHeader.tsx b/src/components/expanded-state/unique-token/UniqueTokenExpandedStateHeader.tsx index 057f1846d0a..028766e1335 100644 --- a/src/components/expanded-state/unique-token/UniqueTokenExpandedStateHeader.tsx +++ b/src/components/expanded-state/unique-token/UniqueTokenExpandedStateHeader.tsx @@ -121,7 +121,7 @@ const getAssetActions = (network: Network) => iconValue: 'looksrare', }, }, - } as const); + }) as const; const FamilyActionsEnum = { collectionWebsite: 'collectionWebsite', diff --git a/src/components/expanded-state/unique-token/ZoomableWrapper.android.js b/src/components/expanded-state/unique-token/ZoomableWrapper.android.js index cadb6787a45..e5277c52484 100644 --- a/src/components/expanded-state/unique-token/ZoomableWrapper.android.js +++ b/src/components/expanded-state/unique-token/ZoomableWrapper.android.js @@ -98,30 +98,28 @@ export const ZoomableWrapper = ({ const maxImageWidth = width || deviceWidth - horizontalPadding * 2; const maxImageHeight = height || deviceHeight / 2; - const [ - containerWidth = maxImageWidth, - containerHeight = maxImageWidth, - ] = useMemo(() => { - const isSquare = aspectRatio === 1; - const isLandscape = aspectRatio > 1; - const isPortrait = aspectRatio < 1; - - if (isSquare) { - return [maxImageWidth, maxImageWidth]; - } - - if (isLandscape) { - return [maxImageWidth, maxImageWidth / aspectRatio]; - } + const [containerWidth = maxImageWidth, containerHeight = maxImageWidth] = + useMemo(() => { + const isSquare = aspectRatio === 1; + const isLandscape = aspectRatio > 1; + const isPortrait = aspectRatio < 1; + + if (isSquare) { + return [maxImageWidth, maxImageWidth]; + } - if (isPortrait) { - if (maxImageWidth / aspectRatio > maxImageHeight) { - return [aspectRatio * maxImageHeight, maxImageHeight]; - } else { + if (isLandscape) { return [maxImageWidth, maxImageWidth / aspectRatio]; } - } - }, [aspectRatio, maxImageHeight, maxImageWidth]); + + if (isPortrait) { + if (maxImageWidth / aspectRatio > maxImageHeight) { + return [aspectRatio * maxImageHeight, maxImageHeight]; + } else { + return [maxImageWidth, maxImageWidth / aspectRatio]; + } + } + }, [aspectRatio, maxImageHeight, maxImageWidth]); const containerWidthValue = useReactiveSharedValue( containerWidth || maxImageWidth diff --git a/src/components/expanded-state/unique-token/ZoomableWrapper.js b/src/components/expanded-state/unique-token/ZoomableWrapper.js index ab125896300..9cac904efce 100644 --- a/src/components/expanded-state/unique-token/ZoomableWrapper.js +++ b/src/components/expanded-state/unique-token/ZoomableWrapper.js @@ -116,30 +116,28 @@ export const ZoomableWrapper = ({ const maxImageWidth = width || deviceWidth - horizontalPadding * 2; const maxImageHeight = height || deviceHeightWithMaybeHiddenStatusBar / 2; - const [ - containerWidth = maxImageWidth, - containerHeight = maxImageWidth, - ] = useMemo(() => { - const isSquare = aspectRatio === 1; - const isLandscape = aspectRatio > 1; - const isPortrait = aspectRatio < 1; - - if (isSquare) { - return [maxImageWidth, maxImageWidth]; - } - - if (isLandscape) { - return [maxImageWidth, maxImageWidth / aspectRatio]; - } + const [containerWidth = maxImageWidth, containerHeight = maxImageWidth] = + useMemo(() => { + const isSquare = aspectRatio === 1; + const isLandscape = aspectRatio > 1; + const isPortrait = aspectRatio < 1; + + if (isSquare) { + return [maxImageWidth, maxImageWidth]; + } - if (isPortrait) { - if (maxImageWidth / aspectRatio > maxImageHeight) { - return [aspectRatio * maxImageHeight, maxImageHeight]; - } else { + if (isLandscape) { return [maxImageWidth, maxImageWidth / aspectRatio]; } - } - }, [aspectRatio, maxImageHeight, maxImageWidth]); + + if (isPortrait) { + if (maxImageWidth / aspectRatio > maxImageHeight) { + return [aspectRatio * maxImageHeight, maxImageHeight]; + } else { + return [maxImageWidth, maxImageWidth / aspectRatio]; + } + } + }, [aspectRatio, maxImageHeight, maxImageWidth]); const containerWidthValue = useReactiveSharedValue( containerWidth || maxImageWidth diff --git a/src/components/fields/BubbleField.js b/src/components/fields/BubbleField.js index 1a2026ce854..f6d7de79b74 100644 --- a/src/components/fields/BubbleField.js +++ b/src/components/fields/BubbleField.js @@ -49,10 +49,10 @@ const BubbleField = ( const [value, setValue] = useState(valueProp); const [wasButtonPressed, setWasButtonPressed] = useState(false); - const formattedValue = useMemo(() => format(String(value || '')), [ - format, - value, - ]); + const formattedValue = useMemo( + () => format(String(value || '')), + [format, value] + ); const handleBlur = useCallback( event => { diff --git a/src/components/fields/SmallBubbleField.js b/src/components/fields/SmallBubbleField.js index 5e5f31f000d..4299539d786 100644 --- a/src/components/fields/SmallBubbleField.js +++ b/src/components/fields/SmallBubbleField.js @@ -21,8 +21,8 @@ const BubbleInput = styled(ExchangeInput).attrs( ? isTinyPhone ? 27 : android || isSmallPhone - ? 31 - : 38 + ? 31 + : 38 : undefined, size: isTinyPhone ? 'big' : isSmallPhone ? 'bigger' : 'h3', weight: 'semibold', @@ -65,10 +65,10 @@ const BubbleField = ( const ref = useRef(); useImperativeHandle(forwardedRef, () => ref.current); - const formattedValue = useMemo(() => format(String(value || '')), [ - format, - value, - ]); + const formattedValue = useMemo( + () => format(String(value || '')), + [format, value] + ); const handleBlur = useCallback( event => { diff --git a/src/components/floating-emojis/FloatingEmojis.js b/src/components/floating-emojis/FloatingEmojis.js index 9fca2c356f9..c430fb278fc 100644 --- a/src/components/floating-emojis/FloatingEmojis.js +++ b/src/components/floating-emojis/FloatingEmojis.js @@ -56,8 +56,8 @@ const FloatingEmojis = ({ (existingEmojis.length + 1) % 7 === 0 && !disableRainbow ? 'rainbow' : emojisArray.length === 1 - ? emojisArray[0] - : emojisArray[getEmoji(emojisArray)], + ? emojisArray[0] + : emojisArray[getEmoji(emojisArray)], x: x ? x - getRandomNumber(-20, 20) : getRandomNumber(...range) + '%', y: y || 0, }; diff --git a/src/components/gas/GasSpeedButton.js b/src/components/gas/GasSpeedButton.js index 11425af3523..3c2df0ab2eb 100644 --- a/src/components/gas/GasSpeedButton.js +++ b/src/components/gas/GasSpeedButton.js @@ -365,9 +365,8 @@ const GasSpeedButton = ({ type: 'crossChainGas', }); } else { - const nativeAsset = await ethereumUtils.getNativeAssetForNetwork( - networkName - ); + const nativeAsset = + await ethereumUtils.getNativeAssetForNetwork(networkName); navigate(Routes.EXPLAIN_SHEET, { network: networkName, type: 'gas', @@ -445,13 +444,13 @@ const GasSpeedButton = ({ const gweiDisplay = !shouldRoundGwei ? gasFeeParamsBySpeed[gasOption]?.gasPrice?.display : gasOption === 'custom' && selectedGasFeeOption !== 'custom' - ? '' - : greaterThan(estimatedGwei, totalGwei) - ? `${toFixedDecimals(totalGwei, isL2 ? 4 : 0)} Gwei` - : `${toFixedDecimals(estimatedGwei, isL2 ? 4 : 0)}–${toFixedDecimals( - totalGwei, - isL2 ? 4 : 0 - )} Gwei`; + ? '' + : greaterThan(estimatedGwei, totalGwei) + ? `${toFixedDecimals(totalGwei, isL2 ? 4 : 0)} Gwei` + : `${toFixedDecimals(estimatedGwei, isL2 ? 4 : 0)}–${toFixedDecimals( + totalGwei, + isL2 ? 4 : 0 + )} Gwei`; return { actionKey: gasOption, actionTitle: @@ -477,9 +476,10 @@ const GasSpeedButton = ({ isL2, ]); - const gasOptionsAvailable = useMemo(() => speedOptions.length > 1, [ - speedOptions.length, - ]); + const gasOptionsAvailable = useMemo( + () => speedOptions.length > 1, + [speedOptions.length] + ); const onDonePress = useCallback(() => { if (canGoBack) { diff --git a/src/components/images/ImagePreviewOverlay.tsx b/src/components/images/ImagePreviewOverlay.tsx index 096fd331772..bdcd7917cda 100644 --- a/src/components/images/ImagePreviewOverlay.tsx +++ b/src/components/images/ImagePreviewOverlay.tsx @@ -591,8 +591,8 @@ export function ImagePreviewOverlayTarget({ givenHeight ? givenHeight : height - ? { custom: height } - : { custom: 0 } + ? { custom: height } + : { custom: 0 } } onLayout={handleLayout} ref={zoomableWrapperRef} diff --git a/src/components/inputs/InlineField.tsx b/src/components/inputs/InlineField.tsx index 9f83a0c08ec..171618e26ba 100644 --- a/src/components/inputs/InlineField.tsx +++ b/src/components/inputs/InlineField.tsx @@ -100,18 +100,18 @@ export default function InlineField({ ? 11 : 15 : android - ? valueRef.current - ? 16 - : 11 - : 0, + ? valueRef.current + ? 16 + : 11 + : 0, textAlignVertical: 'top', width: startsWith ? ios ? 0.55 * width : 0.56 * width : ios - ? 0.6 * width - : 0.61 * width, + ? 0.6 * width + : 0.61 * width, }), [textStyle, inputHeight, inputProps?.multiline, startsWith, width] ); diff --git a/src/components/layout/LayoutWithDividers.js b/src/components/layout/LayoutWithDividers.js index fd82f238c36..68304226d86 100644 --- a/src/components/layout/LayoutWithDividers.js +++ b/src/components/layout/LayoutWithDividers.js @@ -6,9 +6,10 @@ const LayoutWithDividers = ( { children, dividerHorizontal, dividerRenderer = Divider, ...props }, ref ) => { - const dividerProps = useMemo(() => ({ horizontal: dividerHorizontal }), [ - dividerHorizontal, - ]); + const dividerProps = useMemo( + () => ({ horizontal: dividerHorizontal }), + [dividerHorizontal] + ); return ( diff --git a/src/components/qrcode-scanner/CameraDimmer.js b/src/components/qrcode-scanner/CameraDimmer.js index affef4c4b2d..19a638d79d3 100644 --- a/src/components/qrcode-scanner/CameraDimmer.js +++ b/src/components/qrcode-scanner/CameraDimmer.js @@ -10,9 +10,8 @@ const Dim = styled(Animated.View)({ }); export default function CameraDimmer({ children, cameraVisible }) { - const delayedCameraVisible = useDelayedValueWithLayoutAnimation( - cameraVisible - ); + const delayedCameraVisible = + useDelayedValueWithLayoutAnimation(cameraVisible); return ( diff --git a/src/components/remote-promo-sheet/RemotePromoSheet.tsx b/src/components/remote-promo-sheet/RemotePromoSheet.tsx index bcb3b71efb7..239c348072d 100644 --- a/src/components/remote-promo-sheet/RemotePromoSheet.tsx +++ b/src/components/remote-promo-sheet/RemotePromoSheet.tsx @@ -58,9 +58,8 @@ const getKeyForLanguage = ( export function RemotePromoSheet() { const { colors } = useTheme(); const { goBack, navigate } = useNavigation(); - const { params } = useRoute< - RouteProp - >(); + const { params } = + useRoute>(); const { campaignId, campaignKey } = params; const { language } = useAccountSettings(); diff --git a/src/components/remote-promo-sheet/checkForCampaign.ts b/src/components/remote-promo-sheet/checkForCampaign.ts index 76eacbc1d20..ccd8aca8045 100644 --- a/src/components/remote-promo-sheet/checkForCampaign.ts +++ b/src/components/remote-promo-sheet/checkForCampaign.ts @@ -146,7 +146,10 @@ export const shouldPromptCampaign = async ( export const __INTERNAL_ACTION_CHECKS: { [key: string]: ActionFn; -} = Object.keys(fns).reduce((acc, fnKey) => { - acc[fnKey] = fns[fnKey as keyof typeof fns]; - return acc; -}, {} as { [key: string]: ActionFn }); +} = Object.keys(fns).reduce( + (acc, fnKey) => { + acc[fnKey] = fns[fnKey as keyof typeof fns]; + return acc; + }, + {} as { [key: string]: ActionFn } +); diff --git a/src/components/remote-promo-sheet/notificationsPromoCampaign.ts b/src/components/remote-promo-sheet/notificationsPromoCampaign.ts index ad46a99c731..8060dd1f27d 100644 --- a/src/components/remote-promo-sheet/notificationsPromoCampaign.ts +++ b/src/components/remote-promo-sheet/notificationsPromoCampaign.ts @@ -26,35 +26,36 @@ export const notificationsCampaignAction = async () => { }, 1000); }; -export const notificationsCampaignCheck = async (): Promise => { - const hasShownCampaign = mmkv.getBoolean(CampaignKey.notificationsLaunch); - const isFirstLaunch = mmkv.getBoolean(STORAGE_IDS.FIRST_APP_LAUNCH); +export const notificationsCampaignCheck = + async (): Promise => { + const hasShownCampaign = mmkv.getBoolean(CampaignKey.notificationsLaunch); + const isFirstLaunch = mmkv.getBoolean(STORAGE_IDS.FIRST_APP_LAUNCH); - logger.debug(`Notifications promo`, { hasShownCampaign }); + logger.debug(`Notifications promo`, { hasShownCampaign }); - const { - selected: currentWallet, - }: { - selected: RainbowWallet | undefined; - } = store.getState().wallets; + const { + selected: currentWallet, + }: { + selected: RainbowWallet | undefined; + } = store.getState().wallets; - /** - * stop if: - * there's no wallet - * the campaign has already been activated - * the user is launching Rainbow for the first time - */ - if (!currentWallet || hasShownCampaign || isFirstLaunch) { - logger.debug(`Notifications promo: not activating`); - return GenericCampaignCheckResponse.nonstarter; - } + /** + * stop if: + * there's no wallet + * the campaign has already been activated + * the user is launching Rainbow for the first time + */ + if (!currentWallet || hasShownCampaign || isFirstLaunch) { + logger.debug(`Notifications promo: not activating`); + return GenericCampaignCheckResponse.nonstarter; + } - logger.debug(`Notifications promo: activating`); + logger.debug(`Notifications promo: activating`); - NotificationsPromoCampaign.action(); + NotificationsPromoCampaign.action(); - return GenericCampaignCheckResponse.activated; -}; + return GenericCampaignCheckResponse.activated; + }; export const NotificationsPromoCampaign: Campaign = { action: async () => await notificationsCampaignAction(), diff --git a/src/components/secret-display/states.ts b/src/components/secret-display/states.ts index 8928f8c93b0..6617e2d0fb8 100644 --- a/src/components/secret-display/states.ts +++ b/src/components/secret-display/states.ts @@ -5,4 +5,5 @@ export const SecretDisplayStates = { securedWithBiometrics: 'securedWithBiometrics', } as const; -export type SecretDisplayStatesType = typeof SecretDisplayStates[keyof typeof SecretDisplayStates]; +export type SecretDisplayStatesType = + (typeof SecretDisplayStates)[keyof typeof SecretDisplayStates]; diff --git a/src/components/send/SendAssetFormField.js b/src/components/send/SendAssetFormField.js index ebbe344cd8f..600c6779c70 100644 --- a/src/components/send/SendAssetFormField.js +++ b/src/components/send/SendAssetFormField.js @@ -124,8 +124,8 @@ const SendAssetFormField = ( ? isTinyPhone ? 27 : android || isSmallPhone - ? 31 - : 38 + ? 31 + : 38 : null } size={isTinyPhone ? 'big' : android || isSmallPhone ? 'bigger' : 'h3'} diff --git a/src/components/send/SendAssetFormToken.js b/src/components/send/SendAssetFormToken.js index eb9c0780665..7bb9d966cab 100644 --- a/src/components/send/SendAssetFormToken.js +++ b/src/components/send/SendAssetFormToken.js @@ -52,10 +52,8 @@ export default function SendAssetFormToken({ const { isSmallPhone, isTinyPhone } = useDimensions(); const { colors } = useTheme(); - const { - mask: nativeMask, - placeholder: nativePlaceholder, - } = supportedNativeCurrencies[nativeCurrency]; + const { mask: nativeMask, placeholder: nativePlaceholder } = + supportedNativeCurrencies[nativeCurrency]; return ( diff --git a/src/components/send/SendButton.js b/src/components/send/SendButton.js index 2d3e1ca7e33..99fb461e045 100644 --- a/src/components/send/SendButton.js +++ b/src/components/send/SendButton.js @@ -41,8 +41,8 @@ export default function SendButton({ disabled && requiresChecks ? `􀄨 ${lang.t('wallet.transaction.complete_checks')}` : insufficientEth - ? lang.t('button.confirm_exchange.insufficient_funds') - : lang.t('button.hold_to_send') + ? lang.t('button.confirm_exchange.insufficient_funds') + : lang.t('button.hold_to_send') } onLongPress={onLongPress} parentHorizontalPadding={19} diff --git a/src/components/send/SendHeader.js b/src/components/send/SendHeader.js index a9c45153cae..300ba7868a8 100644 --- a/src/components/send/SendHeader.js +++ b/src/components/send/SendHeader.js @@ -28,10 +28,10 @@ const AddressInputContainer = styled(Row).attrs({ align: 'center' })( ...(android ? padding.object(0, 19) : isTinyPhone - ? padding.object(23, 15, 10) - : isSmallPhone - ? padding.object(11, 19, 15) - : padding.object(18, 19, 19)), + ? padding.object(23, 15, 10) + : isSmallPhone + ? padding.object(11, 19, 15) + : padding.object(18, 19, 19)), backgroundColor: colors.white, overflow: 'hidden', width: '100%', diff --git a/src/components/sheet/SlackSheet.js b/src/components/sheet/SlackSheet.js index 2329026d2b2..5e772573e11 100644 --- a/src/components/sheet/SlackSheet.js +++ b/src/components/sheet/SlackSheet.js @@ -46,8 +46,8 @@ const Container = styled(Centered).attrs({ direction: 'column' })( typeof additionalTopPadding === 'number' ? additionalTopPadding : contentHeight && additionalTopPadding - ? deviceHeight - contentHeight - : 0, + ? deviceHeight - contentHeight + : 0, }), ...(IS_ANDROID ? { borderTopLeftRadius: 30, borderTopRightRadius: 30 } diff --git a/src/components/unique-token/Tag.js b/src/components/unique-token/Tag.js index f46c042b3dd..bfee605339b 100644 --- a/src/components/unique-token/Tag.js +++ b/src/components/unique-token/Tag.js @@ -115,9 +115,8 @@ const Tag = ({ typeof originalValue === 'string' && originalValue.toLowerCase().startsWith('https://'); - const viewTraitOnNftMarketplaceAction = getViewTraitOnNftMarketplaceAction( - marketplaceName - ); + const viewTraitOnNftMarketplaceAction = + getViewTraitOnNftMarketplaceAction(marketplaceName); const handlePressMenuItem = useCallback( ({ nativeEvent: { actionKey } }) => { diff --git a/src/components/unique-token/UniqueTokenCard.js b/src/components/unique-token/UniqueTokenCard.js index a4e1d58c2cd..8a13bffda2b 100644 --- a/src/components/unique-token/UniqueTokenCard.js +++ b/src/components/unique-token/UniqueTokenCard.js @@ -50,9 +50,10 @@ const UniqueTokenCard = ({ const { colors } = useTheme(); - const defaultShadow = useMemo(() => UniqueTokenCardShadowFactory(colors), [ - colors, - ]); + const defaultShadow = useMemo( + () => UniqueTokenCardShadowFactory(colors), + [colors] + ); return ( ChartTimespans.indexOf(chartType), [ - chartType, - ]); + const timespanIndex = useMemo( + () => ChartTimespans.indexOf(chartType), + [chartType] + ); const { progress } = useChartData(); const spinnerRotation = useSharedValue(0); diff --git a/src/components/walletconnect-list/WalletConnectV2ListItem.tsx b/src/components/walletconnect-list/WalletConnectV2ListItem.tsx index fd0b5ac8071..419401b0b2d 100644 --- a/src/components/walletconnect-list/WalletConnectV2ListItem.tsx +++ b/src/components/walletconnect-list/WalletConnectV2ListItem.tsx @@ -77,55 +77,50 @@ export function WalletConnectV2ListItem({ }, }; - const { - dappName, - dappUrl, - dappLogo, - address, - chainIds, - } = React.useMemo(() => { - const { namespaces, requiredNamespaces, peer } = session; - const { metadata } = peer; - const { chains } = requiredNamespaces.eip155; - const eip155Account = namespaces.eip155?.accounts?.[0] || undefined; + const { dappName, dappUrl, dappLogo, address, chainIds } = + React.useMemo(() => { + const { namespaces, requiredNamespaces, peer } = session; + const { metadata } = peer; + const { chains } = requiredNamespaces.eip155; + const eip155Account = namespaces.eip155?.accounts?.[0] || undefined; - if (!eip155Account || !chains || !chains.length) { - const e = new RainbowError( - `WalletConnectV2ListItem: unsupported namespace` - ); - logger.error(e); + if (!eip155Account || !chains || !chains.length) { + const e = new RainbowError( + `WalletConnectV2ListItem: unsupported namespace` + ); + logger.error(e); - // defensive, just for types, should never happen - throw e; - } + // defensive, just for types, should never happen + throw e; + } - const [ns, rawChainId, address] = eip155Account?.split(':') as [ - string, - string, - string - ]; - const chainIds = chains - .map(chain => parseInt(chain.split(':')[1])) - .filter(isSupportedChain); + const [ns, rawChainId, address] = eip155Account?.split(':') as [ + string, + string, + string, + ]; + const chainIds = chains + .map(chain => parseInt(chain.split(':')[1])) + .filter(isSupportedChain); - if (!address) { - const e = new RainbowError( - `WalletConnectV2ListItem: could not parse address` - ); - logger.error(e); + if (!address) { + const e = new RainbowError( + `WalletConnectV2ListItem: could not parse address` + ); + logger.error(e); - // defensive, just for types, should never happen - throw e; - } + // defensive, just for types, should never happen + throw e; + } - return { - dappName: metadata.name || 'Unknown Dapp', - dappUrl: metadata.url || 'Unknown URL', - dappLogo: metadata && metadata.icons ? metadata.icons[0] : undefined, - address, - chainIds, - }; - }, [session]); + return { + dappName: metadata.name || 'Unknown Dapp', + dappUrl: metadata.url || 'Unknown URL', + dappLogo: metadata && metadata.icons ? metadata.icons[0] : undefined, + address, + chainIds, + }; + }, [session]); const availableNetworks = useMemo(() => { return chainIds diff --git a/src/design-system/color/AccentColorContext.tsx b/src/design-system/color/AccentColorContext.tsx index 4fb7c01dacc..237c45e6643 100644 --- a/src/design-system/color/AccentColorContext.tsx +++ b/src/design-system/color/AccentColorContext.tsx @@ -34,7 +34,7 @@ export function AccentColorProvider({ color, mode: chroma.contrast(color, '#fff') > 2.125 ? 'darkTinted' : 'lightTinted', - } as const), + }) as const, [color] ); diff --git a/src/design-system/color/palettes.docs.tsx b/src/design-system/color/palettes.docs.tsx index 6b33ea44ddf..05d3efe9569 100644 --- a/src/design-system/color/palettes.docs.tsx +++ b/src/design-system/color/palettes.docs.tsx @@ -22,17 +22,15 @@ const BackgroundColors = ({ mode }: { mode: ColorMode }) => ( - {(Object.keys( - backgroundColors - ) as (keyof typeof backgroundColors)[]).map( - (color: BackgroundColor) => ( - - - {color} - - - ) - )} + {( + Object.keys(backgroundColors) as (keyof typeof backgroundColors)[] + ).map((color: BackgroundColor) => ( + + + {color} + + + ))} diff --git a/src/design-system/color/palettes.ts b/src/design-system/color/palettes.ts index 6edd3d3c44b..a29b9960a19 100644 --- a/src/design-system/color/palettes.ts +++ b/src/design-system/color/palettes.ts @@ -676,7 +676,7 @@ export const palettes: Record = { }; function selectForegroundColors< - SelectedColors extends readonly (ForegroundColor | 'accent')[] + SelectedColors extends readonly (ForegroundColor | 'accent')[], >(...colors: SelectedColors): SelectedColors { return colors; } @@ -707,7 +707,7 @@ export const textColors = selectForegroundColors( 'secondary70 (Deprecated)', 'secondary80 (Deprecated)' ); -export type TextColor = typeof textColors[number]; +export type TextColor = (typeof textColors)[number]; export const shadowColors = selectForegroundColors( 'accent', @@ -719,7 +719,7 @@ export const shadowColors = selectForegroundColors( 'orange', 'yellow' ); -export type ShadowColor = typeof shadowColors[number]; +export type ShadowColor = (typeof shadowColors)[number]; export const separatorColors = selectForegroundColors( 'separator', @@ -731,4 +731,4 @@ export const separatorColors = selectForegroundColors( 'divider80 (Deprecated)', 'divider100 (Deprecated)' ); -export type SeparatorColor = typeof separatorColors[number]; +export type SeparatorColor = (typeof separatorColors)[number]; diff --git a/src/design-system/components/Box/Box.tsx b/src/design-system/components/Box/Box.tsx index 02364d831c7..4373cd9bdf9 100644 --- a/src/design-system/components/Box/Box.tsx +++ b/src/design-system/components/Box/Box.tsx @@ -23,7 +23,7 @@ import { ApplyShadow } from '../private/ApplyShadow/ApplyShadow'; import type * as Polymorphic from './polymorphic'; const positions = ['absolute'] as const; -type Position = typeof positions[number]; +type Position = (typeof positions)[number]; export function resolveToken( scale: Record, diff --git a/src/design-system/components/Box/polymorphic.ts b/src/design-system/components/Box/polymorphic.ts index c82958bc076..15c9fba053f 100644 --- a/src/design-system/components/Box/polymorphic.ts +++ b/src/design-system/components/Box/polymorphic.ts @@ -44,9 +44,8 @@ type OwnProps = E extends ForwardRefComponent ? P : {}; /** * Infers the JSX.IntrinsicElement if E is a ForwardRefExoticComponentWithAs */ -type IntrinsicElement = E extends ForwardRefComponent - ? I - : never; +type IntrinsicElement = + E extends ForwardRefComponent ? I : never; type ForwardRefExoticComponent = React.ForwardRefExoticComponent< Merge< @@ -61,7 +60,7 @@ type ForwardRefExoticComponent = React.ForwardRefExoticComponent< interface ForwardRefComponent< DefaultComponentType, - OwnProps = {} + OwnProps = {}, /** * Extends original type to ensure built in React types play nice * with polymorphic components still e.g. `React.ElementRef` etc. diff --git a/src/design-system/components/Heading/Heading.examples.tsx b/src/design-system/components/Heading/Heading.examples.tsx index e1571db546f..f8dbcc5f41c 100644 --- a/src/design-system/components/Heading/Heading.examples.tsx +++ b/src/design-system/components/Heading/Heading.examples.tsx @@ -13,9 +13,9 @@ import { Heading } from './Heading'; const loremIpsum = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.'; -export const sizes: Example[] = (Object.keys( - typeHierarchy.heading -) as HeadingSize[]).map(size => ({ +export const sizes: Example[] = ( + Object.keys(typeHierarchy.heading) as HeadingSize[] +).map(size => ({ name: size, Example: () => source( diff --git a/src/design-system/components/Heading/useHeadingStyle.ts b/src/design-system/components/Heading/useHeadingStyle.ts index 8ff617f57f3..cca61eb2e8a 100644 --- a/src/design-system/components/Heading/useHeadingStyle.ts +++ b/src/design-system/components/Heading/useHeadingStyle.ts @@ -32,7 +32,7 @@ export function useHeadingStyle({ textAlign, ...sizeStyles, ...weightStyles, - } as const), + }) as const, [colorValue, textAlign, sizeStyles, weightStyles] ); diff --git a/src/design-system/components/Inline/Inline.tsx b/src/design-system/components/Inline/Inline.tsx index d356684f6af..3fb44b9cb6f 100644 --- a/src/design-system/components/Inline/Inline.tsx +++ b/src/design-system/components/Inline/Inline.tsx @@ -44,9 +44,10 @@ export function Inline({ const verticalSpace = verticalSpaceProp ?? space; const horizontalSpace = horizontalSpaceProp ?? space; - const flattenedChildren = useMemo(() => flattenChildren(children), [ - children, - ]); + const flattenedChildren = useMemo( + () => flattenChildren(children), + [children] + ); return ( ({ depth, listSpace, paragraphSpace }), [ - depth, - paragraphSpace, - listSpace, - ])} + value={useMemo( + () => ({ depth, listSpace, paragraphSpace }), + [depth, paragraphSpace, listSpace] + )} > {children} @@ -143,10 +142,10 @@ export const MarkdownText = memo(function MarkdownText({ const heading1Color = heading1ColorProp ?? color; const heading2Color = heading2ColorProp ?? heading1ColorProp ?? color; - const spaceProps = useMemo(() => ({ listSpace, paragraphSpace }), [ - paragraphSpace, - listSpace, - ]); + const spaceProps = useMemo( + () => ({ listSpace, paragraphSpace }), + [paragraphSpace, listSpace] + ); const rules: RenderRules = useMemo(() => { return { diff --git a/src/design-system/components/Text/useTextStyle.ts b/src/design-system/components/Text/useTextStyle.ts index 05191e33994..d80cd47b5df 100644 --- a/src/design-system/components/Text/useTextStyle.ts +++ b/src/design-system/components/Text/useTextStyle.ts @@ -50,7 +50,7 @@ export function useTextStyle({ ...weightStyles, ...(uppercase ? { textTransform: 'uppercase' as const } : null), ...(tabularNumbers ? { fontVariant: ['tabular-nums' as const] } : null), - } as const), + }) as const, [sizeStyles, weightStyles, textAlign, colorValue, tabularNumbers, uppercase] ); diff --git a/src/design-system/docs/.playroom/fonts.css b/src/design-system/docs/.playroom/fonts.css index 609ee7d5e6e..893834b4fa2 100644 --- a/src/design-system/docs/.playroom/fonts.css +++ b/src/design-system/docs/.playroom/fonts.css @@ -3,7 +3,8 @@ @font-face { font-family: 'SFRounded'; src: url('../public/fonts/subset-SFRounded-Regular.eot'); - src: url('../public/fonts/subset-SFRounded-Regular.eot?#iefix') + src: + url('../public/fonts/subset-SFRounded-Regular.eot?#iefix') format('embedded-opentype'), url('../public/fonts/subset-SFRounded-Regular.woff2') format('woff2'), url('../public/fonts/subset-SFRounded-Regular.woff') format('woff'), @@ -17,7 +18,8 @@ @font-face { font-family: 'SFRounded'; src: url('../public/fonts/subset-SFRounded-Medium.eot'); - src: url('../public/fonts/subset-SFRounded-Medium.eot?#iefix') + src: + url('../public/fonts/subset-SFRounded-Medium.eot?#iefix') format('embedded-opentype'), url('../public/fonts/subset-SFRounded-Medium.woff2') format('woff2'), url('../public/fonts/subset-SFRounded-Medium.woff') format('woff'), @@ -31,7 +33,8 @@ @font-face { font-family: 'SFRounded'; src: url('../public/fonts/subset-SFRounded-Semibold.eot'); - src: url('../public/fonts/subset-SFRounded-Semibold.eot?#iefix') + src: + url('../public/fonts/subset-SFRounded-Semibold.eot?#iefix') format('embedded-opentype'), url('../public/fonts/subset-SFRounded-Semibold.woff2') format('woff2'), url('../public/fonts/subset-SFRounded-Semibold.woff') format('woff'), @@ -45,7 +48,8 @@ @font-face { font-family: 'SFRounded'; src: url('../public/fonts/subset-SFRounded-Bold.eot'); - src: url('../public/fonts/subset-SFRounded-Bold.eot?#iefix') + src: + url('../public/fonts/subset-SFRounded-Bold.eot?#iefix') format('embedded-opentype'), url('../public/fonts/subset-SFRounded-Bold.woff2') format('woff2'), url('../public/fonts/subset-SFRounded-Bold.woff') format('woff'), @@ -59,7 +63,8 @@ @font-face { font-family: 'SFRounded'; src: url('../public/fonts/subset-SFRounded-Heavy.eot'); - src: url('../public/fonts/subset-SFRounded-Heavy.eot?#iefix') + src: + url('../public/fonts/subset-SFRounded-Heavy.eot?#iefix') format('embedded-opentype'), url('../public/fonts/subset-SFRounded-Heavy.woff2') format('woff2'), url('../public/fonts/subset-SFRounded-Heavy.woff') format('woff'), @@ -73,7 +78,8 @@ @font-face { font-family: 'SF-Pro-Rounded-Regular'; src: url('../public/fonts/subset-SFRounded-Regular.eot'); - src: url('../public/fonts/subset-SFRounded-Regular.eot?#iefix') + src: + url('../public/fonts/subset-SFRounded-Regular.eot?#iefix') format('embedded-opentype'), url('../public/fonts/subset-SFRounded-Regular.woff2') format('woff2'), url('../public/fonts/subset-SFRounded-Regular.woff') format('woff'), @@ -87,7 +93,8 @@ @font-face { font-family: 'SF-Pro-Rounded-Bold'; src: url('../public/fonts/subset-SFRounded-Bold.eot'); - src: url('../public/fonts/subset-SFRounded-Bold.eot?#iefix') + src: + url('../public/fonts/subset-SFRounded-Bold.eot?#iefix') format('embedded-opentype'), url('../public/fonts/subset-SFRounded-Bold.woff2') format('woff2'), url('../public/fonts/subset-SFRounded-Bold.woff') format('woff'), @@ -101,7 +108,8 @@ @font-face { font-family: 'SF-Pro-Rounded-Medium'; src: url('../public/fonts/subset-SFRounded-Medium.eot'); - src: url('../public/fonts/subset-SFRounded-Medium.eot?#iefix') + src: + url('../public/fonts/subset-SFRounded-Medium.eot?#iefix') format('embedded-opentype'), url('../public/fonts/subset-SFRounded-Medium.woff2') format('woff2'), url('../public/fonts/subset-SFRounded-Medium.woff') format('woff'), @@ -115,7 +123,8 @@ @font-face { font-family: 'SF-Pro-Rounded-Semibold'; src: url('../public/fonts/subset-SFRounded-Semibold.eot'); - src: url('../public/fonts/subset-SFRounded-Semibold.eot?#iefix') + src: + url('../public/fonts/subset-SFRounded-Semibold.eot?#iefix') format('embedded-opentype'), url('../public/fonts/subset-SFRounded-Semibold.woff2') format('woff2'), url('../public/fonts/subset-SFRounded-Semibold.woff') format('woff'), @@ -129,7 +138,8 @@ @font-face { font-family: 'SF-Pro-Rounded-Heavy'; src: url('../public/fonts/subset-SFRounded-Heavy.eot'); - src: url('../public/fonts/subset-SFRounded-Heavy.eot?#iefix') + src: + url('../public/fonts/subset-SFRounded-Heavy.eot?#iefix') format('embedded-opentype'), url('../public/fonts/subset-SFRounded-Heavy.woff2') format('woff2'), url('../public/fonts/subset-SFRounded-Heavy.woff') format('woff'), diff --git a/src/design-system/docs/styles/fonts.css b/src/design-system/docs/styles/fonts.css index 22e805bc443..4a2d4b37483 100644 --- a/src/design-system/docs/styles/fonts.css +++ b/src/design-system/docs/styles/fonts.css @@ -3,7 +3,8 @@ @font-face { font-family: 'SFRounded'; src: url('/fonts/subset-SFRounded-Regular.eot'); - src: url('/fonts/subset-SFRounded-Regular.eot?#iefix') + src: + url('/fonts/subset-SFRounded-Regular.eot?#iefix') format('embedded-opentype'), url('/fonts/subset-SFRounded-Regular.woff2') format('woff2'), url('/fonts/subset-SFRounded-Regular.woff') format('woff'), @@ -16,8 +17,8 @@ @font-face { font-family: 'SFRounded'; src: url('/fonts/subset-SFRounded-Medium.eot'); - src: url('/fonts/subset-SFRounded-Medium.eot?#iefix') - format('embedded-opentype'), + src: + url('/fonts/subset-SFRounded-Medium.eot?#iefix') format('embedded-opentype'), url('/fonts/subset-SFRounded-Medium.woff2') format('woff2'), url('/fonts/subset-SFRounded-Medium.woff') format('woff'), url('/fonts/subset-SFRounded-Medium.svg#SFRounded-Medium') format('svg'); @@ -29,7 +30,8 @@ @font-face { font-family: 'SFRounded'; src: url('/fonts/subset-SFRounded-Semibold.eot'); - src: url('/fonts/subset-SFRounded-Semibold.eot?#iefix') + src: + url('/fonts/subset-SFRounded-Semibold.eot?#iefix') format('embedded-opentype'), url('/fonts/subset-SFRounded-Semibold.woff2') format('woff2'), url('/fonts/subset-SFRounded-Semibold.woff') format('woff'), @@ -42,8 +44,8 @@ @font-face { font-family: 'SFRounded'; src: url('/fonts/subset-SFRounded-Bold.eot'); - src: url('/fonts/subset-SFRounded-Bold.eot?#iefix') - format('embedded-opentype'), + src: + url('/fonts/subset-SFRounded-Bold.eot?#iefix') format('embedded-opentype'), url('/fonts/subset-SFRounded-Bold.woff2') format('woff2'), url('/fonts/subset-SFRounded-Bold.woff') format('woff'), url('/fonts/subset-SFRounded-Bold.svg#SFRounded-Bold') format('svg'); @@ -55,8 +57,8 @@ @font-face { font-family: 'SFRounded'; src: url('/fonts/subset-SFRounded-Heavy.eot'); - src: url('/fonts/subset-SFRounded-Heavy.eot?#iefix') - format('embedded-opentype'), + src: + url('/fonts/subset-SFRounded-Heavy.eot?#iefix') format('embedded-opentype'), url('/fonts/subset-SFRounded-Heavy.woff2') format('woff2'), url('/fonts/subset-SFRounded-Heavy.woff') format('woff'), url('/fonts/subset-SFRounded-Heavy.svg#SFRounded-Heavy') format('svg'); @@ -68,7 +70,8 @@ @font-face { font-family: 'SF-Pro-Rounded-Regular'; src: url('/fonts/subset-SFRounded-Regular.eot'); - src: url('/fonts/subset-SFRounded-Regular.eot?#iefix') + src: + url('/fonts/subset-SFRounded-Regular.eot?#iefix') format('embedded-opentype'), url('/fonts/subset-SFRounded-Regular.woff2') format('woff2'), url('/fonts/subset-SFRounded-Regular.woff') format('woff'), @@ -81,8 +84,8 @@ @font-face { font-family: 'SF-Pro-Rounded-Bold'; src: url('/fonts/subset-SFRounded-Bold.eot'); - src: url('/fonts/subset-SFRounded-Bold.eot?#iefix') - format('embedded-opentype'), + src: + url('/fonts/subset-SFRounded-Bold.eot?#iefix') format('embedded-opentype'), url('/fonts/subset-SFRounded-Bold.woff2') format('woff2'), url('/fonts/subset-SFRounded-Bold.woff') format('woff'), url('/fonts/subset-SFRounded-Bold.svg#SFRounded-Bold') format('svg'); @@ -94,8 +97,8 @@ @font-face { font-family: 'SF-Pro-Rounded-Medium'; src: url('/fonts/subset-SFRounded-Medium.eot'); - src: url('/fonts/subset-SFRounded-Medium.eot?#iefix') - format('embedded-opentype'), + src: + url('/fonts/subset-SFRounded-Medium.eot?#iefix') format('embedded-opentype'), url('/fonts/subset-SFRounded-Medium.woff2') format('woff2'), url('/fonts/subset-SFRounded-Medium.woff') format('woff'), url('/fonts/subset-SFRounded-Medium.svg#SFRounded-Medium') format('svg'); @@ -107,7 +110,8 @@ @font-face { font-family: 'SF-Pro-Rounded-Semibold'; src: url('/fonts/subset-SFRounded-Semibold.eot'); - src: url('/fonts/subset-SFRounded-Semibold.eot?#iefix') + src: + url('/fonts/subset-SFRounded-Semibold.eot?#iefix') format('embedded-opentype'), url('/fonts/subset-SFRounded-Semibold.woff2') format('woff2'), url('/fonts/subset-SFRounded-Semibold.woff') format('woff'), @@ -120,8 +124,8 @@ @font-face { font-family: 'SF-Pro-Rounded-Heavy'; src: url('/fonts/subset-SFRounded-Heavy.eot'); - src: url('/fonts/subset-SFRounded-Heavy.eot?#iefix') - format('embedded-opentype'), + src: + url('/fonts/subset-SFRounded-Heavy.eot?#iefix') format('embedded-opentype'), url('/fonts/subset-SFRounded-Heavy.woff2') format('woff2'), url('/fonts/subset-SFRounded-Heavy.woff') format('woff'), url('/fonts/subset-SFRounded-Heavy.svg#SFRounded-Heavy') format('svg'); diff --git a/src/design-system/docs/system/typography.css.ts b/src/design-system/docs/system/typography.css.ts index 2525b5654af..d511f7eb4ed 100644 --- a/src/design-system/docs/system/typography.css.ts +++ b/src/design-system/docs/system/typography.css.ts @@ -36,8 +36,8 @@ export const sizes = { text: mapValues(typeHierarchy.text, createTextSize), }; -export type HeadingSizes = keyof typeof sizes['heading']; -export type TextSizes = keyof typeof sizes['text']; +export type HeadingSizes = keyof (typeof sizes)['heading']; +export type TextSizes = keyof (typeof sizes)['text']; export const letterSpacings = { heading: mapValues( diff --git a/src/design-system/playground/Playground.tsx b/src/design-system/playground/Playground.tsx index 669911968b6..49bcd12cbde 100644 --- a/src/design-system/playground/Playground.tsx +++ b/src/design-system/playground/Playground.tsx @@ -72,9 +72,10 @@ const CodePreview = ({ wrapper: Example['wrapper']; Example: Example['Example']; }) => { - const { element } = React.useMemo(() => getSourceFromExample({ Example }), [ - Example, - ]); + const { element } = React.useMemo( + () => getSourceFromExample({ Example }), + [Example] + ); // @ts-expect-error Argument of type 'Source...' is not assignable to parameter of type 'ReactNode'. return <>{wrapper(element)}; }; diff --git a/src/ens-avatar/src/index.ts b/src/ens-avatar/src/index.ts index ff7518df9c0..ad39dbad96b 100644 --- a/src/ens-avatar/src/index.ts +++ b/src/ens-avatar/src/index.ts @@ -64,9 +64,8 @@ export class AvatarResolver implements IAvatarResolver { } // parse retrieved avatar uri - const { chainID, namespace, contractAddress, tokenID } = parseNFT( - avatarURI - ); + const { chainID, namespace, contractAddress, tokenID } = + parseNFT(avatarURI); // detect avatar spec by namespace const spec = new specs[namespace](); if (!spec) return null; diff --git a/src/featuresToUnlock/unlockableAppIconCheck.ts b/src/featuresToUnlock/unlockableAppIconCheck.ts index 1fb62662724..7b06db4a15c 100644 --- a/src/featuresToUnlock/unlockableAppIconCheck.ts +++ b/src/featuresToUnlock/unlockableAppIconCheck.ts @@ -20,13 +20,8 @@ export const unlockableAppIconCheck = async ( appIconFeature: UnlockableAppIcon, walletsToCheck: EthereumAddress[] ) => { - const { - key, - explainSheetType, - network, - unlockKey, - unlockingNfts, - } = appIconFeature; + const { key, explainSheetType, network, unlockKey, unlockingNfts } = + appIconFeature; const handled = mmkv.getBoolean(unlockKey); diff --git a/src/graphql/utils/getFetchRequester.ts b/src/graphql/utils/getFetchRequester.ts index d51effd20d6..b08b7938367 100644 --- a/src/graphql/utils/getFetchRequester.ts +++ b/src/graphql/utils/getFetchRequester.ts @@ -60,7 +60,7 @@ export function getFetchRequester(config: Config) { return async function requester< TResponse = unknown, - TVariables = Record + TVariables = Record, >( node: DocumentNode, variables?: TVariables, diff --git a/src/handlers/LedgerSigner.ts b/src/handlers/LedgerSigner.ts index 56ab4e74766..ee2130f954d 100644 --- a/src/handlers/LedgerSigner.ts +++ b/src/handlers/LedgerSigner.ts @@ -129,9 +129,8 @@ export class LedgerSigner extends Signer { async signTypedDataMessage(data: any, legacy: boolean): Promise { const version = legacy === false ? SignTypedDataVersion.V4 : SignTypedDataVersion.V3; - const { domain, types, primaryType, message } = TypedDataUtils.sanitizeData( - data - ); + const { domain, types, primaryType, message } = + TypedDataUtils.sanitizeData(data); const domainSeparatorHex = TypedDataUtils.hashStruct( 'EIP712Domain', diff --git a/src/handlers/ens.ts b/src/handlers/ens.ts index 1ce0070b86d..1e6cebb9d58 100644 --- a/src/handlers/ens.ts +++ b/src/handlers/ens.ts @@ -940,12 +940,8 @@ export const formatRecordsForTransaction = ( export const recordsForTransactionAreValid = ( registrationRecords: ENSRegistrationRecords ) => { - const { - coinAddress, - contenthash, - ensAssociatedAddress, - text, - } = registrationRecords; + const { coinAddress, contenthash, ensAssociatedAddress, text } = + registrationRecords; if ( !coinAddress?.length && typeof contenthash !== 'string' && @@ -960,12 +956,8 @@ export const recordsForTransactionAreValid = ( export const getTransactionTypeForRecords = ( registrationRecords: ENSRegistrationRecords ) => { - const { - coinAddress, - contenthash, - ensAssociatedAddress, - text, - } = registrationRecords; + const { coinAddress, contenthash, ensAssociatedAddress, text } = + registrationRecords; if ( ensAssociatedAddress || diff --git a/src/handlers/nftOffers.ts b/src/handlers/nftOffers.ts index d3b7df3f7a6..ce3737597e7 100644 --- a/src/handlers/nftOffers.ts +++ b/src/handlers/nftOffers.ts @@ -22,9 +22,9 @@ const getStateDiff = async ( provider: StaticJsonRpcProvider, approval: TxData ): Promise => { - const { - number: blockNumber, - } = await (provider.getBlock as () => Promise)(); + const { number: blockNumber } = await ( + provider.getBlock as () => Promise + )(); const { trace_call_block_number_offset } = getRemoteConfig(); // trace_call default params diff --git a/src/handlers/swap.ts b/src/handlers/swap.ts index 4c576da0b67..85fccc15317 100644 --- a/src/handlers/swap.ts +++ b/src/handlers/swap.ts @@ -141,9 +141,9 @@ export const getStateDiff = async ( const fromAddr = tradeDetails.from; const toAddr = RAINBOW_ROUTER_CONTRACT_ADDRESS; const tokenContract = new Contract(tokenAddress, erc20ABI, provider); - const { - number: blockNumber, - } = await (provider.getBlock as () => Promise)(); + const { number: blockNumber } = await ( + provider.getBlock as () => Promise + )(); // Get data const { data } = await tokenContract.populateTransaction.approve( @@ -337,11 +337,12 @@ export const estimateSwapGasLimit = async ({ IS_TESTING !== 'true' ) { try { - const gasLimitWithFakeApproval = await getSwapGasLimitWithFakeApproval( - chainId, - provider, - tradeDetails - ); + const gasLimitWithFakeApproval = + await getSwapGasLimitWithFakeApproval( + chainId, + provider, + tradeDetails + ); logger.debug( ' ✅ Got gasLimitWithFakeApproval!', gasLimitWithFakeApproval @@ -390,11 +391,12 @@ export const estimateCrosschainSwapGasLimit = async ({ IS_TESTING !== 'true' ) { try { - const gasLimitWithFakeApproval = await getSwapGasLimitWithFakeApproval( - chainId, - provider, - tradeDetails - ); + const gasLimitWithFakeApproval = + await getSwapGasLimitWithFakeApproval( + chainId, + provider, + tradeDetails + ); logger.debug( ' ✅ Got gasLimitWithFakeApproval!', gasLimitWithFakeApproval @@ -406,9 +408,8 @@ export const estimateCrosschainSwapGasLimit = async ({ } const routeGasLimit = getCrosschainSwapDefaultGasLimit(tradeDetails); - const rainbowDefaultGasLimit = getCrosschainSwapRainbowDefaultGasLimit( - chainId - ); + const rainbowDefaultGasLimit = + getCrosschainSwapRainbowDefaultGasLimit(chainId); if (routeGasLimit && lessThan(rainbowDefaultGasLimit, routeGasLimit)) { return routeGasLimit; } @@ -428,9 +429,8 @@ export const estimateCrosschainSwapGasLimit = async ({ SWAP_GAS_PADDING ); const routeGasLimit = getCrosschainSwapDefaultGasLimit(tradeDetails); - const rainbowDefaultGasLimit = getCrosschainSwapRainbowDefaultGasLimit( - chainId - ); + const rainbowDefaultGasLimit = + getCrosschainSwapRainbowDefaultGasLimit(chainId); let fallbackGasLimit: BigNumberish = rainbowDefaultGasLimit; if (routeGasLimit && lessThan(rainbowDefaultGasLimit, routeGasLimit)) { @@ -439,9 +439,8 @@ export const estimateCrosschainSwapGasLimit = async ({ return gasLimit || fallbackGasLimit; } catch (error) { const routeGasLimit = getCrosschainSwapDefaultGasLimit(tradeDetails); - const rainbowDefaultGasLimit = getCrosschainSwapRainbowDefaultGasLimit( - chainId - ); + const rainbowDefaultGasLimit = + getCrosschainSwapRainbowDefaultGasLimit(chainId); let fallbackGasLimit: BigNumberish = rainbowDefaultGasLimit; if (routeGasLimit && lessThan(rainbowDefaultGasLimit, routeGasLimit)) { diff --git a/src/handlers/web3.ts b/src/handlers/web3.ts index ab91dc87232..de58a72d506 100644 --- a/src/handlers/web3.ts +++ b/src/handlers/web3.ts @@ -149,7 +149,8 @@ type NewTransactionNonNullable = { /** * @desc web3 http instance */ -export let web3Provider: StaticJsonRpcProvider = (null as unknown) as StaticJsonRpcProvider; +export let web3Provider: StaticJsonRpcProvider = + null as unknown as StaticJsonRpcProvider; /** * @desc Checks whether or not a `Network | string` union type should be @@ -413,9 +414,8 @@ export async function estimateGasWithPadding( const saferGasLimit = fraction(gasLimit.toString(), 19, 20); logger.info('⛽ safer gas limit for last block is', { saferGasLimit }); - txPayloadToEstimate[contractCallEstimateGas ? 'gasLimit' : 'gas'] = toHex( - saferGasLimit - ); + txPayloadToEstimate[contractCallEstimateGas ? 'gasLimit' : 'gas'] = + toHex(saferGasLimit); // safety precaution: we want to ensure these properties are not used for gas estimation const cleanTxPayload = omitFlatten(txPayloadToEstimate, [ diff --git a/src/helpers/buildTransactionsSectionsSelector.tsx b/src/helpers/buildTransactionsSectionsSelector.tsx index e656db21e52..33cd348724e 100644 --- a/src/helpers/buildTransactionsSectionsSelector.tsx +++ b/src/helpers/buildTransactionsSectionsSelector.tsx @@ -19,10 +19,11 @@ type RainbowTransactionWithContact = RainbowTransaction & { contact: Contact | null; }; -type RainbowTransactionWithContactAndMainnetAddress = RainbowTransactionWithContact & { - mainnetAddress: string; - accountAddress: string; -}; +type RainbowTransactionWithContactAndMainnetAddress = + RainbowTransactionWithContact & { + mainnetAddress: string; + accountAddress: string; + }; // bad news const groupTransactionByDate = ({ pending, @@ -51,20 +52,22 @@ const groupTransactionByDate = ({ } }; -const addContactInfo = (contacts: { [address: string]: Contact }) => ( - txn: RainbowTransaction -): RainbowTransaction & { - contact: Contact | null; -} => { - const { from, to, status } = txn; - const isSent = status === TransactionStatusTypes.sent; - const contactAddress = (isSent ? to : from) || ''; - const contact = contacts?.[contactAddress?.toLowerCase()] ?? null; - return { - ...txn, - contact, +const addContactInfo = + (contacts: { [address: string]: Contact }) => + ( + txn: RainbowTransaction + ): RainbowTransaction & { + contact: Contact | null; + } => { + const { from, to, status } = txn; + const isSent = status === TransactionStatusTypes.sent; + const contactAddress = (isSent ? to : from) || ''; + const contact = contacts?.[contactAddress?.toLowerCase()] ?? null; + return { + ...txn, + contact, + }; }; -}; export const buildTransactionsSections = ({ accountAddress, @@ -117,21 +120,20 @@ export const buildTransactionsSections = ({ item: RainbowTransactionWithContactAndMainnetAddress; }) => JSX.Element; }[] = filter.map((section: string) => { - const sectionData: RainbowTransactionWithContactAndMainnetAddress[] = transactionsByDate[ - section - ].map(txn => { - const typeTxn = txn as RainbowTransactionWithContact; - const res = { - ...typeTxn, - to: typeTxn.to || '', - from: typeTxn.from || '', - accountAddress, - mainnetAddress: - mainnetAddresses[`${typeTxn.address}_${typeTxn.network}`], - }; + const sectionData: RainbowTransactionWithContactAndMainnetAddress[] = + transactionsByDate[section].map(txn => { + const typeTxn = txn as RainbowTransactionWithContact; + const res = { + ...typeTxn, + to: typeTxn.to || '', + from: typeTxn.from || '', + accountAddress, + mainnetAddress: + mainnetAddresses[`${typeTxn.address}_${typeTxn.network}`], + }; - return res; - }); + return res; + }); return { data: sectionData, diff --git a/src/helpers/buildWalletSections.tsx b/src/helpers/buildWalletSections.tsx index b1c9010d6bf..5184a4a081a 100644 --- a/src/helpers/buildWalletSections.tsx +++ b/src/helpers/buildWalletSections.tsx @@ -78,10 +78,8 @@ const withPositionsSection = (isLoadingUserAssets: boolean) => { const positionsEnabled = getExperimetalFlag(DEFI_POSITIONS); if (!positionsEnabled) return []; - const { - accountAddress: address, - nativeCurrency: currency, - } = store.getState().settings; + const { accountAddress: address, nativeCurrency: currency } = + store.getState().settings; const positionsObj: RainbowPositions | undefined = queryClient.getQueryData( positionsQueryKey({ address, currency }) ); diff --git a/src/helpers/chartTypes.ts b/src/helpers/chartTypes.ts index cef4cdcd027..0b1b8c1929d 100644 --- a/src/helpers/chartTypes.ts +++ b/src/helpers/chartTypes.ts @@ -8,4 +8,4 @@ const chartTypes = { } as const; export default chartTypes; -export type ChartType = typeof chartTypes[keyof typeof chartTypes]; +export type ChartType = (typeof chartTypes)[keyof typeof chartTypes]; diff --git a/src/helpers/emojiHandler.ts b/src/helpers/emojiHandler.ts index 1a5f22d6fa0..04cb1a88d61 100644 --- a/src/helpers/emojiHandler.ts +++ b/src/helpers/emojiHandler.ts @@ -1,7 +1,8 @@ import GraphemeSplitter from 'grapheme-splitter'; import { memoFn } from '../utils/memoFn'; -const regex = /(?:[\u2700-\u27bf]|(?:\ud83c[\udde6-\uddff]){2}|[\ud800-\udbff][\udc00-\udfff]|[\u0023-\u0039]\ufe0f?\u20e3|\u3299|\u3297|\u303d|\u3030|\u24c2|\ud83c[\udd70-\udd71]|\ud83c[\udd7e-\udd7f]|\ud83c\udd8e|\ud83c[\udd91-\udd9a]|\ud83c[\udde6-\uddff]|\ud83c[\ude01-\ude02]|\ud83c\ude1a|\ud83c\ude2f|\ud83c[\ude32-\ude3a]|\ud83c[\ude50-\ude51]|\u203c|\u2049|[\u25aa-\u25ab]|\u25b6|\u25c0|[\u25fb-\u25fe]|\u00a9|\u00ae|\u2122|\u2139|\ud83c\udc04|[\u2600-\u26FF]|\u2b05|\u2b06|\u2b07|\u2b1b|\u2b1c|\u2b50|\u2b55|\u231a|\u231b|\u2328|\u23cf|[\u23e9-\u23f3]|[\u23f8-\u23fa]|\ud83c\udccf|\u2934|\u2935|[\u2190-\u21ff])/g; +const regex = + /(?:[\u2700-\u27bf]|(?:\ud83c[\udde6-\uddff]){2}|[\ud800-\udbff][\udc00-\udfff]|[\u0023-\u0039]\ufe0f?\u20e3|\u3299|\u3297|\u303d|\u3030|\u24c2|\ud83c[\udd70-\udd71]|\ud83c[\udd7e-\udd7f]|\ud83c\udd8e|\ud83c[\udd91-\udd9a]|\ud83c[\udde6-\uddff]|\ud83c[\ude01-\ude02]|\ud83c\ude1a|\ud83c\ude2f|\ud83c[\ude32-\ude3a]|\ud83c[\ude50-\ude51]|\u203c|\u2049|[\u25aa-\u25ab]|\u25b6|\u25c0|[\u25fb-\u25fe]|\u00a9|\u00ae|\u2122|\u2139|\ud83c\udc04|[\u2600-\u26FF]|\u2b05|\u2b06|\u2b07|\u2b1b|\u2b1c|\u2b50|\u2b55|\u231a|\u231b|\u2328|\u23cf|[\u23e9-\u23f3]|[\u23f8-\u23fa]|\ud83c\udccf|\u2934|\u2935|[\u2190-\u21ff])/g; export const removeFirstEmojiFromString = memoFn(string => { if (!string) return ''; diff --git a/src/helpers/ens.ts b/src/helpers/ens.ts index b39be23716d..24adeccf4ac 100644 --- a/src/helpers/ens.ts +++ b/src/helpers/ens.ts @@ -581,9 +581,8 @@ const getENSExecutionDetails = async ({ switch (type) { case ENSRegistrationTransactionType.COMMIT: { if (!name || !ownerAddress) throw new Error('Bad arguments for commit'); - const registrarController = await getENSRegistrarControllerContract( - wallet - ); + const registrarController = + await getENSRegistrarControllerContract(wallet); const commitment = await registrarController.makeCommitmentWithConfig( name.replace(ENS_DOMAIN, ''), ownerAddress, @@ -771,16 +770,14 @@ const formatRentPrice = ( undefined, true ); - const { - display: displayPerYear, - amount: amountPerYear, - } = convertAmountAndPriceToNativeDisplay( - rentPricePerYear, - nativeAssetPrice, - nativeCurrency, - undefined, - true - ); + const { display: displayPerYear, amount: amountPerYear } = + convertAmountAndPriceToNativeDisplay( + rentPricePerYear, + nativeAssetPrice, + nativeCurrency, + undefined, + true + ); return { perYear: { diff --git a/src/helpers/signingWallet.ts b/src/helpers/signingWallet.ts index 4eb400308fe..b505dd62aa4 100644 --- a/src/helpers/signingWallet.ts +++ b/src/helpers/signingWallet.ts @@ -65,7 +65,8 @@ export async function getSignatureForSigningWalletAndCreateSignatureIfNeeded( publicAccessControlOptions ); if (alreadyExistingEncodedSignature) { - const publicKeyForTheSigningWallet = await getPublicKeyOfTheSigningWalletAndCreateWalletIfNeeded(); + const publicKeyForTheSigningWallet = + await getPublicKeyOfTheSigningWalletAndCreateWalletIfNeeded(); const encryptor = new AesEncryptor(); const decryptedSignature = await encryptor.decrypt( RAINBOW_MASTER_KEY, @@ -109,7 +110,8 @@ export async function createSignature( privateKey: string | null = null ) { logger.log('Creating a signature'); - const publicKeyForTheSigningWallet = await getPublicKeyOfTheSigningWalletAndCreateWalletIfNeeded(); + const publicKeyForTheSigningWallet = + await getPublicKeyOfTheSigningWalletAndCreateWalletIfNeeded(); const mainWallet = privateKey ? new Wallet(privateKey) diff --git a/src/helpers/time.ts b/src/helpers/time.ts index 80459f4ca22..e02c8960f81 100644 --- a/src/helpers/time.ts +++ b/src/helpers/time.ts @@ -40,10 +40,8 @@ export const getMinimalTimeUnitStringForMs = ( const { days, hours, minutes, seconds } = parseMilliseconds(Number(ms)); const parsedMs = omitBy({ days, hours, minutes, seconds }, isZero); - const { - unit: highestResolutionUnit, - value: highestResolutionValue, - } = getHighestResolutionUnit(parsedMs); + const { unit: highestResolutionUnit, value: highestResolutionValue } = + getHighestResolutionUnit(parsedMs); const label = buildLocalizedTimeUnitString({ plural, diff --git a/src/helpers/transformUniqueAssetTraitsForPresentation.ts b/src/helpers/transformUniqueAssetTraitsForPresentation.ts index 8fd089a5da1..1c02c955b09 100644 --- a/src/helpers/transformUniqueAssetTraitsForPresentation.ts +++ b/src/helpers/transformUniqueAssetTraitsForPresentation.ts @@ -12,7 +12,8 @@ type MappedTrait = UniqueAssetTrait & { disableMenu?: boolean; } & AdditionalProperties; -const poapDateRegex = /\d\d-(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)-\d\d\d\d/; +const poapDateRegex = + /\d\d-(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)-\d\d\d\d/; const poapDateFormatString = 'dd-MMM-y'; const targetDateFormatString = 'MMM do, y'; diff --git a/src/helpers/utilities.ts b/src/helpers/utilities.ts index 311a34cea08..ca23037637d 100644 --- a/src/helpers/utilities.ts +++ b/src/helpers/utilities.ts @@ -575,13 +575,16 @@ export const pickShallow = ( obj: T, paths: K[] ): Pick => { - return paths.reduce((acc, key) => { - if (obj.hasOwnProperty(key)) { - acc[key] = obj[key]; + return paths.reduce( + (acc, key) => { + if (obj.hasOwnProperty(key)) { + acc[key] = obj[key]; + return acc; + } return acc; - } - return acc; - }, {} as Pick); + }, + {} as Pick + ); }; /** diff --git a/src/hooks/charts/useChartInfo.ts b/src/hooks/charts/useChartInfo.ts index cd3751dac0e..c1d37bff602 100644 --- a/src/hooks/charts/useChartInfo.ts +++ b/src/hooks/charts/useChartInfo.ts @@ -15,7 +15,7 @@ import { NetworkProperties } from '@/networks/types'; import { Network } from '@/helpers'; const chartTimes = ['hour', 'day', 'week', 'month', 'year'] as const; -type ChartTime = typeof chartTimes[number]; +type ChartTime = (typeof chartTimes)[number]; type PriceChartTimeData = { points?: [x: number, y: number][] }; const getChartTimeArg = (selected: ChartTime) => diff --git a/src/hooks/charts/useChartThrottledPoints.ts b/src/hooks/charts/useChartThrottledPoints.ts index d24ab49a76c..5a860c143f1 100644 --- a/src/hooks/charts/useChartThrottledPoints.ts +++ b/src/hooks/charts/useChartThrottledPoints.ts @@ -174,8 +174,9 @@ export default function useChartThrottledPoints({ smoothingStrategy: 'bezier', }); - const debouncedSetThrottledData = useRef(debounce(setThrottledData, 30)) - .current; + const debouncedSetThrottledData = useRef( + debounce(setThrottledData, 30) + ).current; useEffect(() => { if (throttledPoints.points && !fetchingCharts) { diff --git a/src/hooks/useAccountENSDomains.ts b/src/hooks/useAccountENSDomains.ts index 097a53a5562..18d628aa6ec 100644 --- a/src/hooks/useAccountENSDomains.ts +++ b/src/hooks/useAccountENSDomains.ts @@ -70,9 +70,12 @@ export async function prefetchAccountENSDomains({ export default function useAccountENSDomains() { const { accountAddress, accountENS } = useAccountProfile(); - const { data: domains, isLoading, isFetched, isSuccess } = useQuery< - BaseEnsDomainFragment[] - >( + const { + data: domains, + isLoading, + isFetched, + isSuccess, + } = useQuery( queryKey({ accountAddress }), async () => fetchENSDomainsWithCache({ accountAddress }), { @@ -80,28 +83,28 @@ export default function useAccountENSDomains() { } ); - const { - controlledDomains, - primaryDomain, - nonPrimaryDomains, - } = useMemo(() => { - const controlledDomains = domains?.filter( - ({ owner }) => owner?.id?.toLowerCase() === accountAddress?.toLowerCase() - ); - return { - controlledDomains, - nonPrimaryDomains: - controlledDomains?.filter(({ name }) => accountENS !== name) || [], - primaryDomain: controlledDomains?.find(({ name }) => accountENS === name), - }; - }, [accountAddress, accountENS, domains]); + const { controlledDomains, primaryDomain, nonPrimaryDomains } = + useMemo(() => { + const controlledDomains = domains?.filter( + ({ owner }) => + owner?.id?.toLowerCase() === accountAddress?.toLowerCase() + ); + return { + controlledDomains, + nonPrimaryDomains: + controlledDomains?.filter(({ name }) => accountENS !== name) || [], + primaryDomain: controlledDomains?.find( + ({ name }) => accountENS === name + ), + }; + }, [accountAddress, accountENS, domains]); const uniqueDomain = useMemo(() => { return primaryDomain ? primaryDomain : nonPrimaryDomains?.length === 1 - ? nonPrimaryDomains?.[0] - : null; + ? nonPrimaryDomains?.[0] + : null; }, [nonPrimaryDomains, primaryDomain]); return { diff --git a/src/hooks/useAccountTransactions.ts b/src/hooks/useAccountTransactions.ts index 2405565cbf9..3556086ac08 100644 --- a/src/hooks/useAccountTransactions.ts +++ b/src/hooks/useAccountTransactions.ts @@ -31,9 +31,8 @@ export default function useAccountTransactions() { connectedToHardhat, }); - const { - pendingTransactions: storePendingTransactions, - } = usePendingTransactionsStore(); + const { pendingTransactions: storePendingTransactions } = + usePendingTransactionsStore(); const pendingTransactions = useMemo(() => { const txs = storePendingTransactions[accountAddress] || []; diff --git a/src/hooks/useAnimatedPageScrollHandler.ts b/src/hooks/useAnimatedPageScrollHandler.ts index 7441ab63841..b7a2478f2fa 100644 --- a/src/hooks/useAnimatedPageScrollHandler.ts +++ b/src/hooks/useAnimatedPageScrollHandler.ts @@ -6,8 +6,8 @@ import { NativeScrollEvent, Platform } from 'react-native'; // ts wants to lint reanimated codebase but it doesn't quite work // so let's just assume it's any for now /* eslint-disable import/no-commonjs */ -const WorkletEventHandlerClass = require('react-native-reanimated/src/reanimated2/WorkletEventHandler') - .default; +const WorkletEventHandlerClass = + require('react-native-reanimated/src/reanimated2/WorkletEventHandler').default; const { makeRemote } = require('react-native-reanimated/src/reanimated2/core'); /* eslint-enable import/no-commonjs */ diff --git a/src/hooks/useCoinListEditOptions.ts b/src/hooks/useCoinListEditOptions.ts index ec3cf1c9c3d..8e855880fba 100644 --- a/src/hooks/useCoinListEditOptions.ts +++ b/src/hooks/useCoinListEditOptions.ts @@ -52,9 +52,10 @@ export default function useCoinListEditOptions() { [setSelectedItems] ); - const clearSelectedCoins = useCallback(() => setSelectedItems([]), [ - setSelectedItems, - ]); + const clearSelectedCoins = useCallback( + () => setSelectedItems([]), + [setSelectedItems] + ); return { clearSelectedCoins, diff --git a/src/hooks/useCoinListEdited.ts b/src/hooks/useCoinListEdited.ts index 3bd3ac1a654..6878f568345 100644 --- a/src/hooks/useCoinListEdited.ts +++ b/src/hooks/useCoinListEdited.ts @@ -6,9 +6,8 @@ const isCoinListEditedAtom = atom({ }); export default function useCoinListEdited() { - const [isCoinListEdited, setIsCoinListEdited] = useRecoilState( - isCoinListEditedAtom - ); + const [isCoinListEdited, setIsCoinListEdited] = + useRecoilState(isCoinListEditedAtom); return { isCoinListEdited, diff --git a/src/hooks/useDeleteWallet.ts b/src/hooks/useDeleteWallet.ts index 9e10c801233..1b2191eb6d9 100644 --- a/src/hooks/useDeleteWallet.ts +++ b/src/hooks/useDeleteWallet.ts @@ -16,12 +16,11 @@ export default function useDeleteWallet({ const [watchingWalletId] = useMemo(() => { return ( - Object.entries( - wallets || {} - ).find(([_, wallet]: [string, RainbowWallet]) => - wallet.addresses.some( - ({ address }: RainbowAccount) => address === primaryAddress - ) + Object.entries(wallets || {}).find( + ([_, wallet]: [string, RainbowWallet]) => + wallet.addresses.some( + ({ address }: RainbowAccount) => address === primaryAddress + ) ) || ['', ''] ); }, [primaryAddress, wallets]); @@ -31,12 +30,11 @@ export default function useDeleteWallet({ ...wallets, [watchingWalletId]: { ...wallets![watchingWalletId], - addresses: wallets![ - watchingWalletId - ].addresses.map((account: { address: string }) => - account.address.toLowerCase() === primaryAddress?.toLowerCase() - ? { ...(account as RainbowAccount), visible: false } - : (account as RainbowAccount) + addresses: wallets![watchingWalletId].addresses.map( + (account: { address: string }) => + account.address.toLowerCase() === primaryAddress?.toLowerCase() + ? { ...(account as RainbowAccount), visible: false } + : (account as RainbowAccount) ), }, }; diff --git a/src/hooks/useENSModifiedRegistration.ts b/src/hooks/useENSModifiedRegistration.ts index 31d3d0fd45c..bd6a61a9080 100644 --- a/src/hooks/useENSModifiedRegistration.ts +++ b/src/hooks/useENSModifiedRegistration.ts @@ -153,9 +153,9 @@ export default function useENSModifiedRegistration({ {} ); - const recordKeysWithValue = (Object.keys( - records - ) as (keyof Records)[]).filter((key: keyof Records) => { + const recordKeysWithValue = ( + Object.keys(records) as (keyof Records)[] + ).filter((key: keyof Records) => { return Boolean(records[key]); }); diff --git a/src/hooks/useENSRegistrationActionHandler.ts b/src/hooks/useENSRegistrationActionHandler.ts index a358b9a1686..7261de3ffb7 100644 --- a/src/hooks/useENSRegistrationActionHandler.ts +++ b/src/hooks/useENSRegistrationActionHandler.ts @@ -178,10 +178,8 @@ export default function useENSRegistrationActionHandler( const registerAction = useCallback( async (callback: () => void = NOOP) => { - const { - name, - duration, - } = registrationParameters as RegistrationParameters; + const { name, duration } = + registrationParameters as RegistrationParameters; const provider = await getProviderForNetwork(); const wallet = await loadWallet(undefined, false, provider); diff --git a/src/hooks/useENSRegistrationCosts.ts b/src/hooks/useENSRegistrationCosts.ts index 0590ff1f7c0..4042eb91e96 100644 --- a/src/hooks/useENSRegistrationCosts.ts +++ b/src/hooks/useENSRegistrationCosts.ts @@ -124,8 +124,8 @@ export default function useENSRegistrationCosts({ }, [accountAddress, duration, name, rentPriceInWei]); const getRegisterRapGasLimit = useCallback(async () => { - const newRegisterRapGasLimit = await estimateENSRegisterSetRecordsAndNameGasLimit( - { + const newRegisterRapGasLimit = + await estimateENSRegisterSetRecordsAndNameGasLimit({ duration, name, ownerAddress: accountAddress, @@ -133,8 +133,7 @@ export default function useENSRegistrationCosts({ rentPrice: registrationParameters?.rentPrice, salt: registrationParameters?.salt, setReverseRecord: sendReverseRecord, - } - ); + }); return newRegisterRapGasLimit || ''; }, [ accountAddress, diff --git a/src/hooks/useENSRegistrationForm.ts b/src/hooks/useENSRegistrationForm.ts index 4b38a93cd28..bc889067af2 100644 --- a/src/hooks/useENSRegistrationForm.ts +++ b/src/hooks/useENSRegistrationForm.ts @@ -120,9 +120,8 @@ export default function useENSRegistrationForm({ setDisabled(mode === REGISTRATION_MODES.EDIT && isEmpty(changedRecords)); }, [changedRecords, mode, setDisabled]); - const [selectedFields, setSelectedFields] = useRecoilState( - selectedFieldsAtom - ); + const [selectedFields, setSelectedFields] = + useRecoilState(selectedFieldsAtom); useEffect(() => { if (!initializeForm) return; // If there are existing records in the global state, then we diff --git a/src/hooks/useENSRegistrationStepHandler.tsx b/src/hooks/useENSRegistrationStepHandler.tsx index cefe8c228b6..7cc331b48c3 100644 --- a/src/hooks/useENSRegistrationStepHandler.tsx +++ b/src/hooks/useENSRegistrationStepHandler.tsx @@ -63,17 +63,15 @@ export default function useENSRegistrationStepHandler(observer = true) { const timeout = useRef(); - const [ - secondsSinceCommitConfirmed, - setSecondsSinceCommitConfirmed, - ] = useState( - (registrationParameters?.commitTransactionConfirmedAt && - differenceInSeconds( - Date.now(), - registrationParameters?.commitTransactionConfirmedAt - )) || - -1 - ); + const [secondsSinceCommitConfirmed, setSecondsSinceCommitConfirmed] = + useState( + (registrationParameters?.commitTransactionConfirmedAt && + differenceInSeconds( + Date.now(), + registrationParameters?.commitTransactionConfirmedAt + )) || + -1 + ); const isTestingHardhat = useMemo( () => isHardHat(web3Provider.connection.url), diff --git a/src/hooks/useExpandedStateNavigation.ts b/src/hooks/useExpandedStateNavigation.ts index b70260d51bc..322ce42eeff 100644 --- a/src/hooks/useExpandedStateNavigation.ts +++ b/src/hooks/useExpandedStateNavigation.ts @@ -9,7 +9,7 @@ import { useNavigation } from '@/navigation'; import { watchingAlert } from '@/utils'; export default function useExpandedStateNavigation( - inputType: typeof AssetInputTypes[keyof typeof AssetInputTypes], + inputType: (typeof AssetInputTypes)[keyof typeof AssetInputTypes], fromDiscover = false ) { const { goBack, navigate } = useNavigation(); diff --git a/src/hooks/useInteraction.ts b/src/hooks/useInteraction.ts index b6a835efac3..e1d131053fd 100644 --- a/src/hooks/useInteraction.ts +++ b/src/hooks/useInteraction.ts @@ -8,7 +8,7 @@ type HandleType = Handle | null; export default function useInteraction(): [ CreateHandleType, RemoveHandleType, - MutableRefObject + MutableRefObject, ] { const interactionHandle = useRef(null); diff --git a/src/hooks/useInterval.ts b/src/hooks/useInterval.ts index 2f14b99bcb4..8ab9bc38f40 100644 --- a/src/hooks/useInterval.ts +++ b/src/hooks/useInterval.ts @@ -3,7 +3,7 @@ import { MutableRefObject, useCallback, useEffect, useRef } from 'react'; export default function useInterval(): [ (func: () => void, ms?: number) => void, () => void, - MutableRefObject + MutableRefObject, ] { const handle = useRef(null); diff --git a/src/hooks/useInvalidPaste.ts b/src/hooks/useInvalidPaste.ts index e80dc528415..eb6055bdda2 100644 --- a/src/hooks/useInvalidPaste.ts +++ b/src/hooks/useInvalidPaste.ts @@ -21,9 +21,10 @@ export default function useInvalidPaste() { }, [isInvalidPaste, setGlobalState, startTimeout, stopTimeout]); // 🚪️ Reset isInvalidPaste when we leave the screen - useEffect(() => () => setGlobalState({ isInvalidPaste: false }), [ - setGlobalState, - ]); + useEffect( + () => () => setGlobalState({ isInvalidPaste: false }), + [setGlobalState] + ); return { isInvalidPaste, diff --git a/src/hooks/useLatestCallback.ts b/src/hooks/useLatestCallback.ts index 1a15d7f3678..6852fa57b71 100644 --- a/src/hooks/useLatestCallback.ts +++ b/src/hooks/useLatestCallback.ts @@ -10,12 +10,12 @@ const useIsomorphicLayoutEffect = export default function useLatestCallback(callback: T): T { const ref = React.useRef(callback); - const latestCallback = React.useRef((function latestCallback( + const latestCallback = React.useRef(function latestCallback( this: unknown, ...args: unknown[] ) { return ref.current.apply(this, args); - } as unknown) as T).current; + } as unknown as T).current; useIsomorphicLayoutEffect(() => { ref.current = callback; diff --git a/src/hooks/useOnAvatarPress.ts b/src/hooks/useOnAvatarPress.ts index f4f05fedf11..0c2513f6826 100644 --- a/src/hooks/useOnAvatarPress.ts +++ b/src/hooks/useOnAvatarPress.ts @@ -77,12 +77,11 @@ export default ({ screenType = 'transaction' }: UseOnAvatarPressProps = {}) => { ...wallets, [selectedWallet.id]: { ...wallets![selectedWallet.id], - addresses: wallets![ - selectedWallet.id - ].addresses.map((account: RainbowAccount) => - account.address.toLowerCase() === accountAddress?.toLowerCase() - ? { ...account, image: null } - : account + addresses: wallets![selectedWallet.id].addresses.map( + (account: RainbowAccount) => + account.address.toLowerCase() === accountAddress?.toLowerCase() + ? { ...account, image: null } + : account ), }, }; @@ -101,12 +100,11 @@ export default ({ screenType = 'transaction' }: UseOnAvatarPressProps = {}) => { ...wallets, [selectedWallet.id]: { ...wallets![selectedWallet.id], - addresses: wallets![ - selectedWallet.id - ].addresses.map((account: RainbowAccount) => - account.address.toLowerCase() === accountAddress?.toLowerCase() - ? { ...account, image: imagePath } - : account + addresses: wallets![selectedWallet.id].addresses.map( + (account: RainbowAccount) => + account.address.toLowerCase() === accountAddress?.toLowerCase() + ? { ...account, image: imagePath } + : account ), }, }; diff --git a/src/hooks/useParamsForExchangeModal.ts b/src/hooks/useParamsForExchangeModal.ts index 46bd4e356db..70b7d0e6781 100644 --- a/src/hooks/useParamsForExchangeModal.ts +++ b/src/hooks/useParamsForExchangeModal.ts @@ -32,11 +32,8 @@ export default function ({ }>(); const dispatch = useDispatch(); - const { - updateInputAmount, - updateNativeAmount, - updateOutputAmount, - } = useSwapInputHandlers(); + const { updateInputAmount, updateNativeAmount, updateOutputAmount } = + useSwapInputHandlers(); const [isFillingParams, setIsFillingParams] = useState(false); diff --git a/src/hooks/usePortfolios.ts b/src/hooks/usePortfolios.ts index 7b49c0c70b9..f87922ce0fa 100644 --- a/src/hooks/usePortfolios.ts +++ b/src/hooks/usePortfolios.ts @@ -30,9 +30,10 @@ export default function usePortfolios() { keys(portfolios).forEach(address => { keys(portfolios[address]).forEach(key => { if (!isNil(total[key as keyof typeof total])) { - total[key as keyof typeof total] += portfolios[address][ - key as keyof typeof portfolios[typeof address] - ]!; + total[key as keyof typeof total] += + portfolios[address][ + key as keyof (typeof portfolios)[typeof address] + ]!; } }); }); diff --git a/src/hooks/usePriceImpactDetails.ts b/src/hooks/usePriceImpactDetails.ts index 7443dc7c85d..e547c5c6367 100644 --- a/src/hooks/usePriceImpactDetails.ts +++ b/src/hooks/usePriceImpactDetails.ts @@ -125,9 +125,8 @@ export default function usePriceImpactDetails( const { impactDisplay, priceImpact, percentDisplay } = useMemo(() => { const nativeAmountImpact = subtract(inputNativeAmount, outputNativeAmount); const priceImpact = divide(nativeAmountImpact, inputNativeAmount); - const percentDisplay = convertAmountToPercentageDisplayWithThreshold( - priceImpact - ); + const percentDisplay = + convertAmountToPercentageDisplayWithThreshold(priceImpact); const impactDisplay = convertAmountToNativeDisplay( nativeAmountImpact, nativeCurrency diff --git a/src/hooks/useRouteExistsInNavigationState.ts b/src/hooks/useRouteExistsInNavigationState.ts index 5e7ada4f808..4a1a43f4531 100644 --- a/src/hooks/useRouteExistsInNavigationState.ts +++ b/src/hooks/useRouteExistsInNavigationState.ts @@ -3,8 +3,8 @@ import { useMemo } from 'react'; export default function useRouteExistsInNavigationState(routeName: string) { const routes = useNavigationState(state => state.routes); - return useMemo(() => routes.find(route => route.name === routeName), [ - routeName, - routes, - ]); + return useMemo( + () => routes.find(route => route.name === routeName), + [routeName, routes] + ); } diff --git a/src/hooks/useSearchCurrencyList.ts b/src/hooks/useSearchCurrencyList.ts index db0b178f1b1..fdf07fb2ddf 100644 --- a/src/hooks/useSearchCurrencyList.ts +++ b/src/hooks/useSearchCurrencyList.ts @@ -103,10 +103,8 @@ const useSearchCurrencyList = ( [searchChainId, searchQuery] ); - const { - favorites: favoriteAddresses, - favoritesMetadata: favoriteMap, - } = useFavorites(); + const { favorites: favoriteAddresses, favoritesMetadata: favoriteMap } = + useFavorites(); const curatedMap = rainbowTokenList.CURATED_TOKENS; const unfilteredFavorites = Object.values(favoriteMap); @@ -117,19 +115,16 @@ const useSearchCurrencyList = ( const [highLiquidityAssets, setHighLiquidityAssets] = useState([]); const [lowLiquidityAssets, setLowLiquidityAssets] = useState([]); const [verifiedAssets, setVerifiedAssets] = useState([]); - const [fetchingCrosschainAssets, setFetchingCrosschainAssets] = useState( - false - ); - const [ - crosschainVerifiedAssets, - setCrosschainVerifiedAssets, - ] = useState({ - [Network.mainnet]: [], - [Network.optimism]: [], - [Network.polygon]: [], - [Network.bsc]: [], - [Network.arbitrum]: [], - }); + const [fetchingCrosschainAssets, setFetchingCrosschainAssets] = + useState(false); + const [crosschainVerifiedAssets, setCrosschainVerifiedAssets] = + useState({ + [Network.mainnet]: [], + [Network.optimism]: [], + [Network.polygon]: [], + [Network.bsc]: [], + [Network.arbitrum]: [], + }); const crosschainSwapsEnabled = useExperimentalFlag(CROSSCHAIN_SWAPS); diff --git a/src/hooks/useSendSheetInputRefs.ts b/src/hooks/useSendSheetInputRefs.ts index b14179c5293..a45fa37c5a9 100644 --- a/src/hooks/useSendSheetInputRefs.ts +++ b/src/hooks/useSendSheetInputRefs.ts @@ -6,11 +6,8 @@ export default function useSendSheetInputRefs() { const assetInputRef = useRef(); const nativeCurrencyInputRef = useRef(); - const { - handleFocus, - lastFocusedInputHandle, - setLastFocusedInputHandle, - } = useMagicAutofocus(nativeCurrencyInputRef, null, true); + const { handleFocus, lastFocusedInputHandle, setLastFocusedInputHandle } = + useMagicAutofocus(nativeCurrencyInputRef, null, true); return { assetInputRef, diff --git a/src/hooks/useSwapCurrencyHandlers.ts b/src/hooks/useSwapCurrencyHandlers.ts index bb0f7f42b63..500425fe13f 100644 --- a/src/hooks/useSwapCurrencyHandlers.ts +++ b/src/hooks/useSwapCurrencyHandlers.ts @@ -44,11 +44,8 @@ export default function useSwapCurrencyHandlers({ const { derivedValues } = useSwapDerivedValues(); - const { - updateInputAmount, - updateNativeAmount, - updateOutputAmount, - } = useSwapInputHandlers(); + const { updateInputAmount, updateNativeAmount, updateOutputAmount } = + useSwapInputHandlers(); const { defaultInputItemInWallet, defaultOutputItem } = useMemo(() => { if (type === ExchangeModalTypes.swap) { diff --git a/src/hooks/useSwapCurrencyList.ts b/src/hooks/useSwapCurrencyList.ts index 3ac4e67ff5e..7f70d6af687 100644 --- a/src/hooks/useSwapCurrencyList.ts +++ b/src/hooks/useSwapCurrencyList.ts @@ -101,10 +101,8 @@ const useSwapCurrencyList = ( [searchChainId, searchQuery] ); - const { - favorites: favoriteAddresses, - favoritesMetadata: favoriteMap, - } = useFavorites(); + const { favorites: favoriteAddresses, favoritesMetadata: favoriteMap } = + useFavorites(); const curatedMap = rainbowTokenList.CURATED_TOKENS; const unfilteredFavorites = Object.values(favoriteMap); @@ -115,19 +113,16 @@ const useSwapCurrencyList = ( const [highLiquidityAssets, setHighLiquidityAssets] = useState([]); const [lowLiquidityAssets, setLowLiquidityAssets] = useState([]); const [verifiedAssets, setVerifiedAssets] = useState([]); - const [fetchingCrosschainAssets, setFetchingCrosschainAssets] = useState( - false - ); - const [ - crosschainVerifiedAssets, - setCrosschainVerifiedAssets, - ] = useState({ - [Network.mainnet]: [], - [Network.optimism]: [], - [Network.polygon]: [], - [Network.bsc]: [], - [Network.arbitrum]: [], - }); + const [fetchingCrosschainAssets, setFetchingCrosschainAssets] = + useState(false); + const [crosschainVerifiedAssets, setCrosschainVerifiedAssets] = + useState({ + [Network.mainnet]: [], + [Network.optimism]: [], + [Network.polygon]: [], + [Network.bsc]: [], + [Network.arbitrum]: [], + }); const crosschainSwapsEnabled = useExperimentalFlag(CROSSCHAIN_SWAPS); const { inputCurrency } = useSwapCurrencies(); diff --git a/src/hooks/useSwapDerivedOutputs.ts b/src/hooks/useSwapDerivedOutputs.ts index 2124676a61d..93d7c08faa8 100644 --- a/src/hooks/useSwapDerivedOutputs.ts +++ b/src/hooks/useSwapDerivedOutputs.ts @@ -131,7 +131,7 @@ const getInputAmount = async ( // if no quote, if quote is error or there's no sell amount if (!quote || (quote as QuoteError).error || !(quote as Quote).sellAmount) { if ((quote as QuoteError).error) { - const quoteError = (quote as unknown) as QuoteError; + const quoteError = quote as unknown as QuoteError; logger.error(new RainbowError('[getInputAmount]: Quote error'), { code: quoteError.error_code, msg: quoteError.message, @@ -238,13 +238,9 @@ const getOutputAmount = async ( logger.debug('[getOutputAmount]: Getting quote', { rand, quoteParams }); // Do not deleeeet the comment below 😤 // @ts-ignore About to get quote - const quote: - | Quote - | CrosschainQuote - | QuoteError - | null = await (isCrosschainSwap ? getCrosschainQuote : getQuote)( - quoteParams - ); + const quote: Quote | CrosschainQuote | QuoteError | null = await ( + isCrosschainSwap ? getCrosschainQuote : getQuote + )(quoteParams); logger.debug('[getOutputAmount]: Got quote', { rand, quote }); if ( diff --git a/src/hooks/useSwapInputRefs.ts b/src/hooks/useSwapInputRefs.ts index 67b43f63832..c9eb3f5a107 100644 --- a/src/hooks/useSwapInputRefs.ts +++ b/src/hooks/useSwapInputRefs.ts @@ -35,11 +35,8 @@ export default function useSwapInputRefs() { [inputCurrency, outputCurrency] ); - const { - handleFocus, - lastFocusedInputHandle, - setLastFocusedInputHandle, - } = useMagicAutofocus(inputFieldRef, findNextInput, true); + const { handleFocus, lastFocusedInputHandle, setLastFocusedInputHandle } = + useMagicAutofocus(inputFieldRef, findNextInput, true); return { handleFocus, diff --git a/src/hooks/useSwapRefuel.ts b/src/hooks/useSwapRefuel.ts index 29a0035811b..0a51792bec9 100644 --- a/src/hooks/useSwapRefuel.ts +++ b/src/hooks/useSwapRefuel.ts @@ -36,38 +36,29 @@ export default function useSwapRefuel({ const { accountAddress } = useAccountSettings(); const { selectedGasFee } = useGas(); - const [ - outputNativeAsset, - setOutputNativeAsset, - ] = useState(); - const [ - inputNativeAsset, - setInputNativeAsset, - ] = useState(); + const [outputNativeAsset, setOutputNativeAsset] = + useState(); + const [inputNativeAsset, setInputNativeAsset] = + useState(); - const { - inputNetwork, - outputNetwork, - chainId, - toChainId, - isCrosschainSwap, - } = useMemo(() => { - const inputNetwork = inputCurrency.network; - const outputNetwork = outputCurrency.network; - const chainId = ethereumUtils.getChainIdFromNetwork(inputNetwork); + const { inputNetwork, outputNetwork, chainId, toChainId, isCrosschainSwap } = + useMemo(() => { + const inputNetwork = inputCurrency.network; + const outputNetwork = outputCurrency.network; + const chainId = ethereumUtils.getChainIdFromNetwork(inputNetwork); - const toChainId = ethereumUtils.getChainIdFromNetwork(outputNetwork); - const isCrosschainSwap = - crosschainSwapsEnabled && inputNetwork !== outputNetwork; + const toChainId = ethereumUtils.getChainIdFromNetwork(outputNetwork); + const isCrosschainSwap = + crosschainSwapsEnabled && inputNetwork !== outputNetwork; - return { - inputNetwork, - outputNetwork, - chainId, - toChainId, - isCrosschainSwap, - }; - }, [crosschainSwapsEnabled, inputCurrency.network, outputCurrency.network]); + return { + inputNetwork, + outputNetwork, + chainId, + toChainId, + isCrosschainSwap, + }; + }, [crosschainSwapsEnabled, inputCurrency.network, outputCurrency.network]); const { data: minRefuelAmount } = useMinRefuelAmount( { diff --git a/src/hooks/useSwappableUserAssets.ts b/src/hooks/useSwappableUserAssets.ts index f642f4c8665..bee2d2b4e10 100644 --- a/src/hooks/useSwappableUserAssets.ts +++ b/src/hooks/useSwappableUserAssets.ts @@ -105,9 +105,8 @@ export const useSwappableUserAssets = (params: { ? ETH_ADDRESS_AGGREGATORS : asset?.address; - const isSwappable = swappableAssetsRef.current[assetNetwork]?.includes( - assetAddress - ); + const isSwappable = + swappableAssetsRef.current[assetNetwork]?.includes(assetAddress); return isSwappable; }), [filteredAssetsInWallet] @@ -123,9 +122,8 @@ export const useSwappableUserAssets = (params: { : asset?.address; // we place our testnets (goerli) in the Network type which creates this type issue // @ts-ignore - const isNotSwappable = !swappableAssetsRef.current[ - assetNetwork - ]?.includes(assetAddress); + const isNotSwappable = + !swappableAssetsRef.current[assetNetwork]?.includes(assetAddress); return isNotSwappable; }), [filteredAssetsInWallet] diff --git a/src/hooks/useTimeout.ts b/src/hooks/useTimeout.ts index ab945cd5b30..e856b1bf31a 100644 --- a/src/hooks/useTimeout.ts +++ b/src/hooks/useTimeout.ts @@ -3,7 +3,7 @@ import { MutableRefObject, useCallback, useEffect, useRef } from 'react'; export default function useTimeout(): [ (func: () => void, ms?: number) => void, () => void, - MutableRefObject + MutableRefObject, ] { const handle = useRef(null); diff --git a/src/hooks/useWalletSectionsData.ts b/src/hooks/useWalletSectionsData.ts index c538fb8cc10..6011e7ae1fe 100644 --- a/src/hooks/useWalletSectionsData.ts +++ b/src/hooks/useWalletSectionsData.ts @@ -17,18 +17,12 @@ export default function useWalletSectionsData({ }: { type?: string; } = {}) { - const { - isLoading: isLoadingUserAssets, - data: sortedAssets = [], - } = useSortedUserAssets(); + const { isLoading: isLoadingUserAssets, data: sortedAssets = [] } = + useSortedUserAssets(); const isWalletEthZero = useIsWalletEthZero(); - const { - accountAddress, - language, - network, - nativeCurrency, - } = useAccountSettings(); + const { accountAddress, language, network, nativeCurrency } = + useAccountSettings(); const { sendableUniqueTokens } = useSendableUniqueTokens(); const { data: { nfts: allUniqueTokens }, @@ -39,10 +33,8 @@ export default function useWalletSectionsData({ const { hiddenTokens } = useHiddenTokens(); const { isReadOnlyWallet } = useWallets(); - const { - hiddenCoinsObj: hiddenCoins, - pinnedCoinsObj: pinnedCoins, - } = useCoinListEditOptions(); + const { hiddenCoinsObj: hiddenCoins, pinnedCoinsObj: pinnedCoins } = + useCoinListEditOptions(); const { isCoinListEdited } = useCoinListEdited(); diff --git a/src/hooks/useWatchPendingTxs.ts b/src/hooks/useWatchPendingTxs.ts index 32b0fbcc2ff..c91c067791e 100644 --- a/src/hooks/useWatchPendingTxs.ts +++ b/src/hooks/useWatchPendingTxs.ts @@ -95,14 +95,12 @@ export const useWatchPendingTransactions = ({ let updatedTransaction: RainbowTransaction = { ...tx }; try { if (tx.network && tx.hash && address) { - updatedTransaction = await processSupportedNetworkTransaction( - updatedTransaction - ); + updatedTransaction = + await processSupportedNetworkTransaction(updatedTransaction); // if flashbots tx and no blockNumber, check if it failed if (!(tx as any).blockNumber && tx.flashbots) { - updatedTransaction = await processFlashbotsTransaction( - updatedTransaction - ); + updatedTransaction = + await processFlashbotsTransaction(updatedTransaction); } } else { throw new Error('Pending transaction missing chain id'); @@ -211,23 +209,21 @@ export const useWatchPendingTransactions = ({ processNonces(updatedPendingTransactions); - const { - newPendingTransactions, - minedTransactions, - } = updatedPendingTransactions.reduce( - (acc, tx) => { - if (tx?.status === 'pending') { - acc.newPendingTransactions.push(tx); - } else { - acc.minedTransactions.push(tx as MinedTransaction); + const { newPendingTransactions, minedTransactions } = + updatedPendingTransactions.reduce( + (acc, tx) => { + if (tx?.status === 'pending') { + acc.newPendingTransactions.push(tx); + } else { + acc.minedTransactions.push(tx as MinedTransaction); + } + return acc; + }, + { + newPendingTransactions: [] as RainbowTransaction[], + minedTransactions: [] as MinedTransaction[], } - return acc; - }, - { - newPendingTransactions: [] as RainbowTransaction[], - minedTransactions: [] as MinedTransaction[], - } - ); + ); if (minedTransactions.length) { console.log('we mined a transaction'); diff --git a/src/hooks/useWatchWallet.ts b/src/hooks/useWatchWallet.ts index 63eb03348da..d156fc63698 100644 --- a/src/hooks/useWatchWallet.ts +++ b/src/hooks/useWatchWallet.ts @@ -57,13 +57,10 @@ export default function useWatchWallet({ ); const { accountAddress } = useAccountProfile(); - const { - isImporting, - handleSetSeedPhrase, - handlePressImportButton, - } = useImportingWallet({ - showImportModal, - }); + const { isImporting, handleSetSeedPhrase, handlePressImportButton } = + useImportingWallet({ + showImportModal, + }); const watchWallet = useCallback(async () => { if (!isWatching) { handleSetSeedPhrase(ensName ?? ''); diff --git a/src/keychain/index.ts b/src/keychain/index.ts index 240b5a1fce4..799ac3306ab 100644 --- a/src/keychain/index.ts +++ b/src/keychain/index.ts @@ -274,7 +274,7 @@ export async function set( * JSON. */ export async function getObject< - T extends Record = Record + T extends Record = Record, >(key: string, options: KeychainOptions = {}): Promise> { logger.debug(`keychain: getObject`, { key }, logger.DebugContext.keychain); diff --git a/src/model/backup.ts b/src/model/backup.ts index 8a8b66127b9..92eb0d2b4df 100644 --- a/src/model/backup.ts +++ b/src/model/backup.ts @@ -233,7 +233,8 @@ export const RestoreCloudBackupResultStates = { incorrectPinCode: 'incorrectPinCode', } as const; -type RestoreCloudBackupResultStatesType = typeof RestoreCloudBackupResultStates[keyof typeof RestoreCloudBackupResultStates]; +type RestoreCloudBackupResultStatesType = + (typeof RestoreCloudBackupResultStates)[keyof typeof RestoreCloudBackupResultStates]; /** * Restores a cloud backup. @@ -368,7 +369,8 @@ async function restoreCurrentBackupIntoKeychain( ): Promise { try { // Access control config per each type of key - const privateAccessControlOptions = await keychain.getPrivateAccessControlOptions(); + const privateAccessControlOptions = + await keychain.getPrivateAccessControlOptions(); const encryptedBackupPinData = backedUpData[pinKey]; const backupPIN = await decryptPIN(encryptedBackupPinData); diff --git a/src/model/migrations.ts b/src/model/migrations.ts index 019c412af77..fbbb22cfc4d 100644 --- a/src/model/migrations.ts +++ b/src/model/migrations.ts @@ -387,9 +387,9 @@ export default async function runMigrations() { color: isNumber(contact.color) ? newColorIndexes[contact.color] : typeof contact.color === 'string' && - colors.avatarBackgrounds.includes(contact.color) - ? colors.avatarBackgrounds.indexOf(contact.color) - : getRandomColor(), + colors.avatarBackgrounds.includes(contact.color) + ? colors.avatarBackgrounds.indexOf(contact.color) + : getRandomColor(), }; } logger.log('update contacts to index new colors'); @@ -688,10 +688,8 @@ export default async function runMigrations() { ); if (favoritesMetadata) { - const lowercasedFavoritesMetadata: Record< - EthereumAddress, - RainbowToken - > = {}; + const lowercasedFavoritesMetadata: Record = + {}; Object.keys(favoritesMetadata).forEach((address: string) => { lowercasedFavoritesMetadata[address.toLowerCase()] = favoritesMetadata[address]; diff --git a/src/model/preferences.ts b/src/model/preferences.ts index 46a1437f9e1..f718fd657a1 100644 --- a/src/model/preferences.ts +++ b/src/model/preferences.ts @@ -36,9 +36,8 @@ export async function setPreference( value?: any | undefined ): Promise { try { - const signature = await getSignatureForSigningWalletAndCreateSignatureIfNeeded( - address - ); + const signature = + await getSignatureForSigningWalletAndCreateSignatureIfNeeded(address); if (!signature) { return false; } @@ -56,7 +55,8 @@ export async function setPreference( signature, signature2, }); - const responseData: PreferencesResponse = response.data as PreferencesResponse; + const responseData: PreferencesResponse = + response.data as PreferencesResponse; logger.debug('☁️ RESPONSE', { reason: responseData?.reason, success: responseData?.success, @@ -78,7 +78,8 @@ export async function getPreference( const response = await preferencesAPI.get(`${PREFS_ENDPOINT}/${key}`, { params: { address }, }); - const responseData: PreferencesResponse = response.data as PreferencesResponse; + const responseData: PreferencesResponse = + response.data as PreferencesResponse; logger.debug('☁️ RESPONSE', { reason: responseData?.reason, success: responseData?.success, diff --git a/src/model/wallet.ts b/src/model/wallet.ts index f0166e362f4..2b3c3753c7f 100644 --- a/src/model/wallet.ts +++ b/src/model/wallet.ts @@ -552,12 +552,13 @@ export const signTypedDataMessage = async ( } }; -export const oldLoadSeedPhrase = async (): Promise => { - const seedPhrase = await keychain.loadString(seedPhraseKey, { - authenticationPrompt, - }); - return seedPhrase as string | null; -}; +export const oldLoadSeedPhrase = + async (): Promise => { + const seedPhrase = await keychain.loadString(seedPhraseKey, { + authenticationPrompt, + }); + return seedPhrase as string | null; + }; export const loadAddress = (): Promise => keychain.loadString(addressKey) as Promise; @@ -1081,7 +1082,8 @@ export const savePrivateKey = async ( androidEncryptionPin, }: Pick = {} ) => { - const privateAccessControlOptions = await keychain.getPrivateAccessControlOptions(); + const privateAccessControlOptions = + await keychain.getPrivateAccessControlOptions(); const key = `${address}_${privateKeyKey}`; const val = { @@ -1178,7 +1180,8 @@ export const saveSeedPhrase = async ( androidEncryptionPin, }: Pick = {} ): Promise => { - const privateAccessControlOptions = await keychain.getPrivateAccessControlOptions(); + const privateAccessControlOptions = + await keychain.getPrivateAccessControlOptions(); const key = `${keychain_id}_${seedPhraseKey}`; const val = { id: keychain_id, @@ -1240,18 +1243,19 @@ export const setSelectedWallet = async ( ); }; -export const getSelectedWallet = async (): Promise => { - try { - const selectedWalletData = await keychain.loadObject(selectedWalletKey); - if (selectedWalletData) { - return selectedWalletData as RainbowSelectedWalletData; +export const getSelectedWallet = + async (): Promise => { + try { + const selectedWalletData = await keychain.loadObject(selectedWalletKey); + if (selectedWalletData) { + return selectedWalletData as RainbowSelectedWalletData; + } + return null; + } catch (error) { + logger.error(new RainbowError('Error in getSelectedWallet'), { error }); + return null; } - return null; - } catch (error) { - logger.error(new RainbowError('Error in getSelectedWallet'), { error }); - return null; - } -}; + }; export const saveAllWallets = async (wallets: AllRainbowWallets) => { const val = { @@ -1266,18 +1270,19 @@ export const saveAllWallets = async (wallets: AllRainbowWallets) => { ); }; -export const getAllWallets = async (): Promise => { - try { - const allWallets = await keychain.loadObject(allWalletsKey); - if (allWallets) { - return allWallets as AllRainbowWalletsData; +export const getAllWallets = + async (): Promise => { + try { + const allWallets = await keychain.loadObject(allWalletsKey); + if (allWallets) { + return allWallets as AllRainbowWalletsData; + } + return null; + } catch (error) { + logger.error(new RainbowError('Error in getAllWallets'), { error }); + return null; } - return null; - } catch (error) { - logger.error(new RainbowError('Error in getAllWallets'), { error }); - return null; - } -}; + }; let callbackAfterSeeds: null | (() => void) = null; export function setCallbackAfterObtainingSeedsFromKeychainOrError( @@ -1401,9 +1406,8 @@ const migrateSecrets = async (): Promise => { break; case EthereumWalletType.mnemonic: { - const { wallet: ethereumJSWallet } = await deriveAccountFromMnemonic( - seedphrase - ); + const { wallet: ethereumJSWallet } = + await deriveAccountFromMnemonic(seedphrase); if (!ethereumJSWallet) return null; const walletPkey = addHexPrefix( ethereumJSWallet.getPrivateKey().toString('hex') diff --git a/src/navigation/HardwareWalletTxNavigator.tsx b/src/navigation/HardwareWalletTxNavigator.tsx index 183eabb164b..98d43459fd6 100644 --- a/src/navigation/HardwareWalletTxNavigator.tsx +++ b/src/navigation/HardwareWalletTxNavigator.tsx @@ -65,9 +65,8 @@ export const HardwareWalletTxNavigator = () => { const deviceId = selectedWallet?.deviceId; const [isReady, setIsReady] = useRecoilState(LedgerIsReadyAtom); - const [readyForPolling, setReadyForPolling] = useRecoilState( - readyForPollingAtom - ); + const [readyForPolling, setReadyForPolling] = + useRecoilState(readyForPollingAtom); const [triggerPollerCleanup, setTriggerPollerCleanup] = useRecoilState( triggerPollerCleanupAtom ); diff --git a/src/navigation/PairHardwareWalletNavigator.tsx b/src/navigation/PairHardwareWalletNavigator.tsx index 87d52fbbc68..8f9191ee8c5 100644 --- a/src/navigation/PairHardwareWalletNavigator.tsx +++ b/src/navigation/PairHardwareWalletNavigator.tsx @@ -30,9 +30,8 @@ export const LedgerImportDeviceIdAtom = atom({ }); export function PairHardwareWalletNavigator() { - const { params } = useRoute< - RouteProp - >(); + const { params } = + useRoute>(); const { height, width } = useDimensions(); const [currentRouteName, setCurrentRouteName] = useState( diff --git a/src/navigation/RecyclerListViewScrollToTopContext.tsx b/src/navigation/RecyclerListViewScrollToTopContext.tsx index aeb45bc46a5..7bcc13b2df4 100644 --- a/src/navigation/RecyclerListViewScrollToTopContext.tsx +++ b/src/navigation/RecyclerListViewScrollToTopContext.tsx @@ -14,15 +14,13 @@ type ScrollToTopProviderProps = { children: React.ReactNode; }; -const RecyclerListViewScrollToTopProvider: React.FC = ({ - children, -}) => { +const RecyclerListViewScrollToTopProvider: React.FC< + ScrollToTopProviderProps +> = ({ children }) => { const insets = useSafeAreaInsets(); - const [ - scrollToTopRef, - setScrollToTopRef, - ] = useState(null); + const [scrollToTopRef, setScrollToTopRef] = + useState(null); const scrollToTop = () => { scrollToTopRef?.scrollToOffset(0, -insets.top, true); diff --git a/src/navigation/RegisterENSNavigator.tsx b/src/navigation/RegisterENSNavigator.tsx index 24c4c6f63f9..e4b96224aae 100644 --- a/src/navigation/RegisterENSNavigator.tsx +++ b/src/navigation/RegisterENSNavigator.tsx @@ -68,11 +68,8 @@ export default function RegisterENSNavigator() { const { clearValues } = useENSRegistrationForm(); - const { - removeRecordByKey, - clearCurrentRegistrationName, - startRegistration, - } = useENSRegistration(); + const { removeRecordByKey, clearCurrentRegistrationName, startRegistration } = + useENSRegistration(); const initialRouteName = useMemo(() => { const { ensName, mode } = params || { mode: REGISTRATION_MODES.CREATE }; @@ -93,9 +90,10 @@ export default function RegisterENSNavigator() { const [currentRouteName, setCurrentRouteName] = useState(initialRouteName); const previousRouteName = usePrevious(currentRouteName); - const screenOptions = useMemo(() => defaultScreenOptions[currentRouteName], [ - currentRouteName, - ]); + const screenOptions = useMemo( + () => defaultScreenOptions[currentRouteName], + [currentRouteName] + ); useEffect( () => () => { diff --git a/src/navigation/Routes.android.tsx b/src/navigation/Routes.android.tsx index 65a72f857c5..16c8ce162c8 100644 --- a/src/navigation/Routes.android.tsx +++ b/src/navigation/Routes.android.tsx @@ -93,7 +93,7 @@ const AuthStack = createStackNavigator(); const BSStack = createBottomSheetNavigator(); function MainNavigator() { - const initialRoute = (useContext(InitialRouteContext) as unknown) as string; + const initialRoute = useContext(InitialRouteContext) as unknown as string; return ( void; } -export const BottomSheetNavigatorContext = createContext( - null -); +export const BottomSheetNavigatorContext = + createContext(null); diff --git a/src/navigation/bottom-sheet/types.d.ts b/src/navigation/bottom-sheet/types.d.ts index 6e8410d7f4b..415ec86585a 100644 --- a/src/navigation/bottom-sheet/types.d.ts +++ b/src/navigation/bottom-sheet/types.d.ts @@ -41,7 +41,7 @@ export type BottomSheetNavigationHelpers = NavigationHelpers< export type BottomSheetNavigationProp< ParamList extends ParamListBase, - RouteName extends keyof ParamList = string + RouteName extends keyof ParamList = string, > = NavigationProp< ParamList, RouteName, @@ -53,7 +53,7 @@ export type BottomSheetNavigationProp< export type BottomSheetScreenProps< ParamList extends ParamListBase, - RouteName extends keyof ParamList = string + RouteName extends keyof ParamList = string, > = { navigation: BottomSheetNavigationProp; route: RouteProp; diff --git a/src/navigation/config.tsx b/src/navigation/config.tsx index 7a193411288..7e24f0e85c5 100644 --- a/src/navigation/config.tsx +++ b/src/navigation/config.tsx @@ -65,8 +65,8 @@ const buildCoolModalConfig = (params: any): CoolModalConfigOptions => ({ ? 30 : 0.666 // 0.666 gets the screen corner radius internally : params.cornerRadius === 0 - ? 0 - : params.cornerRadius || 39, + ? 0 + : params.cornerRadius || 39, customStack: true, disableShortFormAfterTransitionToLongForm: params.disableShortFormAfterTransitionToLongForm || @@ -294,17 +294,18 @@ export const qrScannerConfig: PartialNavigatorConfigOptions = { }), }; -export const pairHardwareWalletNavigatorConfig: PartialNavigatorConfigOptions = { - options: ({ route: { params = {} } }) => ({ - ...buildCoolModalConfig({ - ...params, - backgroundOpacity: 1, - scrollEnabled: true, - springDamping: 1, - transitionDuration: 0.2, +export const pairHardwareWalletNavigatorConfig: PartialNavigatorConfigOptions = + { + options: ({ route: { params = {} } }) => ({ + ...buildCoolModalConfig({ + ...params, + backgroundOpacity: 1, + scrollEnabled: true, + springDamping: 1, + transitionDuration: 0.2, + }), }), - }), -}; + }; export const hardwareWalletTxNavigatorConfig: PartialNavigatorConfigOptions = { options: ({ route: { params = {} } }) => ({ @@ -448,15 +449,16 @@ export const expandedAssetSheetConfig: PartialNavigatorConfigOptions = { }), }; -export const expandedAssetSheetConfigWithLimit: PartialNavigatorConfigOptions = { - options: ({ route: { params = {} } }) => ({ - ...buildCoolModalConfig({ - ...params, - scrollEnabled: true, +export const expandedAssetSheetConfigWithLimit: PartialNavigatorConfigOptions = + { + options: ({ route: { params = {} } }) => ({ + ...buildCoolModalConfig({ + ...params, + scrollEnabled: true, + }), + limitActiveModals: true, }), - limitActiveModals: true, - }), -}; + }; export const restoreSheetConfig: PartialNavigatorConfigOptions = { // @ts-ignore @@ -521,12 +523,13 @@ export const nativeStackDefaultConfig: CoolModalConfigOptions = { transitionDuration: 0.3, }; -export const nativeStackDefaultConfigWithoutStatusBar: CoolModalConfigOptions = { - ...nativeStackDefaultConfig, - onWillDismiss: () => { - onWillPop(); - }, -}; +export const nativeStackDefaultConfigWithoutStatusBar: CoolModalConfigOptions = + { + ...nativeStackDefaultConfig, + onWillDismiss: () => { + onWillPop(); + }, + }; export const exchangeTabNavigatorConfig = { initialLayout: deviceUtils.dimensions, diff --git a/src/navigation/effects.tsx b/src/navigation/effects.tsx index 70c4941da2d..e0178cd9d7d 100644 --- a/src/navigation/effects.tsx +++ b/src/navigation/effects.tsx @@ -130,34 +130,33 @@ const exchangeStyleInterpolator = ({ }; }; -export const expandStyleInterpolator = (targetOpacity: number) => ({ - current: { progress: current }, - layouts: { screen }, -}: any) => { - const backgroundOpacity = current.interpolate({ - inputRange: [-1, 0, 0.975, 2], - outputRange: [0, 0, targetOpacity, targetOpacity], - }); +export const expandStyleInterpolator = + (targetOpacity: number) => + ({ current: { progress: current }, layouts: { screen } }: any) => { + const backgroundOpacity = current.interpolate({ + inputRange: [-1, 0, 0.975, 2], + outputRange: [0, 0, targetOpacity, targetOpacity], + }); - const translateY = current.interpolate({ - inputRange: [0, 1, 2], - outputRange: [screen.height, 0, -screen.height / 3], - }); + const translateY = current.interpolate({ + inputRange: [0, 1, 2], + outputRange: [screen.height, 0, -screen.height / 3], + }); - return { - cardStyle: { - shadowColor: colors.themedColors?.shadow, - shadowOffset: { height: 10, width: 0 }, - shadowOpacity: 0.5, - shadowRadius: 25, - transform: [{ translateY }], - }, - overlayStyle: { - backgroundColor: lightModeThemeColors.blueGreyDarker, - opacity: backgroundOpacity, - }, + return { + cardStyle: { + shadowColor: colors.themedColors?.shadow, + shadowOffset: { height: 10, width: 0 }, + shadowOpacity: 0.5, + shadowRadius: 25, + transform: [{ translateY }], + }, + overlayStyle: { + backgroundColor: lightModeThemeColors.blueGreyDarker, + opacity: backgroundOpacity, + }, + }; }; -}; const savingsStyleInterpolator = ({ current: { progress: current }, @@ -189,35 +188,34 @@ const savingsStyleInterpolator = ({ }; }; -const sheetStyleInterpolator = (targetOpacity = 1) => ({ - current: { progress: current }, - layouts: { screen }, -}: any) => { - const backgroundOpacity = current.interpolate({ - inputRange: [-1, 0, 0.975, 2], - outputRange: [0, 0, targetOpacity, targetOpacity], - }); +const sheetStyleInterpolator = + (targetOpacity = 1) => + ({ current: { progress: current }, layouts: { screen } }: any) => { + const backgroundOpacity = current.interpolate({ + inputRange: [-1, 0, 0.975, 2], + outputRange: [0, 0, targetOpacity, targetOpacity], + }); - const translateY = current.interpolate({ - extrapolate: 'clamp', - inputRange: [0, 1], - outputRange: [screen.height, 0], - }); + const translateY = current.interpolate({ + extrapolate: 'clamp', + inputRange: [0, 1], + outputRange: [screen.height, 0], + }); - return { - cardStyle: { - shadowColor: colors.themedColors?.shadowBlack, - shadowOffset: { height: 10, width: 0 }, - shadowOpacity: 0.6, - shadowRadius: 25, - transform: [{ translateY }], - }, - overlayStyle: { - backgroundColor: lightModeThemeColors.shadowBlack, - opacity: backgroundOpacity, - }, + return { + cardStyle: { + shadowColor: colors.themedColors?.shadowBlack, + shadowOffset: { height: 10, width: 0 }, + shadowOpacity: 0.6, + shadowRadius: 25, + transform: [{ translateY }], + }, + overlayStyle: { + backgroundColor: lightModeThemeColors.shadowBlack, + opacity: backgroundOpacity, + }, + }; }; -}; const swapDetailInterpolator = ({ current: { progress: current }, diff --git a/src/navigation/onNavigationStateChange.js b/src/navigation/onNavigationStateChange.js index 8c11e49e73a..51507d8eb04 100644 --- a/src/navigation/onNavigationStateChange.js +++ b/src/navigation/onNavigationStateChange.js @@ -34,8 +34,8 @@ export function onHandleStatusBar(currentState, prevState) { StatusBarHelper.setLightContent(); return; } - const isFromWalletScreen = Navigation.getActiveRoute()?.params - ?.isFromWalletScreen; + const isFromWalletScreen = + Navigation.getActiveRoute()?.params?.isFromWalletScreen; const isRoutesLengthDecrease = prevState?.routes.length > currentState?.routes.length; diff --git a/src/notifications/NotificationsHandler.tsx b/src/notifications/NotificationsHandler.tsx index 25621f65243..b36e244a048 100644 --- a/src/notifications/NotificationsHandler.tsx +++ b/src/notifications/NotificationsHandler.tsx @@ -70,7 +70,8 @@ export const NotificationsHandler = ({ walletReady }: Props) => { const dispatch: ThunkDispatch = useDispatch(); const walletsRef = useRef(wallets); const prevWalletReady = usePrevious(walletReady); - const subscriptionChangesListener = useRef(); + const subscriptionChangesListener = + useRef(); const onTokenRefreshListener = useRef(); const foregroundNotificationListener = useRef(); const notificationOpenedListener = useRef(); @@ -179,7 +180,7 @@ export const NotificationsHandler = ({ walletReady }: Props) => { } // casting data payload to type that was agreed on with backend - const data = (notification.data as unknown) as TransactionNotificationData; + const data = notification.data as unknown as TransactionNotificationData; const wallets = walletsRef.current; const { accountAddress, nativeCurrency } = store.getState().settings; @@ -307,7 +308,7 @@ export const NotificationsHandler = ({ walletReady }: Props) => { logger.info(`NotificationsHandler: handling marketing notification`, { notification, }); - const data = (notification.data as unknown) as MarketingNotificationData; + const data = notification.data as unknown as MarketingNotificationData; if (data?.route) { const parsedProps = JSON.parse(data?.routeProps || '{}'); Navigation.handleAction((Routes as any)[data.route], { @@ -325,7 +326,8 @@ export const NotificationsHandler = ({ walletReady }: Props) => { setupAndroidChannels(); saveFCMToken(); trackWalletsSubscribedForNotifications(); - subscriptionChangesListener.current = registerNotificationSubscriptionChangesListener(); + subscriptionChangesListener.current = + registerNotificationSubscriptionChangesListener(); onTokenRefreshListener.current = registerTokenRefreshListener(); foregroundNotificationListener.current = messaging().onMessage( onForegroundRemoteNotification diff --git a/src/notifications/analytics.ts b/src/notifications/analytics.ts index 59fd786a49d..6d1c679fe63 100644 --- a/src/notifications/analytics.ts +++ b/src/notifications/analytics.ts @@ -89,23 +89,24 @@ export type NotificationSubscriptionChangesListener = { remove: () => void; }; -export const registerNotificationSubscriptionChangesListener = (): NotificationSubscriptionChangesListener => { - return notificationSettingsStorage.addOnValueChangedListener(key => { - if (key === WALLET_GROUPS_STORAGE_KEY) { - const stringValue = notificationSettingsStorage.getString(key); - if (stringValue) { - const value = JSON.parse(stringValue) as GroupSettings; - onGroupStateChange(value); +export const registerNotificationSubscriptionChangesListener = + (): NotificationSubscriptionChangesListener => { + return notificationSettingsStorage.addOnValueChangedListener(key => { + if (key === WALLET_GROUPS_STORAGE_KEY) { + const stringValue = notificationSettingsStorage.getString(key); + if (stringValue) { + const value = JSON.parse(stringValue) as GroupSettings; + onGroupStateChange(value); + } + } else if (key === WALLET_TOPICS_STORAGE_KEY) { + const stringValue = notificationSettingsStorage.getString(key); + if (stringValue) { + const value = JSON.parse(stringValue); + onTopicsStateChange(value); + } } - } else if (key === WALLET_TOPICS_STORAGE_KEY) { - const stringValue = notificationSettingsStorage.getString(key); - if (stringValue) { - const value = JSON.parse(stringValue); - onTopicsStateChange(value); - } - } - }); -}; + }); + }; const onGroupStateChange = (state: GroupSettings) => { const stringValue = notificationSettingsStorage.getString( diff --git a/src/notifications/settings/hooks.ts b/src/notifications/settings/hooks.ts index cd8a90cc3f0..1580e38a595 100644 --- a/src/notifications/settings/hooks.ts +++ b/src/notifications/settings/hooks.ts @@ -24,21 +24,19 @@ import { Hook to constantly listen to notification settings. */ export const useAllNotificationSettingsFromStorage = () => { - const walletNotificationSettingsData = getAllWalletNotificationSettingsFromStorage(); - const globalNotificationSettingsData = getAllGlobalNotificationSettingsFromStorage(); + const walletNotificationSettingsData = + getAllWalletNotificationSettingsFromStorage(); + const globalNotificationSettingsData = + getAllGlobalNotificationSettingsFromStorage(); const existingGroupSettingsData = getExistingGroupSettingsFromStorage(); const [walletNotificationSettings, setWalletNotificationSettings] = useState< WalletNotificationSettings[] >(walletNotificationSettingsData); - const [ - globalNotificationSettings, - setGlobalNotificationSettings, - ] = useState(globalNotificationSettingsData); - const [ - existingGroupSettings, - setExistingGroupSettings, - ] = useState(existingGroupSettingsData); + const [globalNotificationSettings, setGlobalNotificationSettings] = + useState(globalNotificationSettingsData); + const [existingGroupSettings, setExistingGroupSettings] = + useState(existingGroupSettingsData); const listener = notificationSettingsStorage.addOnValueChangedListener( changedKey => { if (changedKey === WALLET_TOPICS_STORAGE_KEY) { @@ -71,10 +69,8 @@ export const useAllNotificationSettingsFromStorage = () => { Provides a function for updating the group settings. */ export const useWalletGroupNotificationSettings = () => { - const { - walletNotificationSettings, - existingGroupSettings, - } = useAllNotificationSettingsFromStorage(); + const { walletNotificationSettings, existingGroupSettings } = + useAllNotificationSettingsFromStorage(); const ownerEnabled = existingGroupSettings[WalletNotificationRelationship.OWNER]; diff --git a/src/notifications/settings/initialization.ts b/src/notifications/settings/initialization.ts index 631dab3e076..8cbc4ed84db 100644 --- a/src/notifications/settings/initialization.ts +++ b/src/notifications/settings/initialization.ts @@ -69,35 +69,34 @@ export const initializeGlobalNotificationSettings = () => { * schedules subscribing to owned wallets that haven't been initialized yet * schedules removing settings for wallets that are no longer prersent but removal failed previously */ -export const initializeNotificationSettingsForAllAddressesAndCleanupSettingsForRemovedWallets = ( - addresses: AddressWithRelationship[] -) => { - const initializationState = _prepareInitializationState(); - // Set of wallet addresses we have in app (unrelated to notification settings entries) - const walletAddresses = new Set( - addresses.map(addressWithRelationship => addressWithRelationship.address) - ); - const removedWalletsThatWereNotUnsubscribedProperly: string[] = [ - ...initializationState.alreadySaved.keys(), - ].filter(address => !walletAddresses.has(address)); - - const queue = _prepareSubscriptionQueueAndCreateInitialSettings( - addresses, - initializationState - ); +export const initializeNotificationSettingsForAllAddressesAndCleanupSettingsForRemovedWallets = + (addresses: AddressWithRelationship[]) => { + const initializationState = _prepareInitializationState(); + // Set of wallet addresses we have in app (unrelated to notification settings entries) + const walletAddresses = new Set( + addresses.map(addressWithRelationship => addressWithRelationship.address) + ); + const removedWalletsThatWereNotUnsubscribedProperly: string[] = [ + ...initializationState.alreadySaved.keys(), + ].filter(address => !walletAddresses.has(address)); - InteractionManager.runAfterInteractions(() => { - _processSubscriptionQueue(queue); - }); + const queue = _prepareSubscriptionQueueAndCreateInitialSettings( + addresses, + initializationState + ); - if (removedWalletsThatWereNotUnsubscribedProperly.length) { InteractionManager.runAfterInteractions(() => { - removedWalletsThatWereNotUnsubscribedProperly.forEach(address => { - removeNotificationSettingsForWallet(address); - }); + _processSubscriptionQueue(queue); }); - } -}; + + if (removedWalletsThatWereNotUnsubscribedProperly.length) { + InteractionManager.runAfterInteractions(() => { + removedWalletsThatWereNotUnsubscribedProperly.forEach(address => { + removeNotificationSettingsForWallet(address); + }); + }); + } + }; /** * Adds fresh disabled settings for all wallets that didn't have settings diff --git a/src/notifications/settings/types.ts b/src/notifications/settings/types.ts index 25331590548..83ad972501b 100644 --- a/src/notifications/settings/types.ts +++ b/src/notifications/settings/types.ts @@ -4,11 +4,14 @@ import { WalletNotificationTopic, } from '@/notifications/settings/constants'; -export type WalletNotificationTopicType = typeof WalletNotificationTopic[keyof typeof WalletNotificationTopic]; +export type WalletNotificationTopicType = + (typeof WalletNotificationTopic)[keyof typeof WalletNotificationTopic]; -export type GlobalNotificationTopicType = typeof GlobalNotificationTopic[keyof typeof GlobalNotificationTopic]; +export type GlobalNotificationTopicType = + (typeof GlobalNotificationTopic)[keyof typeof GlobalNotificationTopic]; -export type WalletNotificationRelationshipType = typeof WalletNotificationRelationship[keyof typeof WalletNotificationRelationship]; +export type WalletNotificationRelationshipType = + (typeof WalletNotificationRelationship)[keyof typeof WalletNotificationRelationship]; export type WalletNotificationTopics = { [key: WalletNotificationTopicType]: boolean; diff --git a/src/notifications/types.ts b/src/notifications/types.ts index 8d92896ced5..1ab6edb57c5 100644 --- a/src/notifications/types.ts +++ b/src/notifications/types.ts @@ -6,7 +6,8 @@ export const NotificationTypes = { marketing: 'marketing', } as const; -export type NotificationTypesType = typeof NotificationTypes[keyof typeof NotificationTypes]; +export type NotificationTypesType = + (typeof NotificationTypes)[keyof typeof NotificationTypes]; // FCM sends a different kind than the typings cover export interface FixedRemoteMessage @@ -44,7 +45,8 @@ export const NotificationTransactionTypes = { withdraw: 'withdraw', } as const; -export type NotificationTransactionTypesType = typeof NotificationTransactionTypes[keyof typeof NotificationTransactionTypes]; +export type NotificationTransactionTypesType = + (typeof NotificationTransactionTypes)[keyof typeof NotificationTransactionTypes]; export interface MarketingNotificationData { type: 'marketing'; diff --git a/src/parsers/accounts.js b/src/parsers/accounts.js index d221e6eb2f5..55f947faf9b 100644 --- a/src/parsers/accounts.js +++ b/src/parsers/accounts.js @@ -73,8 +73,10 @@ export const parseAssetNative = (asset, nativeCurrency) => { change: isLowerCaseMatch(asset.symbol, nativeCurrency) ? null : assetNativePrice.relative_change_24h - ? convertAmountToPercentageDisplay(assetNativePrice.relative_change_24h) - : '', + ? convertAmountToPercentageDisplay( + assetNativePrice.relative_change_24h + ) + : '', price: { amount: priceUnit, display: convertAmountToNativeDisplay(priceUnit, nativeCurrency), diff --git a/src/performance/tracking/types/PerformanceMetrics.ts b/src/performance/tracking/types/PerformanceMetrics.ts index 12b23a8f081..feda5714cd0 100644 --- a/src/performance/tracking/types/PerformanceMetrics.ts +++ b/src/performance/tracking/types/PerformanceMetrics.ts @@ -10,4 +10,5 @@ export const PerformanceMetrics = { useInitializeWallet: 'Performance Wallet Initialize Time', } as const; -export type PerformanceMetricsType = typeof PerformanceMetrics[keyof typeof PerformanceMetrics]; +export type PerformanceMetricsType = + (typeof PerformanceMetrics)[keyof typeof PerformanceMetrics]; diff --git a/src/performance/tracking/types/PerformanceTags.ts b/src/performance/tracking/types/PerformanceTags.ts index 5ee88f42fac..9893221d5dc 100644 --- a/src/performance/tracking/types/PerformanceTags.ts +++ b/src/performance/tracking/types/PerformanceTags.ts @@ -2,4 +2,5 @@ export const PerformanceTags = { lodash: 'lodash', } as const; -export type PerformanceTagsType = typeof PerformanceTags[keyof typeof PerformanceTags]; +export type PerformanceTagsType = + (typeof PerformanceTags)[keyof typeof PerformanceTags]; diff --git a/src/raps/actions/crosschainSwap.ts b/src/raps/actions/crosschainSwap.ts index a00e8882f2b..58d5f66a350 100644 --- a/src/raps/actions/crosschainSwap.ts +++ b/src/raps/actions/crosschainSwap.ts @@ -82,12 +82,8 @@ const crosschainSwap = async ( baseNonce?: number ): Promise => { logger.log(`[${actionName}] base nonce`, baseNonce, 'index:', index); - const { - inputAmount, - tradeDetails, - chainId, - requiresApprove, - } = parameters as CrosschainSwapActionParameters; + const { inputAmount, tradeDetails, chainId, requiresApprove } = + parameters as CrosschainSwapActionParameters; const { dispatch } = store; const { accountAddress } = store.getState().settings; const { inputCurrency, outputCurrency } = store.getState().swap; diff --git a/src/raps/actions/ens.ts b/src/raps/actions/ens.ts index fa66c1307d8..b16bfa4b158 100644 --- a/src/raps/actions/ens.ts +++ b/src/raps/actions/ens.ts @@ -333,15 +333,8 @@ const ensAction = async ( const { accountAddress: ownerAddress } = store.getState().settings; const { selectedGasFee } = store.getState().gas; - const { - name, - duration, - rentPrice, - records, - salt, - toAddress, - mode, - } = parameters; + const { name, duration, rentPrice, records, salt, toAddress, mode } = + parameters; logger.log(`[${actionName}] rap for`, name); diff --git a/src/raps/actions/swap.ts b/src/raps/actions/swap.ts index fd5fadb5b54..3d257291905 100644 --- a/src/raps/actions/swap.ts +++ b/src/raps/actions/swap.ts @@ -134,13 +134,8 @@ const swap = async ( baseNonce?: number ): Promise => { logger.log(`[${actionName}] base nonce`, baseNonce, 'index:', index); - const { - inputAmount, - tradeDetails, - permit, - chainId, - requiresApprove, - } = parameters as SwapActionParameters; + const { inputAmount, tradeDetails, permit, chainId, requiresApprove } = + parameters as SwapActionParameters; const { dispatch } = store; const { accountAddress } = store.getState().settings; const { inputCurrency, outputCurrency } = store.getState().swap; diff --git a/src/raps/actions/unlock.ts b/src/raps/actions/unlock.ts index 6b061b4b7ea..ce9f1b07b86 100644 --- a/src/raps/actions/unlock.ts +++ b/src/raps/actions/unlock.ts @@ -131,11 +131,8 @@ const unlock = async ( const { dispatch } = store; const { accountAddress } = store.getState().settings; const { gasFeeParamsBySpeed, selectedGasFee } = store.getState().gas; - const { - assetToUnlock, - contractAddress, - chainId, - } = parameters as UnlockActionParameters; + const { assetToUnlock, contractAddress, chainId } = + parameters as UnlockActionParameters; const { address: assetAddress } = assetToUnlock; logger.log(`[${actionName}] rap for`, assetToUnlock); @@ -191,7 +188,8 @@ const unlock = async ( throw e; } const walletAddress = await wallet.getAddress(); - const cacheKey = `${walletAddress}|${assetAddress}|${contractAddress}`.toLowerCase(); + const cacheKey = + `${walletAddress}|${assetAddress}|${contractAddress}`.toLowerCase(); // Cache the approved value AllowancesCache.cache[cacheKey] = MaxUint256.toString(); @@ -232,7 +230,8 @@ export const assetNeedsUnlocking = async ( if (address === ETH_ADDRESS) return false; if (alwaysRequireApprove) return true; - const cacheKey = `${accountAddress}|${address}|${contractAddress}`.toLowerCase(); + const cacheKey = + `${accountAddress}|${address}|${contractAddress}`.toLowerCase(); const allowance = await getRawAllowance( accountAddress, diff --git a/src/raps/registerENS.ts b/src/raps/registerENS.ts index 0afc52076e1..c3a513fffbc 100644 --- a/src/raps/registerENS.ts +++ b/src/raps/registerENS.ts @@ -131,13 +131,8 @@ export const createTransferENSRap = async ( ) => { let actions: RapENSAction[] = []; - const { - clearRecords, - records, - setAddress, - transferControl, - toAddress, - } = ensActionParameters; + const { clearRecords, records, setAddress, transferControl, toAddress } = + ensActionParameters; if (clearRecords) { const emptyRecords = Object.keys(records ?? {}).reduce( diff --git a/src/react-native-animated-charts/Example/src/BasicExample/index.js b/src/react-native-animated-charts/Example/src/BasicExample/index.js index 786df331da3..2ddf47f2df4 100644 --- a/src/react-native-animated-charts/Example/src/BasicExample/index.js +++ b/src/react-native-animated-charts/Example/src/BasicExample/index.js @@ -32,12 +32,14 @@ const BasicExample = () => ( + }} + > + }} + > + }} + > {/**/} {/* Generic Example (swipe right for a real-life example)*/} @@ -148,7 +148,8 @@ function GenericExample() { + }} + > Yes @@ -156,7 +157,8 @@ function GenericExample() { + }} + > No @@ -166,24 +168,28 @@ function GenericExample() { setSmoothingWhileTransitioningEnabled(true)}> + onPress={() => setSmoothingWhileTransitioningEnabled(true)} + > + }} + > Yes setSmoothingWhileTransitioningEnabled(false)}> + onPress={() => setSmoothingWhileTransitioningEnabled(false)} + > + }} + > No @@ -194,7 +200,8 @@ function GenericExample() { + }} + > 0 @@ -202,7 +209,8 @@ function GenericExample() { + }} + > 30 @@ -210,7 +218,8 @@ function GenericExample() { + }} + > 50 @@ -247,7 +256,8 @@ function GenericExample() { Pick range: + style={{flexDirection: 'row', justifyContent: 'space-around'}} + > setPickRange(2)}> 2 @@ -260,13 +270,15 @@ function GenericExample() { setPickRange(10)}> + style={{color: pickRange === 10 ? 'lightgreen' : 'white'}} + > 10 setPickRange(25)}> + style={{color: pickRange === 25 ? 'lightgreen' : 'white'}} + > 25 @@ -275,7 +287,8 @@ function GenericExample() { Include extremes: + style={{flexDirection: 'row', justifyContent: 'space-around'}} + > setIncludeExtremes(true)}> Yes @@ -283,7 +296,8 @@ function GenericExample() { setIncludeExtremes(false)}> + style={{color: !includeExtremes ? 'lightgreen' : 'white'}} + > No @@ -299,7 +313,8 @@ function GenericExample() { style={{ color: interpolationStrategy === 'none' ? 'lightgreen' : 'white', - }}> + }} + > None @@ -307,7 +322,8 @@ function GenericExample() { + }} + > B Spline @@ -316,7 +332,8 @@ function GenericExample() { style={{ color: interpolationStrategy === 'mono' ? 'lightgreen' : 'white', - }}> + }} + > Monotone Qubic Spline @@ -327,12 +344,14 @@ function GenericExample() { BSpline degree: + style={{flexDirection: 'row', justifyContent: 'space-around'}} + > setBSplineDegree(2)}> + }} + > 2 @@ -340,7 +359,8 @@ function GenericExample() { + }} + > 3 @@ -348,7 +368,8 @@ function GenericExample() { + }} + > 4 @@ -356,7 +377,8 @@ function GenericExample() { + }} + > 5 @@ -369,52 +391,61 @@ function GenericExample() { Number of points Interpolated: + style={{flexDirection: 'row', justifyContent: 'space-around'}} + > setNumberOfPointsInterpolated(30)}> + onPress={() => setNumberOfPointsInterpolated(30)} + > + }} + > 30 setNumberOfPointsInterpolated(80)}> + onPress={() => setNumberOfPointsInterpolated(80)} + > + }} + > 80 setNumberOfPointsInterpolated(120)}> + onPress={() => setNumberOfPointsInterpolated(120)} + > + }} + > 120 setNumberOfPointsInterpolated(200)}> + onPress={() => setNumberOfPointsInterpolated(200)} + > + }} + > 200 @@ -429,7 +460,8 @@ function GenericExample() { + }} + > None @@ -437,7 +469,8 @@ function GenericExample() { + }} + > Simple (Quadratic bezier with fixed points) @@ -447,7 +480,8 @@ function GenericExample() { + }} + > Complex (Cubic bezier) @@ -455,7 +489,8 @@ function GenericExample() { + }} + > Bezier @@ -466,12 +501,14 @@ function GenericExample() { Smoothing factor: + style={{flexDirection: 'row', justifyContent: 'space-around'}} + > setSmoothingFactor(0.05)}> + }} + > 0.05 @@ -479,7 +516,8 @@ function GenericExample() { + }} + > 0.1 @@ -487,7 +525,8 @@ function GenericExample() { + }} + > 0.2 @@ -495,7 +534,8 @@ function GenericExample() { + }} + > 0.3 @@ -503,7 +543,8 @@ function GenericExample() { + }} + > 0.5 @@ -511,7 +552,8 @@ function GenericExample() { + }} + > 0.7 @@ -519,7 +561,8 @@ function GenericExample() { + }} + > 0.9 diff --git a/src/react-native-animated-charts/src/charts/linear/ChartLabels.tsx b/src/react-native-animated-charts/src/charts/linear/ChartLabels.tsx index 2a5980bd835..7186a49ec83 100644 --- a/src/react-native-animated-charts/src/charts/linear/ChartLabels.tsx +++ b/src/react-native-animated-charts/src/charts/linear/ChartLabels.tsx @@ -16,11 +16,10 @@ const ChartLabelFactory = (fieldName: 'originalX' | 'originalY') => { // we need to recreate defaultValue on data change // eslint-disable-next-line react-hooks/exhaustive-deps - const defaultValue = useMemo(() => format?.(val.value) ?? val.value, [ - format, - val, - data, - ]); + const defaultValue = useMemo( + () => format?.(val.value) ?? val.value, + [format, val, data] + ); const textProps = useAnimatedProps( () => ({ diff --git a/src/react-native-animated-charts/src/charts/linear/ChartPath.tsx b/src/react-native-animated-charts/src/charts/linear/ChartPath.tsx index 7fa20ca46bf..06f66f8d610 100644 --- a/src/react-native-animated-charts/src/charts/linear/ChartPath.tsx +++ b/src/react-native-animated-charts/src/charts/linear/ChartPath.tsx @@ -305,62 +305,63 @@ const ChartPathInner = React.memo( return props; }, [currentPath]); - const onGestureEvent = useAnimatedGestureHandler( - { - onActive: event => { - if (!isActive.value) { - isActive.value = true; - - pathOpacity.value = withTiming( - 0, - timingFeedbackConfig || timingFeedbackDefaultConfig - ); - - if (hapticsEnabled) { - impactHeavy(); + const onGestureEvent = + useAnimatedGestureHandler( + { + onActive: event => { + if (!isActive.value) { + isActive.value = true; + + pathOpacity.value = withTiming( + 0, + timingFeedbackConfig || timingFeedbackDefaultConfig + ); + + if (hapticsEnabled) { + impactHeavy(); + } } - } - state.value = event.state; - translationX.value = positionXWithMargin(event.x, hitSlop, width); - translationY.value = event.y; - }, - onCancel: event => { - state.value = event.state; - resetGestureState(); - }, - onEnd: event => { - state.value = event.state; - resetGestureState(); - - if (hapticsEnabled) { - impactHeavy(); - } - }, - onFail: event => { - state.value = event.state; - resetGestureState(); - }, - onStart: event => { - // WARNING: the following code does not run on using iOS, but it does on Android. - // I use the same code from onActive - // platform is for safety - if (Platform.OS === 'android') { state.value = event.state; - isActive.value = true; - pathOpacity.value = withTiming( - 0, - timingFeedbackConfig || timingFeedbackDefaultConfig - ); + translationX.value = positionXWithMargin(event.x, hitSlop, width); + translationY.value = event.y; + }, + onCancel: event => { + state.value = event.state; + resetGestureState(); + }, + onEnd: event => { + state.value = event.state; + resetGestureState(); if (hapticsEnabled) { impactHeavy(); } - } + }, + onFail: event => { + state.value = event.state; + resetGestureState(); + }, + onStart: event => { + // WARNING: the following code does not run on using iOS, but it does on Android. + // I use the same code from onActive + // platform is for safety + if (Platform.OS === 'android') { + state.value = event.state; + isActive.value = true; + pathOpacity.value = withTiming( + 0, + timingFeedbackConfig || timingFeedbackDefaultConfig + ); + + if (hapticsEnabled) { + impactHeavy(); + } + } + }, }, - }, - [width, height, hapticsEnabled, hitSlop, timingFeedbackConfig] - ); + [width, height, hapticsEnabled, hitSlop, timingFeedbackConfig] + ); const pathAnimatedStyles = useAnimatedStyle(() => { return { diff --git a/src/react-native-animated-charts/src/helpers/d3Interpolate.js b/src/react-native-animated-charts/src/helpers/d3Interpolate.js index 93b516176a9..44761b117a7 100644 --- a/src/react-native-animated-charts/src/helpers/d3Interpolate.js +++ b/src/react-native-animated-charts/src/helpers/d3Interpolate.js @@ -610,8 +610,7 @@ export function d3Interpolate() { return extended.concat( splitSegment(commandsToExtend[i], commandsToExtend[i + 1], segmentCount) ); - }, - []); // add in the very first point since splitSegment only adds in the ones after it + }, []); // add in the very first point since splitSegment only adds in the ones after it extended.unshift(commandsToExtend[0]); return extended; diff --git a/src/react-query/types.ts b/src/react-query/types.ts index 822898a7f48..2a9d0113def 100644 --- a/src/react-query/types.ts +++ b/src/react-query/types.ts @@ -7,14 +7,12 @@ import { } from '@tanstack/react-query'; // Used to obtain argument types for query functions. -export type QueryFunctionArgs< - T extends (...args: any) => any -> = QueryFunctionContext>; +export type QueryFunctionArgs any> = + QueryFunctionContext>; // Used to obtain types for query function results. -export type QueryFunctionResult< - FnType extends (...args: any) => any -> = PromiseValue>; +export type QueryFunctionResult any> = + PromiseValue>; // Note: we probably want to restrict the amount of configuration // to the React Query hook. So we are picking out the only the @@ -24,7 +22,7 @@ export type QueryConfigWithSelect< TQueryFnData, TError, TData, - TQueryKey extends QueryKey + TQueryKey extends QueryKey, > = Pick< UseQueryOptions, | 'cacheTime' @@ -80,28 +78,26 @@ export type MutationConfig = Pick< >; // Used to obtain types for mutation function results. -export type MutationFunctionResult< - FnType extends (...args: any) => any -> = PromiseValue>; +export type MutationFunctionResult any> = + PromiseValue>; // ////////////////////////////////////////////////////////////////////////////////////// // Deprecated Types -type PromiseValue = PromiseType extends PromiseLike - ? PromiseValue - : PromiseType; +type PromiseValue = + PromiseType extends PromiseLike + ? PromiseValue + : PromiseType; type ExtractFnReturnType any> = PromiseValue< ReturnType >; -export type UseQueryData< - QueryFnType extends (...args: any) => any -> = ExtractFnReturnType; +export type UseQueryData any> = + ExtractFnReturnType; -export type QueryConfigDeprecated< - QueryFnType extends (...args: any) => any -> = Omit< - UseQueryOptions>, - 'queryKey' | 'queryFn' ->; +export type QueryConfigDeprecated any> = + Omit< + UseQueryOptions>, + 'queryKey' | 'queryFn' + >; diff --git a/src/redux/appState.ts b/src/redux/appState.ts index 5969845b0bc..4db93eb39b1 100644 --- a/src/redux/appState.ts +++ b/src/redux/appState.ts @@ -32,14 +32,14 @@ interface AppStateUpdateAction { * * @param stateToUpdate The updates to apply to the state. */ -export const appStateUpdate = (stateToUpdate: Partial) => ( - dispatch: Dispatch -) => { - dispatch({ - payload: stateToUpdate, - type: APP_STATE_UPDATE, - }); -}; +export const appStateUpdate = + (stateToUpdate: Partial) => + (dispatch: Dispatch) => { + dispatch({ + payload: stateToUpdate, + type: APP_STATE_UPDATE, + }); + }; // -- Reducer ----------------------------------------- // diff --git a/src/redux/charts.ts b/src/redux/charts.ts index 53ad0073dca..6cffcedd293 100644 --- a/src/redux/charts.ts +++ b/src/redux/charts.ts @@ -71,39 +71,38 @@ export interface ChartsReceivedMessage { * * @param message The `ChartsReceivedMessage`. */ -export const assetChartsReceived = (message: ChartsReceivedMessage) => ( - dispatch: Dispatch, - getState: AppGetState -) => { - const chartType = message?.meta?.charts_type; - const { charts: existingCharts } = getState().charts; - const assetCharts = message?.payload?.charts ?? {}; - const { nativeCurrency } = getState().settings; - - if (nativeCurrency.toLowerCase() === message?.meta?.currency) { - const newChartData = mapValues(assetCharts, (chartData, address) => { - if (chartType) { +export const assetChartsReceived = + (message: ChartsReceivedMessage) => + (dispatch: Dispatch, getState: AppGetState) => { + const chartType = message?.meta?.charts_type; + const { charts: existingCharts } = getState().charts; + const assetCharts = message?.payload?.charts ?? {}; + const { nativeCurrency } = getState().settings; + + if (nativeCurrency.toLowerCase() === message?.meta?.currency) { + const newChartData = mapValues(assetCharts, (chartData, address) => { + if (chartType) { + return { + ...existingCharts[address], + // .slice to prevent mutation + [chartType]: reverse(chartData?.slice()), + }; + } return { ...existingCharts[address], - // .slice to prevent mutation - [chartType]: reverse(chartData?.slice()), }; - } - return { - ...existingCharts[address], - }; - }); + }); - const updatedCharts = { - ...existingCharts, - ...newChartData, - }; - dispatch({ - payload: updatedCharts, - type: CHARTS_UPDATE, - }); - } -}; + const updatedCharts = { + ...existingCharts, + ...newChartData, + }; + dispatch({ + payload: updatedCharts, + type: CHARTS_UPDATE, + }); + } + }; // -- Reducer ----------------------------------------- // diff --git a/src/redux/contacts.ts b/src/redux/contacts.ts index ea24b0bc238..5c0b44d8283 100644 --- a/src/redux/contacts.ts +++ b/src/redux/contacts.ts @@ -76,61 +76,61 @@ interface ContactsClearStateAction { } // -- Actions ---------------------------------------- // -export const contactsLoadState = () => async ( - dispatch: Dispatch -) => { - try { - const contacts = (await getContacts()) as ContactsState['contacts']; +export const contactsLoadState = + () => async (dispatch: Dispatch) => { + try { + const contacts = (await getContacts()) as ContactsState['contacts']; + dispatch({ + payload: contacts, + type: CONTACTS_LOAD, + }); + // eslint-disable-next-line no-empty + } catch (error) {} + }; + +export const contactsAddOrUpdate = + ( + address: string, + nickname: string, + color: number, + network: Network, + ens: string + ) => + (dispatch: Dispatch, getState: AppGetState) => { + const loweredAddress = address.toLowerCase(); + const { contacts } = getState().contacts; + const updatedContacts = { + ...contacts, + [loweredAddress]: { + address: loweredAddress, + color, + ens, + network, + nickname, + }, + }; + saveContacts(updatedContacts); + + setTimeout(() => { + handleReviewPromptAction(ReviewPromptAction.AddingContact); + }, 500); dispatch({ - payload: contacts, - type: CONTACTS_LOAD, + payload: updatedContacts, + type: CONTACTS_UPDATE, }); - // eslint-disable-next-line no-empty - } catch (error) {} -}; - -export const contactsAddOrUpdate = ( - address: string, - nickname: string, - color: number, - network: Network, - ens: string -) => (dispatch: Dispatch, getState: AppGetState) => { - const loweredAddress = address.toLowerCase(); - const { contacts } = getState().contacts; - const updatedContacts = { - ...contacts, - [loweredAddress]: { - address: loweredAddress, - color, - ens, - network, - nickname, - }, }; - saveContacts(updatedContacts); - - setTimeout(() => { - handleReviewPromptAction(ReviewPromptAction.AddingContact); - }, 500); - dispatch({ - payload: updatedContacts, - type: CONTACTS_UPDATE, - }); -}; -export const removeContact = (address: string) => ( - dispatch: Dispatch, - getState: AppGetState -) => { - const { contacts } = getState().contacts; - const updatedContacts = omitFlatten(contacts, address.toLowerCase()); - saveContacts(updatedContacts); - dispatch({ - payload: updatedContacts, - type: CONTACTS_UPDATE, - }); -}; +export const removeContact = + (address: string) => + (dispatch: Dispatch, getState: AppGetState) => { + const { contacts } = getState().contacts; + const updatedContacts = omitFlatten(contacts, address.toLowerCase()); + saveContacts(updatedContacts); + dispatch({ + payload: updatedContacts, + type: CONTACTS_UPDATE, + }); + }; // -- Reducer ----------------------------------------- // const INITIAL_STATE: ContactsState = { diff --git a/src/redux/data.ts b/src/redux/data.ts index 0b0d164eae6..814cab7b9d2 100644 --- a/src/redux/data.ts +++ b/src/redux/data.ts @@ -308,75 +308,75 @@ export const DISPERSION_SUCCESS_CODE = 'ok'; /** * Loads initial state from account local storage. */ -export const dataLoadState = () => async ( - dispatch: ThunkDispatch< - AppState, - unknown, - | DataLoadTransactionSuccessAction - | DataLoadTransactionsRequestAction - | DataLoadTransactionsFailureAction - | DataUpdatePendingTransactionSuccessAction - >, - getState: AppGetState -) => { - const { accountAddress, network } = getState().settings; - - try { - dispatch({ type: DATA_LOAD_TRANSACTIONS_REQUEST }); - const transactions = await getLocalTransactions(accountAddress, network); - const pendingTransactions = await getLocalPendingTransactions( - accountAddress, - network - ); - const isCurrentAccountAddress = - accountAddress === getState().settings.accountAddress; - if (!isCurrentAccountAddress) return; +export const dataLoadState = + () => + async ( + dispatch: ThunkDispatch< + AppState, + unknown, + | DataLoadTransactionSuccessAction + | DataLoadTransactionsRequestAction + | DataLoadTransactionsFailureAction + | DataUpdatePendingTransactionSuccessAction + >, + getState: AppGetState + ) => { + const { accountAddress, network } = getState().settings; - dispatch({ - payload: pendingTransactions, - type: DATA_UPDATE_PENDING_TRANSACTIONS_SUCCESS, - }); - dispatch({ - payload: transactions, - type: DATA_LOAD_TRANSACTIONS_SUCCESS, - }); - } catch (error) { - dispatch({ type: DATA_LOAD_TRANSACTIONS_FAILURE }); - } -}; + try { + dispatch({ type: DATA_LOAD_TRANSACTIONS_REQUEST }); + const transactions = await getLocalTransactions(accountAddress, network); + const pendingTransactions = await getLocalPendingTransactions( + accountAddress, + network + ); + const isCurrentAccountAddress = + accountAddress === getState().settings.accountAddress; + if (!isCurrentAccountAddress) return; + + dispatch({ + payload: pendingTransactions, + type: DATA_UPDATE_PENDING_TRANSACTIONS_SUCCESS, + }); + dispatch({ + payload: transactions, + type: DATA_LOAD_TRANSACTIONS_SUCCESS, + }); + } catch (error) { + dispatch({ type: DATA_LOAD_TRANSACTIONS_FAILURE }); + } + }; /** * Resets state, with the exception of generic asset prices, and unsubscribes * from listeners and timeouts. */ -export const dataResetState = () => ( - dispatch: Dispatch -) => { - // cancel any debounced updates so we won't override any new data with stale debounced ones - cancelDebouncedUpdateGenericAssets(); +export const dataResetState = + () => (dispatch: Dispatch) => { + // cancel any debounced updates so we won't override any new data with stale debounced ones + cancelDebouncedUpdateGenericAssets(); - pendingTransactionsHandle && clearTimeout(pendingTransactionsHandle); + pendingTransactionsHandle && clearTimeout(pendingTransactionsHandle); - dispatch({ type: DATA_CLEAR_STATE }); -}; + dispatch({ type: DATA_CLEAR_STATE }); + }; /** * Checks whether or not metadata received from Zerion is valid. * * @param message The message received from Zerion. */ -const checkMeta = (message: DataMessage | undefined) => ( - _: Dispatch, - getState: AppGetState -) => { - const { accountAddress, nativeCurrency } = getState().settings; - const address = message?.meta?.address || message?.meta?.addresses?.[0]; - const currency = message?.meta?.currency; - return ( - isLowerCaseMatch(address!, accountAddress) && - isLowerCaseMatch(currency!, nativeCurrency) - ); -}; +const checkMeta = + (message: DataMessage | undefined) => + (_: Dispatch, getState: AppGetState) => { + const { accountAddress, nativeCurrency } = getState().settings; + const address = message?.meta?.address || message?.meta?.addresses?.[0]; + const currency = message?.meta?.currency; + return ( + isLowerCaseMatch(address!, accountAddress) && + isLowerCaseMatch(currency!, nativeCurrency) + ); + }; /** * Checks to see if a network's nonce should be incremented for an acount @@ -384,30 +384,32 @@ const checkMeta = (message: DataMessage | undefined) => ( * * @param transactionData Incoming transaction data. */ -const checkForUpdatedNonce = (transactionData: ZerionTransaction[]) => ( - dispatch: ThunkDispatch, - getState: AppGetState -) => { - if (transactionData.length) { - const { accountAddress, network } = getState().settings; - const txSortedByDescendingNonce = transactionData - .filter(tx => { - const addressFrom = tx?.address_from; - return ( - addressFrom && - addressFrom.toLowerCase() === accountAddress.toLowerCase() - ); - }) - .sort(({ nonce: n1 }, { nonce: n2 }) => (n2 ?? 0) - (n1 ?? 0)); - const [latestTx] = txSortedByDescendingNonce; - const addressFrom = latestTx?.address_from; - const nonce = latestTx?.nonce; - if (addressFrom && nonce) { - // @ts-ignore-next-line - dispatch(incrementNonce(addressFrom!, nonce, network)); +const checkForUpdatedNonce = + (transactionData: ZerionTransaction[]) => + ( + dispatch: ThunkDispatch, + getState: AppGetState + ) => { + if (transactionData.length) { + const { accountAddress, network } = getState().settings; + const txSortedByDescendingNonce = transactionData + .filter(tx => { + const addressFrom = tx?.address_from; + return ( + addressFrom && + addressFrom.toLowerCase() === accountAddress.toLowerCase() + ); + }) + .sort(({ nonce: n1 }, { nonce: n2 }) => (n2 ?? 0) - (n1 ?? 0)); + const [latestTx] = txSortedByDescendingNonce; + const addressFrom = latestTx?.address_from; + const nonce = latestTx?.nonce; + if (addressFrom && nonce) { + // @ts-ignore-next-line + dispatch(incrementNonce(addressFrom!, nonce, network)); + } } - } -}; + }; /** * Handles an incoming portfolio data message from Zerion and updates state @@ -415,25 +417,25 @@ const checkForUpdatedNonce = (transactionData: ZerionTransaction[]) => ( * * @param message The `PortfolioReceivedMessage`, or undefined. */ -export const portfolioReceived = ( - message: PortfolioReceivedMessage | undefined -) => async ( - dispatch: Dispatch, - getState: AppGetState -) => { - if (message?.meta?.status !== DISPERSION_SUCCESS_CODE) return; - if (!message?.payload?.portfolio) return; - - const { portfolios } = getState().data; - - const newPortfolios = { ...portfolios }; - newPortfolios[message.meta.address!] = message.payload.portfolio; - - dispatch({ - payload: newPortfolios, - type: DATA_UPDATE_PORTFOLIOS, - }); -}; +export const portfolioReceived = + (message: PortfolioReceivedMessage | undefined) => + async ( + dispatch: Dispatch, + getState: AppGetState + ) => { + if (message?.meta?.status !== DISPERSION_SUCCESS_CODE) return; + if (!message?.payload?.portfolio) return; + + const { portfolios } = getState().data; + + const newPortfolios = { ...portfolios }; + newPortfolios[message.meta.address!] = message.payload.portfolio; + + dispatch({ + payload: newPortfolios, + type: DATA_UPDATE_PORTFOLIOS, + }); + }; /** * Handles a `TransactionsReceivedMessage` message from Zerion and updates @@ -442,124 +444,122 @@ export const portfolioReceived = ( * @param message The `TransactionsReceivedMessage`, or undefined. * @param appended Whether or not transactions are being appended. */ -export const transactionsReceived = ( - message: TransactionsReceivedMessage | undefined, - appended = false -) => async ( - dispatch: ThunkDispatch< - AppState, - unknown, - DataLoadTransactionSuccessAction | DataUpdatePendingTransactionSuccessAction - >, - getState: AppGetState -) => { - return; - loggr.debug('transactionsReceived', { - message: { - ...message, - payload: { - transactions: message?.payload?.transactions?.length, +export const transactionsReceived = + (message: TransactionsReceivedMessage | undefined, appended = false) => + async ( + dispatch: ThunkDispatch< + AppState, + unknown, + | DataLoadTransactionSuccessAction + | DataUpdatePendingTransactionSuccessAction + >, + getState: AppGetState + ) => { + return; + loggr.debug('transactionsReceived', { + message: { + ...message, + payload: { + transactions: message?.payload?.transactions?.length, + }, }, - }, - appended, - }); + appended, + }); - const isValidMeta = dispatch(checkMeta(message)); + const isValidMeta = dispatch(checkMeta(message)); - if (!isValidMeta) { - loggr.debug('transactionsReceived: !isValidMeta', { message }); - return; - } + if (!isValidMeta) { + loggr.debug('transactionsReceived: !isValidMeta', { message }); + return; + } - const transactionData = message?.payload?.transactions ?? []; + const transactionData = message?.payload?.transactions ?? []; - const { network } = getState().settings; - let currentNetwork = network; - if (currentNetwork === Network.mainnet && message?.meta?.chain_id) { - currentNetwork = message?.meta?.chain_id; - } - if (transactionData.length && currentNetwork === Network.mainnet) { - loggr.debug('transactionsReceived: dispatching checkForUpdatedNonce'); - dispatch(checkForUpdatedNonce(transactionData)); - } + const { network } = getState().settings; + let currentNetwork = network; + if (currentNetwork === Network.mainnet && message?.meta?.chain_id) { + currentNetwork = message?.meta?.chain_id; + } + if (transactionData.length && currentNetwork === Network.mainnet) { + loggr.debug('transactionsReceived: dispatching checkForUpdatedNonce'); + dispatch(checkForUpdatedNonce(transactionData)); + } - const { accountAddress, nativeCurrency } = getState().settings; - const { pendingTransactions, transactions } = getState().data; - const { selected } = getState().wallets; - - loggr.debug('transactionsReceived: attempting to parse transactions'); - - const { - parsedTransactions, - potentialNftTransaction, - } = await parseTransactions( - transactionData, - accountAddress, - nativeCurrency, - transactions, - pendingTransactions, - undefined, - currentNetwork, - appended - ); - - const isCurrentAccountAddress = - accountAddress === getState().settings.accountAddress; - if (!isCurrentAccountAddress) { - loggr.debug( - 'transactionsReceived: transaction accountAddress does not match current accountAddress', - { - transactionAccountAddress: accountAddress, - currentAccountAddress: getState().settings.accountAddress, - } - ); - return; - } + const { accountAddress, nativeCurrency } = getState().settings; + const { pendingTransactions, transactions } = getState().data; + const { selected } = getState().wallets; - if (appended && potentialNftTransaction) { - setTimeout(() => { - queryClient.invalidateQueries({ - queryKey: nftsQueryKey({ address: accountAddress }), - }); - }, 60000); - } + loggr.debug('transactionsReceived: attempting to parse transactions'); - const txHashes = parsedTransactions.map(tx => ethereumUtils.getHash(tx)); - const updatedPendingTransactions = pendingTransactions.filter( - tx => !txHashes.includes(ethereumUtils.getHash(tx)) - ); - - dispatch({ - payload: updatedPendingTransactions, - type: DATA_UPDATE_PENDING_TRANSACTIONS_SUCCESS, - }); - dispatch({ - payload: parsedTransactions, - type: DATA_LOAD_TRANSACTIONS_SUCCESS, - }); - saveLocalTransactions(parsedTransactions, accountAddress, network); - saveLocalPendingTransactions( - updatedPendingTransactions, - accountAddress, - network - ); - - if (appended && parsedTransactions.length) { - if ( - selected && - !selected.backedUp && - !selected.imported && - selected.type !== WalletTypes.readOnly && - selected.type !== WalletTypes.bluetooth - ) { + const { parsedTransactions, potentialNftTransaction } = + await parseTransactions( + transactionData, + accountAddress, + nativeCurrency, + transactions, + pendingTransactions, + undefined, + currentNetwork, + appended + ); + + const isCurrentAccountAddress = + accountAddress === getState().settings.accountAddress; + if (!isCurrentAccountAddress) { + loggr.debug( + 'transactionsReceived: transaction accountAddress does not match current accountAddress', + { + transactionAccountAddress: accountAddress, + currentAccountAddress: getState().settings.accountAddress, + } + ); + return; + } + + if (appended && potentialNftTransaction) { setTimeout(() => { - triggerOnSwipeLayout(() => - Navigation.handleAction(Routes.BACKUP_SHEET, { single: true }) - ); - }, BACKUP_SHEET_DELAY_MS); + queryClient.invalidateQueries({ + queryKey: nftsQueryKey({ address: accountAddress }), + }); + }, 60000); } - } -}; + + const txHashes = parsedTransactions.map(tx => ethereumUtils.getHash(tx)); + const updatedPendingTransactions = pendingTransactions.filter( + tx => !txHashes.includes(ethereumUtils.getHash(tx)) + ); + + dispatch({ + payload: updatedPendingTransactions, + type: DATA_UPDATE_PENDING_TRANSACTIONS_SUCCESS, + }); + dispatch({ + payload: parsedTransactions, + type: DATA_LOAD_TRANSACTIONS_SUCCESS, + }); + saveLocalTransactions(parsedTransactions, accountAddress, network); + saveLocalPendingTransactions( + updatedPendingTransactions, + accountAddress, + network + ); + + if (appended && parsedTransactions.length) { + if ( + selected && + !selected.backedUp && + !selected.imported && + selected.type !== WalletTypes.readOnly && + selected.type !== WalletTypes.bluetooth + ) { + setTimeout(() => { + triggerOnSwipeLayout(() => + Navigation.handleAction(Routes.BACKUP_SHEET, { single: true }) + ); + }, BACKUP_SHEET_DELAY_MS); + } + } + }; const callbacksOnAssetReceived: { [address: string]: ((asset: ParsedAddressAsset) => unknown) | undefined; @@ -583,103 +583,105 @@ export function scheduleActionOnAssetReceived( * * @param message The message, or undefined. */ -export const assetPricesReceived = ( - message: AssetPricesReceivedMessage | undefined -) => ( - dispatch: Dispatch, - getState: AppGetState -) => { - const newAssetPrices = message?.payload?.prices ?? {}; - const { nativeCurrency } = getState().settings; - - if (nativeCurrency.toLowerCase() === message?.meta?.currency) { - if (isEmpty(newAssetPrices)) return; - const parsedAssets = mapValues(newAssetPrices, asset => - parseAsset(asset) - ) as { - [id: string]: ParsedAddressAsset; - }; - const { genericAssets } = getState().data; +export const assetPricesReceived = + (message: AssetPricesReceivedMessage | undefined) => + ( + dispatch: Dispatch, + getState: AppGetState + ) => { + const newAssetPrices = message?.payload?.prices ?? {}; + const { nativeCurrency } = getState().settings; + + if (nativeCurrency.toLowerCase() === message?.meta?.currency) { + if (isEmpty(newAssetPrices)) return; + const parsedAssets = mapValues(newAssetPrices, asset => + parseAsset(asset) + ) as { + [id: string]: ParsedAddressAsset; + }; + const { genericAssets } = getState().data; - const updatedAssets = { - ...genericAssets, - ...parsedAssets, - }; + const updatedAssets = { + ...genericAssets, + ...parsedAssets, + }; - const assetAddresses = Object.keys(parsedAssets); + const assetAddresses = Object.keys(parsedAssets); - for (const address of assetAddresses) { - callbacksOnAssetReceived[address.toLowerCase()]?.(parsedAssets[address]); - callbacksOnAssetReceived[address.toLowerCase()] = undefined; - } + for (const address of assetAddresses) { + callbacksOnAssetReceived[address.toLowerCase()]?.( + parsedAssets[address] + ); + callbacksOnAssetReceived[address.toLowerCase()] = undefined; + } - dispatch({ - payload: updatedAssets, - type: DATA_UPDATE_GENERIC_ASSETS, - }); - } - if ( - message?.meta?.currency?.toLowerCase() === - NativeCurrencyKeys.USD.toLowerCase() && - newAssetPrices[ETH_ADDRESS] - ) { - const value = newAssetPrices[ETH_ADDRESS]?.price?.value; - dispatch({ - payload: value, - type: DATA_UPDATE_ETH_USD, - }); - } -}; + dispatch({ + payload: updatedAssets, + type: DATA_UPDATE_GENERIC_ASSETS, + }); + } + if ( + message?.meta?.currency?.toLowerCase() === + NativeCurrencyKeys.USD.toLowerCase() && + newAssetPrices[ETH_ADDRESS] + ) { + const value = newAssetPrices[ETH_ADDRESS]?.price?.value; + dispatch({ + payload: value, + type: DATA_UPDATE_ETH_USD, + }); + } + }; /** * Handles a `AssetPricesChangedMessage` from Zerion and updates state. * * @param message The message. */ -export const assetPricesChanged = ( - message: AssetPricesChangedMessage | undefined -) => ( - dispatch: Dispatch, - getState: AppGetState -) => { - const { nativeCurrency } = getState().settings; - - const price = message?.payload?.prices?.[0]?.price; - const assetAddress = message?.meta?.asset_code; - if (isNil(price) || isNil(assetAddress)) return; - - if (nativeCurrency?.toLowerCase() === message?.meta?.currency) { - const { genericAssets } = getState().data; - const genericAsset = { - ...genericAssets?.[assetAddress], - price, - }; - const updatedAssets = { - ...genericAssets, - [assetAddress]: genericAsset, - } as { - [address: string]: ParsedAddressAsset; - }; +export const assetPricesChanged = + (message: AssetPricesChangedMessage | undefined) => + ( + dispatch: Dispatch, + getState: AppGetState + ) => { + const { nativeCurrency } = getState().settings; + + const price = message?.payload?.prices?.[0]?.price; + const assetAddress = message?.meta?.asset_code; + if (isNil(price) || isNil(assetAddress)) return; + + if (nativeCurrency?.toLowerCase() === message?.meta?.currency) { + const { genericAssets } = getState().data; + const genericAsset = { + ...genericAssets?.[assetAddress], + price, + }; + const updatedAssets = { + ...genericAssets, + [assetAddress]: genericAsset, + } as { + [address: string]: ParsedAddressAsset; + }; - debouncedUpdateGenericAssets( - { - payload: updatedAssets, - type: DATA_UPDATE_GENERIC_ASSETS, - }, - dispatch - ); - } - if ( - message?.meta?.currency?.toLowerCase() === - NativeCurrencyKeys.USD.toLowerCase() && - assetAddress === ETH_ADDRESS - ) { - dispatch({ - payload: price?.value, - type: DATA_UPDATE_ETH_USD, - }); - } -}; + debouncedUpdateGenericAssets( + { + payload: updatedAssets, + type: DATA_UPDATE_GENERIC_ASSETS, + }, + dispatch + ); + } + if ( + message?.meta?.currency?.toLowerCase() === + NativeCurrencyKeys.USD.toLowerCase() && + assetAddress === ETH_ADDRESS + ) { + dispatch({ + payload: price?.value, + type: DATA_UPDATE_ETH_USD, + }); + } + }; /** * Updates state and account local storage with a new transaction. @@ -692,129 +694,138 @@ export const assetPricesChanged = ( * @param provider A `StaticJsonRpcProvider` to use for watching the pending * transaction, or null to use the default provider. */ -export const dataAddNewTransaction = ( - txDetails: NewTransactionOrAddCashTransaction, - accountAddressToUpdate: string | null = null, - disableTxnWatcher = false, - provider: StaticJsonRpcProvider | null = null -) => async ( - dispatch: ThunkDispatch< - AppState, - unknown, - DataUpdatePendingTransactionSuccessAction - >, - getState: AppGetState -) => { - return; - loggr.debug('dataAddNewTransaction', {}, loggr.DebugContext.f2c); - - const { pendingTransactions } = getState().data; - const { accountAddress, nativeCurrency, network } = getState().settings; - - if ( - accountAddressToUpdate && - accountAddressToUpdate.toLowerCase() !== accountAddress.toLowerCase() - ) { - loggr.debug( - 'dataAddNewTransaction: accountAddressToUpdate does not match accountAddress', - {}, - loggr.DebugContext.f2c - ); +export const dataAddNewTransaction = + ( + txDetails: NewTransactionOrAddCashTransaction, + accountAddressToUpdate: string | null = null, + disableTxnWatcher = false, + provider: StaticJsonRpcProvider | null = null + ) => + async ( + dispatch: ThunkDispatch< + AppState, + unknown, + DataUpdatePendingTransactionSuccessAction + >, + getState: AppGetState + ) => { return; - } - - try { - const parsedTransaction = await parseNewTransaction( - txDetails, - nativeCurrency - ); - - const _pendingTransactions = [parsedTransaction, ...pendingTransactions]; - dispatch({ - payload: _pendingTransactions, - type: DATA_UPDATE_PENDING_TRANSACTIONS_SUCCESS, - }); - saveLocalPendingTransactions(_pendingTransactions, accountAddress, network); + loggr.debug('dataAddNewTransaction', {}, loggr.DebugContext.f2c); - loggr.debug( - 'dataAddNewTransaction: adding pending transactions', - {}, - loggr.DebugContext.f2c - ); + const { pendingTransactions } = getState().data; + const { accountAddress, nativeCurrency, network } = getState().settings; - if (parsedTransaction.from && parsedTransaction.nonce) { - dispatch( - // @ts-ignore-next-line - incrementNonce( - parsedTransaction.from, - parsedTransaction.nonce, - parsedTransaction.network - ) - ); - } if ( - !disableTxnWatcher || - network !== Network.mainnet || - parsedTransaction?.network + accountAddressToUpdate && + accountAddressToUpdate.toLowerCase() !== accountAddress.toLowerCase() ) { loggr.debug( - 'dataAddNewTransaction: watching new pending transactions', + 'dataAddNewTransaction: accountAddressToUpdate does not match accountAddress', {}, loggr.DebugContext.f2c ); - dispatch( - watchPendingTransactions( - accountAddress, - parsedTransaction.network - ? TXN_WATCHER_MAX_TRIES_LAYER_2 - : TXN_WATCHER_MAX_TRIES, - null, - // @ts-expect-error `watchPendingTransactions` only takes 3 arguments. - provider - ) - ); + return; } - loggr.debug('dataAddNewTransaction: complete', {}, loggr.DebugContext.f2c); + try { + const parsedTransaction = await parseNewTransaction( + txDetails, + nativeCurrency + ); - return parsedTransaction; - } catch (error) { - loggr.error(new Error('dataAddNewTransaction: failed'), { error }); - } -}; + const _pendingTransactions = [parsedTransaction, ...pendingTransactions]; + dispatch({ + payload: _pendingTransactions, + type: DATA_UPDATE_PENDING_TRANSACTIONS_SUCCESS, + }); + saveLocalPendingTransactions( + _pendingTransactions, + accountAddress, + network + ); -export const dataRemovePendingTransaction = ( - txHash: string, - network: Network -) => async ( - dispatch: ThunkDispatch< - AppState, - unknown, - DataUpdatePendingTransactionSuccessAction - >, - getState: AppGetState -) => { - loggr.debug('dataRemovePendingTransaction', { txHash }); - - const { pendingTransactions } = getState().data; - const { accountAddress } = getState().settings; - - const _pendingTransactions = pendingTransactions.filter(tx => { - // if we find the pending tx, filter it out - if (tx.hash === txHash && tx.network === network) { - loggr.debug('dataRemovePendingTransaction: removed tx', { txHash }); - return false; - } else { - return true; + loggr.debug( + 'dataAddNewTransaction: adding pending transactions', + {}, + loggr.DebugContext.f2c + ); + + if (parsedTransaction.from && parsedTransaction.nonce) { + dispatch( + // @ts-ignore-next-line + incrementNonce( + parsedTransaction.from, + parsedTransaction.nonce, + parsedTransaction.network + ) + ); + } + if ( + !disableTxnWatcher || + network !== Network.mainnet || + parsedTransaction?.network + ) { + loggr.debug( + 'dataAddNewTransaction: watching new pending transactions', + {}, + loggr.DebugContext.f2c + ); + dispatch( + watchPendingTransactions( + accountAddress, + parsedTransaction.network + ? TXN_WATCHER_MAX_TRIES_LAYER_2 + : TXN_WATCHER_MAX_TRIES, + null, + // @ts-expect-error `watchPendingTransactions` only takes 3 arguments. + provider + ) + ); + } + + loggr.debug( + 'dataAddNewTransaction: complete', + {}, + loggr.DebugContext.f2c + ); + + return parsedTransaction; + } catch (error) { + loggr.error(new Error('dataAddNewTransaction: failed'), { error }); } - }); + }; - dispatch({ - payload: _pendingTransactions, - type: DATA_UPDATE_PENDING_TRANSACTIONS_SUCCESS, - }); - saveLocalPendingTransactions(_pendingTransactions, accountAddress, network); -}; +export const dataRemovePendingTransaction = + (txHash: string, network: Network) => + async ( + dispatch: ThunkDispatch< + AppState, + unknown, + DataUpdatePendingTransactionSuccessAction + >, + getState: AppGetState + ) => { + loggr.debug('dataRemovePendingTransaction', { txHash }); + + const { pendingTransactions } = getState().data; + const { accountAddress } = getState().settings; + + const _pendingTransactions = pendingTransactions.filter(tx => { + // if we find the pending tx, filter it out + if (tx.hash === txHash && tx.network === network) { + loggr.debug('dataRemovePendingTransaction: removed tx', { txHash }); + return false; + } else { + return true; + } + }); + + dispatch({ + payload: _pendingTransactions, + type: DATA_UPDATE_PENDING_TRANSACTIONS_SUCCESS, + }); + saveLocalPendingTransactions(_pendingTransactions, accountAddress, network); + }; /** * Watches pending transactions and updates state and account local storage @@ -825,110 +836,110 @@ export const dataRemovePendingTransaction = ( * @param currentNonce The nonce of the last confirmed transaction, used to * determine if a transaction has been dropped. */ -export const dataWatchPendingTransactions = ( - provider: StaticJsonRpcProvider | null = null, - currentNonce = -1 -) => async ( - dispatch: ThunkDispatch< - AppState, - unknown, - DataLoadTransactionSuccessAction | DataUpdatePendingTransactionSuccessAction - >, - getState: AppGetState -) => { - const { pendingTransactions: pending } = getState().data; - if (isEmpty(pending)) { - return true; - } - let txStatusesDidChange = false; - const updatedPendingTransactions = await Promise.all( - pending.map(async tx => { - const updatedPendingTransaction: RainbowTransaction = { ...tx }; - const txHash = ethereumUtils.getHash(tx) || ''; - let pendingTransactionData: { - title: string; - minedAt: number | null; - pending: boolean; - status: TransactionStatus; - } | null = { - status: TransactionStatus.sending, - title: tx?.title || TransactionStatus.sending, - minedAt: null, - pending: true, - }; - return; - try { - logger.log('Checking pending tx with hash', txHash); - const p = - (await getProviderForNetwork(updatedPendingTransaction.network)) || - provider; - const txObj: TransactionResponse | undefined = await p.getTransaction( - txHash - ); - // if the nonce of last confirmed tx is higher than this pending tx then it got dropped - const nonceAlreadyIncluded = currentNonce > (tx?.nonce ?? txObj.nonce); - if ( - (txObj && txObj?.blockNumber && txObj?.blockHash) || - nonceAlreadyIncluded - ) { - // When speeding up a non "normal tx" we need to resubscribe - // because zerion "append" event isn't reliable - logger.log('TX CONFIRMED!', txObj); - if (!nonceAlreadyIncluded) { - appEvents.emit('transactionConfirmed', { - ...txObj, - internalType: tx.type, - }); - } - if (tx?.ensRegistration) { - fetchWalletENSDataAfterRegistration(); - } - - if (updatedPendingTransaction?.swap?.type === SwapType.crossChain) { - pendingTransactionData = await getTransactionSocketStatus( - updatedPendingTransaction - ); - if (!pendingTransactionData.pending) { +export const dataWatchPendingTransactions = + (provider: StaticJsonRpcProvider | null = null, currentNonce = -1) => + async ( + dispatch: ThunkDispatch< + AppState, + unknown, + | DataLoadTransactionSuccessAction + | DataUpdatePendingTransactionSuccessAction + >, + getState: AppGetState + ) => { + const { pendingTransactions: pending } = getState().data; + if (isEmpty(pending)) { + return true; + } + let txStatusesDidChange = false; + const updatedPendingTransactions = await Promise.all( + pending.map(async tx => { + const updatedPendingTransaction: RainbowTransaction = { ...tx }; + const txHash = ethereumUtils.getHash(tx) || ''; + let pendingTransactionData: { + title: string; + minedAt: number | null; + pending: boolean; + status: TransactionStatus; + } | null = { + status: TransactionStatus.sending, + title: tx?.title || TransactionStatus.sending, + minedAt: null, + pending: true, + }; + return; + try { + logger.log('Checking pending tx with hash', txHash); + const p = + (await getProviderForNetwork(updatedPendingTransaction.network)) || + provider; + const txObj: TransactionResponse | undefined = + await p.getTransaction(txHash); + // if the nonce of last confirmed tx is higher than this pending tx then it got dropped + const nonceAlreadyIncluded = + currentNonce > (tx?.nonce ?? txObj.nonce); + if ( + (txObj && txObj?.blockNumber && txObj?.blockHash) || + nonceAlreadyIncluded + ) { + // When speeding up a non "normal tx" we need to resubscribe + // because zerion "append" event isn't reliable + logger.log('TX CONFIRMED!', txObj); + if (!nonceAlreadyIncluded) { appEvents.emit('transactionConfirmed', { ...txObj, internalType: tx.type, }); + } + if (tx?.ensRegistration) { + fetchWalletENSDataAfterRegistration(); + } + + if (updatedPendingTransaction?.swap?.type === SwapType.crossChain) { + pendingTransactionData = await getTransactionSocketStatus( + updatedPendingTransaction + ); + if (!pendingTransactionData.pending) { + appEvents.emit('transactionConfirmed', { + ...txObj, + internalType: tx.type, + }); + txStatusesDidChange = true; + } + } else { + pendingTransactionData = getPendingTransactionData( + updatedPendingTransaction, + transactionStatus + ); txStatusesDidChange = true; } - } else { - pendingTransactionData = getPendingTransactionData( + } else if (tx.flashbots) { + pendingTransactionData = await getTransactionFlashbotStatus( updatedPendingTransaction, - transactionStatus + txHash ); - txStatusesDidChange = true; + if (pendingTransactionData && !pendingTransactionData.pending) { + txStatusesDidChange = true; + // decrement the nonce since it was dropped + // @ts-ignore-next-line + dispatch(decrementNonce(tx.from!, tx.nonce!, Network.mainnet)); + } } - } else if (tx.flashbots) { - pendingTransactionData = await getTransactionFlashbotStatus( - updatedPendingTransaction, - txHash - ); - if (pendingTransactionData && !pendingTransactionData.pending) { - txStatusesDidChange = true; - // decrement the nonce since it was dropped - // @ts-ignore-next-line - dispatch(decrementNonce(tx.from!, tx.nonce!, Network.mainnet)); + if (pendingTransactionData) { + updatedPendingTransaction.title = pendingTransactionData.title; + updatedPendingTransaction.status = pendingTransactionData.status; + updatedPendingTransaction.pending = pendingTransactionData.pending; + updatedPendingTransaction.minedAt = pendingTransactionData.minedAt; } + } catch (error) { + logger.log('Error watching pending txn', error); } - if (pendingTransactionData) { - updatedPendingTransaction.title = pendingTransactionData.title; - updatedPendingTransaction.status = pendingTransactionData.status; - updatedPendingTransaction.pending = pendingTransactionData.pending; - updatedPendingTransaction.minedAt = pendingTransactionData.minedAt; - } - } catch (error) { - logger.log('Error watching pending txn', error); - } - return updatedPendingTransaction; - }) - ); + return updatedPendingTransaction; + }) + ); - return false; -}; + return false; + }; /** * Updates a transaction in state and account local storage and watches it, @@ -940,42 +951,44 @@ export const dataWatchPendingTransactions = ( * @param provider A `StaticJsonRpcProvider`, or null to use the default * provider. */ -export const dataUpdateTransaction = ( - txHash: string, - txObj: RainbowTransaction, - watch: boolean, - provider: StaticJsonRpcProvider | null = null -) => async ( - dispatch: ThunkDispatch< - AppState, - unknown, - DataUpdatePendingTransactionSuccessAction - >, - getState: AppGetState -) => { - return; - const { pendingTransactions } = getState().data; - - const allOtherTx = pendingTransactions.filter(tx => tx.hash !== txHash); - const updatedTransactions = [txObj].concat(allOtherTx); - - dispatch({ - payload: updatedTransactions, - type: DATA_UPDATE_PENDING_TRANSACTIONS_SUCCESS, - }); - const { accountAddress, network } = getState().settings; - saveLocalPendingTransactions(updatedTransactions, accountAddress, network); - // Always watch cancellation and speed up - if (watch) { - dispatch( - watchPendingTransactions( - accountAddress, - txObj.network ? TXN_WATCHER_MAX_TRIES_LAYER_2 : TXN_WATCHER_MAX_TRIES, - provider - ) - ); - } -}; +export const dataUpdateTransaction = + ( + txHash: string, + txObj: RainbowTransaction, + watch: boolean, + provider: StaticJsonRpcProvider | null = null + ) => + async ( + dispatch: ThunkDispatch< + AppState, + unknown, + DataUpdatePendingTransactionSuccessAction + >, + getState: AppGetState + ) => { + return; + const { pendingTransactions } = getState().data; + + const allOtherTx = pendingTransactions.filter(tx => tx.hash !== txHash); + const updatedTransactions = [txObj].concat(allOtherTx); + + dispatch({ + payload: updatedTransactions, + type: DATA_UPDATE_PENDING_TRANSACTIONS_SUCCESS, + }); + const { accountAddress, network } = getState().settings; + saveLocalPendingTransactions(updatedTransactions, accountAddress, network); + // Always watch cancellation and speed up + if (watch) { + dispatch( + watchPendingTransactions( + accountAddress, + txObj.network ? TXN_WATCHER_MAX_TRIES_LAYER_2 : TXN_WATCHER_MAX_TRIES, + provider + ) + ); + } + }; /** * Checks the current account's transaction count and subscribes to pending @@ -986,36 +999,36 @@ export const dataUpdateTransaction = ( * @param provider A `StaticJsonRpcProvider`, or null to use the default * provider. */ -export const checkPendingTransactionsOnInitialize = ( - accountAddressToWatch: string, - provider: StaticJsonRpcProvider | null = null -) => async ( - dispatch: ThunkDispatch, - getState: AppGetState -) => { - return; - const { - accountAddress: currentAccountAddress, - network, - } = getState().settings; - if (currentAccountAddress !== accountAddressToWatch) return; - const providerForNetwork = await getProviderForNetwork(network); - const currentNonce = await ( - provider || providerForNetwork - ).getTransactionCount(currentAccountAddress, 'latest'); - const notPendingTxs = await dispatch( - dataWatchPendingTransactions(provider, currentNonce) - ); - if (!notPendingTxs) { - dispatch( - watchPendingTransactions( - currentAccountAddress, - TXN_WATCHER_MAX_TRIES, - null - ) +export const checkPendingTransactionsOnInitialize = + ( + accountAddressToWatch: string, + provider: StaticJsonRpcProvider | null = null + ) => + async ( + dispatch: ThunkDispatch, + getState: AppGetState + ) => { + return; + const { accountAddress: currentAccountAddress, network } = + getState().settings; + if (currentAccountAddress !== accountAddressToWatch) return; + const providerForNetwork = await getProviderForNetwork(network); + const currentNonce = await ( + provider || providerForNetwork + ).getTransactionCount(currentAccountAddress, 'latest'); + const notPendingTxs = await dispatch( + dataWatchPendingTransactions(provider, currentNonce) ); - } -}; + if (!notPendingTxs) { + dispatch( + watchPendingTransactions( + currentAccountAddress, + TXN_WATCHER_MAX_TRIES, + null + ) + ); + } + }; /** * Repeatedly attempts to subscribe to transaction updates using @@ -1028,35 +1041,37 @@ export const checkPendingTransactionsOnInitialize = ( * @param provider A `StaticJsonRpcProvider`, or null to use the default * provider. */ -export const watchPendingTransactions = ( - accountAddressToWatch: string, - remainingTries: number = TXN_WATCHER_MAX_TRIES, - provider: StaticJsonRpcProvider | null = null -) => async ( - dispatch: ThunkDispatch, - getState: AppGetState -) => { - return; - pendingTransactionsHandle && clearTimeout(pendingTransactionsHandle); - if (remainingTries === 0) return; - - const { accountAddress: currentAccountAddress } = getState().settings; - if (currentAccountAddress !== accountAddressToWatch) return; - - const done = await dispatch(dataWatchPendingTransactions(provider)); - - if (!done) { - pendingTransactionsHandle = setTimeout(() => { - dispatch( - watchPendingTransactions( - accountAddressToWatch, - remainingTries - 1, - provider - ) - ); - }, TXN_WATCHER_POLL_INTERVAL); - } -}; +export const watchPendingTransactions = + ( + accountAddressToWatch: string, + remainingTries: number = TXN_WATCHER_MAX_TRIES, + provider: StaticJsonRpcProvider | null = null + ) => + async ( + dispatch: ThunkDispatch, + getState: AppGetState + ) => { + return; + pendingTransactionsHandle && clearTimeout(pendingTransactionsHandle); + if (remainingTries === 0) return; + + const { accountAddress: currentAccountAddress } = getState().settings; + if (currentAccountAddress !== accountAddressToWatch) return; + + const done = await dispatch(dataWatchPendingTransactions(provider)); + + if (!done) { + pendingTransactionsHandle = setTimeout(() => { + dispatch( + watchPendingTransactions( + accountAddressToWatch, + remainingTries - 1, + provider + ) + ); + }, TXN_WATCHER_POLL_INTERVAL); + } + }; // -- Reducer ----------------------------------------- // const INITIAL_STATE: DataState = { diff --git a/src/redux/editOptions.ts b/src/redux/editOptions.ts index d171cd1a2d0..f5bb88b5599 100644 --- a/src/redux/editOptions.ts +++ b/src/redux/editOptions.ts @@ -37,14 +37,14 @@ type EditOptionsAction = EditOptionsSetHiddenCoinsAction; * * @param coins The `uniqueId`s of the new hidden coins. */ -export const setHiddenCoins = (coins: EditOptionsState['hiddenCoins']) => ( - dispatch: Dispatch -) => { - dispatch({ - payload: coins, - type: SET_HIDDEN_COINS, - }); -}; +export const setHiddenCoins = + (coins: EditOptionsState['hiddenCoins']) => + (dispatch: Dispatch) => { + dispatch({ + payload: coins, + type: SET_HIDDEN_COINS, + }); + }; // -- Reducer ----------------------------------------- // const INITIAL_STATE: EditOptionsState = { diff --git a/src/redux/ensRegistration.ts b/src/redux/ensRegistration.ts index e65ee6aad0b..71a6a135344 100644 --- a/src/redux/ensRegistration.ts +++ b/src/redux/ensRegistration.ts @@ -132,362 +132,353 @@ export type EnsRegistrationActionTypes = /** * Loads initial state from account local storage. */ -export const ensRegistrationsLoadState = () => async ( - dispatch: Dispatch, - getState: AppGetState -) => { - const { accountAddress, network } = getState().settings; - try { - const registrations = await getLocalENSRegistrations( - accountAddress, - network - ); - dispatch({ - payload: { registrations }, - type: ENS_LOAD_STATE, - }); - // eslint-disable-next-line no-empty - } catch (error) {} -}; +export const ensRegistrationsLoadState = + () => + async ( + dispatch: Dispatch, + getState: AppGetState + ) => { + const { accountAddress, network } = getState().settings; + try { + const registrations = await getLocalENSRegistrations( + accountAddress, + network + ); + dispatch({ + payload: { registrations }, + type: ENS_LOAD_STATE, + }); + // eslint-disable-next-line no-empty + } catch (error) {} + }; -export const startRegistration = ( - name: string, - mode: keyof typeof REGISTRATION_MODES -) => async (dispatch: AppDispatch, getState: AppGetState) => { - const { - ensRegistration: { registrations }, - settings: { accountAddress }, - } = getState(); - const lcAccountAddress = accountAddress.toLowerCase(); - const accountRegistrations = registrations?.[lcAccountAddress] || {}; - const registration = accountRegistrations[name] || {}; - - const updatedEnsRegistrationManager = { - currentRegistrationName: name, - registrations: { - ...registrations, - [lcAccountAddress]: { - ...accountRegistrations, - [name]: { ...registration, mode, name }, +export const startRegistration = + (name: string, mode: keyof typeof REGISTRATION_MODES) => + async (dispatch: AppDispatch, getState: AppGetState) => { + const { + ensRegistration: { registrations }, + settings: { accountAddress }, + } = getState(); + const lcAccountAddress = accountAddress.toLowerCase(); + const accountRegistrations = registrations?.[lcAccountAddress] || {}; + const registration = accountRegistrations[name] || {}; + + const updatedEnsRegistrationManager = { + currentRegistrationName: name, + registrations: { + ...registrations, + [lcAccountAddress]: { + ...accountRegistrations, + [name]: { ...registration, mode, name }, + }, }, - }, + }; + dispatch({ + payload: updatedEnsRegistrationManager, + type: ENS_START_REGISTRATION, + }); }; - dispatch({ - payload: updatedEnsRegistrationManager, - type: ENS_START_REGISTRATION, - }); -}; -export const continueRegistration = (name: string) => async ( - dispatch: AppDispatch -) => { - const updatedEnsRegistrationManager = { - currentRegistrationName: name, +export const continueRegistration = + (name: string) => async (dispatch: AppDispatch) => { + const updatedEnsRegistrationManager = { + currentRegistrationName: name, + }; + dispatch({ + payload: updatedEnsRegistrationManager, + type: ENS_CONTINUE_REGISTRATION, + }); }; - dispatch({ - payload: updatedEnsRegistrationManager, - type: ENS_CONTINUE_REGISTRATION, - }); -}; -export const removeExpiredRegistrations = () => async ( - dispatch: AppDispatch, - getState: AppGetState -) => { - const { - ensRegistration: { registrations }, - settings: { accountAddress }, - } = getState(); +export const removeExpiredRegistrations = + () => async (dispatch: AppDispatch, getState: AppGetState) => { + const { + ensRegistration: { registrations }, + settings: { accountAddress }, + } = getState(); - const accountRegistrations = - registrations?.[accountAddress.toLowerCase()] || []; + const accountRegistrations = + registrations?.[accountAddress.toLowerCase()] || []; - const registrationsArray = Object.values(accountRegistrations); + const registrationsArray = Object.values(accountRegistrations); - const sevenDaysAgoMs = subDays(new Date(), 7).getTime(); + const sevenDaysAgoMs = subDays(new Date(), 7).getTime(); - const activeRegistrations = registrationsArray.filter(registration => - registration?.commitTransactionConfirmedAt - ? registration?.commitTransactionConfirmedAt >= sevenDaysAgoMs - : true - ); + const activeRegistrations = registrationsArray.filter(registration => + registration?.commitTransactionConfirmedAt + ? registration?.commitTransactionConfirmedAt >= sevenDaysAgoMs + : true + ); - dispatch({ - payload: activeRegistrations, - type: ENS_REMOVE_EXPIRED_REGISTRATIONS, - }); -}; + dispatch({ + payload: activeRegistrations, + type: ENS_REMOVE_EXPIRED_REGISTRATIONS, + }); + }; -export const setInitialRecords = (records: Records) => async ( - dispatch: AppDispatch, - getState: AppGetState -) => { - const { - ensRegistration: { registrations, currentRegistrationName }, - settings: { accountAddress }, - } = getState(); - const lcAccountAddress = accountAddress.toLowerCase(); - const accountRegistrations = registrations?.[lcAccountAddress] || {}; - const registration = accountRegistrations[currentRegistrationName] || {}; - - const updatedEnsRegistrationManagerForAccount = { - registrations: { - ...registrations, - [lcAccountAddress]: { - ...accountRegistrations, - [currentRegistrationName]: { - ...registration, - initialRecords: records, - records, +export const setInitialRecords = + (records: Records) => + async (dispatch: AppDispatch, getState: AppGetState) => { + const { + ensRegistration: { registrations, currentRegistrationName }, + settings: { accountAddress }, + } = getState(); + const lcAccountAddress = accountAddress.toLowerCase(); + const accountRegistrations = registrations?.[lcAccountAddress] || {}; + const registration = accountRegistrations[currentRegistrationName] || {}; + + const updatedEnsRegistrationManagerForAccount = { + registrations: { + ...registrations, + [lcAccountAddress]: { + ...accountRegistrations, + [currentRegistrationName]: { + ...registration, + initialRecords: records, + records, + }, }, }, - }, + }; + dispatch({ + payload: updatedEnsRegistrationManagerForAccount, + type: ENS_REGISTRATION_SET_INITIAL_RECORDS, + }); }; - dispatch({ - payload: updatedEnsRegistrationManagerForAccount, - type: ENS_REGISTRATION_SET_INITIAL_RECORDS, - }); -}; -export const setChangedRecords = (changedRecords: Records) => async ( - dispatch: AppDispatch, - getState: AppGetState -) => { - const { - ensRegistration: { registrations, currentRegistrationName }, - settings: { accountAddress }, - } = getState(); - const lcAccountAddress = accountAddress.toLowerCase(); - const accountRegistrations = registrations?.[lcAccountAddress] || {}; - const registration = accountRegistrations[currentRegistrationName] || {}; - - const updatedEnsRegistrationManagerForAccount = { - registrations: { - ...registrations, - [lcAccountAddress]: { - ...accountRegistrations, - [currentRegistrationName]: { - ...registration, - changedRecords, +export const setChangedRecords = + (changedRecords: Records) => + async (dispatch: AppDispatch, getState: AppGetState) => { + const { + ensRegistration: { registrations, currentRegistrationName }, + settings: { accountAddress }, + } = getState(); + const lcAccountAddress = accountAddress.toLowerCase(); + const accountRegistrations = registrations?.[lcAccountAddress] || {}; + const registration = accountRegistrations[currentRegistrationName] || {}; + + const updatedEnsRegistrationManagerForAccount = { + registrations: { + ...registrations, + [lcAccountAddress]: { + ...accountRegistrations, + [currentRegistrationName]: { + ...registration, + changedRecords, + }, }, }, - }, + }; + dispatch({ + payload: updatedEnsRegistrationManagerForAccount, + type: ENS_REGISTRATION_SET_CHANGED_RECORDS, + }); }; - dispatch({ - payload: updatedEnsRegistrationManagerForAccount, - type: ENS_REGISTRATION_SET_CHANGED_RECORDS, - }); -}; -export const updateRecords = (records: Records) => async ( - dispatch: AppDispatch, - getState: AppGetState -) => { - const { - ensRegistration: { registrations, currentRegistrationName }, - settings: { accountAddress }, - } = getState(); - const lcAccountAddress = accountAddress.toLowerCase(); - const accountRegistrations = registrations?.[lcAccountAddress] || {}; - const registration = accountRegistrations[currentRegistrationName] || {}; - - const updatedEnsRegistrationManagerForAccount = { - registrations: { - ...registrations, - [lcAccountAddress]: { - ...accountRegistrations, - [currentRegistrationName]: { ...registration, records }, +export const updateRecords = + (records: Records) => + async (dispatch: AppDispatch, getState: AppGetState) => { + const { + ensRegistration: { registrations, currentRegistrationName }, + settings: { accountAddress }, + } = getState(); + const lcAccountAddress = accountAddress.toLowerCase(); + const accountRegistrations = registrations?.[lcAccountAddress] || {}; + const registration = accountRegistrations[currentRegistrationName] || {}; + + const updatedEnsRegistrationManagerForAccount = { + registrations: { + ...registrations, + [lcAccountAddress]: { + ...accountRegistrations, + [currentRegistrationName]: { ...registration, records }, + }, }, - }, + }; + dispatch({ + payload: updatedEnsRegistrationManagerForAccount, + type: ENS_REGISTRATION_UPDATE_RECORDS, + }); }; - dispatch({ - payload: updatedEnsRegistrationManagerForAccount, - type: ENS_REGISTRATION_UPDATE_RECORDS, - }); -}; -export const updateRecordByKey = (key: string, value: string) => async ( - dispatch: AppDispatch, - getState: AppGetState -) => { - const { - ensRegistration: { registrations, currentRegistrationName }, - settings: { accountAddress }, - } = getState(); - const lcAccountAddress = accountAddress.toLowerCase(); - - const accountRegistrations = registrations?.[lcAccountAddress] || {}; - const registration = accountRegistrations[currentRegistrationName] || {}; - const registrationRecords = registration?.records || {}; - const updatedEnsRegistrationManagerForAccount = { - registrations: { - ...registrations, - [lcAccountAddress]: { - ...accountRegistrations, - [currentRegistrationName]: { - ...registration, - records: { ...registrationRecords, [key]: value }, +export const updateRecordByKey = + (key: string, value: string) => + async (dispatch: AppDispatch, getState: AppGetState) => { + const { + ensRegistration: { registrations, currentRegistrationName }, + settings: { accountAddress }, + } = getState(); + const lcAccountAddress = accountAddress.toLowerCase(); + + const accountRegistrations = registrations?.[lcAccountAddress] || {}; + const registration = accountRegistrations[currentRegistrationName] || {}; + const registrationRecords = registration?.records || {}; + const updatedEnsRegistrationManagerForAccount = { + registrations: { + ...registrations, + [lcAccountAddress]: { + ...accountRegistrations, + [currentRegistrationName]: { + ...registration, + records: { ...registrationRecords, [key]: value }, + }, }, }, - }, + }; + dispatch({ + payload: updatedEnsRegistrationManagerForAccount, + type: ENS_REGISTRATION_UPDATE_RECORDS, + }); }; - dispatch({ - payload: updatedEnsRegistrationManagerForAccount, - type: ENS_REGISTRATION_UPDATE_RECORDS, - }); -}; -export const removeRecordByKey = (key: string) => async ( - dispatch: AppDispatch, - getState: AppGetState -) => { - const { - ensRegistration: { registrations, currentRegistrationName }, - settings: { accountAddress }, - } = getState(); - - const lcAccountAddress = accountAddress.toLowerCase(); - const accountRegistrations = registrations?.[lcAccountAddress] || {}; - const registration = accountRegistrations[currentRegistrationName] || {}; - const registrationRecords = registration?.records || {}; - - const newRecords = omitFlatten(registrationRecords, key as ENS_RECORDS); - - const updatedEnsRegistrationManagerForAccount = { - registrations: { - ...registrations, - [lcAccountAddress]: { - ...accountRegistrations, - [currentRegistrationName]: { - ...registration, - records: newRecords, +export const removeRecordByKey = + (key: string) => async (dispatch: AppDispatch, getState: AppGetState) => { + const { + ensRegistration: { registrations, currentRegistrationName }, + settings: { accountAddress }, + } = getState(); + + const lcAccountAddress = accountAddress.toLowerCase(); + const accountRegistrations = registrations?.[lcAccountAddress] || {}; + const registration = accountRegistrations[currentRegistrationName] || {}; + const registrationRecords = registration?.records || {}; + + const newRecords = omitFlatten(registrationRecords, key as ENS_RECORDS); + + const updatedEnsRegistrationManagerForAccount = { + registrations: { + ...registrations, + [lcAccountAddress]: { + ...accountRegistrations, + [currentRegistrationName]: { + ...registration, + records: newRecords, + }, }, }, - }, - }; + }; - dispatch({ - payload: updatedEnsRegistrationManagerForAccount, - type: ENS_REGISTRATION_REMOVE_RECORD_BY_KEY, - }); -}; + dispatch({ + payload: updatedEnsRegistrationManagerForAccount, + type: ENS_REGISTRATION_REMOVE_RECORD_BY_KEY, + }); + }; -export const saveCommitRegistrationParameters = ( - registrationParameters: - | RegistrationParameters - | TransactionRegistrationParameters -) => async (dispatch: AppDispatch, getState: AppGetState) => { - const { - ensRegistration: { registrations, currentRegistrationName }, - settings: { accountAddress }, - } = getState(); - const registrationName = - (registrationParameters as RegistrationParameters)?.name || - currentRegistrationName; - const lcAccountAddress = accountAddress.toLowerCase(); - const accountRegistrations = registrations?.[lcAccountAddress] || {}; - const registration = accountRegistrations[registrationName] || {}; - const updatedEnsRegistrationManager = { - registrations: { - ...registrations, - [lcAccountAddress]: { - ...accountRegistrations, - [registrationName]: { - ...registration, - ...registrationParameters, +export const saveCommitRegistrationParameters = + ( + registrationParameters: + | RegistrationParameters + | TransactionRegistrationParameters + ) => + async (dispatch: AppDispatch, getState: AppGetState) => { + const { + ensRegistration: { registrations, currentRegistrationName }, + settings: { accountAddress }, + } = getState(); + const registrationName = + (registrationParameters as RegistrationParameters)?.name || + currentRegistrationName; + const lcAccountAddress = accountAddress.toLowerCase(); + const accountRegistrations = registrations?.[lcAccountAddress] || {}; + const registration = accountRegistrations[registrationName] || {}; + const updatedEnsRegistrationManager = { + registrations: { + ...registrations, + [lcAccountAddress]: { + ...accountRegistrations, + [registrationName]: { + ...registration, + ...registrationParameters, + }, }, }, - }, - }; + }; - saveLocalENSRegistrations( - updatedEnsRegistrationManager.registrations, - accountAddress, - NetworkTypes.mainnet - ); + saveLocalENSRegistrations( + updatedEnsRegistrationManager.registrations, + accountAddress, + NetworkTypes.mainnet + ); - dispatch({ - payload: updatedEnsRegistrationManager, - type: ENS_SAVE_COMMIT_REGISTRATION_PARAMETERS, - }); -}; + dispatch({ + payload: updatedEnsRegistrationManager, + type: ENS_SAVE_COMMIT_REGISTRATION_PARAMETERS, + }); + }; -export const clearCurrentRegistrationName = () => async ( - dispatch: AppDispatch -) => { - dispatch({ - type: ENS_CLEAR_CURRENT_REGISTRATION_NAME, - }); -}; +export const clearCurrentRegistrationName = + () => async (dispatch: AppDispatch) => { + dispatch({ + type: ENS_CLEAR_CURRENT_REGISTRATION_NAME, + }); + }; -export const updateTransactionRegistrationParameters = ( - registrationParameters: TransactionRegistrationParameters -) => async (dispatch: AppDispatch, getState: AppGetState) => { - const { - ensRegistration: { registrations, currentRegistrationName }, - settings: { accountAddress }, - } = getState(); - - const lcAccountAddress = accountAddress.toLowerCase(); - const accountRegistrations = registrations?.[lcAccountAddress] || {}; - const registration = accountRegistrations[currentRegistrationName] || {}; - const updatedEnsRegistrationManager = { - registrations: { - ...registrations, - [lcAccountAddress]: { - ...accountRegistrations, - [currentRegistrationName]: { - ...registration, - ...registrationParameters, +export const updateTransactionRegistrationParameters = + (registrationParameters: TransactionRegistrationParameters) => + async (dispatch: AppDispatch, getState: AppGetState) => { + const { + ensRegistration: { registrations, currentRegistrationName }, + settings: { accountAddress }, + } = getState(); + + const lcAccountAddress = accountAddress.toLowerCase(); + const accountRegistrations = registrations?.[lcAccountAddress] || {}; + const registration = accountRegistrations[currentRegistrationName] || {}; + const updatedEnsRegistrationManager = { + registrations: { + ...registrations, + [lcAccountAddress]: { + ...accountRegistrations, + [currentRegistrationName]: { + ...registration, + ...registrationParameters, + }, }, }, - }, - }; + }; - saveLocalENSRegistrations( - updatedEnsRegistrationManager.registrations, - accountAddress, - NetworkTypes.mainnet - ); + saveLocalENSRegistrations( + updatedEnsRegistrationManager.registrations, + accountAddress, + NetworkTypes.mainnet + ); - dispatch({ - payload: updatedEnsRegistrationManager, - type: ENS_UPDATE_REGISTRATION_PARAMETERS, - }); -}; + dispatch({ + payload: updatedEnsRegistrationManager, + type: ENS_UPDATE_REGISTRATION_PARAMETERS, + }); + }; -export const removeRegistrationByName = (name: string) => async ( - dispatch: AppDispatch, - getState: AppGetState -) => { - const { - ensRegistration: { registrations }, - settings: { accountAddress }, - } = getState(); - - const lcAccountAddress = accountAddress.toLowerCase(); - const accountRegistrations = registrations?.[lcAccountAddress] || {}; - delete accountRegistrations?.[name]; - const updatedEnsRegistrationManager = { - registrations: { - ...registrations, - [lcAccountAddress]: { - ...accountRegistrations, +export const removeRegistrationByName = + (name: string) => async (dispatch: AppDispatch, getState: AppGetState) => { + const { + ensRegistration: { registrations }, + settings: { accountAddress }, + } = getState(); + + const lcAccountAddress = accountAddress.toLowerCase(); + const accountRegistrations = registrations?.[lcAccountAddress] || {}; + delete accountRegistrations?.[name]; + const updatedEnsRegistrationManager = { + registrations: { + ...registrations, + [lcAccountAddress]: { + ...accountRegistrations, + }, }, - }, - }; + }; - saveLocalENSRegistrations( - updatedEnsRegistrationManager.registrations, - accountAddress, - NetworkTypes.mainnet - ); + saveLocalENSRegistrations( + updatedEnsRegistrationManager.registrations, + accountAddress, + NetworkTypes.mainnet + ); - dispatch({ - payload: updatedEnsRegistrationManager, - type: ENS_UPDATE_REGISTRATION_PARAMETERS, - }); -}; + dispatch({ + payload: updatedEnsRegistrationManager, + type: ENS_UPDATE_REGISTRATION_PARAMETERS, + }); + }; // -- Reducer ----------------------------------------- // const INITIAL_STATE: ENSRegistrationState = { diff --git a/src/redux/explorer.ts b/src/redux/explorer.ts index aa6648fb292..5799b5ef2a9 100644 --- a/src/redux/explorer.ts +++ b/src/redux/explorer.ts @@ -193,24 +193,22 @@ const portfolioSubscription = ( * @param address The address to subscribe to. * @returns Arguments for an `emit` function call. */ -export const notificationsSubscription = (address: string) => ( - _: Dispatch, - getState: AppGetState -) => { - const { addressSocket } = getState().explorer; - - const payload: SocketEmitArguments = [ - 'get', - { - payload: { - address, - action: 'subscribe', +export const notificationsSubscription = + (address: string) => (_: Dispatch, getState: AppGetState) => { + const { addressSocket } = getState().explorer; + + const payload: SocketEmitArguments = [ + 'get', + { + payload: { + address, + action: 'subscribe', + }, + scope: ['notifications'], }, - scope: ['notifications'], - }, - ]; - addressSocket?.emit(...payload); -}; + ]; + addressSocket?.emit(...payload); + }; /** * Configures an asset price subscription. @@ -293,39 +291,34 @@ const l2AddressTransactionHistoryRequest = ( * * @param assetAddress The address or addresses to fetch. */ -export const fetchAssetPrices = (assetAddress: string | string[]) => ( - _: Dispatch, - getState: AppGetState -) => { - const { assetsSocket } = getState().explorer; - const { nativeCurrency } = getState().settings; - - const assetCodes = Array.isArray(assetAddress) - ? assetAddress - : [assetAddress]; - - const payload: SocketEmitArguments = [ - 'get', - { - payload: { - asset_codes: assetCodes, - currency: toLower(nativeCurrency), +export const fetchAssetPrices = + (assetAddress: string | string[]) => (_: Dispatch, getState: AppGetState) => { + const { assetsSocket } = getState().explorer; + const { nativeCurrency } = getState().settings; + + const assetCodes = Array.isArray(assetAddress) + ? assetAddress + : [assetAddress]; + + const payload: SocketEmitArguments = [ + 'get', + { + payload: { + asset_codes: assetCodes, + currency: toLower(nativeCurrency), + }, + scope: ['prices'], }, - scope: ['prices'], - }, - ]; - assetsSocket?.emit(...payload); -}; + ]; + assetsSocket?.emit(...payload); + }; /** * Unsubscribes from existing asset subscriptions. */ const explorerUnsubscribe = () => (_: Dispatch, getState: AppGetState) => { - const { - addressSocket, - addressSubscribed, - assetsSocket, - } = getState().explorer; + const { addressSocket, addressSubscribed, assetsSocket } = + getState().explorer; const { nativeCurrency } = getState().settings; const pairs = rainbowTokenList.CURATED_TOKENS; if (!isNil(addressSocket)) { @@ -345,63 +338,65 @@ const explorerUnsubscribe = () => (_: Dispatch, getState: AppGetState) => { /** * Clears the explorer's state and unsubscribes from listeners. */ -export const explorerClearState = () => ( - dispatch: ThunkDispatch -) => { - dispatch(explorerUnsubscribe()); - dispatch({ type: EXPLORER_CLEAR_STATE }); -}; +export const explorerClearState = + () => + (dispatch: ThunkDispatch) => { + dispatch(explorerUnsubscribe()); + dispatch({ type: EXPLORER_CLEAR_STATE }); + }; /** * Initializes the explorer, creating sockets and configuring listeners. */ -export const explorerInit = () => async ( - dispatch: ThunkDispatch, - getState: AppGetState -) => { - const { network, accountAddress, nativeCurrency } = getState().settings; - const pairs = rainbowTokenList.CURATED_TOKENS; - const { addressSocket, assetsSocket } = getState().explorer; - - // if there is another socket unsubscribe first - if (addressSocket || assetsSocket) { - dispatch(explorerUnsubscribe()); - } +export const explorerInit = + () => + async ( + dispatch: ThunkDispatch, + getState: AppGetState + ) => { + const { network, accountAddress, nativeCurrency } = getState().settings; + const pairs = rainbowTokenList.CURATED_TOKENS; + const { addressSocket, assetsSocket } = getState().explorer; + + // if there is another socket unsubscribe first + if (addressSocket || assetsSocket) { + dispatch(explorerUnsubscribe()); + } - const provider = await getProviderForNetwork(network); - const providerUrl = provider?.connection?.url; - if (isHardHat(providerUrl) || network !== Network.mainnet) { - return; - } + const provider = await getProviderForNetwork(network); + const providerUrl = provider?.connection?.url; + if (isHardHat(providerUrl) || network !== Network.mainnet) { + return; + } - const newAddressSocket = createSocket('address'); - const newAssetsSocket = createSocket('assets'); - dispatch({ - payload: { - addressSocket: newAddressSocket, - addressSubscribed: accountAddress, - assetsSocket: newAssetsSocket, - }, - type: EXPLORER_UPDATE_SOCKETS, - }); + const newAddressSocket = createSocket('address'); + const newAssetsSocket = createSocket('assets'); + dispatch({ + payload: { + addressSocket: newAddressSocket, + addressSubscribed: accountAddress, + assetsSocket: newAssetsSocket, + }, + type: EXPLORER_UPDATE_SOCKETS, + }); - dispatch(listenOnAddressMessages(newAddressSocket)); + dispatch(listenOnAddressMessages(newAddressSocket)); - newAddressSocket.on(messages.CONNECT, () => { - newAddressSocket.emit( - ...addressSubscription(accountAddress, nativeCurrency) - ); - }); + newAddressSocket.on(messages.CONNECT, () => { + newAddressSocket.emit( + ...addressSubscription(accountAddress, nativeCurrency) + ); + }); - dispatch(listenOnAssetMessages(newAssetsSocket)); + dispatch(listenOnAssetMessages(newAssetsSocket)); - newAssetsSocket.on(messages.CONNECT, () => { - dispatch(emitAssetRequest(keys(pairs))); + newAssetsSocket.on(messages.CONNECT, () => { + dispatch(emitAssetRequest(keys(pairs))); - // we want to get ETH info ASAP - dispatch(emitAssetRequest(ETH_ADDRESS)); - }); -}; + // we want to get ETH info ASAP + dispatch(emitAssetRequest(ETH_ADDRESS)); + }); + }; /** * Emits a portfolio request. The result is handled by a listener in @@ -410,15 +405,14 @@ export const explorerInit = () => async ( * @param address The address. * @param currency The currency to use. */ -export const emitPortfolioRequest = (address: string, currency?: string) => ( - _: Dispatch, - getState: AppGetState -) => { - const nativeCurrency = currency || getState().settings.nativeCurrency; - const { addressSocket } = getState().explorer; - - addressSocket?.emit(...portfolioSubscription(address, nativeCurrency)); -}; +export const emitPortfolioRequest = + (address: string, currency?: string) => + (_: Dispatch, getState: AppGetState) => { + const nativeCurrency = currency || getState().settings.nativeCurrency; + const { addressSocket } = getState().explorer; + + addressSocket?.emit(...portfolioSubscription(address, nativeCurrency)); + }; /** * Subscribes to asset price information. The result is handled by a listener @@ -426,163 +420,160 @@ export const emitPortfolioRequest = (address: string, currency?: string) => ( * * @param assetAddress The asset address or addresses to request. */ -export const emitAssetRequest = (assetAddress: string | string[]) => ( - _: Dispatch, - getState: AppGetState -) => { - const { nativeCurrency } = getState().settings; - const { assetsSocket } = getState().explorer; - - const assetCodes = Array.isArray(assetAddress) - ? assetAddress - : [assetAddress]; +export const emitAssetRequest = + (assetAddress: string | string[]) => (_: Dispatch, getState: AppGetState) => { + const { nativeCurrency } = getState().settings; + const { assetsSocket } = getState().explorer; - const newAssetsCodes = assetCodes.filter( - code => !TokensListenedCache?.[nativeCurrency]?.[code] - ); + const assetCodes = Array.isArray(assetAddress) + ? assetAddress + : [assetAddress]; - newAssetsCodes.forEach(code => { - if (!TokensListenedCache?.[nativeCurrency]) { - TokensListenedCache[nativeCurrency] = {}; - } - assetsSocket && (TokensListenedCache[nativeCurrency][code] = true); - }); + const newAssetsCodes = assetCodes.filter( + code => !TokensListenedCache?.[nativeCurrency]?.[code] + ); - if (assetsSocket) { - if (newAssetsCodes.length > 0) { - assetsSocket.emit( - ...assetPricesSubscription(newAssetsCodes, nativeCurrency) - ); - assetsSocket.emit(...ethUSDSubscription); - return true; + newAssetsCodes.forEach(code => { + if (!TokensListenedCache?.[nativeCurrency]) { + TokensListenedCache[nativeCurrency] = {}; + } + assetsSocket && (TokensListenedCache[nativeCurrency][code] = true); + }); + + if (assetsSocket) { + if (newAssetsCodes.length > 0) { + assetsSocket.emit( + ...assetPricesSubscription(newAssetsCodes, nativeCurrency) + ); + assetsSocket.emit(...ethUSDSubscription); + return true; + } + } else { + setTimeout(() => emitAssetRequest(assetAddress), 100); } - } else { - setTimeout(() => emitAssetRequest(assetAddress), 100); - } - return false; -}; + return false; + }; /** * Emits a layer-2 transaction history request for the current address. The * result is handled by a listener in `listenOnAddressMessages`. */ -export const emitL2TransactionHistoryRequest = () => ( - _: Dispatch, - getState: AppGetState -) => { - const { accountAddress, nativeCurrency } = getState().settings; - const { addressSocket } = getState().explorer; - addressSocket!.emit( - ...l2AddressTransactionHistoryRequest(accountAddress, nativeCurrency) - ); -}; +export const emitL2TransactionHistoryRequest = + () => (_: Dispatch, getState: AppGetState) => { + const { accountAddress, nativeCurrency } = getState().settings; + const { addressSocket } = getState().explorer; + addressSocket!.emit( + ...l2AddressTransactionHistoryRequest(accountAddress, nativeCurrency) + ); + }; /** * Adds asset message listeners to a given socket. * * @param socket The socket to add listeners to. */ -const listenOnAssetMessages = (socket: Socket) => ( - dispatch: ThunkDispatch -) => { - socket.on(messages.ASSETS.RECEIVED, (message: AssetPricesReceivedMessage) => { - dispatch(assetPricesReceived(message)); - }); +const listenOnAssetMessages = + (socket: Socket) => (dispatch: ThunkDispatch) => { + socket.on( + messages.ASSETS.RECEIVED, + (message: AssetPricesReceivedMessage) => { + dispatch(assetPricesReceived(message)); + } + ); - socket.on(messages.ASSETS.CHANGED, (message: AssetPricesChangedMessage) => { - dispatch(assetPricesChanged(message)); - }); + socket.on(messages.ASSETS.CHANGED, (message: AssetPricesChangedMessage) => { + dispatch(assetPricesChanged(message)); + }); - socket.on( - messages.ASSET_CHARTS.RECEIVED, - (message: ChartsReceivedMessage) => { - // logger.log('charts received', message?.payload?.charts); - dispatch(assetChartsReceived(message)); - } - ); -}; + socket.on( + messages.ASSET_CHARTS.RECEIVED, + (message: ChartsReceivedMessage) => { + // logger.log('charts received', message?.payload?.charts); + dispatch(assetChartsReceived(message)); + } + ); + }; /** * Adds listeners for address information messages to a given socket. * * @param socket The socket to add listeners to. */ -const listenOnAddressMessages = (socket: Socket) => ( - dispatch: ThunkDispatch -) => { - socket.on( - messages.ADDRESS_PORTFOLIO.RECEIVED, - (message: PortfolioReceivedMessage) => { - dispatch(portfolioReceived(message)); - } - ); +const listenOnAddressMessages = + (socket: Socket) => (dispatch: ThunkDispatch) => { + socket.on( + messages.ADDRESS_PORTFOLIO.RECEIVED, + (message: PortfolioReceivedMessage) => { + dispatch(portfolioReceived(message)); + } + ); - socket.on( - messages.ADDRESS_TRANSACTIONS.RECEIVED, - (message: TransactionsReceivedMessage) => { - // logger.log('mainnet txns received', message?.payload?.transactions); + socket.on( + messages.ADDRESS_TRANSACTIONS.RECEIVED, + (message: TransactionsReceivedMessage) => { + // logger.log('mainnet txns received', message?.payload?.transactions); - if (getExperimetalFlag(L2_TXS)) { - dispatch(emitL2TransactionHistoryRequest()); + if (getExperimetalFlag(L2_TXS)) { + dispatch(emitL2TransactionHistoryRequest()); + } + dispatch(transactionsReceived(message)); } - dispatch(transactionsReceived(message)); - } - ); + ); - socket.on( - messages.ADDRESS_TRANSACTIONS.RECEIVED_ARBITRUM, - (message: TransactionsReceivedMessage) => { - // logger.log('arbitrum txns received', message?.payload?.transactions); - dispatch(transactionsReceived(message)); - } - ); + socket.on( + messages.ADDRESS_TRANSACTIONS.RECEIVED_ARBITRUM, + (message: TransactionsReceivedMessage) => { + // logger.log('arbitrum txns received', message?.payload?.transactions); + dispatch(transactionsReceived(message)); + } + ); - socket.on( - messages.ADDRESS_TRANSACTIONS.RECEIVED_OPTIMISM, - (message: TransactionsReceivedMessage) => { - // logger.log('optimism txns received', message?.payload?.transactions); - dispatch(transactionsReceived(message)); - } - ); + socket.on( + messages.ADDRESS_TRANSACTIONS.RECEIVED_OPTIMISM, + (message: TransactionsReceivedMessage) => { + // logger.log('optimism txns received', message?.payload?.transactions); + dispatch(transactionsReceived(message)); + } + ); - socket.on( - messages.ADDRESS_TRANSACTIONS.RECEIVED_POLYGON, - (message: TransactionsReceivedMessage) => { - // logger.log('polygon txns received', message?.payload?.transactions); - dispatch(transactionsReceived(message)); - } - ); + socket.on( + messages.ADDRESS_TRANSACTIONS.RECEIVED_POLYGON, + (message: TransactionsReceivedMessage) => { + // logger.log('polygon txns received', message?.payload?.transactions); + dispatch(transactionsReceived(message)); + } + ); - socket.on( - messages.ADDRESS_TRANSACTIONS.RECEIVED_BSC, - (message: TransactionsReceivedMessage) => { - // logger.log('bsc txns received', message?.payload?.transactions); - dispatch(transactionsReceived(message)); - } - ); - socket.on( - messages.ADDRESS_TRANSACTIONS.RECEIVED_ZORA, - (message: TransactionsReceivedMessage) => { - // logger.log('zora txns received', message?.payload?.transactions); - dispatch(transactionsReceived(message)); - } - ); - socket.on( - messages.ADDRESS_TRANSACTIONS.RECEIVED_BASE, - (message: TransactionsReceivedMessage) => { - // logger.log('base txns received', message?.payload?.transactions); - dispatch(transactionsReceived(message)); - } - ); + socket.on( + messages.ADDRESS_TRANSACTIONS.RECEIVED_BSC, + (message: TransactionsReceivedMessage) => { + // logger.log('bsc txns received', message?.payload?.transactions); + dispatch(transactionsReceived(message)); + } + ); + socket.on( + messages.ADDRESS_TRANSACTIONS.RECEIVED_ZORA, + (message: TransactionsReceivedMessage) => { + // logger.log('zora txns received', message?.payload?.transactions); + dispatch(transactionsReceived(message)); + } + ); + socket.on( + messages.ADDRESS_TRANSACTIONS.RECEIVED_BASE, + (message: TransactionsReceivedMessage) => { + // logger.log('base txns received', message?.payload?.transactions); + dispatch(transactionsReceived(message)); + } + ); - socket.on( - messages.ADDRESS_TRANSACTIONS.APPENDED, - (message: TransactionsReceivedMessage) => { - logger.log('txns appended', message?.payload?.transactions); - dispatch(transactionsReceived(message, true)); - } - ); -}; + socket.on( + messages.ADDRESS_TRANSACTIONS.APPENDED, + (message: TransactionsReceivedMessage) => { + logger.log('txns appended', message?.payload?.transactions); + dispatch(transactionsReceived(message, true)); + } + ); + }; // -- Reducer ----------------------------------------- // const INITIAL_STATE: ExplorerState = { diff --git a/src/redux/gas.ts b/src/redux/gas.ts index 7e0e45fb0ee..193ba3fd834 100644 --- a/src/redux/gas.ts +++ b/src/redux/gas.ts @@ -183,91 +183,90 @@ const getUpdatedGasFeeParams = ( * @param speed * @param newMaxPriorityFeePerGas */ -export const updateGasFeeForSpeed = ( - speed: string, - newMaxPriorityFeePerGas: string -) => async (dispatch: AppDispatch, getState: AppGetState) => { - const { gasFeeParamsBySpeed } = getState().gas; - const newGasFeeParams = { ...gasFeeParamsBySpeed }; - newGasFeeParams[speed].maxPriorityFeePerGas = parseGasFeeParam( - newMaxPriorityFeePerGas - ); - - dispatch({ - payload: { - gasFeeParamsBySpeed: newGasFeeParams, - }, - type: GAS_PRICES_SUCCESS, - }); -}; - -export const gasUpdateToCustomGasFee = (gasParams: GasFeeParams) => async ( - dispatch: AppDispatch, - getState: AppGetState -) => { - const { - txNetwork, - defaultGasLimit, - gasFeesBySpeed, - gasFeeParamsBySpeed, - gasLimit, - currentBlockParams, - blocksToConfirmation, - secondsPerNewBlock, - l1GasFeeOptimism, - } = getState().gas; +export const updateGasFeeForSpeed = + (speed: string, newMaxPriorityFeePerGas: string) => + async (dispatch: AppDispatch, getState: AppGetState) => { + const { gasFeeParamsBySpeed } = getState().gas; + const newGasFeeParams = { ...gasFeeParamsBySpeed }; + newGasFeeParams[speed].maxPriorityFeePerGas = parseGasFeeParam( + newMaxPriorityFeePerGas + ); - const { nativeCurrency } = getState().settings; - const _gasLimit = gasLimit || getDefaultGasLimit(txNetwork, defaultGasLimit); + dispatch({ + payload: { + gasFeeParamsBySpeed: newGasFeeParams, + }, + type: GAS_PRICES_SUCCESS, + }); + }; - let nativeTokenPriceUnit = ethereumUtils.getEthPriceUnit(); +export const gasUpdateToCustomGasFee = + (gasParams: GasFeeParams) => + async (dispatch: AppDispatch, getState: AppGetState) => { + const { + txNetwork, + defaultGasLimit, + gasFeesBySpeed, + gasFeeParamsBySpeed, + gasLimit, + currentBlockParams, + blocksToConfirmation, + secondsPerNewBlock, + l1GasFeeOptimism, + } = getState().gas; - switch (txNetwork) { - case Network.polygon: - nativeTokenPriceUnit = ethereumUtils.getMaticPriceUnit(); - break; - case Network.bsc: - nativeTokenPriceUnit = ethereumUtils.getBnbPriceUnit(); - break; - default: - nativeTokenPriceUnit = ethereumUtils.getEthPriceUnit(); - break; - } + const { nativeCurrency } = getState().settings; + const _gasLimit = + gasLimit || getDefaultGasLimit(txNetwork, defaultGasLimit); + + let nativeTokenPriceUnit = ethereumUtils.getEthPriceUnit(); + + switch (txNetwork) { + case Network.polygon: + nativeTokenPriceUnit = ethereumUtils.getMaticPriceUnit(); + break; + case Network.bsc: + nativeTokenPriceUnit = ethereumUtils.getBnbPriceUnit(); + break; + default: + nativeTokenPriceUnit = ethereumUtils.getEthPriceUnit(); + break; + } - const customGasFees = parseGasFees( - gasParams, - currentBlockParams?.baseFeePerGas, - _gasLimit, - nativeTokenPriceUnit, - nativeCurrency, - l1GasFeeOptimism - ); - const newGasFeesBySpeed = { ...gasFeesBySpeed }; - const newGasFeeParamsBySpeed = { ...gasFeeParamsBySpeed }; - - newGasFeesBySpeed[CUSTOM] = customGasFees; - newGasFeeParamsBySpeed[CUSTOM] = defaultGasParamsFormat( - CUSTOM, - gasParams.maxBaseFee.amount, - gasParams.maxPriorityFeePerGas.amount, - blocksToConfirmation, - secondsPerNewBlock - ); - const newSelectedGasFee = getSelectedGasFee( - newGasFeeParamsBySpeed, - newGasFeesBySpeed, - CUSTOM - ); - dispatch({ - payload: { - customGasFeeModifiedByUser: true, - gasFeeParamsBySpeed: newGasFeeParamsBySpeed, - gasFeesBySpeed: newGasFeesBySpeed, - selectedGasFee: newSelectedGasFee.selectedGasFee, - }, - type: GAS_PRICES_CUSTOM_UPDATE, - }); -}; + const customGasFees = parseGasFees( + gasParams, + currentBlockParams?.baseFeePerGas, + _gasLimit, + nativeTokenPriceUnit, + nativeCurrency, + l1GasFeeOptimism + ); + const newGasFeesBySpeed = { ...gasFeesBySpeed }; + const newGasFeeParamsBySpeed = { ...gasFeeParamsBySpeed }; + + newGasFeesBySpeed[CUSTOM] = customGasFees; + newGasFeeParamsBySpeed[CUSTOM] = defaultGasParamsFormat( + CUSTOM, + gasParams.maxBaseFee.amount, + gasParams.maxPriorityFeePerGas.amount, + blocksToConfirmation, + secondsPerNewBlock + ); + const newSelectedGasFee = getSelectedGasFee( + newGasFeeParamsBySpeed, + newGasFeesBySpeed, + CUSTOM + ); + dispatch({ + payload: { + customGasFeeModifiedByUser: true, + gasFeeParamsBySpeed: newGasFeeParamsBySpeed, + gasFeesBySpeed: newGasFeesBySpeed, + selectedGasFee: newSelectedGasFee.selectedGasFee, + }, + type: GAS_PRICES_CUSTOM_UPDATE, + }); + }; export const getPolygonGasPrices = async () => { try { @@ -440,299 +439,301 @@ export const getEIP1559GasParams = async (network: Network) => { }; }; -export const gasPricesStartPolling = ( - network = Network.mainnet, - flashbots = false -) => async (dispatch: AppDispatch, getState: AppGetState) => { - dispatch(gasPricesStopPolling()); - - // this should be chain agnostic - const getGasPrices = (network: Network) => - withRunExclusive( - () => - new Promise(async (fetchResolve, fetchReject) => { - try { - dispatch({ - payload: network, - type: GAS_UPDATE_TRANSACTION_NETWORK, - }); - const { - gasFeeParamsBySpeed: existingGasFees, - customGasFeeModifiedByUser, - defaultGasLimit, - gasLimit, - selectedGasFee, - txNetwork, - selectedGasFee: lastSelectedGasFee, - gasFeesBySpeed: lastGasFeesBySpeed, - currentBlockParams, - l1GasFeeOptimism, - } = getState().gas; - const { nativeCurrency } = getState().settings; - - const networkObj = getNetworkObj(network); - let dataIsReady = true; - - if (networkObj.gas.gasType === 'legacy') { - // OP chains have an additional fee we need to load - if (getNetworkObj(network).gas?.OptimismTxFee) { - dataIsReady = l1GasFeeOptimism !== null; - } - - const adjustedGasFees = await networkObj.gas.getGasPrices(); - - if (!adjustedGasFees) return; - - const gasFeeParamsBySpeed = parseL2GasPrices(adjustedGasFees); - if (!gasFeeParamsBySpeed) return; - - const _selectedGasFeeOption = selectedGasFee.option || NORMAL; - const _gasLimit = - gasLimit || getDefaultGasLimit(txNetwork, defaultGasLimit); - const { - selectedGasFee: updatedSelectedGasFee, - gasFeesBySpeed: updatedGasFeesBySpeed, - } = dataIsReady - ? getUpdatedGasFeeParams( - currentBlockParams?.baseFeePerGas, - gasFeeParamsBySpeed, - _gasLimit, - nativeCurrency, - _selectedGasFeeOption, - txNetwork, - l1GasFeeOptimism - ) - : { - gasFeesBySpeed: lastGasFeesBySpeed, - selectedGasFee: lastSelectedGasFee, - }; +export const gasPricesStartPolling = + (network = Network.mainnet, flashbots = false) => + async (dispatch: AppDispatch, getState: AppGetState) => { + dispatch(gasPricesStopPolling()); + + // this should be chain agnostic + const getGasPrices = (network: Network) => + withRunExclusive( + () => + new Promise(async (fetchResolve, fetchReject) => { + try { dispatch({ - payload: { - gasFeeParamsBySpeed, - gasFeesBySpeed: updatedGasFeesBySpeed, - selectedGasFee: updatedSelectedGasFee, - }, - type: GAS_FEES_SUCCESS, + payload: network, + type: GAS_UPDATE_TRANSACTION_NETWORK, }); - } else { - try { - const { - gasFeeParamsBySpeed, - baseFeePerGas, - trend, - currentBaseFee, - blocksToConfirmation, - secondsPerNewBlock, - } = await getEIP1559GasParams(network); - - if (flashbots) { - [SLOW, NORMAL, FAST, URGENT].forEach(speed => { - // Override min tip to 5 if needed, when flashbots is enabled - // See https://docs.flashbots.net/flashbots-protect/rpc/quick-start#choosing-the-right-gas-price - if (gasFeeParamsBySpeed[speed]) { - if ( - Number( - gasFeeParamsBySpeed[speed].maxPriorityFeePerGas.gwei - ) < FLASHBOTS_MIN_TIP - ) { - gasFeeParamsBySpeed[speed] = { - ...gasFeeParamsBySpeed[speed], - maxPriorityFeePerGas: { - amount: `${FLASHBOTS_MIN_TIP}000000000`, - display: `${FLASHBOTS_MIN_TIP} gwei`, - gwei: `${FLASHBOTS_MIN_TIP}`, - }, - }; - } - } - }); + const { + gasFeeParamsBySpeed: existingGasFees, + customGasFeeModifiedByUser, + defaultGasLimit, + gasLimit, + selectedGasFee, + txNetwork, + selectedGasFee: lastSelectedGasFee, + gasFeesBySpeed: lastGasFeesBySpeed, + currentBlockParams, + l1GasFeeOptimism, + } = getState().gas; + const { nativeCurrency } = getState().settings; + + const networkObj = getNetworkObj(network); + let dataIsReady = true; + + if (networkObj.gas.gasType === 'legacy') { + // OP chains have an additional fee we need to load + if (getNetworkObj(network).gas?.OptimismTxFee) { + dataIsReady = l1GasFeeOptimism !== null; } - // Set a really gas estimate to guarantee that we're gonna be over - // the basefee at the time we fork mainnet during our hardhat tests - let baseFee = baseFeePerGas; - if (network === Network.mainnet && IS_TESTING === 'true') { - const providerUrl = ( - web3Provider || - ({} as { - connection: { url: string }; - }) - )?.connection?.url; - if (isHardHat(providerUrl)) { - baseFee = parseGasFeeParam(gweiToWei(1000)); - } - } + const adjustedGasFees = await networkObj.gas.getGasPrices(); + + if (!adjustedGasFees) return; + + const gasFeeParamsBySpeed = parseL2GasPrices(adjustedGasFees); + if (!gasFeeParamsBySpeed) return; - if (customGasFeeModifiedByUser) { - // Preserve custom values while updating prices - gasFeeParamsBySpeed[CUSTOM] = { - ...existingGasFees[CUSTOM], - baseFeePerGas: baseFee, - }; - } else { - // set CUSTOM to URGENT if not defined - gasFeeParamsBySpeed[CUSTOM] = gasFeeParamsBySpeed[URGENT]; - } const _selectedGasFeeOption = selectedGasFee.option || NORMAL; const _gasLimit = gasLimit || getDefaultGasLimit(txNetwork, defaultGasLimit); - const { selectedGasFee: updatedSelectedGasFee, - gasFeesBySpeed, - } = getUpdatedGasFeeParams( - currentBaseFee, - gasFeeParamsBySpeed, - _gasLimit, - nativeCurrency, - _selectedGasFeeOption, - txNetwork, - l1GasFeeOptimism - ); - + gasFeesBySpeed: updatedGasFeesBySpeed, + } = dataIsReady + ? getUpdatedGasFeeParams( + currentBlockParams?.baseFeePerGas, + gasFeeParamsBySpeed, + _gasLimit, + nativeCurrency, + _selectedGasFeeOption, + txNetwork, + l1GasFeeOptimism + ) + : { + gasFeesBySpeed: lastGasFeesBySpeed, + selectedGasFee: lastSelectedGasFee, + }; dispatch({ payload: { - blocksToConfirmation, - currentBlockParams: { - baseFeePerGas: currentBaseFee, - trend, - }, - gasFeeParamsBySpeed: gasFeeParamsBySpeed, - gasFeesBySpeed, + gasFeeParamsBySpeed, + gasFeesBySpeed: updatedGasFeesBySpeed, selectedGasFee: updatedSelectedGasFee, - secondsPerNewBlock, }, type: GAS_FEES_SUCCESS, }); - } catch (e) { - logger.error( - new RainbowError(`Etherscan gas estimates error: ${e}`) - ); - logger.debug('falling back to eth gas station'); + } else { + try { + const { + gasFeeParamsBySpeed, + baseFeePerGas, + trend, + currentBaseFee, + blocksToConfirmation, + secondsPerNewBlock, + } = await getEIP1559GasParams(network); + + if (flashbots) { + [SLOW, NORMAL, FAST, URGENT].forEach(speed => { + // Override min tip to 5 if needed, when flashbots is enabled + // See https://docs.flashbots.net/flashbots-protect/rpc/quick-start#choosing-the-right-gas-price + if (gasFeeParamsBySpeed[speed]) { + if ( + Number( + gasFeeParamsBySpeed[speed].maxPriorityFeePerGas.gwei + ) < FLASHBOTS_MIN_TIP + ) { + gasFeeParamsBySpeed[speed] = { + ...gasFeeParamsBySpeed[speed], + maxPriorityFeePerGas: { + amount: `${FLASHBOTS_MIN_TIP}000000000`, + display: `${FLASHBOTS_MIN_TIP} gwei`, + gwei: `${FLASHBOTS_MIN_TIP}`, + }, + }; + } + } + }); + } + + // Set a really gas estimate to guarantee that we're gonna be over + // the basefee at the time we fork mainnet during our hardhat tests + let baseFee = baseFeePerGas; + if (network === Network.mainnet && IS_TESTING === 'true') { + const providerUrl = ( + web3Provider || + ({} as { + connection: { url: string }; + }) + )?.connection?.url; + if (isHardHat(providerUrl)) { + baseFee = parseGasFeeParam(gweiToWei(1000)); + } + } + + if (customGasFeeModifiedByUser) { + // Preserve custom values while updating prices + gasFeeParamsBySpeed[CUSTOM] = { + ...existingGasFees[CUSTOM], + baseFeePerGas: baseFee, + }; + } else { + // set CUSTOM to URGENT if not defined + gasFeeParamsBySpeed[CUSTOM] = gasFeeParamsBySpeed[URGENT]; + } + const _selectedGasFeeOption = selectedGasFee.option || NORMAL; + const _gasLimit = + gasLimit || getDefaultGasLimit(txNetwork, defaultGasLimit); + + const { + selectedGasFee: updatedSelectedGasFee, + gasFeesBySpeed, + } = getUpdatedGasFeeParams( + currentBaseFee, + gasFeeParamsBySpeed, + _gasLimit, + nativeCurrency, + _selectedGasFeeOption, + txNetwork, + l1GasFeeOptimism + ); + + dispatch({ + payload: { + blocksToConfirmation, + currentBlockParams: { + baseFeePerGas: currentBaseFee, + trend, + }, + gasFeeParamsBySpeed: gasFeeParamsBySpeed, + gasFeesBySpeed, + selectedGasFee: updatedSelectedGasFee, + secondsPerNewBlock, + }, + type: GAS_FEES_SUCCESS, + }); + } catch (e) { + logger.error( + new RainbowError(`Etherscan gas estimates error: ${e}`) + ); + logger.debug('falling back to eth gas station'); + } } + fetchResolve(true); + } catch (e) { + logger.error( + new RainbowError(`Gas Estimates Failed for ${network}: ${e}`) + ); + fetchReject(e); } - fetchResolve(true); - } catch (e) { - logger.error( - new RainbowError(`Gas Estimates Failed for ${network}: ${e}`) - ); - fetchReject(e); - } - }) - ); + }) + ); - const watchGasPrices = async (network: Network, pollingInterval: number) => { - try { - await getGasPrices(network); - // eslint-disable-next-line no-empty - } catch (e) { - } finally { - gasPricesHandle && clearTimeout(gasPricesHandle); - gasPricesHandle = setTimeout(() => { - watchGasPrices(network, pollingInterval); - }, pollingInterval); - } + const watchGasPrices = async ( + network: Network, + pollingInterval: number + ) => { + try { + await getGasPrices(network); + // eslint-disable-next-line no-empty + } catch (e) { + } finally { + gasPricesHandle && clearTimeout(gasPricesHandle); + gasPricesHandle = setTimeout(() => { + watchGasPrices(network, pollingInterval); + }, pollingInterval); + } + }; + + const pollingInterval = getGasPricePollingInterval(network); + watchGasPrices(network, pollingInterval); }; - const pollingInterval = getGasPricePollingInterval(network); - watchGasPrices(network, pollingInterval); -}; +export const gasUpdateGasFeeOption = + (newGasPriceOption: string) => + (dispatch: AppDispatch, getState: AppGetState) => + withRunExclusive(async () => { + const { + gasFeeParamsBySpeed, + gasFeesBySpeed, + selectedGasFee: oldSelectedFee, + } = getState().gas; + if (oldSelectedFee.option === newGasPriceOption) return; -export const gasUpdateGasFeeOption = (newGasPriceOption: string) => ( - dispatch: AppDispatch, - getState: AppGetState -) => - withRunExclusive(async () => { - const { - gasFeeParamsBySpeed, - gasFeesBySpeed, - selectedGasFee: oldSelectedFee, - } = getState().gas; - if (oldSelectedFee.option === newGasPriceOption) return; + const gasPriceOption = newGasPriceOption || NORMAL; + if (isEmpty(gasFeeParamsBySpeed)) return; + const selectedGasFee = getSelectedGasFee( + gasFeeParamsBySpeed, + gasFeesBySpeed, + gasPriceOption + ); + dispatch({ + payload: selectedGasFee, + type: GAS_UPDATE_GAS_PRICE_OPTION, + }); + analytics.track('Updated Gas Price', { gasPriceOption: gasPriceOption }); + }); - const gasPriceOption = newGasPriceOption || NORMAL; - if (isEmpty(gasFeeParamsBySpeed)) return; - const selectedGasFee = getSelectedGasFee( - gasFeeParamsBySpeed, - gasFeesBySpeed, - gasPriceOption - ); +export const gasUpdateDefaultGasLimit = + (defaultGasLimit = ethUnits.basic_tx) => + (dispatch: AppDispatch) => { dispatch({ - payload: selectedGasFee, - type: GAS_UPDATE_GAS_PRICE_OPTION, + payload: defaultGasLimit, + type: GAS_UPDATE_DEFAULT_GAS_LIMIT, }); - analytics.track('Updated Gas Price', { gasPriceOption: gasPriceOption }); - }); - -export const gasUpdateDefaultGasLimit = ( - defaultGasLimit = ethUnits.basic_tx -) => (dispatch: AppDispatch) => { - dispatch({ - payload: defaultGasLimit, - type: GAS_UPDATE_DEFAULT_GAS_LIMIT, - }); - dispatch(gasUpdateTxFee(defaultGasLimit)); -}; - -export const gasUpdateTxFee = ( - updatedGasLimit?: number, - overrideGasOption?: string, - l1GasFeeOptimism: BigNumber | null = null -) => (dispatch: AppDispatch, getState: AppGetState) => - withRunExclusive(async () => { - const { - defaultGasLimit, - gasLimit, - gasFeeParamsBySpeed, - selectedGasFee, - txNetwork, - currentBlockParams, - } = getState().gas; - - const { nativeCurrency } = getState().settings; - if ( - isEmpty(gasFeeParamsBySpeed) || - (getNetworkObj(txNetwork).gas?.OptimismTxFee && l1GasFeeOptimism === null) - ) { - // if fee prices not ready, we need to store the gas limit for future calculations - // the rest is as the initial state value - if (updatedGasLimit) { - dispatch({ - payload: updatedGasLimit, - type: GAS_UPDATE_GAS_LIMIT, - }); - } - } else { - const _selectedGasFeeOption = - overrideGasOption || selectedGasFee.option || NORMAL; - const _gasLimit = - updatedGasLimit || - gasLimit || - getDefaultGasLimit(txNetwork, defaultGasLimit); + dispatch(gasUpdateTxFee(defaultGasLimit)); + }; +export const gasUpdateTxFee = + ( + updatedGasLimit?: number, + overrideGasOption?: string, + l1GasFeeOptimism: BigNumber | null = null + ) => + (dispatch: AppDispatch, getState: AppGetState) => + withRunExclusive(async () => { const { - selectedGasFee: updatedSelectedGasFee, - gasFeesBySpeed, - } = getUpdatedGasFeeParams( - currentBlockParams?.baseFeePerGas, + defaultGasLimit, + gasLimit, gasFeeParamsBySpeed, - _gasLimit, - nativeCurrency, - _selectedGasFeeOption, + selectedGasFee, txNetwork, - l1GasFeeOptimism - ); - dispatch({ - payload: { - gasFeesBySpeed, - gasLimit: _gasLimit, - l1GasFeeOptimism, - selectedGasFee: updatedSelectedGasFee, - }, - type: GAS_UPDATE_TX_FEE, - }); - } - }); + currentBlockParams, + } = getState().gas; + + const { nativeCurrency } = getState().settings; + if ( + isEmpty(gasFeeParamsBySpeed) || + (getNetworkObj(txNetwork).gas?.OptimismTxFee && + l1GasFeeOptimism === null) + ) { + // if fee prices not ready, we need to store the gas limit for future calculations + // the rest is as the initial state value + if (updatedGasLimit) { + dispatch({ + payload: updatedGasLimit, + type: GAS_UPDATE_GAS_LIMIT, + }); + } + } else { + const _selectedGasFeeOption = + overrideGasOption || selectedGasFee.option || NORMAL; + const _gasLimit = + updatedGasLimit || + gasLimit || + getDefaultGasLimit(txNetwork, defaultGasLimit); + + const { selectedGasFee: updatedSelectedGasFee, gasFeesBySpeed } = + getUpdatedGasFeeParams( + currentBlockParams?.baseFeePerGas, + gasFeeParamsBySpeed, + _gasLimit, + nativeCurrency, + _selectedGasFeeOption, + txNetwork, + l1GasFeeOptimism + ); + dispatch({ + payload: { + gasFeesBySpeed, + gasLimit: _gasLimit, + l1GasFeeOptimism, + selectedGasFee: updatedSelectedGasFee, + }, + type: GAS_UPDATE_TX_FEE, + }); + } + }); export const gasPricesStopPolling = () => (dispatch: AppDispatch) => { gasPricesHandle && clearTimeout(gasPricesHandle); diff --git a/src/redux/hiddenTokens.ts b/src/redux/hiddenTokens.ts index 25e0164e7d6..e5c69b5a1ab 100644 --- a/src/redux/hiddenTokens.ts +++ b/src/redux/hiddenTokens.ts @@ -85,118 +85,120 @@ interface HiddenTokensUpdateAction { * Loads hidden token IDs and web-data settings from local storage and * updates state. */ -export const hiddenTokensLoadState = () => async ( - dispatch: Dispatch< - HiddenTokensLoadSuccessAction | HiddenTokensLoadFailureAction - >, - getState: AppGetState -) => { - try { - const { accountAddress, network } = getState().settings; - - const hiddenTokens = await getHiddenTokens(accountAddress, network); - - dispatch({ - payload: { - hiddenTokens, - }, - type: HIDDEN_TOKENS_LOAD_SUCCESS, - }); - } catch (error) { - dispatch({ type: HIDDEN_TOKENS_LOAD_FAILURE }); - } -}; +export const hiddenTokensLoadState = + () => + async ( + dispatch: Dispatch< + HiddenTokensLoadSuccessAction | HiddenTokensLoadFailureAction + >, + getState: AppGetState + ) => { + try { + const { accountAddress, network } = getState().settings; + + const hiddenTokens = await getHiddenTokens(accountAddress, network); + + dispatch({ + payload: { + hiddenTokens, + }, + type: HIDDEN_TOKENS_LOAD_SUCCESS, + }); + } catch (error) { + dispatch({ type: HIDDEN_TOKENS_LOAD_FAILURE }); + } + }; /** * Loads hidden token IDs and web-data settings from firebase and * updates state. */ -export const hiddenTokensUpdateStateFromWeb = () => async ( - dispatch: Dispatch< - HiddenTokensFetchSuccessAction | HiddenTokensFetchFailureAction - >, - getState: AppGetState -) => { - try { - const isReadOnlyWallet = - getState().wallets.selected?.type === WalletTypes.readOnly; - const { accountAddress, network } = getState().settings; - - // if web data is enabled, fetch values from cloud - const pref = await getWebDataEnabled(accountAddress, network); - - if ((!isReadOnlyWallet && pref) || isReadOnlyWallet) { - const hiddenTokensFromCloud = (await getPreference( - 'hidden', - accountAddress - )) as any | undefined; - if ( - hiddenTokensFromCloud?.hidden?.ids && - hiddenTokensFromCloud?.hidden?.ids.length > 0 - ) { - dispatch({ - payload: { - hiddenTokens: hiddenTokensFromCloud?.hidden?.ids, - }, - type: HIDDEN_TOKENS_FETCH_SUCCESS, - }); +export const hiddenTokensUpdateStateFromWeb = + () => + async ( + dispatch: Dispatch< + HiddenTokensFetchSuccessAction | HiddenTokensFetchFailureAction + >, + getState: AppGetState + ) => { + try { + const isReadOnlyWallet = + getState().wallets.selected?.type === WalletTypes.readOnly; + const { accountAddress, network } = getState().settings; + + // if web data is enabled, fetch values from cloud + const pref = await getWebDataEnabled(accountAddress, network); + + if ((!isReadOnlyWallet && pref) || isReadOnlyWallet) { + const hiddenTokensFromCloud = (await getPreference( + 'hidden', + accountAddress + )) as any | undefined; + if ( + hiddenTokensFromCloud?.hidden?.ids && + hiddenTokensFromCloud?.hidden?.ids.length > 0 + ) { + dispatch({ + payload: { + hiddenTokens: hiddenTokensFromCloud?.hidden?.ids, + }, + type: HIDDEN_TOKENS_FETCH_SUCCESS, + }); + } } + } catch (e) { + dispatch({ type: HIDDEN_TOKENS_FETCH_FAILURE }); } - } catch (e) { - dispatch({ type: HIDDEN_TOKENS_FETCH_FAILURE }); - } -}; + }; /** * Adds a token ID to the hidden in state and updates local storage. * * @param tokenId The new token ID. */ -export const addHiddenToken = (tokenId: string) => ( - dispatch: Dispatch, - getState: AppGetState -) => { - const account = getState().wallets.selected!; - - if (account.type === WalletTypes.readOnly) return; - - const { accountAddress, network } = getState().settings; - const { hiddenTokens } = getState().hiddenTokens; - const updatedHiddenTokens = concat(hiddenTokens, tokenId); - dispatch({ - payload: { - hiddenTokens: updatedHiddenTokens, - }, - type: HIDDEN_TOKENS_UPDATE, - }); - saveHiddenTokens(updatedHiddenTokens, accountAddress, network); -}; +export const addHiddenToken = + (tokenId: string) => + (dispatch: Dispatch, getState: AppGetState) => { + const account = getState().wallets.selected!; + + if (account.type === WalletTypes.readOnly) return; + + const { accountAddress, network } = getState().settings; + const { hiddenTokens } = getState().hiddenTokens; + const updatedHiddenTokens = concat(hiddenTokens, tokenId); + dispatch({ + payload: { + hiddenTokens: updatedHiddenTokens, + }, + type: HIDDEN_TOKENS_UPDATE, + }); + saveHiddenTokens(updatedHiddenTokens, accountAddress, network); + }; /** * Removes a token ID from the hidden in state and updates local storage. * * @param tokenId The token ID to remove. */ -export const removeHiddenToken = (tokenId: string) => ( - dispatch: Dispatch, - getState: AppGetState -) => { - const account = getState().wallets.selected!; +export const removeHiddenToken = + (tokenId: string) => + (dispatch: Dispatch, getState: AppGetState) => { + const account = getState().wallets.selected!; - if (account.type === WalletTypes.readOnly) return; + if (account.type === WalletTypes.readOnly) return; - const { accountAddress, network } = getState().settings; - const { hiddenTokens } = getState().hiddenTokens; + const { accountAddress, network } = getState().settings; + const { hiddenTokens } = getState().hiddenTokens; - const updatedHiddenTokens = without(hiddenTokens, tokenId); + const updatedHiddenTokens = without(hiddenTokens, tokenId); - dispatch({ - payload: { hiddenTokens: updatedHiddenTokens }, - type: HIDDEN_TOKENS_UPDATE, - }); + dispatch({ + payload: { hiddenTokens: updatedHiddenTokens }, + type: HIDDEN_TOKENS_UPDATE, + }); - saveHiddenTokens(updatedHiddenTokens, accountAddress, network); -}; + saveHiddenTokens(updatedHiddenTokens, accountAddress, network); + }; const INITIAL_STATE: HiddenTokensState = { hiddenTokens: [], diff --git a/src/redux/imageMetadata.ts b/src/redux/imageMetadata.ts index 9234df32039..2a3d21b2042 100644 --- a/src/redux/imageMetadata.ts +++ b/src/redux/imageMetadata.ts @@ -63,34 +63,29 @@ interface UpdateImageMetadataFunctionParameter { } // -- Actions ---------------------------------------- // -export const clearImageMetadataCache = () => ( - dispatch: Dispatch -) => dispatch({ type: CLEAR }); +export const clearImageMetadataCache = + () => (dispatch: Dispatch) => + dispatch({ type: CLEAR }); -export const imageMetadataCacheLoadState = () => async ( - dispatch: Dispatch -) => { - const metadataCache = await getImageMetadata(); - dispatch({ - payload: metadataCache, - type: LOAD, - }); -}; +export const imageMetadataCacheLoadState = + () => async (dispatch: Dispatch) => { + const metadataCache = await getImageMetadata(); + dispatch({ + payload: metadataCache, + type: LOAD, + }); + }; -export const updateImageMetadataCache = ({ - id, - metadata, -}: UpdateImageMetadataFunctionParameter) => ( - dispatch: Dispatch, - getState: AppGetState -) => { - const { imageMetadata } = getState().imageMetadata; - dispatch({ id, metadata, type: MERGE }); - saveImageMetadata({ - ...imageMetadata, - [id]: metadata, - }); -}; +export const updateImageMetadataCache = + ({ id, metadata }: UpdateImageMetadataFunctionParameter) => + (dispatch: Dispatch, getState: AppGetState) => { + const { imageMetadata } = getState().imageMetadata; + dispatch({ id, metadata, type: MERGE }); + saveImageMetadata({ + ...imageMetadata, + [id]: metadata, + }); + }; // -- Reducer ----------------------------------------- // const INITIAL_STATE: ImageMetadataState = { diff --git a/src/redux/keyboardHeight.ts b/src/redux/keyboardHeight.ts index 092701f92b0..b8583b0895e 100644 --- a/src/redux/keyboardHeight.ts +++ b/src/redux/keyboardHeight.ts @@ -78,39 +78,40 @@ const INITIAL_STATE: KeyboardHeightState = { }, }; -export const keyboardHeightsLoadState = () => async ( - dispatch: Dispatch -) => { - const cachedKeyboardHeights = await loadKeyboardHeights(); +export const keyboardHeightsLoadState = + () => async (dispatch: Dispatch) => { + const cachedKeyboardHeights = await loadKeyboardHeights(); - dispatch({ - payload: { - ...INITIAL_STATE.keyboardHeight, - ...cachedKeyboardHeights, - }, - type: LOAD, - }); -}; + dispatch({ + payload: { + ...INITIAL_STATE.keyboardHeight, + ...cachedKeyboardHeights, + }, + type: LOAD, + }); + }; -export const setKeyboardHeight = ({ - height, - keyboardType = KeyboardType.default, -}: SetKeyboardHeightFunctionParameter) => async ( - dispatch: Dispatch, - getState: AppGetState -) => { - await dispatch({ +export const setKeyboardHeight = + ({ height, - keyboardType, - type: SAVE, - }); + keyboardType = KeyboardType.default, + }: SetKeyboardHeightFunctionParameter) => + async ( + dispatch: Dispatch, + getState: AppGetState + ) => { + await dispatch({ + height, + keyboardType, + type: SAVE, + }); - const prevState = getState().keyboardHeight.keyboardHeight; - saveKeyboardHeight({ - ...prevState, - [keyboardType]: height, - }); -}; + const prevState = getState().keyboardHeight.keyboardHeight; + saveKeyboardHeight({ + ...prevState, + [keyboardType]: height, + }); + }; // -- Reducer ----------------------------------------- // export default ( diff --git a/src/redux/nonceManager.ts b/src/redux/nonceManager.ts index 84930984710..f3dffb16714 100644 --- a/src/redux/nonceManager.ts +++ b/src/redux/nonceManager.ts @@ -42,71 +42,68 @@ export const nonceManagerLoadState = () => async (dispatch: AppDispatch) => { } }; -export const incrementNonce = ( - accountAddress: EthereumAddress, - nonce: number, - network = Network.mainnet -) => (dispatch: AppDispatch) => - dispatch(updateNonce(accountAddress, nonce, network)); +export const incrementNonce = + (accountAddress: EthereumAddress, nonce: number, network = Network.mainnet) => + (dispatch: AppDispatch) => + dispatch(updateNonce(accountAddress, nonce, network)); -export const decrementNonce = ( - accountAddress: EthereumAddress, - nonce: number, - network = Network.mainnet -) => (dispatch: AppDispatch) => - dispatch(updateNonce(accountAddress, nonce, network, false)); +export const decrementNonce = + (accountAddress: EthereumAddress, nonce: number, network = Network.mainnet) => + (dispatch: AppDispatch) => + dispatch(updateNonce(accountAddress, nonce, network, false)); -export const updateNonce = ( - accountAddress: EthereumAddress, - nonce: number, - network = Network.mainnet, - increment: boolean = true -) => (dispatch: AppDispatch, getState: AppGetState) => { - const { nonceManager: currentNonceData } = getState(); - const currentNonce = - currentNonceData[accountAddress.toLowerCase()]?.[network]?.nonce; - const counterShouldBeUpdated = - isNil(currentNonce) || - (increment ? currentNonce < nonce : currentNonce >= nonce); +export const updateNonce = + ( + accountAddress: EthereumAddress, + nonce: number, + network = Network.mainnet, + increment: boolean = true + ) => + (dispatch: AppDispatch, getState: AppGetState) => { + const { nonceManager: currentNonceData } = getState(); + const currentNonce = + currentNonceData[accountAddress.toLowerCase()]?.[network]?.nonce; + const counterShouldBeUpdated = + isNil(currentNonce) || + (increment ? currentNonce < nonce : currentNonce >= nonce); - if (counterShouldBeUpdated) { - const newNonce = increment ? nonce : nonce - 1; - logger.log('Updating nonce: ', accountAddress, network, newNonce); + if (counterShouldBeUpdated) { + const newNonce = increment ? nonce : nonce - 1; + logger.log('Updating nonce: ', accountAddress, network, newNonce); - const lcAccountAddress = accountAddress.toLowerCase(); - const updatedNonceManager = { + const lcAccountAddress = accountAddress.toLowerCase(); + const updatedNonceManager = { + ...currentNonceData, + [lcAccountAddress]: { + ...(currentNonceData[lcAccountAddress] || {}), + [network]: { nonce: newNonce }, + }, + }; + dispatch({ + payload: updatedNonceManager, + type: NONCE_MANAGER_UPDATE_NONCE, + }); + saveNonceManager(updatedNonceManager); + } + }; +export const resetNonces = + (accountAddress: EthereumAddress) => + async (dispatch: AppDispatch, getState: AppGetState) => { + const { nonceManager: currentNonceData } = getState(); + + const currentAccountAddress = accountAddress.toLowerCase(); + + const updatedNonceManager: NonceManager = { ...currentNonceData, - [lcAccountAddress]: { - ...(currentNonceData[lcAccountAddress] || {}), - [network]: { nonce: newNonce }, - }, + [currentAccountAddress]: {}, }; + dispatch({ payload: updatedNonceManager, type: NONCE_MANAGER_UPDATE_NONCE, }); saveNonceManager(updatedNonceManager); - } -}; -export const resetNonces = (accountAddress: EthereumAddress) => async ( - dispatch: AppDispatch, - getState: AppGetState -) => { - const { nonceManager: currentNonceData } = getState(); - - const currentAccountAddress = accountAddress.toLowerCase(); - - const updatedNonceManager: NonceManager = { - ...currentNonceData, - [currentAccountAddress]: {}, }; - - dispatch({ - payload: updatedNonceManager, - type: NONCE_MANAGER_UPDATE_NONCE, - }); - saveNonceManager(updatedNonceManager); -}; // -- Reducer ----------------------------------------- // const INITIAL_STATE: NonceManager = {}; diff --git a/src/redux/requests.ts b/src/redux/requests.ts index d9ee7f05113..7aaae5d84ff 100644 --- a/src/redux/requests.ts +++ b/src/redux/requests.ts @@ -137,18 +137,23 @@ interface RequestsClearStateAction { /** * Loads requests from local storage into state. */ -export const requestsLoadState = () => async ( - dispatch: Dispatch, - getState: AppGetState -) => { - const { accountAddress, network } = getState().settings; - try { - const requests = await getLocalRequests(accountAddress, network); - const _requests = requests || {}; - dispatch({ payload: _requests, type: REQUESTS_UPDATE_REQUESTS_TO_APPROVE }); - // eslint-disable-next-line no-empty - } catch (error) {} -}; +export const requestsLoadState = + () => + async ( + dispatch: Dispatch, + getState: AppGetState + ) => { + const { accountAddress, network } = getState().settings; + try { + const requests = await getLocalRequests(accountAddress, network); + const _requests = requests || {}; + dispatch({ + payload: _requests, + type: REQUESTS_UPDATE_REQUESTS_TO_APPROVE, + }); + // eslint-disable-next-line no-empty + } catch (error) {} + }; /** * Adds a new request to state and updates local storage. @@ -159,70 +164,72 @@ export const requestsLoadState = () => async ( * @param payload The request payload. * @param peerMeta The WalletConnect peer metadata. */ -export const addRequestToApprove = ( - clientId: string, - peerId: string, - requestId: number, - payload: any, - peerMeta: - | undefined - | null - | { - name?: string; - url?: string; - scheme?: string; - icons?: string[]; - } -) => ( - dispatch: Dispatch, - getState: AppGetState -) => { - const { requests } = getState().requests; - const { walletConnectors } = getState().walletconnect; - const { accountAddress, network, nativeCurrency } = getState().settings; - const walletConnector = walletConnectors[peerId]; - // @ts-expect-error "_chainId" is private. - const chainId = walletConnector._chainId; - const dappNetwork = ethereumUtils.getNetworkFromChainId(Number(chainId)); - const displayDetails = getRequestDisplayDetails( - payload, - nativeCurrency, - dappNetwork - ); - const oneHourAgoTs = Date.now() - EXPIRATION_THRESHOLD_IN_MS; - // @ts-expect-error This fails to compile as `displayDetails` does not - // always return an object with `timestampInMs`. Still, the error thrown - // by an invalid access might be caught or expected elsewhere, so for now - // `ts-expect-error` is used. - if (displayDetails.timestampInMs < oneHourAgoTs) { - logger.log('request expired!'); - return; - } - const unsafeImageUrl = peerMeta?.icons?.[0]; - const imageUrl = maybeSignUri(unsafeImageUrl, { w: 200 }); - const dappName = peerMeta?.name || 'Unknown Dapp'; - const dappUrl = peerMeta?.url || 'Unknown Url'; - const dappScheme = peerMeta?.scheme || null; +export const addRequestToApprove = + ( + clientId: string, + peerId: string, + requestId: number, + payload: any, + peerMeta: + | undefined + | null + | { + name?: string; + url?: string; + scheme?: string; + icons?: string[]; + } + ) => + ( + dispatch: Dispatch, + getState: AppGetState + ) => { + const { requests } = getState().requests; + const { walletConnectors } = getState().walletconnect; + const { accountAddress, network, nativeCurrency } = getState().settings; + const walletConnector = walletConnectors[peerId]; + // @ts-expect-error "_chainId" is private. + const chainId = walletConnector._chainId; + const dappNetwork = ethereumUtils.getNetworkFromChainId(Number(chainId)); + const displayDetails = getRequestDisplayDetails( + payload, + nativeCurrency, + dappNetwork + ); + const oneHourAgoTs = Date.now() - EXPIRATION_THRESHOLD_IN_MS; + // @ts-expect-error This fails to compile as `displayDetails` does not + // always return an object with `timestampInMs`. Still, the error thrown + // by an invalid access might be caught or expected elsewhere, so for now + // `ts-expect-error` is used. + if (displayDetails.timestampInMs < oneHourAgoTs) { + logger.log('request expired!'); + return; + } + const unsafeImageUrl = peerMeta?.icons?.[0]; + const imageUrl = maybeSignUri(unsafeImageUrl, { w: 200 }); + const dappName = peerMeta?.name || 'Unknown Dapp'; + const dappUrl = peerMeta?.url || 'Unknown Url'; + const dappScheme = peerMeta?.scheme || null; - const request: RequestData = { - clientId, - dappName, - dappScheme, - dappUrl, - displayDetails, - imageUrl, - payload, - peerId, - requestId, + const request: RequestData = { + clientId, + dappName, + dappScheme, + dappUrl, + displayDetails, + imageUrl, + payload, + peerId, + requestId, + }; + const updatedRequests = { ...requests, [requestId]: request }; + dispatch({ + payload: updatedRequests, + type: REQUESTS_UPDATE_REQUESTS_TO_APPROVE, + }); + saveLocalRequests(updatedRequests, accountAddress, network); + return request; }; - const updatedRequests = { ...requests, [requestId]: request }; - dispatch({ - payload: updatedRequests, - type: REQUESTS_UPDATE_REQUESTS_TO_APPROVE, - }); - saveLocalRequests(updatedRequests, accountAddress, network); - return request; -}; /** * Filters requests that match a given client ID. @@ -230,39 +237,40 @@ export const addRequestToApprove = ( * @param topic The client ID to filter for. * @returns The matching requests. */ -export const requestsForTopic = (topic: string | undefined) => ( - dispatch: unknown, - getState: AppGetState -): RequestData[] => { - const { requests } = getState().requests; - return Object.values(requests).filter(({ clientId }) => clientId === topic); -}; +export const requestsForTopic = + (topic: string | undefined) => + (dispatch: unknown, getState: AppGetState): RequestData[] => { + const { requests } = getState().requests; + return Object.values(requests).filter(({ clientId }) => clientId === topic); + }; /** * Resets the state. */ -export const requestsResetState = () => ( - dispatch: Dispatch -) => dispatch({ type: REQUESTS_CLEAR_STATE }); +export const requestsResetState = + () => (dispatch: Dispatch) => + dispatch({ type: REQUESTS_CLEAR_STATE }); /** * Removes a request from state by its request ID. * * @param requestId The request ID to remove. */ -export const removeRequest = (requestId: number) => ( - dispatch: Dispatch, - getState: AppGetState -) => { - const { accountAddress, network } = getState().settings; - const { requests } = getState().requests; - const updatedRequests = omitFlatten(requests, [requestId]); - removeLocalRequest(accountAddress, network, requestId); - dispatch({ - payload: updatedRequests, - type: REQUESTS_UPDATE_REQUESTS_TO_APPROVE, - }); -}; +export const removeRequest = + (requestId: number) => + ( + dispatch: Dispatch, + getState: AppGetState + ) => { + const { accountAddress, network } = getState().settings; + const { requests } = getState().requests; + const updatedRequests = omitFlatten(requests, [requestId]); + removeLocalRequest(accountAddress, network, requestId); + dispatch({ + payload: updatedRequests, + type: REQUESTS_UPDATE_REQUESTS_TO_APPROVE, + }); + }; // -- Reducer ----------------------------------------- // diff --git a/src/redux/settings.ts b/src/redux/settings.ts index ac97c76929a..4206243184e 100644 --- a/src/redux/settings.ts +++ b/src/redux/settings.ts @@ -123,196 +123,197 @@ interface SettingsStateUpdateLanguageSuccessAction { payload: SettingsState['language']; } -export const settingsLoadState = () => async ( - dispatch: ThunkDispatch< - AppState, - unknown, - | SettingsStateUpdateNativeCurrencyAndTestnetsSuccessAction - | SettingsStateUpdateAppIconSuccessAction - > -) => { - try { - const nativeCurrency = await getNativeCurrency(); - const testnetsEnabled = await getTestnetsEnabled(); - const appIcon = (await getAppIcon()) as string; - dispatch({ - payload: appIcon, - type: SETTINGS_UPDATE_APP_ICON_SUCCESS, - }); - - const flashbotsEnabled = await getFlashbotsEnabled(); +export const settingsLoadState = + () => + async ( + dispatch: ThunkDispatch< + AppState, + unknown, + | SettingsStateUpdateNativeCurrencyAndTestnetsSuccessAction + | SettingsStateUpdateAppIconSuccessAction + > + ) => { + try { + const nativeCurrency = await getNativeCurrency(); + const testnetsEnabled = await getTestnetsEnabled(); + const appIcon = (await getAppIcon()) as string; + dispatch({ + payload: appIcon, + type: SETTINGS_UPDATE_APP_ICON_SUCCESS, + }); - analytics.identify({ - currency: nativeCurrency, - enabledFlashbots: flashbotsEnabled, - enabledTestnets: testnetsEnabled, - }); + const flashbotsEnabled = await getFlashbotsEnabled(); - dispatch({ - payload: { flashbotsEnabled, nativeCurrency, testnetsEnabled }, - type: SETTINGS_UPDATE_ACCOUNT_SETTINGS_SUCCESS, - }); - } catch (error) { - logger.log('Error loading native currency and testnets pref', error); - } -}; - -export const settingsLoadNetwork = () => async ( - dispatch: Dispatch -) => { - try { - const network = await getNetwork(); - const chainId = ethereumUtils.getChainIdFromNetwork(network); - await web3SetHttpProvider(network); - dispatch({ - payload: { chainId, network }, - type: SETTINGS_UPDATE_NETWORK_SUCCESS, - }); - } catch (error) { - logger.log('Error loading network settings', error); - } -}; + analytics.identify({ + currency: nativeCurrency, + enabledFlashbots: flashbotsEnabled, + enabledTestnets: testnetsEnabled, + }); -export const settingsLoadLanguage = () => async ( - dispatch: Dispatch -) => { - try { - const language = await getLanguage(); - updateLanguageLocale(language as Language); - dispatch({ - payload: language, - type: SETTINGS_UPDATE_LANGUAGE_SUCCESS, - }); - analytics.identify({ - language, - }); - } catch (error) { - logger.log('Error loading language settings', error); - } -}; + dispatch({ + payload: { flashbotsEnabled, nativeCurrency, testnetsEnabled }, + type: SETTINGS_UPDATE_ACCOUNT_SETTINGS_SUCCESS, + }); + } catch (error) { + logger.log('Error loading native currency and testnets pref', error); + } + }; -export const settingsChangeTestnetsEnabled = ( - testnetsEnabled: boolean -) => async (dispatch: Dispatch) => { - dispatch({ - payload: testnetsEnabled, - type: SETTINGS_UPDATE_TESTNET_PREF_SUCCESS, - }); - saveTestnetsEnabled(testnetsEnabled); -}; +export const settingsLoadNetwork = + () => async (dispatch: Dispatch) => { + try { + const network = await getNetwork(); + const chainId = ethereumUtils.getChainIdFromNetwork(network); + await web3SetHttpProvider(network); + dispatch({ + payload: { chainId, network }, + type: SETTINGS_UPDATE_NETWORK_SUCCESS, + }); + } catch (error) { + logger.log('Error loading network settings', error); + } + }; -export const settingsChangeAppIcon = (appIcon: string) => ( - dispatch: Dispatch -) => { - const callback = async () => { - logger.log('changing app icon to', appIcon); +export const settingsLoadLanguage = + () => + async (dispatch: Dispatch) => { try { - await changeIcon(appIcon); - logger.log('icon changed to ', appIcon); - saveAppIcon(appIcon); + const language = await getLanguage(); + updateLanguageLocale(language as Language); dispatch({ - payload: appIcon, - type: SETTINGS_UPDATE_APP_ICON_SUCCESS, + payload: language, + type: SETTINGS_UPDATE_LANGUAGE_SUCCESS, + }); + analytics.identify({ + language, }); } catch (error) { - logger.log('Error changing app icon', error); + logger.log('Error loading language settings', error); } }; - if (android) { - Alert.alert( - lang.t('settings.icon_change.title'), - lang.t('settings.icon_change.warning'), - [ - { - onPress: () => {}, - text: lang.t('settings.icon_change.cancel'), - }, - { - onPress: callback, - text: lang.t('settings.icon_change.confirm'), - }, - ] - ); - } else { - callback(); - } -}; +export const settingsChangeTestnetsEnabled = + (testnetsEnabled: boolean) => + async (dispatch: Dispatch) => { + dispatch({ + payload: testnetsEnabled, + type: SETTINGS_UPDATE_TESTNET_PREF_SUCCESS, + }); + saveTestnetsEnabled(testnetsEnabled); + }; -export const settingsChangeFlashbotsEnabled = ( - flashbotsEnabled: boolean -) => async (dispatch: Dispatch) => { - dispatch({ - payload: flashbotsEnabled, - type: SETTINGS_UPDATE_FLASHBOTS_PREF_SUCCESS, - }); - saveFlashbotsEnabled(flashbotsEnabled); -}; +export const settingsChangeAppIcon = + (appIcon: string) => + (dispatch: Dispatch) => { + const callback = async () => { + logger.log('changing app icon to', appIcon); + try { + await changeIcon(appIcon); + logger.log('icon changed to ', appIcon); + saveAppIcon(appIcon); + dispatch({ + payload: appIcon, + type: SETTINGS_UPDATE_APP_ICON_SUCCESS, + }); + } catch (error) { + logger.log('Error changing app icon', error); + } + }; -export const settingsUpdateAccountAddress = (accountAddress: string) => async ( - dispatch: Dispatch -) => { - dispatch({ - payload: accountAddress, - type: SETTINGS_UPDATE_SETTINGS_ADDRESS, - }); -}; + if (android) { + Alert.alert( + lang.t('settings.icon_change.title'), + lang.t('settings.icon_change.warning'), + [ + { + onPress: () => {}, + text: lang.t('settings.icon_change.cancel'), + }, + { + onPress: callback, + text: lang.t('settings.icon_change.confirm'), + }, + ] + ); + } else { + callback(); + } + }; -export const settingsUpdateNetwork = (network: Network) => async ( - dispatch: Dispatch -) => { - const chainId = ethereumUtils.getChainIdFromNetwork(network); - await web3SetHttpProvider(network); - try { +export const settingsChangeFlashbotsEnabled = + (flashbotsEnabled: boolean) => + async (dispatch: Dispatch) => { dispatch({ - payload: { chainId, network }, - type: SETTINGS_UPDATE_NETWORK_SUCCESS, + payload: flashbotsEnabled, + type: SETTINGS_UPDATE_FLASHBOTS_PREF_SUCCESS, }); - saveNetwork(network); - } catch (error) { - logger.log('Error updating network settings', error); - } -}; + saveFlashbotsEnabled(flashbotsEnabled); + }; -export const settingsChangeLanguage = (language: Language) => async ( - dispatch: Dispatch -) => { - updateLanguageLocale(language); - try { +export const settingsUpdateAccountAddress = + (accountAddress: string) => + async (dispatch: Dispatch) => { dispatch({ - payload: language, - type: SETTINGS_UPDATE_LANGUAGE_SUCCESS, + payload: accountAddress, + type: SETTINGS_UPDATE_SETTINGS_ADDRESS, }); - saveLanguage(language); - analytics.identify({ language }); - } catch (error) { - logger.log('Error changing language', error); - } -}; + }; -export const settingsChangeNativeCurrency = ( - nativeCurrency: NativeCurrencyKey -) => async ( - dispatch: ThunkDispatch< - AppState, - unknown, - SettingsStateUpdateNativeCurrencySuccessAction - > -) => { - dispatch(dataResetState()); - dispatch(explorerClearState()); - try { - dispatch({ - payload: nativeCurrency, - type: SETTINGS_UPDATE_NATIVE_CURRENCY_SUCCESS, - }); - dispatch(explorerInit()); - saveNativeCurrency(nativeCurrency); - analytics.identify({ currency: nativeCurrency }); - } catch (error) { - logger.log('Error changing native currency', error); - } -}; +export const settingsUpdateNetwork = + (network: Network) => + async (dispatch: Dispatch) => { + const chainId = ethereumUtils.getChainIdFromNetwork(network); + await web3SetHttpProvider(network); + try { + dispatch({ + payload: { chainId, network }, + type: SETTINGS_UPDATE_NETWORK_SUCCESS, + }); + saveNetwork(network); + } catch (error) { + logger.log('Error updating network settings', error); + } + }; + +export const settingsChangeLanguage = + (language: Language) => + async (dispatch: Dispatch) => { + updateLanguageLocale(language); + try { + dispatch({ + payload: language, + type: SETTINGS_UPDATE_LANGUAGE_SUCCESS, + }); + saveLanguage(language); + analytics.identify({ language }); + } catch (error) { + logger.log('Error changing language', error); + } + }; + +export const settingsChangeNativeCurrency = + (nativeCurrency: NativeCurrencyKey) => + async ( + dispatch: ThunkDispatch< + AppState, + unknown, + SettingsStateUpdateNativeCurrencySuccessAction + > + ) => { + dispatch(dataResetState()); + dispatch(explorerClearState()); + try { + dispatch({ + payload: nativeCurrency, + type: SETTINGS_UPDATE_NATIVE_CURRENCY_SUCCESS, + }); + dispatch(explorerInit()); + saveNativeCurrency(nativeCurrency); + analytics.identify({ currency: nativeCurrency }); + } catch (error) { + logger.log('Error changing native currency', error); + } + }; // -- Reducer --------------------------------------------------------------- // export const INITIAL_STATE: SettingsState = { diff --git a/src/redux/showcaseTokens.ts b/src/redux/showcaseTokens.ts index 3156ef46a1a..abc3286cb4b 100644 --- a/src/redux/showcaseTokens.ts +++ b/src/redux/showcaseTokens.ts @@ -111,119 +111,121 @@ interface ShowcaseTokensUpdateAction { * Loads showcased token IDs and web-data settings from local storage and * updates state. */ -export const showcaseTokensLoadState = () => async ( - dispatch: Dispatch< - ShowcaseTokensLoadSuccessAction | ShowcaseTokensLoadFailureAction - >, - getState: AppGetState -) => { - try { - const { accountAddress, network } = getState().settings; +export const showcaseTokensLoadState = + () => + async ( + dispatch: Dispatch< + ShowcaseTokensLoadSuccessAction | ShowcaseTokensLoadFailureAction + >, + getState: AppGetState + ) => { + try { + const { accountAddress, network } = getState().settings; - const showcaseTokens = await getShowcaseTokens(accountAddress, network); - const pref = await getWebDataEnabled(accountAddress, network); + const showcaseTokens = await getShowcaseTokens(accountAddress, network); + const pref = await getWebDataEnabled(accountAddress, network); - dispatch({ - payload: { - showcaseTokens, - webDataEnabled: !!pref, - }, - type: SHOWCASE_TOKENS_LOAD_SUCCESS, - }); - } catch (error) { - dispatch({ type: SHOWCASE_TOKENS_LOAD_FAILURE }); - } -}; + dispatch({ + payload: { + showcaseTokens, + webDataEnabled: !!pref, + }, + type: SHOWCASE_TOKENS_LOAD_SUCCESS, + }); + } catch (error) { + dispatch({ type: SHOWCASE_TOKENS_LOAD_FAILURE }); + } + }; /** * Loads showcased token IDs and web-data settings from firebase and * updates state. */ -export const showcaseTokensUpdateStateFromWeb = () => async ( - dispatch: Dispatch< - ShowcaseTokensFetchSuccessAction | ShowcaseTokensFetchFailureAction - >, - getState: AppGetState -) => { - try { - const isReadOnlyWallet = - getState().wallets.selected?.type === WalletTypes.readOnly; - const { accountAddress, network } = getState().settings; +export const showcaseTokensUpdateStateFromWeb = + () => + async ( + dispatch: Dispatch< + ShowcaseTokensFetchSuccessAction | ShowcaseTokensFetchFailureAction + >, + getState: AppGetState + ) => { + try { + const isReadOnlyWallet = + getState().wallets.selected?.type === WalletTypes.readOnly; + const { accountAddress, network } = getState().settings; - // if web data is enabled, fetch values from cloud - const pref = await getWebDataEnabled(accountAddress, network); + // if web data is enabled, fetch values from cloud + const pref = await getWebDataEnabled(accountAddress, network); - if ((!isReadOnlyWallet && pref) || isReadOnlyWallet) { - const showcaseTokensFromCloud = (await getPreference( - 'showcase', - accountAddress - )) as any | undefined; - if ( - showcaseTokensFromCloud?.showcase?.ids && - showcaseTokensFromCloud?.showcase?.ids.length > 0 - ) { - dispatch({ - payload: { - showcaseTokens: showcaseTokensFromCloud.showcase.ids, - webDataEnabled: !!pref, - }, - type: SHOWCASE_TOKENS_FETCH_SUCCESS, - }); + if ((!isReadOnlyWallet && pref) || isReadOnlyWallet) { + const showcaseTokensFromCloud = (await getPreference( + 'showcase', + accountAddress + )) as any | undefined; + if ( + showcaseTokensFromCloud?.showcase?.ids && + showcaseTokensFromCloud?.showcase?.ids.length > 0 + ) { + dispatch({ + payload: { + showcaseTokens: showcaseTokensFromCloud.showcase.ids, + webDataEnabled: !!pref, + }, + type: SHOWCASE_TOKENS_FETCH_SUCCESS, + }); + } } + } catch (error) { + dispatch({ type: SHOWCASE_TOKENS_FETCH_FAILURE }); } - } catch (error) { - dispatch({ type: SHOWCASE_TOKENS_FETCH_FAILURE }); - } -}; + }; /** * Adds a token ID to the showcase in state and updates local storage. * * @param tokenId The new token ID. */ -export const addShowcaseToken = (tokenId: string) => ( - dispatch: Dispatch, - getState: AppGetState -) => { - const account = getState().wallets.selected!; +export const addShowcaseToken = + (tokenId: string) => + (dispatch: Dispatch, getState: AppGetState) => { + const account = getState().wallets.selected!; - if (account.type === WalletTypes.readOnly) return; + if (account.type === WalletTypes.readOnly) return; - const { accountAddress, network } = getState().settings; - const { showcaseTokens = [] } = getState().showcaseTokens; - const updatedShowcaseTokens = showcaseTokens.concat(tokenId); - dispatch({ - payload: updatedShowcaseTokens, - type: SHOWCASE_TOKENS_UPDATE, - }); - saveShowcaseTokens(updatedShowcaseTokens, accountAddress, network); -}; + const { accountAddress, network } = getState().settings; + const { showcaseTokens = [] } = getState().showcaseTokens; + const updatedShowcaseTokens = showcaseTokens.concat(tokenId); + dispatch({ + payload: updatedShowcaseTokens, + type: SHOWCASE_TOKENS_UPDATE, + }); + saveShowcaseTokens(updatedShowcaseTokens, accountAddress, network); + }; /** * Removes a token ID from the showcase in state and updates local storage. * * @param tokenId The token ID to remove. */ -export const removeShowcaseToken = (tokenId: string) => ( - dispatch: Dispatch, - getState: AppGetState -) => { - const account = getState().wallets.selected!; +export const removeShowcaseToken = + (tokenId: string) => + (dispatch: Dispatch, getState: AppGetState) => { + const account = getState().wallets.selected!; - if (account.type === WalletTypes.readOnly) return; + if (account.type === WalletTypes.readOnly) return; - const { accountAddress, network } = getState().settings; - const { showcaseTokens } = getState().showcaseTokens; + const { accountAddress, network } = getState().settings; + const { showcaseTokens } = getState().showcaseTokens; - const updatedShowcaseTokens = without(showcaseTokens, tokenId); + const updatedShowcaseTokens = without(showcaseTokens, tokenId); - dispatch({ - payload: updatedShowcaseTokens, - type: SHOWCASE_TOKENS_UPDATE, - }); + dispatch({ + payload: updatedShowcaseTokens, + type: SHOWCASE_TOKENS_UPDATE, + }); - saveShowcaseTokens(updatedShowcaseTokens, accountAddress, network); -}; + saveShowcaseTokens(updatedShowcaseTokens, accountAddress, network); + }; /** * Updates whether or not web data should be enabled in state and @@ -233,17 +235,15 @@ export const removeShowcaseToken = (tokenId: string) => ( * @param address The current user's address. * @param network The current network. */ -export const updateWebDataEnabled = ( - enabled: boolean, - address: string, - network = networkTypes.mainnet -) => async (dispatch: Dispatch) => { - dispatch({ - payload: enabled, - type: UPDATE_WEB_DATA_ENABLED, - }); - await saveWebDataEnabled(enabled, address.toLowerCase(), network); -}; +export const updateWebDataEnabled = + (enabled: boolean, address: string, network = networkTypes.mainnet) => + async (dispatch: Dispatch) => { + dispatch({ + payload: enabled, + type: UPDATE_WEB_DATA_ENABLED, + }); + await saveWebDataEnabled(enabled, address.toLowerCase(), network); + }; // -- Reducer ----------------------------------------- // diff --git a/src/redux/swap.ts b/src/redux/swap.ts index 3f0299c3c01..9cea3464c70 100644 --- a/src/redux/swap.ts +++ b/src/redux/swap.ts @@ -58,147 +58,141 @@ const SWAP_UPDATE_QUOTE = 'swap/SWAP_UPDATE_QUOTE'; const SWAP_CLEAR_STATE = 'swap/SWAP_CLEAR_STATE'; // -- Actions ---------------------------------------- // -export const updateSwapTypeDetails = ( - type: string, - typeSpecificParameters?: TypeSpecificParameters | null -) => (dispatch: AppDispatch) => { - dispatch({ - payload: { - type, - typeSpecificParameters, - }, - type: SWAP_UPDATE_TYPE_DETAILS, - }); -}; +export const updateSwapTypeDetails = + (type: string, typeSpecificParameters?: TypeSpecificParameters | null) => + (dispatch: AppDispatch) => { + dispatch({ + payload: { + type, + typeSpecificParameters, + }, + type: SWAP_UPDATE_TYPE_DETAILS, + }); + }; -export const updateSwapSlippage = (slippage: number) => ( - dispatch: AppDispatch -) => { - dispatch({ - payload: slippage, - type: SWAP_UPDATE_SLIPPAGE, - }); -}; +export const updateSwapSlippage = + (slippage: number) => (dispatch: AppDispatch) => { + dispatch({ + payload: slippage, + type: SWAP_UPDATE_SLIPPAGE, + }); + }; -export const updateSwapSource = (newSource: Source) => ( - dispatch: AppDispatch -) => { - dispatch({ - payload: newSource, - type: SWAP_UPDATE_SOURCE, - }); -}; +export const updateSwapSource = + (newSource: Source) => (dispatch: AppDispatch) => { + dispatch({ + payload: newSource, + type: SWAP_UPDATE_SOURCE, + }); + }; -export const updateSwapInputAmount = ( - value: string | null, - maxInputUpdate = false -) => (dispatch: AppDispatch) => { - dispatch({ - payload: { independentValue: value, maxInputUpdate }, - type: SWAP_UPDATE_INPUT_AMOUNT, - }); -}; +export const updateSwapInputAmount = + (value: string | null, maxInputUpdate = false) => + (dispatch: AppDispatch) => { + dispatch({ + payload: { independentValue: value, maxInputUpdate }, + type: SWAP_UPDATE_INPUT_AMOUNT, + }); + }; -export const updateSwapNativeAmount = (value: string | null) => ( - dispatch: AppDispatch -) => { - dispatch({ - payload: value, - type: SWAP_UPDATE_NATIVE_AMOUNT, - }); -}; +export const updateSwapNativeAmount = + (value: string | null) => (dispatch: AppDispatch) => { + dispatch({ + payload: value, + type: SWAP_UPDATE_NATIVE_AMOUNT, + }); + }; -export const updateSwapOutputAmount = (value: string | null) => ( - dispatch: AppDispatch -) => { - dispatch({ - payload: value, - type: SWAP_UPDATE_OUTPUT_AMOUNT, - }); -}; +export const updateSwapOutputAmount = + (value: string | null) => (dispatch: AppDispatch) => { + dispatch({ + payload: value, + type: SWAP_UPDATE_OUTPUT_AMOUNT, + }); + }; -export const updateSwapInputCurrency = ( - newInputCurrency: SwappableAsset | null, - ignoreTypeCheck = false -) => (dispatch: AppDispatch, getState: AppGetState) => { - const { independentField, outputCurrency, type } = getState().swap; - if ( - type === ExchangeModalTypes.swap && - newInputCurrency?.uniqueId === outputCurrency?.uniqueId && - newInputCurrency - ) { - dispatch(flipSwapCurrencies(false)); - } else { - dispatch({ payload: newInputCurrency, type: SWAP_UPDATE_INPUT_CURRENCY }); +export const updateSwapInputCurrency = + (newInputCurrency: SwappableAsset | null, ignoreTypeCheck = false) => + (dispatch: AppDispatch, getState: AppGetState) => { + const { independentField, outputCurrency, type } = getState().swap; if ( type === ExchangeModalTypes.swap && - newInputCurrency?.network !== outputCurrency?.network && - newInputCurrency && - !ignoreTypeCheck + newInputCurrency?.uniqueId === outputCurrency?.uniqueId && + newInputCurrency ) { - dispatch(updateSwapOutputCurrency(null, true)); - } + dispatch(flipSwapCurrencies(false)); + } else { + dispatch({ payload: newInputCurrency, type: SWAP_UPDATE_INPUT_CURRENCY }); + if ( + type === ExchangeModalTypes.swap && + newInputCurrency?.network !== outputCurrency?.network && + newInputCurrency && + !ignoreTypeCheck + ) { + dispatch(updateSwapOutputCurrency(null, true)); + } - if (newInputCurrency) { - dispatch(fetchAssetPrices(newInputCurrency.address)); - } - if (independentField === SwapModalField.input) { - dispatch(updateSwapInputAmount(null)); + if (newInputCurrency) { + dispatch(fetchAssetPrices(newInputCurrency.address)); + } + if (independentField === SwapModalField.input) { + dispatch(updateSwapInputAmount(null)); + } } - } -}; + }; -export const updateSwapOutputCurrency = ( - newOutputCurrency: SwappableAsset | null, - ignoreTypeCheck = false -) => (dispatch: AppDispatch, getState: AppGetState) => { - const { independentField, inputCurrency, type } = getState().swap; - if ( - newOutputCurrency?.uniqueId === inputCurrency?.uniqueId && - newOutputCurrency - ) { - dispatch(flipSwapCurrencies(true)); - } else { +export const updateSwapOutputCurrency = + (newOutputCurrency: SwappableAsset | null, ignoreTypeCheck = false) => + (dispatch: AppDispatch, getState: AppGetState) => { + const { independentField, inputCurrency, type } = getState().swap; if ( - type === ExchangeModalTypes.swap && - newOutputCurrency?.network !== inputCurrency?.network && - newOutputCurrency && - !ignoreTypeCheck + newOutputCurrency?.uniqueId === inputCurrency?.uniqueId && + newOutputCurrency ) { - dispatch(updateSwapInputCurrency(null, true)); - } + dispatch(flipSwapCurrencies(true)); + } else { + if ( + type === ExchangeModalTypes.swap && + newOutputCurrency?.network !== inputCurrency?.network && + newOutputCurrency && + !ignoreTypeCheck + ) { + dispatch(updateSwapInputCurrency(null, true)); + } - dispatch({ payload: newOutputCurrency, type: SWAP_UPDATE_OUTPUT_CURRENCY }); - if (newOutputCurrency) { - dispatch(fetchAssetPrices(newOutputCurrency.address)); + dispatch({ + payload: newOutputCurrency, + type: SWAP_UPDATE_OUTPUT_CURRENCY, + }); + if (newOutputCurrency) { + dispatch(fetchAssetPrices(newOutputCurrency.address)); + } + if ( + independentField === SwapModalField.output || + newOutputCurrency === null + ) { + dispatch(updateSwapOutputAmount(null)); + } } - if ( - independentField === SwapModalField.output || - newOutputCurrency === null - ) { - dispatch(updateSwapOutputAmount(null)); - } - } -}; + }; -export const flipSwapCurrencies = ( - outputIndependentField: boolean, - independentValue?: string | null -) => (dispatch: AppDispatch, getState: AppGetState) => { - const { inputCurrency, outputCurrency } = getState().swap; - dispatch({ - payload: { - flipCurrenciesUpdate: true, - independentField: outputIndependentField - ? SwapModalField.output - : SwapModalField.input, - independentValue, - newInputCurrency: outputCurrency, - newOutputCurrency: inputCurrency, - }, - type: SWAP_FLIP_CURRENCIES, - }); -}; +export const flipSwapCurrencies = + (outputIndependentField: boolean, independentValue?: string | null) => + (dispatch: AppDispatch, getState: AppGetState) => { + const { inputCurrency, outputCurrency } = getState().swap; + dispatch({ + payload: { + flipCurrenciesUpdate: true, + independentField: outputIndependentField + ? SwapModalField.output + : SwapModalField.input, + independentValue, + newInputCurrency: outputCurrency, + newOutputCurrency: inputCurrency, + }, + type: SWAP_FLIP_CURRENCIES, + }); + }; export const updateSwapQuote = (value: any) => (dispatch: AppDispatch) => { dispatch({ diff --git a/src/redux/transactionSignatures.ts b/src/redux/transactionSignatures.ts index 5efd5604c45..a83c8969dc9 100644 --- a/src/redux/transactionSignatures.ts +++ b/src/redux/transactionSignatures.ts @@ -10,39 +10,37 @@ const TRANSACTION_SIGNATURES_LOAD_TRANSACTION_SIGNATURES_SUCCESS = 'transactionSignatures/DATA_LOAD_TRANSACTION_SIGNATURES_SUCCESS'; // -- Actions ---------------------------------------- // -export const transactionSignaturesLoadState = () => async ( - dispatch: AppDispatch -) => { - try { - const signatures = await getTransactionSignatures(); - dispatch({ - payload: signatures, - type: TRANSACTION_SIGNATURES_LOAD_TRANSACTION_SIGNATURES_SUCCESS, - }); - // eslint-disable-next-line no-empty - } catch (error) {} -}; - -export const transactionSignaturesDataAddNewSignature = ( - parsedSignature: string, - bytes: string -) => async (dispatch: AppDispatch, getState: AppGetState) => { - const { signatures } = getState().transactionSignatures; - if (parsedSignature) { - const newTransactionSignatures = { - ...signatures, - [bytes]: parsedSignature, - }; +export const transactionSignaturesLoadState = + () => async (dispatch: AppDispatch) => { try { + const signatures = await getTransactionSignatures(); dispatch({ - payload: newTransactionSignatures, - type: TRANSACTION_SIGNATURES_ADD_NEW_TRANSACTION_SIGNATURE_SUCCESS, + payload: signatures, + type: TRANSACTION_SIGNATURES_LOAD_TRANSACTION_SIGNATURES_SUCCESS, }); - saveTransactionSignatures(newTransactionSignatures); // eslint-disable-next-line no-empty - } catch (e) {} - } -}; + } catch (error) {} + }; + +export const transactionSignaturesDataAddNewSignature = + (parsedSignature: string, bytes: string) => + async (dispatch: AppDispatch, getState: AppGetState) => { + const { signatures } = getState().transactionSignatures; + if (parsedSignature) { + const newTransactionSignatures = { + ...signatures, + [bytes]: parsedSignature, + }; + try { + dispatch({ + payload: newTransactionSignatures, + type: TRANSACTION_SIGNATURES_ADD_NEW_TRANSACTION_SIGNATURE_SUCCESS, + }); + saveTransactionSignatures(newTransactionSignatures); + // eslint-disable-next-line no-empty + } catch (e) {} + } + }; // -- Reducer ----------------------------------------- // const INITIAL_STATE: { signatures: { [key: string]: string } } = { diff --git a/src/redux/walletconnect.ts b/src/redux/walletconnect.ts index 26fcc41459f..b1a970f0444 100644 --- a/src/redux/walletconnect.ts +++ b/src/redux/walletconnect.ts @@ -234,13 +234,12 @@ const getNativeOptions = async () => { /** * Updates the state to mark as pending redirection. */ -export const walletConnectSetPendingRedirect = () => ( - dispatch: Dispatch -) => { - dispatch({ - type: WALLETCONNECT_SET_PENDING_REDIRECT, - }); -}; +export const walletConnectSetPendingRedirect = + () => (dispatch: Dispatch) => { + dispatch({ + type: WALLETCONNECT_SET_PENDING_REDIRECT, + }); + }; /** * Updaets the state to disable a pending redirect and either redirect or @@ -250,48 +249,47 @@ export const walletConnectSetPendingRedirect = () => ( * a scheme is not specified. * @param scheme The scheme to open, if specified. */ -export const walletConnectRemovePendingRedirect = ( - type: WalletconnectResultType, - scheme?: string | null -) => (dispatch: Dispatch) => { - dispatch({ - type: WALLETCONNECT_REMOVE_PENDING_REDIRECT, - }); - const lastActiveTime = new Date().getTime(); - if (scheme) { - Linking.openURL(`${scheme}://`); - } else if (type !== 'timedOut') { - if (type === 'sign' || type === 'transaction') { - showRedirectSheetThreshold += BIOMETRICS_ANIMATION_DELAY; - if (!IS_IOS) { - setTimeout(() => { - Minimizer.goBack(); - }, BIOMETRICS_ANIMATION_DELAY); - } - } else if (type === 'sign-canceled' || type === 'transaction-canceled') { - if (!IS_IOS) { - setTimeout(() => { - Minimizer.goBack(); - }, 300); +export const walletConnectRemovePendingRedirect = + (type: WalletconnectResultType, scheme?: string | null) => + (dispatch: Dispatch) => { + dispatch({ + type: WALLETCONNECT_REMOVE_PENDING_REDIRECT, + }); + const lastActiveTime = new Date().getTime(); + if (scheme) { + Linking.openURL(`${scheme}://`); + } else if (type !== 'timedOut') { + if (type === 'sign' || type === 'transaction') { + showRedirectSheetThreshold += BIOMETRICS_ANIMATION_DELAY; + if (!IS_IOS) { + setTimeout(() => { + Minimizer.goBack(); + }, BIOMETRICS_ANIMATION_DELAY); + } + } else if (type === 'sign-canceled' || type === 'transaction-canceled') { + if (!IS_IOS) { + setTimeout(() => { + Minimizer.goBack(); + }, 300); + } + } else { + !IS_TEST && !IS_IOS && Minimizer.goBack(); } - } else { - !IS_TEST && !IS_IOS && Minimizer.goBack(); + // If it's still active after showRedirectSheetThreshold + // We need to show the redirect sheet cause the redirect + // didn't work + setTimeout(() => { + const now = new Date().getTime(); + const delta = now - lastActiveTime; + if (AppState.currentState === 'active' && delta < 1000) { + return Navigation.handleAction(Routes.WALLET_CONNECT_REDIRECT_SHEET, { + type, + }); + } + return; + }, showRedirectSheetThreshold); } - // If it's still active after showRedirectSheetThreshold - // We need to show the redirect sheet cause the redirect - // didn't work - setTimeout(() => { - const now = new Date().getTime(); - const delta = now - lastActiveTime; - if (AppState.currentState === 'active' && delta < 1000) { - return Navigation.handleAction(Routes.WALLET_CONNECT_REDIRECT_SHEET, { - type, - }); - } - return; - }, showRedirectSheetThreshold); - } -}; + }; /** * Handles an incoming WalletConnect session request and updates state @@ -300,208 +298,206 @@ export const walletConnectRemovePendingRedirect = ( * @param uri The WalletConnect URI. * @param callback The callback function to use. */ -export const walletConnectOnSessionRequest = ( - uri: string, - connector?: string, - callback?: WalletconnectRequestCallback -) => async ( - dispatch: ThunkDispatch, - getState: AppGetState -) => { - // branch and linking are triggering this twice - // also branch trigger this when the app is coming back from background - // so this is a way to handle this case without persisting anything - const { walletConnectUris } = getState().walletconnect; - if (walletConnectUris.includes(uri)) return; - dispatch(saveWalletConnectUri(uri)); - - let timeout: ReturnType | null = null; - let walletConnector: WalletConnect | null = null; - const receivedTimestamp = Date.now(); - try { - const { clientMeta, push } = await getNativeOptions(); +export const walletConnectOnSessionRequest = + (uri: string, connector?: string, callback?: WalletconnectRequestCallback) => + async ( + dispatch: ThunkDispatch, + getState: AppGetState + ) => { + // branch and linking are triggering this twice + // also branch trigger this when the app is coming back from background + // so this is a way to handle this case without persisting anything + const { walletConnectUris } = getState().walletconnect; + if (walletConnectUris.includes(uri)) return; + dispatch(saveWalletConnectUri(uri)); + + let timeout: ReturnType | null = null; + let walletConnector: WalletConnect | null = null; + const receivedTimestamp = Date.now(); try { - // Don't initiate a new session if we have already established one using this walletconnect URI - const allSessions = await getAllValidWalletConnectSessions(); - const wcUri = parseWalletConnectUri(uri); + const { clientMeta, push } = await getNativeOptions(); + try { + // Don't initiate a new session if we have already established one using this walletconnect URI + const allSessions = await getAllValidWalletConnectSessions(); + const wcUri = parseWalletConnectUri(uri); + + const alreadyConnected = Object.values(allSessions).some(session => { + return ( + session.handshakeTopic === wcUri.handshakeTopic && + session.key === wcUri.key + ); + }); - const alreadyConnected = Object.values(allSessions).some(session => { - return ( - session.handshakeTopic === wcUri.handshakeTopic && - session.key === wcUri.key - ); - }); + if (alreadyConnected) { + return; + } - if (alreadyConnected) { - return; - } + walletConnector = new WalletConnect({ clientMeta, uri }, push); + let meta: WalletconnectApprovalSheetRouteParams['meta'] | false = false; + let navigated = false; + let timedOut = false; + let routeParams: WalletconnectApprovalSheetRouteParams = { + callback: async ( + approved, + chainId, + accountAddress, + peerId, + dappScheme, + dappName, + dappUrl + ) => { + if (approved) { + dispatch(setPendingRequest(peerId, walletConnector!)); + dispatch( + walletConnectApproveSession( + peerId, + callback, + dappScheme, + chainId, + accountAddress + ) + ); + analytics.track('Approved new WalletConnect session', { + dappName, + dappUrl, + connector, + }); + } else if (!timedOut) { + await dispatch( + walletConnectRejectSession(peerId, walletConnector!) + ); + callback?.('reject', dappScheme); + analytics.track('Rejected new WalletConnect session', { + dappName, + dappUrl, + connector, + }); + } else { + callback?.('timedOut', dappScheme); + const url = new URL(uri); + // @ts-ignore + const bridge = qs.parse(url?.query)?.bridge; + analytics.track('New WalletConnect session time out', { + bridge, + dappName, + dappUrl, + connector, + }); + } + }, + receivedTimestamp, + }; - walletConnector = new WalletConnect({ clientMeta, uri }, push); - let meta: WalletconnectApprovalSheetRouteParams['meta'] | false = false; - let navigated = false; - let timedOut = false; - let routeParams: WalletconnectApprovalSheetRouteParams = { - callback: async ( - approved, - chainId, - accountAddress, - peerId, - dappScheme, - dappName, - dappUrl - ) => { - if (approved) { - dispatch(setPendingRequest(peerId, walletConnector!)); - dispatch( - walletConnectApproveSession( - peerId, - callback, - dappScheme, - chainId, - accountAddress - ) - ); - analytics.track('Approved new WalletConnect session', { - dappName, - dappUrl, - connector, + walletConnector?.on('session_request', (error, payload) => { + clearTimeout(timeout!); + if (error) { + analytics.track('Error on wc session_request', { + // @ts-ignore + error, + payload, }); - } else if (!timedOut) { - await dispatch( - walletConnectRejectSession(peerId, walletConnector!) - ); - callback?.('reject', dappScheme); - analytics.track('Rejected new WalletConnect session', { - dappName, - dappUrl, - connector, - }); - } else { - callback?.('timedOut', dappScheme); - const url = new URL(uri); - // @ts-ignore - const bridge = qs.parse(url?.query)?.bridge; - analytics.track('New WalletConnect session time out', { - bridge, - dappName, - dappUrl, - connector, + logger.error(new RainbowError('WC: Error on wc session_request'), { + error, + payload, }); + return; } - }, - receivedTimestamp, - }; + const { peerId, peerMeta, chainId } = payload.params[0]; - walletConnector?.on('session_request', (error, payload) => { - clearTimeout(timeout!); - if (error) { - analytics.track('Error on wc session_request', { - // @ts-ignore - error, - payload, - }); - logger.error(new RainbowError('WC: Error on wc session_request'), { - error, - payload, - }); - return; - } - const { peerId, peerMeta, chainId } = payload.params[0]; + const imageUrl = peerMeta?.icons?.[0]; + const dappName = peerMeta?.name; + const dappUrl = peerMeta?.url; + const dappScheme = peerMeta?.scheme; - const imageUrl = peerMeta?.icons?.[0]; - const dappName = peerMeta?.name; - const dappUrl = peerMeta?.url; - const dappScheme = peerMeta?.scheme; + analytics.track('Showing Walletconnect session request', { + dappName, + dappUrl, + connector, + }); - analytics.track('Showing Walletconnect session request', { - dappName, - dappUrl, - connector, + meta = { + chainIds: [chainId], + dappName, + dappScheme, + dappUrl, + imageUrl, + peerId, + }; + + // If we already showed the sheet + // We need navigate to the same route with the updated params + // which now includes the meta + if (navigated && !timedOut) { + routeParams = { ...routeParams, meta, timeout }; + Navigation.handleAction( + Routes.WALLET_CONNECT_APPROVAL_SHEET, + routeParams + ); + } }); - meta = { - chainIds: [chainId], - dappName, - dappScheme, - dappUrl, - imageUrl, - peerId, - }; - - // If we already showed the sheet - // We need navigate to the same route with the updated params - // which now includes the meta - if (navigated && !timedOut) { - routeParams = { ...routeParams, meta, timeout }; - Navigation.handleAction( - Routes.WALLET_CONNECT_APPROVAL_SHEET, - routeParams - ); + let waitingFn: (callback: () => unknown, timeout: number) => unknown = + InteractionManager.runAfterInteractions; + if (IS_TEST) { + waitingFn = setTimeout; } - }); - - let waitingFn: (callback: () => unknown, timeout: number) => unknown = - InteractionManager.runAfterInteractions; - if (IS_TEST) { - waitingFn = setTimeout; - } - waitingFn(async () => { - if (IS_TEST) { - // Wait until the app is idle so we can navigate - // This usually happens only when coming from a cold start - while (!getState().appState.walletReady) { - await delay(300); + waitingFn(async () => { + if (IS_TEST) { + // Wait until the app is idle so we can navigate + // This usually happens only when coming from a cold start + while (!getState().appState.walletReady) { + await delay(300); + } } - } - // We need to add a timeout in case the bridge is down - // to explain the user what's happening - timeout = setTimeout(() => { + // We need to add a timeout in case the bridge is down + // to explain the user what's happening + timeout = setTimeout(() => { + meta = android ? Navigation.getActiveRoute()?.params?.meta : meta; + if (meta) return; + timedOut = true; + routeParams = { ...routeParams, timedOut }; + Navigation.handleAction( + Routes.WALLET_CONNECT_APPROVAL_SHEET, + routeParams + ); + }, 20000); + + // If we have the meta, send it meta = android ? Navigation.getActiveRoute()?.params?.meta : meta; - if (meta) return; - timedOut = true; - routeParams = { ...routeParams, timedOut }; + if (meta) { + routeParams = { ...routeParams, meta }; + } + navigated = true; Navigation.handleAction( Routes.WALLET_CONNECT_APPROVAL_SHEET, routeParams ); - }, 20000); - - // If we have the meta, send it - meta = android ? Navigation.getActiveRoute()?.params?.meta : meta; - if (meta) { - routeParams = { ...routeParams, meta }; - } - navigated = true; - Navigation.handleAction( - Routes.WALLET_CONNECT_APPROVAL_SHEET, - routeParams + }, 2000); + } catch (error: any) { + clearTimeout(timeout!); + logger.error( + new RainbowError('WC: Exception during wc session_request'), + { error } ); - }, 2000); + analytics.track('Exception on wc session_request', { + error, + }); + Alert.alert(lang.t('wallet.wallet_connect.error')); + } } catch (error: any) { clearTimeout(timeout!); logger.error( - new RainbowError('WC: Exception during wc session_request'), + new RainbowError('WC: FCM exception during wc session_request'), { error } ); - analytics.track('Exception on wc session_request', { + analytics.track('FCM exception on wc session_request', { error, }); - Alert.alert(lang.t('wallet.wallet_connect.error')); + Alert.alert(lang.t('wallet.wallet_connect.missing_fcm')); } - } catch (error: any) { - clearTimeout(timeout!); - logger.error( - new RainbowError('WC: FCM exception during wc session_request'), - { error } - ); - analytics.track('FCM exception on wc session_request', { - error, - }); - Alert.alert(lang.t('wallet.wallet_connect.missing_fcm')); - } -}; + }; /** * Starts listening for requests on a given `WalletConnect` instance. @@ -509,228 +505,241 @@ export const walletConnectOnSessionRequest = ( * @param walletConnector The `WalletConnect` instance to listen for requests * on. */ -const listenOnNewMessages = (walletConnector: WalletConnect) => ( - dispatch: ThunkDispatch, - getState: AppGetState -) => { - walletConnector.on('call_request', async (error, payload) => { - logger.debug( - 'WC: Request!', - { error, payload }, - logger.DebugContext.walletconnect - ); - - if (error) { - analytics.track('Error on wc call_request', { - // @ts-ignore - error, - payload, - }); - logger.error(new RainbowError('WC: Error on wc call_request'), { - message: error, - }); - return; - } - - const { clientId, peerId, peerMeta } = walletConnector; - const imageUrl = peerMeta?.icons?.[0]; - const dappName = peerMeta?.name; - const dappUrl = peerMeta?.url; - const requestId = payload.id; - if ( - payload.method === 'wallet_addEthereumChain' || - payload.method === `wallet_switchEthereumChain` - ) { - const { chainId } = payload.params[0]; - const currentNetwork = ethereumUtils.getNetworkFromChainId( - // @ts-expect-error "_chainId" is private. - Number(walletConnector._chainId) +const listenOnNewMessages = + (walletConnector: WalletConnect) => + ( + dispatch: ThunkDispatch, + getState: AppGetState + ) => { + walletConnector.on('call_request', async (error, payload) => { + logger.debug( + 'WC: Request!', + { error, payload }, + logger.DebugContext.walletconnect ); - const supportedChains = RainbowNetworks.filter( - network => network.features.walletconnect - ).map(network => network.id.toString()); - const numericChainId = convertHexToString(chainId); - if (supportedChains.includes(numericChainId)) { - dispatch(walletConnectSetPendingRedirect()); - Navigation.handleAction(Routes.WALLET_CONNECT_APPROVAL_SHEET, { - callback: async (approved: boolean) => { - if (approved) { - walletConnector.approveRequest({ - id: requestId, - result: null, - }); - const { accountAddress } = getState().settings; - logger.debug( - 'WC: Updating session for chainID', - { numericChainId }, - logger.DebugContext.walletconnect - ); - await walletConnector.updateSession({ - accounts: [accountAddress], - // @ts-expect-error "numericChainId" is a string, not a number. - chainId: numericChainId, - }); - dispatch(setWalletConnector(walletConnector)); - saveWalletConnectSession( - walletConnector.peerId, - walletConnector.session - ); - analytics.track('Approved WalletConnect network switch', { - chainId, - dappName, - dappUrl, - }); - dispatch(walletConnectRemovePendingRedirect('connect')); - } else { - walletConnector.rejectRequest({ - error: { message: 'User rejected request' }, - id: requestId, - }); - analytics.track('Rejected new WalletConnect chain request', { - dappName, - dappUrl, - }); - } - }, - currentNetwork, - meta: { - chainIds: [Number(numericChainId)], - dappName, - dappUrl, - imageUrl, - }, - type: WalletConnectApprovalSheetType.switch_chain, + + if (error) { + analytics.track('Error on wc call_request', { + // @ts-ignore + error, + payload, }); - } else { - logger.info('WC: NOT SUPPORTED CHAIN'); - walletConnector.rejectRequest({ - error: { message: 'Chain currently not supported' }, - id: requestId, + logger.error(new RainbowError('WC: Error on wc call_request'), { + message: error, }); + return; } - return; - } else if (!isSigningMethod(payload.method)) { - sendRpcCall(payload) - .then(result => { - walletConnector.approveRequest({ - id: payload.id, - result, + const { clientId, peerId, peerMeta } = walletConnector; + const imageUrl = peerMeta?.icons?.[0]; + const dappName = peerMeta?.name; + const dappUrl = peerMeta?.url; + const requestId = payload.id; + if ( + payload.method === 'wallet_addEthereumChain' || + payload.method === `wallet_switchEthereumChain` + ) { + const { chainId } = payload.params[0]; + const currentNetwork = ethereumUtils.getNetworkFromChainId( + // @ts-expect-error "_chainId" is private. + Number(walletConnector._chainId) + ); + const supportedChains = RainbowNetworks.filter( + network => network.features.walletconnect + ).map(network => network.id.toString()); + const numericChainId = convertHexToString(chainId); + if (supportedChains.includes(numericChainId)) { + dispatch(walletConnectSetPendingRedirect()); + Navigation.handleAction(Routes.WALLET_CONNECT_APPROVAL_SHEET, { + callback: async (approved: boolean) => { + if (approved) { + walletConnector.approveRequest({ + id: requestId, + result: null, + }); + const { accountAddress } = getState().settings; + logger.debug( + 'WC: Updating session for chainID', + { numericChainId }, + logger.DebugContext.walletconnect + ); + await walletConnector.updateSession({ + accounts: [accountAddress], + // @ts-expect-error "numericChainId" is a string, not a number. + chainId: numericChainId, + }); + dispatch(setWalletConnector(walletConnector)); + saveWalletConnectSession( + walletConnector.peerId, + walletConnector.session + ); + analytics.track('Approved WalletConnect network switch', { + chainId, + dappName, + dappUrl, + }); + dispatch(walletConnectRemovePendingRedirect('connect')); + } else { + walletConnector.rejectRequest({ + error: { message: 'User rejected request' }, + id: requestId, + }); + analytics.track('Rejected new WalletConnect chain request', { + dappName, + dappUrl, + }); + } + }, + currentNetwork, + meta: { + chainIds: [Number(numericChainId)], + dappName, + dappUrl, + imageUrl, + }, + type: WalletConnectApprovalSheetType.switch_chain, }); - }) - .catch(error => { + } else { + logger.info('WC: NOT SUPPORTED CHAIN'); walletConnector.rejectRequest({ - error, - id: payload.id, + error: { message: 'Chain currently not supported' }, + id: requestId, }); - }); - return; - } else { - const { wallets } = getState().wallets; - // @ts-expect-error "_accounts" is private. - const address = walletConnector._accounts?.[0]; - const selectedWallet = findWalletWithAccount(wallets!, address); - const isReadOnlyWallet = selectedWallet!.type === WalletTypes.readOnly; - if (isReadOnlyWallet && !enableActionsOnReadOnlyWallet) { - watchingAlert(); - walletConnector.rejectRequest({ - error: { message: 'JSON RPC method not supported' }, - id: payload.id, - }); + } + return; - } - const { requests: pendingRequests } = getState().requests; - const request = !pendingRequests[requestId] - ? dispatch( - addRequestToApprove(clientId, peerId, requestId, payload, peerMeta) - ) - : null; - if (request) { - Navigation.handleAction(Routes.CONFIRM_REQUEST, { - openAutomatically: true, - transactionDetails: request, - }); - InteractionManager.runAfterInteractions(() => { - analytics.track('Showing Walletconnect signing request', { - dappName, - dappUrl, + } else if (!isSigningMethod(payload.method)) { + sendRpcCall(payload) + .then(result => { + walletConnector.approveRequest({ + id: payload.id, + result, + }); + }) + .catch(error => { + walletConnector.rejectRequest({ + error, + id: payload.id, + }); }); - }); + return; + } else { + const { wallets } = getState().wallets; + // @ts-expect-error "_accounts" is private. + const address = walletConnector._accounts?.[0]; + const selectedWallet = findWalletWithAccount(wallets!, address); + const isReadOnlyWallet = selectedWallet!.type === WalletTypes.readOnly; + if (isReadOnlyWallet && !enableActionsOnReadOnlyWallet) { + watchingAlert(); + walletConnector.rejectRequest({ + error: { message: 'JSON RPC method not supported' }, + id: payload.id, + }); + return; + } + const { requests: pendingRequests } = getState().requests; + const request = !pendingRequests[requestId] + ? dispatch( + addRequestToApprove( + clientId, + peerId, + requestId, + payload, + peerMeta + ) + ) + : null; + if (request) { + Navigation.handleAction(Routes.CONFIRM_REQUEST, { + openAutomatically: true, + transactionDetails: request, + }); + InteractionManager.runAfterInteractions(() => { + analytics.track('Showing Walletconnect signing request', { + dappName, + dappUrl, + }); + }); + } } - } - }); - walletConnector.on('disconnect', error => { - if (error) { - logger.error(new RainbowError('WC: Error on wc disconnect'), { - message: error, - }); + }); + walletConnector.on('disconnect', error => { + if (error) { + logger.error(new RainbowError('WC: Error on wc disconnect'), { + message: error, + }); - // we used to throw, so for parity, return - return; - } + // we used to throw, so for parity, return + return; + } - dispatch( - walletConnectDisconnectAllByDappUrl(walletConnector.peerMeta!.url, false) - ); - }); - return walletConnector; -}; + dispatch( + walletConnectDisconnectAllByDappUrl( + walletConnector.peerMeta!.url, + false + ) + ); + }); + return walletConnector; + }; /** * Begins listening to WalletConnect events on existing connections. */ -export const walletConnectLoadState = () => async ( - dispatch: ThunkDispatch< - StoreAppState, - unknown, - WalletconnectUpdateConnectorsAction - >, - getState: AppGetState -) => { - while (!getState().walletconnect.walletConnectors) { - await delay(50); - } - const { walletConnectors } = getState().walletconnect; - let newWalletConnectors = {}; - try { - const allSessions = await getAllValidWalletConnectSessions(); - const { clientMeta, push } = await getNativeOptions(); - - newWalletConnectors = mapValues(allSessions, session => { - const connector = walletConnectors[session.peerId]; - // @ts-expect-error "_transport" is private. - const connectorConnected = connector?._transport.connected; - if (!connectorConnected) { - // @ts-expect-error "_eventManager" is private. - if (connector?._eventManager) { +export const walletConnectLoadState = + () => + async ( + dispatch: ThunkDispatch< + StoreAppState, + unknown, + WalletconnectUpdateConnectorsAction + >, + getState: AppGetState + ) => { + while (!getState().walletconnect.walletConnectors) { + await delay(50); + } + const { walletConnectors } = getState().walletconnect; + let newWalletConnectors = {}; + try { + const allSessions = await getAllValidWalletConnectSessions(); + const { clientMeta, push } = await getNativeOptions(); + + newWalletConnectors = mapValues(allSessions, session => { + const connector = walletConnectors[session.peerId]; + // @ts-expect-error "_transport" is private. + const connectorConnected = connector?._transport.connected; + if (!connectorConnected) { // @ts-expect-error "_eventManager" is private. - connector._eventManager = null; + if (connector?._eventManager) { + // @ts-expect-error "_eventManager" is private. + connector._eventManager = null; + } + const walletConnector = new WalletConnect( + { clientMeta, session }, + push + ); + return dispatch(listenOnNewMessages(walletConnector)); } - const walletConnector = new WalletConnect( - { clientMeta, session }, - push - ); - return dispatch(listenOnNewMessages(walletConnector)); - } - return connector; - }); - } catch (error) { - analytics.track('Error on walletConnectLoadState', { - // @ts-ignore - error, - }); - logger.error(new RainbowError('WC: Error on wc walletConnectLoadState'), { - error, - }); - newWalletConnectors = {}; - } - if (!isEmpty(newWalletConnectors)) { - dispatch({ - payload: newWalletConnectors, - type: WALLETCONNECT_UPDATE_CONNECTORS, - }); - } -}; + return connector; + }); + } catch (error) { + analytics.track('Error on walletConnectLoadState', { + // @ts-ignore + error, + }); + logger.error(new RainbowError('WC: Error on wc walletConnectLoadState'), { + error, + }); + newWalletConnectors = {}; + } + if (!isEmpty(newWalletConnectors)) { + dispatch({ + payload: newWalletConnectors, + type: WALLETCONNECT_UPDATE_CONNECTORS, + }); + } + }; /** * Updates the pending requests to include a new connector. @@ -738,23 +747,22 @@ export const walletConnectLoadState = () => async ( * @param peerId The peer ID for the pending request. * @param walletConnector The `WalletConnect` instance for the pending request. */ -export const setPendingRequest = ( - peerId: string, - walletConnector: WalletConnect -) => ( - dispatch: Dispatch, - getState: AppGetState -) => { - const { pendingRequests } = getState().walletconnect; - const updatedPendingRequests = { - ...pendingRequests, - [peerId]: walletConnector, +export const setPendingRequest = + (peerId: string, walletConnector: WalletConnect) => + ( + dispatch: Dispatch, + getState: AppGetState + ) => { + const { pendingRequests } = getState().walletconnect; + const updatedPendingRequests = { + ...pendingRequests, + [peerId]: walletConnector, + }; + dispatch({ + payload: updatedPendingRequests, + type: WALLETCONNECT_UPDATE_REQUESTS, + }); }; - dispatch({ - payload: updatedPendingRequests, - type: WALLETCONNECT_UPDATE_REQUESTS, - }); -}; /** * Gets an existing pending request for a given peer ID. @@ -763,33 +771,33 @@ export const setPendingRequest = ( * @returns Within a dispatch, returns the pending request's `WalletConnector`, * or undefined. */ -export const getPendingRequest = (peerId: string) => ( - _: Dispatch, - getState: AppGetState -) => { - const { pendingRequests } = getState().walletconnect; - return pendingRequests[peerId]; -}; +export const getPendingRequest = + (peerId: string) => (_: Dispatch, getState: AppGetState) => { + const { pendingRequests } = getState().walletconnect; + return pendingRequests[peerId]; + }; /** * Removes a pending request from state given a peer ID. * @param peerId The peer ID for the pending request to remove. */ -export const removePendingRequest = (peerId: string) => ( - dispatch: Dispatch, - getState: AppGetState -) => { - const { pendingRequests } = getState().walletconnect; - const updatedPendingRequests = pendingRequests; - if (updatedPendingRequests[peerId]) { - // eslint-disable-next-line @typescript-eslint/no-dynamic-delete - delete updatedPendingRequests[peerId]; - } - dispatch({ - payload: updatedPendingRequests, - type: WALLETCONNECT_UPDATE_REQUESTS, - }); -}; +export const removePendingRequest = + (peerId: string) => + ( + dispatch: Dispatch, + getState: AppGetState + ) => { + const { pendingRequests } = getState().walletconnect; + const updatedPendingRequests = pendingRequests; + if (updatedPendingRequests[peerId]) { + // eslint-disable-next-line @typescript-eslint/no-dynamic-delete + delete updatedPendingRequests[peerId]; + } + dispatch({ + payload: updatedPendingRequests, + type: WALLETCONNECT_UPDATE_REQUESTS, + }); + }; /** * Updates the state's `walletConnectors` to include a new instance based on @@ -797,20 +805,22 @@ export const removePendingRequest = (peerId: string) => ( * * @param walletConnector The new `WalletConnect` instance. */ -export const setWalletConnector = (walletConnector: WalletConnect) => ( - dispatch: Dispatch, - getState: AppGetState -) => { - const { walletConnectors } = getState().walletconnect; - const updatedWalletConnectors = { - ...walletConnectors, - [walletConnector.peerId]: walletConnector, +export const setWalletConnector = + (walletConnector: WalletConnect) => + ( + dispatch: Dispatch, + getState: AppGetState + ) => { + const { walletConnectors } = getState().walletconnect; + const updatedWalletConnectors = { + ...walletConnectors, + [walletConnector.peerId]: walletConnector, + }; + dispatch({ + payload: updatedWalletConnectors, + type: WALLETCONNECT_UPDATE_CONNECTORS, + }); }; - dispatch({ - payload: updatedWalletConnectors, - type: WALLETCONNECT_UPDATE_CONNECTORS, - }); -}; /** * Gets a `WalletConnect` instance from `walletConnectors` in state based on a @@ -819,14 +829,12 @@ export const setWalletConnector = (walletConnector: WalletConnect) => ( * @param peerId The peer ID for the `WalletConnect` instance. * @returns Within a dispatch, the `WalletConnect` instance. */ -export const getWalletConnector = (peerId: string) => ( - _: Dispatch, - getState: AppGetState -) => { - const { walletConnectors } = getState().walletconnect; - const walletConnector = walletConnectors[peerId]; - return walletConnector; -}; +export const getWalletConnector = + (peerId: string) => (_: Dispatch, getState: AppGetState) => { + const { walletConnectors } = getState().walletconnect; + const walletConnector = walletConnectors[peerId]; + return walletConnector; + }; /** * Removes a `WalletConnect` instance from the state's `walletConnectors` based @@ -834,21 +842,23 @@ export const getWalletConnector = (peerId: string) => ( * * @param peerId The peer ID of the `WalletConnect` instance to remove. */ -export const removeWalletConnector = (peerId: string) => ( - dispatch: Dispatch, - getState: AppGetState -) => { - const { walletConnectors } = getState().walletconnect; - const updatedWalletConnectors = walletConnectors; - if (updatedWalletConnectors[peerId]) { - // eslint-disable-next-line @typescript-eslint/no-dynamic-delete - delete updatedWalletConnectors[peerId]; - } - dispatch({ - payload: updatedWalletConnectors, - type: WALLETCONNECT_UPDATE_CONNECTORS, - }); -}; +export const removeWalletConnector = + (peerId: string) => + ( + dispatch: Dispatch, + getState: AppGetState + ) => { + const { walletConnectors } = getState().walletconnect; + const updatedWalletConnectors = walletConnectors; + if (updatedWalletConnectors[peerId]) { + // eslint-disable-next-line @typescript-eslint/no-dynamic-delete + delete updatedWalletConnectors[peerId]; + } + dispatch({ + payload: updatedWalletConnectors, + type: WALLETCONNECT_UPDATE_CONNECTORS, + }); + }; /** * Updates the account address and chain ID for all connectors that match @@ -858,31 +868,29 @@ export const removeWalletConnector = (peerId: string) => ( * @param accountAddress The account address to use. * @param chainId The chain ID to use. */ -export const walletConnectUpdateSessionConnectorByDappUrl = ( - dappUrl: RequestData['dappUrl'], - accountAddress: string, - chainId: number -) => ( - dispatch: Dispatch, - getState: AppGetState -) => { - const { walletConnectors } = getState().walletconnect; - const connectors = pickBy(walletConnectors, connector => { - return connector?.peerMeta?.url === dappUrl; - }); - const newSessionData = { - accounts: [accountAddress], - chainId, +export const walletConnectUpdateSessionConnectorByDappUrl = + (dappUrl: RequestData['dappUrl'], accountAddress: string, chainId: number) => + ( + dispatch: Dispatch, + getState: AppGetState + ) => { + const { walletConnectors } = getState().walletconnect; + const connectors = pickBy(walletConnectors, connector => { + return connector?.peerMeta?.url === dappUrl; + }); + const newSessionData = { + accounts: [accountAddress], + chainId, + }; + values(connectors).forEach(connector => { + connector.updateSession(newSessionData); + saveWalletConnectSession(connector.peerId, connector.session); + }); + dispatch({ + payload: clone(walletConnectors), + type: WALLETCONNECT_UPDATE_CONNECTORS, + }); }; - values(connectors).forEach(connector => { - connector.updateSession(newSessionData); - saveWalletConnectSession(connector.peerId, connector.session); - }); - dispatch({ - payload: clone(walletConnectors), - type: WALLETCONNECT_UPDATE_CONNECTORS, - }); -}; /** * Approves a WalletConnect session and updates state accordingly. @@ -893,31 +901,33 @@ export const walletConnectUpdateSessionConnectorByDappUrl = ( * @param chainId The chain ID to use in the approval. * @param accountAddress The account address to use in the approval. */ -export const walletConnectApproveSession = ( - peerId: string, - callback: WalletconnectRequestCallback | undefined, - dappScheme: RequestData['dappScheme'], - chainId: number, - accountAddress: string -) => (dispatch: ThunkDispatch) => { - const walletConnector = dispatch(getPendingRequest(peerId)); - walletConnector.approveSession({ - accounts: [accountAddress], - chainId, - }); - - dispatch(removePendingRequest(peerId)); - saveWalletConnectSession(walletConnector.peerId, walletConnector.session); - - const listeningWalletConnector = dispatch( - listenOnNewMessages(walletConnector) - ); - - dispatch(setWalletConnector(listeningWalletConnector)); - if (callback) { - callback('connect', dappScheme); - } -}; +export const walletConnectApproveSession = + ( + peerId: string, + callback: WalletconnectRequestCallback | undefined, + dappScheme: RequestData['dappScheme'], + chainId: number, + accountAddress: string + ) => + (dispatch: ThunkDispatch) => { + const walletConnector = dispatch(getPendingRequest(peerId)); + walletConnector.approveSession({ + accounts: [accountAddress], + chainId, + }); + + dispatch(removePendingRequest(peerId)); + saveWalletConnectSession(walletConnector.peerId, walletConnector.session); + + const listeningWalletConnector = dispatch( + listenOnNewMessages(walletConnector) + ); + + dispatch(setWalletConnector(listeningWalletConnector)); + if (callback) { + callback('connect', dappScheme); + } + }; /** * Rejects a WalletConnect session and updates state accordingly. @@ -925,13 +935,12 @@ export const walletConnectApproveSession = ( * @param peerId The peer ID for the request to reject. * @param walletConnector The `WalletConnect` instance to reject. */ -export const walletConnectRejectSession = ( - peerId: string, - walletConnector: WalletConnect -) => (dispatch: ThunkDispatch) => { - walletConnector.rejectSession(); - dispatch(removePendingRequest(peerId)); -}; +export const walletConnectRejectSession = + (peerId: string, walletConnector: WalletConnect) => + (dispatch: ThunkDispatch) => { + walletConnector.rejectSession(); + dispatch(removePendingRequest(peerId)); + }; /** * Removes all current WalletConnect sessions matching a given URL and @@ -941,44 +950,44 @@ export const walletConnectRejectSession = ( * @param killSession Whether or not to kill the corresponding WalletConnect * session. */ -export const walletConnectDisconnectAllByDappUrl = ( - dappUrl: string, - killSession = true -) => async ( - dispatch: Dispatch, - getState: AppGetState -) => { - const { walletConnectors } = getState().walletconnect; - const matchingWalletConnectors = values( - pickBy( - walletConnectors, - connector => connector?.peerMeta?.url === dappUrl || !connector?.peerMeta - ) - ); - try { - const peerIds = values( - mapValues( - matchingWalletConnectors, - (walletConnector: WalletConnect) => walletConnector.peerId +export const walletConnectDisconnectAllByDappUrl = + (dappUrl: string, killSession = true) => + async ( + dispatch: Dispatch, + getState: AppGetState + ) => { + const { walletConnectors } = getState().walletconnect; + const matchingWalletConnectors = values( + pickBy( + walletConnectors, + connector => + connector?.peerMeta?.url === dappUrl || !connector?.peerMeta ) ); - await removeWalletConnectSessions(peerIds); + try { + const peerIds = values( + mapValues( + matchingWalletConnectors, + (walletConnector: WalletConnect) => walletConnector.peerId + ) + ); + await removeWalletConnectSessions(peerIds); - if (killSession) { - matchingWalletConnectors.forEach(connector => connector?.killSession()); - } + if (killSession) { + matchingWalletConnectors.forEach(connector => connector?.killSession()); + } - dispatch({ - payload: omitBy( - walletConnectors, - connector => connector?.peerMeta?.url === dappUrl - ), - type: WALLETCONNECT_UPDATE_CONNECTORS, - }); - } catch (error) { - Alert.alert(lang.t('wallet.wallet_connect.failed_to_disconnect')); - } -}; + dispatch({ + payload: omitBy( + walletConnectors, + connector => connector?.peerMeta?.url === dappUrl + ), + type: WALLETCONNECT_UPDATE_CONNECTORS, + }); + } catch (error) { + Alert.alert(lang.t('wallet.wallet_connect.failed_to_disconnect')); + } + }; /** * Responds to a `WalletConnect` request. @@ -987,53 +996,57 @@ export const walletConnectDisconnectAllByDappUrl = ( * @param requestId The request ID to respond to. * @param response The response to send. */ -export const walletConnectSendStatus = ( - peerId: string, - requestId: number, - response: { result?: any; error?: any } -) => async (_: Dispatch, getState: AppGetState) => { - const walletConnector = getState().walletconnect.walletConnectors[peerId]; - if (walletConnector) { - const { result, error } = response; - try { - if (result) { - await walletConnector.approveRequest({ id: requestId, result }); - } else { - await walletConnector.rejectRequest({ - error, - id: requestId, - }); +export const walletConnectSendStatus = + ( + peerId: string, + requestId: number, + response: { result?: any; error?: any } + ) => + async (_: Dispatch, getState: AppGetState) => { + const walletConnector = getState().walletconnect.walletConnectors[peerId]; + if (walletConnector) { + const { result, error } = response; + try { + if (result) { + await walletConnector.approveRequest({ id: requestId, result }); + } else { + await walletConnector.rejectRequest({ + error, + id: requestId, + }); + } + } catch (error) { + Alert.alert( + lang.t('wallet.wallet_connect.failed_to_send_request_status') + ); } - } catch (error) { + } else { Alert.alert( - lang.t('wallet.wallet_connect.failed_to_send_request_status') + lang.t( + 'wallet.wallet_connect.walletconnect_session_has_expired_while_trying_to_send' + ) ); } - } else { - Alert.alert( - lang.t( - 'wallet.wallet_connect.walletconnect_session_has_expired_while_trying_to_send' - ) - ); - } -}; + }; /** * Adds a new WalletConnect URI to state. * * @param uri The new URI. */ -export const saveWalletConnectUri = (uri: string) => async ( - dispatch: Dispatch, - getState: AppGetState -) => { - const { walletConnectUris } = getState().walletconnect; - const newWalletConnectUris = [...walletConnectUris, uri]; - dispatch({ - payload: newWalletConnectUris, - type: WALLETCONNECT_ADD_URI, - }); -}; +export const saveWalletConnectUri = + (uri: string) => + async ( + dispatch: Dispatch, + getState: AppGetState + ) => { + const { walletConnectUris } = getState().walletconnect; + const newWalletConnectUris = [...walletConnectUris, uri]; + dispatch({ + payload: newWalletConnectUris, + type: WALLETCONNECT_ADD_URI, + }); + }; // -- Reducer ----------------------------------------- // const INITIAL_STATE: WalletconnectState = { diff --git a/src/redux/wallets.ts b/src/redux/wallets.ts index ab48c8dd7de..ae75024d3a5 100644 --- a/src/redux/wallets.ts +++ b/src/redux/wallets.ts @@ -145,125 +145,127 @@ const WALLETS_SET_SELECTED = 'wallets/SET_SELECTED'; /** * Loads wallet information from storage and updates state accordingly. */ -export const walletsLoadState = (profilesEnabled = false) => async ( - dispatch: ThunkDispatch, - getState: AppGetState -) => { - try { - const { accountAddress } = getState().settings; - let addressFromKeychain: string | null = accountAddress; - const allWalletsResult = await getAllWallets(); - const wallets = allWalletsResult?.wallets || {}; - if (isEmpty(wallets)) return; - const selected = await getSelectedWallet(); - // Prevent irrecoverable state (no selected wallet) - let selectedWallet = selected?.wallet; - // Check if the selected wallet is among all the wallets - if (selectedWallet && !wallets[selectedWallet.id]) { - // If not then we should clear it and default to the first one - const firstWalletKey = Object.keys(wallets)[0]; - selectedWallet = wallets[firstWalletKey]; - await setSelectedWallet(selectedWallet); - } +export const walletsLoadState = + (profilesEnabled = false) => + async ( + dispatch: ThunkDispatch, + getState: AppGetState + ) => { + try { + const { accountAddress } = getState().settings; + let addressFromKeychain: string | null = accountAddress; + const allWalletsResult = await getAllWallets(); + const wallets = allWalletsResult?.wallets || {}; + if (isEmpty(wallets)) return; + const selected = await getSelectedWallet(); + // Prevent irrecoverable state (no selected wallet) + let selectedWallet = selected?.wallet; + // Check if the selected wallet is among all the wallets + if (selectedWallet && !wallets[selectedWallet.id]) { + // If not then we should clear it and default to the first one + const firstWalletKey = Object.keys(wallets)[0]; + selectedWallet = wallets[firstWalletKey]; + await setSelectedWallet(selectedWallet); + } - if (!selectedWallet) { - const address = await loadAddress(); - keys(wallets).some(key => { - const someWallet = wallets[key]; - const found = someWallet.addresses.some(account => { - return ( - toChecksumAddress(account.address) === toChecksumAddress(address!) - ); + if (!selectedWallet) { + const address = await loadAddress(); + keys(wallets).some(key => { + const someWallet = wallets[key]; + const found = someWallet.addresses.some(account => { + return ( + toChecksumAddress(account.address) === toChecksumAddress(address!) + ); + }); + if (found) { + selectedWallet = someWallet; + logger.info('Found selected wallet based on loadAddress result'); + } + return found; }); - if (found) { - selectedWallet = someWallet; - logger.info('Found selected wallet based on loadAddress result'); - } - return found; - }); - } + } - // Recover from broken state (account address not in selected wallet) - if (!addressFromKeychain) { - addressFromKeychain = await loadAddress(); - logger.info( - "addressFromKeychain wasn't set on settings so it is being loaded from loadAddress" - ); - } + // Recover from broken state (account address not in selected wallet) + if (!addressFromKeychain) { + addressFromKeychain = await loadAddress(); + logger.info( + "addressFromKeychain wasn't set on settings so it is being loaded from loadAddress" + ); + } - const selectedAddress = selectedWallet?.addresses.find(a => { - return a.visible && a.address === addressFromKeychain; - }); + const selectedAddress = selectedWallet?.addresses.find(a => { + return a.visible && a.address === addressFromKeychain; + }); - // Let's select the first visible account if we don't have a selected address - if (!selectedAddress) { - const allWallets = Object.values(allWalletsResult?.wallets || {}); - let account = null; - for (const wallet of allWallets) { - for (const rainbowAccount of wallet.addresses) { - if (rainbowAccount.visible) { - account = rainbowAccount; - break; + // Let's select the first visible account if we don't have a selected address + if (!selectedAddress) { + const allWallets = Object.values(allWalletsResult?.wallets || {}); + let account = null; + for (const wallet of allWallets) { + for (const rainbowAccount of wallet.addresses) { + if (rainbowAccount.visible) { + account = rainbowAccount; + break; + } } } + if (!account) return; + await dispatch(settingsUpdateAccountAddress(account.address)); + await saveAddress(account.address); + logger.info( + 'Selected the first visible address because there was not selected one' + ); } - if (!account) return; - await dispatch(settingsUpdateAccountAddress(account.address)); - await saveAddress(account.address); - logger.info( - 'Selected the first visible address because there was not selected one' - ); - } - const walletNames = await getWalletNames(); - dispatch({ - payload: { - selected: selectedWallet, - walletNames, - wallets, - }, - type: WALLETS_LOAD, - }); + const walletNames = await getWalletNames(); + dispatch({ + payload: { + selected: selectedWallet, + walletNames, + wallets, + }, + type: WALLETS_LOAD, + }); - dispatch(fetchWalletNames()); - profilesEnabled && dispatch(fetchWalletENSAvatars()); - return wallets; - } catch (error) { - logger.error(new RainbowError('Exception during walletsLoadState'), { - message: (error as Error)?.message, - }); - } -}; + dispatch(fetchWalletNames()); + profilesEnabled && dispatch(fetchWalletENSAvatars()); + return wallets; + } catch (error) { + logger.error(new RainbowError('Exception during walletsLoadState'), { + message: (error as Error)?.message, + }); + } + }; /** * Saves new wallets to storage and updates state accordingly. * * @param wallets The new wallets. */ -export const walletsUpdate = (wallets: { - [key: string]: RainbowWallet; -}) => async (dispatch: Dispatch) => { - await saveAllWallets(wallets); - dispatch({ - payload: wallets, - type: WALLETS_UPDATE, - }); -}; +export const walletsUpdate = + (wallets: { [key: string]: RainbowWallet }) => + async (dispatch: Dispatch) => { + await saveAllWallets(wallets); + dispatch({ + payload: wallets, + type: WALLETS_UPDATE, + }); + }; /** * Sets the selected wallet in storage and updates state accordingly. * * @param wallet The wallet to mark as selected. */ -export const walletsSetSelected = (wallet: RainbowWallet) => async ( - dispatch: Dispatch -) => { - await setSelectedWallet(wallet); - dispatch({ - payload: wallet, - type: WALLETS_SET_SELECTED, - }); -}; +export const walletsSetSelected = + (wallet: RainbowWallet) => + async (dispatch: Dispatch) => { + await setSelectedWallet(wallet); + dispatch({ + payload: wallet, + type: WALLETS_SET_SELECTED, + }); + }; /** * Marks all wallets with passed ids as backed-up @@ -275,48 +277,50 @@ export const walletsSetSelected = (wallet: RainbowWallet) => async ( * @param backupFile The backup file, if present. * @param updateUserMetadata Whether to update user metadata. */ -export const setAllWalletsWithIdsAsBackedUp = ( - walletIds: RainbowWallet['id'][], - method: RainbowWallet['backupType'], - backupFile: RainbowWallet['backupFile'] = null, - updateUserMetadata = true -) => async ( - dispatch: ThunkDispatch, - getState: AppGetState -) => { - const { wallets, selected } = getState().wallets; - const newWallets = { ...wallets }; - - walletIds.forEach(walletId => { - newWallets[walletId] = { - ...newWallets[walletId], - backedUp: true, - // @ts-expect-error "Date" is not "string." - backupDate: Date.now(), - backupFile, - backupType: method, - }; - }); +export const setAllWalletsWithIdsAsBackedUp = + ( + walletIds: RainbowWallet['id'][], + method: RainbowWallet['backupType'], + backupFile: RainbowWallet['backupFile'] = null, + updateUserMetadata = true + ) => + async ( + dispatch: ThunkDispatch, + getState: AppGetState + ) => { + const { wallets, selected } = getState().wallets; + const newWallets = { ...wallets }; + + walletIds.forEach(walletId => { + newWallets[walletId] = { + ...newWallets[walletId], + backedUp: true, + // @ts-expect-error "Date" is not "string." + backupDate: Date.now(), + backupFile, + backupType: method, + }; + }); - await dispatch(walletsUpdate(newWallets)); - if (selected?.id && walletIds.includes(selected?.id)) { - await dispatch(walletsSetSelected(newWallets[selected.id])); - } + await dispatch(walletsUpdate(newWallets)); + if (selected?.id && walletIds.includes(selected?.id)) { + await dispatch(walletsSetSelected(newWallets[selected.id])); + } - if (method === WalletBackupTypes.cloud && updateUserMetadata) { - try { - await backupUserDataIntoCloud({ wallets: newWallets }); - } catch (e) { - logger.error( - new RainbowError('Saving multiple wallets UserData to cloud failed.'), - { - message: (e as Error)?.message, - } - ); - throw e; + if (method === WalletBackupTypes.cloud && updateUserMetadata) { + try { + await backupUserDataIntoCloud({ wallets: newWallets }); + } catch (e) { + logger.error( + new RainbowError('Saving multiple wallets UserData to cloud failed.'), + { + message: (e as Error)?.message, + } + ); + throw e; + } } - } -}; + }; /** * Marks a wallet as backed-up using a specified method and file in storage @@ -327,82 +331,88 @@ export const setAllWalletsWithIdsAsBackedUp = ( * @param backupFile The backup file, if present. * @param updateUserMetadata Whether to update user metadata. */ -export const setWalletBackedUp = ( - walletId: RainbowWallet['id'], - method: RainbowWallet['backupType'], - backupFile: RainbowWallet['backupFile'] = null, - updateUserMetadata = true -) => async ( - dispatch: ThunkDispatch, - getState: AppGetState -) => { - const { wallets, selected } = getState().wallets; - const newWallets = { ...wallets }; - newWallets[walletId] = { - ...newWallets[walletId], - backedUp: true, - // @ts-expect-error "Date" is not "string." - backupDate: Date.now(), - backupFile, - backupType: method, - }; +export const setWalletBackedUp = + ( + walletId: RainbowWallet['id'], + method: RainbowWallet['backupType'], + backupFile: RainbowWallet['backupFile'] = null, + updateUserMetadata = true + ) => + async ( + dispatch: ThunkDispatch, + getState: AppGetState + ) => { + const { wallets, selected } = getState().wallets; + const newWallets = { ...wallets }; + newWallets[walletId] = { + ...newWallets[walletId], + backedUp: true, + // @ts-expect-error "Date" is not "string." + backupDate: Date.now(), + backupFile, + backupType: method, + }; - await dispatch(walletsUpdate(newWallets)); - if (selected!.id === walletId) { - await dispatch(walletsSetSelected(newWallets[walletId])); - } + await dispatch(walletsUpdate(newWallets)); + if (selected!.id === walletId) { + await dispatch(walletsSetSelected(newWallets[walletId])); + } - if (method === WalletBackupTypes.cloud && updateUserMetadata) { - try { - await backupUserDataIntoCloud({ wallets: newWallets }); - } catch (e) { - logger.error( - new RainbowError('Saving wallet UserData to cloud failed.'), - { - message: (e as Error)?.message, - } - ); - throw e; + if (method === WalletBackupTypes.cloud && updateUserMetadata) { + try { + await backupUserDataIntoCloud({ wallets: newWallets }); + } catch (e) { + logger.error( + new RainbowError('Saving wallet UserData to cloud failed.'), + { + message: (e as Error)?.message, + } + ); + throw e; + } } - } -}; + }; /** * Grabs user data stored in the cloud and based on this data marks wallets * as backed up or not */ -export const updateWalletBackupStatusesBasedOnCloudUserData = () => async ( - dispatch: ThunkDispatch, - getState: AppGetState -) => { - const { wallets, selected } = getState().wallets; - const newWallets = { ...wallets }; - - let currentUserData: { wallets: { [p: string]: RainbowWallet } } | undefined; - try { - currentUserData = await fetchUserDataFromCloud(); - } catch (error) { - logger.error( - new RainbowError( - 'There was an error when trying to update wallet backup statuses' - ), - { error: (error as Error).message } - ); - return; - } - if (currentUserData === undefined) { - return; - } +export const updateWalletBackupStatusesBasedOnCloudUserData = + () => + async ( + dispatch: ThunkDispatch, + getState: AppGetState + ) => { + const { wallets, selected } = getState().wallets; + const newWallets = { ...wallets }; - // build hashmap of address to wallet based on backup metadata - const addressToWalletLookup = new Map(); - Object.values(currentUserData.wallets).forEach(wallet => { - wallet.addresses.forEach(account => { - addressToWalletLookup.set(account.address, wallet); + let currentUserData: + | { wallets: { [p: string]: RainbowWallet } } + | undefined; + try { + currentUserData = await fetchUserDataFromCloud(); + } catch (error) { + logger.error( + new RainbowError( + 'There was an error when trying to update wallet backup statuses' + ), + { error: (error as Error).message } + ); + return; + } + if (currentUserData === undefined) { + return; + } + + // build hashmap of address to wallet based on backup metadata + const addressToWalletLookup = new Map(); + Object.values(currentUserData.wallets).forEach(wallet => { + wallet.addresses.forEach(account => { + addressToWalletLookup.set(account.address, wallet); + }); }); - }); - /* + /* marking wallet as already backed up if all addresses are backed up properly and linked to the same wallet @@ -411,68 +421,70 @@ export const updateWalletBackupStatusesBasedOnCloudUserData = () => async ( * we have an address in the backup metadata, but it's linked to multiple wallet ids (should never happen, but that's a sanity check) */ - Object.values(newWallets).forEach(wallet => { - const localWalletId = wallet.id; + Object.values(newWallets).forEach(wallet => { + const localWalletId = wallet.id; - let relatedCloudWalletId: string | null = null; - for (const account of wallet.addresses) { - const walletDataForCurrentAddress = addressToWalletLookup.get( - account.address - ); - if (!walletDataForCurrentAddress) { - return; + let relatedCloudWalletId: string | null = null; + for (const account of wallet.addresses) { + const walletDataForCurrentAddress = addressToWalletLookup.get( + account.address + ); + if (!walletDataForCurrentAddress) { + return; + } + if (relatedCloudWalletId === null) { + relatedCloudWalletId = walletDataForCurrentAddress.id; + } else if (relatedCloudWalletId !== walletDataForCurrentAddress.id) { + logger.warn( + 'Wallet address is linked to multiple or different accounts in the cloud backup metadata. It could mean that there is an issue with the cloud backup metadata.' + ); + return; + } } + if (relatedCloudWalletId === null) { - relatedCloudWalletId = walletDataForCurrentAddress.id; - } else if (relatedCloudWalletId !== walletDataForCurrentAddress.id) { - logger.warn( - 'Wallet address is linked to multiple or different accounts in the cloud backup metadata. It could mean that there is an issue with the cloud backup metadata.' - ); return; } - } - if (relatedCloudWalletId === null) { - return; - } + // update only if we checked the wallet is actually backed up + const cloudBackupData = currentUserData?.wallets[relatedCloudWalletId]; + if (cloudBackupData) { + newWallets[localWalletId] = { + ...newWallets[localWalletId], + backedUp: cloudBackupData.backedUp, + backupDate: cloudBackupData.backupDate, + backupFile: cloudBackupData.backupFile, + backupType: cloudBackupData.backupType, + }; + } + }); - // update only if we checked the wallet is actually backed up - const cloudBackupData = currentUserData?.wallets[relatedCloudWalletId]; - if (cloudBackupData) { - newWallets[localWalletId] = { - ...newWallets[localWalletId], - backedUp: cloudBackupData.backedUp, - backupDate: cloudBackupData.backupDate, - backupFile: cloudBackupData.backupFile, - backupType: cloudBackupData.backupType, - }; + await dispatch(walletsUpdate(newWallets)); + if (selected?.id) { + await dispatch(walletsSetSelected(newWallets[selected.id])); } - }); - - await dispatch(walletsUpdate(newWallets)); - if (selected?.id) { - await dispatch(walletsSetSelected(newWallets[selected.id])); - } -}; + }; /** * Clears backup status for all users' wallets */ -export const clearAllWalletsBackupStatus = () => async ( - dispatch: ThunkDispatch, - getState: AppGetState -) => { - const { wallets } = getState().wallets; - const newWallets = { ...wallets }; - Object.keys(newWallets).forEach(key => { - newWallets[key].backedUp = undefined; - newWallets[key].backupDate = undefined; - newWallets[key].backupFile = undefined; - newWallets[key].backupType = undefined; - }); +export const clearAllWalletsBackupStatus = + () => + async ( + dispatch: ThunkDispatch, + getState: AppGetState + ) => { + const { wallets } = getState().wallets; + const newWallets = { ...wallets }; + Object.keys(newWallets).forEach(key => { + newWallets[key].backedUp = undefined; + newWallets[key].backupDate = undefined; + newWallets[key].backupFile = undefined; + newWallets[key].backupType = undefined; + }); - await dispatch(walletsUpdate(newWallets)); -}; + await dispatch(walletsUpdate(newWallets)); + }; /** * Updates the selected address in state. @@ -489,54 +501,56 @@ export const addressSetSelected = (address: string) => () => * @param name The name for the new address. * @returns Within a dispatch, a new mapping from wallet IDs to wallet objects. */ -export const createAccountForWallet = ( - id: RainbowWallet['id'], - color: RainbowWallet['color'], - name: RainbowWallet['name'] -) => async ( - dispatch: ThunkDispatch, - getState: AppGetState -) => { - const { wallets } = getState().wallets; - const newWallets = { ...wallets }; - let index = 0; - newWallets[id].addresses.forEach( - account => (index = Math.max(index, account.index)) - ); - const newIndex = index + 1; - const account = (await generateAccount(id, newIndex))!; - const walletColorIndex = - color !== null ? color : addressHashedColorIndex(account!.address)!; - newWallets[id].addresses.push({ - address: account.address, - avatar: null, - color: walletColorIndex, - index: newIndex, - label: name, - visible: true, - }); +export const createAccountForWallet = + ( + id: RainbowWallet['id'], + color: RainbowWallet['color'], + name: RainbowWallet['name'] + ) => + async ( + dispatch: ThunkDispatch, + getState: AppGetState + ) => { + const { wallets } = getState().wallets; + const newWallets = { ...wallets }; + let index = 0; + newWallets[id].addresses.forEach( + account => (index = Math.max(index, account.index)) + ); + const newIndex = index + 1; + const account = (await generateAccount(id, newIndex))!; + const walletColorIndex = + color !== null ? color : addressHashedColorIndex(account!.address)!; + newWallets[id].addresses.push({ + address: account.address, + avatar: null, + color: walletColorIndex, + index: newIndex, + label: name, + visible: true, + }); - await dispatch(updateWebDataEnabled(true, account.address)); + await dispatch(updateWebDataEnabled(true, account.address)); - setPreference(PreferenceActionType.init, 'profile', account.address, { - accountColor: lightModeThemeColors.avatarBackgrounds[walletColorIndex], - accountSymbol: addressHashedEmoji(account.address), - }); + setPreference(PreferenceActionType.init, 'profile', account.address, { + accountColor: lightModeThemeColors.avatarBackgrounds[walletColorIndex], + accountSymbol: addressHashedEmoji(account.address), + }); - // Save all the wallets - saveAllWallets(newWallets); - // Set the address selected (KEYCHAIN) - await saveAddress(account.address); - // Set the wallet selected (KEYCHAIN) - await setSelectedWallet(newWallets[id]); + // Save all the wallets + saveAllWallets(newWallets); + // Set the address selected (KEYCHAIN) + await saveAddress(account.address); + // Set the wallet selected (KEYCHAIN) + await setSelectedWallet(newWallets[id]); - dispatch({ - payload: { selected: newWallets[id], wallets: newWallets }, - type: WALLETS_ADDED_ACCOUNT, - }); + dispatch({ + payload: { selected: newWallets[id], wallets: newWallets }, + type: WALLETS_ADDED_ACCOUNT, + }); - return newWallets; -}; + return newWallets; + }; /** * Fetches ENS avatars for the given `walletsState` and updates state @@ -630,163 +644,177 @@ export const getWalletENSAvatars = async ( * Fetches wallet ENS avatars using `getWalletENSAvatars` with the current * wallets in state. */ -export const fetchWalletENSAvatars = () => async ( - dispatch: ThunkDispatch, - getState: AppGetState -) => getWalletENSAvatars(getState().wallets, dispatch); +export const fetchWalletENSAvatars = + () => + async ( + dispatch: ThunkDispatch, + getState: AppGetState + ) => + getWalletENSAvatars(getState().wallets, dispatch); /** * Fetches wallet names and updates storage and state. */ -export const fetchWalletNames = () => async ( - dispatch: Dispatch, - getState: AppGetState -) => { - const { wallets } = getState().wallets; - const updatedWalletNames: { [address: string]: string } = {}; - - // Fetch ENS names - await Promise.all( - Object.values(wallets ?? {}).flatMap(wallet => { - const visibleAccounts = wallet.addresses?.filter( - address => address.visible - ); - return visibleAccounts.map(async account => { - try { - const ens = await fetchReverseRecordWithRetry(account.address); - if (ens && ens !== account.address) { - updatedWalletNames[account.address] = ens; - } - // eslint-disable-next-line no-empty - } catch (error) {} - return account; - }); - }) - ); +export const fetchWalletNames = + () => + async ( + dispatch: Dispatch, + getState: AppGetState + ) => { + const { wallets } = getState().wallets; + const updatedWalletNames: { [address: string]: string } = {}; + + // Fetch ENS names + await Promise.all( + Object.values(wallets ?? {}).flatMap(wallet => { + const visibleAccounts = wallet.addresses?.filter( + address => address.visible + ); + return visibleAccounts.map(async account => { + try { + const ens = await fetchReverseRecordWithRetry(account.address); + if (ens && ens !== account.address) { + updatedWalletNames[account.address] = ens; + } + // eslint-disable-next-line no-empty + } catch (error) {} + return account; + }); + }) + ); - dispatch({ - payload: updatedWalletNames, - type: WALLETS_UPDATE_NAMES, - }); - saveWalletNames(updatedWalletNames); -}; + dispatch({ + payload: updatedWalletNames, + type: WALLETS_UPDATE_NAMES, + }); + saveWalletNames(updatedWalletNames); + }; /** * Checks the validity of the keychain and updates storage and state * accordingly if the keychain is unhealthy. */ -export const checkKeychainIntegrity = () => async ( - dispatch: ThunkDispatch, - getState: AppGetState -) => { - try { - let healthyKeychain = true; - logger.info('[KeychainIntegrityCheck]: starting checks'); - - const hasAddress = await hasKey(addressKey); - if (hasAddress) { - logger.info('[KeychainIntegrityCheck]: address is ok'); - } else { - healthyKeychain = false; - logger.info( - `[KeychainIntegrityCheck]: address is missing: ${hasAddress}` - ); - } +export const checkKeychainIntegrity = + () => + async ( + dispatch: ThunkDispatch, + getState: AppGetState + ) => { + try { + let healthyKeychain = true; + logger.info('[KeychainIntegrityCheck]: starting checks'); - const hasOldSeedPhraseMigratedFlag = await hasKey(oldSeedPhraseMigratedKey); - if (hasOldSeedPhraseMigratedFlag) { - logger.info('[KeychainIntegrityCheck]: migrated flag is OK'); - } else { - logger.info( - `[KeychainIntegrityCheck]: migrated flag is present: ${hasOldSeedPhraseMigratedFlag}` - ); - } + const hasAddress = await hasKey(addressKey); + if (hasAddress) { + logger.info('[KeychainIntegrityCheck]: address is ok'); + } else { + healthyKeychain = false; + logger.info( + `[KeychainIntegrityCheck]: address is missing: ${hasAddress}` + ); + } - const hasOldSeedphrase = await hasKey(seedPhraseKey); - if (hasOldSeedphrase) { - logger.info('[KeychainIntegrityCheck]: old seed is still present!'); - } else { - logger.info( - `[KeychainIntegrityCheck]: old seed is present: ${hasOldSeedphrase}` + const hasOldSeedPhraseMigratedFlag = await hasKey( + oldSeedPhraseMigratedKey ); - } - - const { wallets, selected } = getState().wallets; - if (!wallets) { - logger.warn('[KeychainIntegrityCheck]: wallets are missing from redux'); - } + if (hasOldSeedPhraseMigratedFlag) { + logger.info('[KeychainIntegrityCheck]: migrated flag is OK'); + } else { + logger.info( + `[KeychainIntegrityCheck]: migrated flag is present: ${hasOldSeedPhraseMigratedFlag}` + ); + } - if (!selected) { - logger.warn( - '[KeychainIntegrityCheck]: selectedWallet is missing from redux' - ); - } + const hasOldSeedphrase = await hasKey(seedPhraseKey); + if (hasOldSeedphrase) { + logger.info('[KeychainIntegrityCheck]: old seed is still present!'); + } else { + logger.info( + `[KeychainIntegrityCheck]: old seed is present: ${hasOldSeedphrase}` + ); + } - const nonReadOnlyWalletKeys = keys(wallets).filter( - key => wallets![key].type !== WalletTypes.readOnly - ); + const { wallets, selected } = getState().wallets; + if (!wallets) { + logger.warn('[KeychainIntegrityCheck]: wallets are missing from redux'); + } - for (const key of nonReadOnlyWalletKeys) { - let healthyWallet = true; - const wallet = wallets![key]; - const seedKeyFound = await hasKey(`${key}_${seedPhraseKey}`); - if (!seedKeyFound) { - healthyWallet = false; - logger.warn('[KeychainIntegrityCheck]: seed key is missing'); - } else { - logger.info('[KeychainIntegrityCheck]: seed key is present'); + if (!selected) { + logger.warn( + '[KeychainIntegrityCheck]: selectedWallet is missing from redux' + ); } - for (const account of wallet.addresses) { - const pkeyFound = await hasKey(`${account.address}_${privateKeyKey}`); - if (!pkeyFound) { + const nonReadOnlyWalletKeys = keys(wallets).filter( + key => wallets![key].type !== WalletTypes.readOnly + ); + + for (const key of nonReadOnlyWalletKeys) { + let healthyWallet = true; + const wallet = wallets![key]; + const seedKeyFound = await hasKey(`${key}_${seedPhraseKey}`); + if (!seedKeyFound) { healthyWallet = false; - logger.warn(`[KeychainIntegrityCheck]: pkey is missing`); + logger.warn('[KeychainIntegrityCheck]: seed key is missing'); } else { - logger.info(`[KeychainIntegrityCheck]: pkey is present`); + logger.info('[KeychainIntegrityCheck]: seed key is present'); } - } - // Handle race condition: - // A wallet is NOT damaged if: - // - it's not imported - // - and hasn't been migrated yet - // - and the old seedphrase is still there - if ( - !wallet.imported && - !hasOldSeedPhraseMigratedFlag && - hasOldSeedphrase - ) { - healthyWallet = true; - } + for (const account of wallet.addresses) { + const pkeyFound = await hasKey(`${account.address}_${privateKeyKey}`); + if (!pkeyFound) { + healthyWallet = false; + logger.warn(`[KeychainIntegrityCheck]: pkey is missing`); + } else { + logger.info(`[KeychainIntegrityCheck]: pkey is present`); + } + } - if (!healthyWallet) { - logger.warn('[KeychainIntegrityCheck]: declaring wallet unhealthy...'); - healthyKeychain = false; - wallet.damaged = true; - await dispatch(walletsUpdate(wallets!)); - // Update selected wallet if needed - if (wallet.id === selected!.id) { + // Handle race condition: + // A wallet is NOT damaged if: + // - it's not imported + // - and hasn't been migrated yet + // - and the old seedphrase is still there + if ( + !wallet.imported && + !hasOldSeedPhraseMigratedFlag && + hasOldSeedphrase + ) { + healthyWallet = true; + } + + if (!healthyWallet) { logger.warn( - '[KeychainIntegrityCheck]: declaring selected wallet unhealthy...' + '[KeychainIntegrityCheck]: declaring wallet unhealthy...' ); - await dispatch(walletsSetSelected(wallets![wallet.id])); + healthyKeychain = false; + wallet.damaged = true; + await dispatch(walletsUpdate(wallets!)); + // Update selected wallet if needed + if (wallet.id === selected!.id) { + logger.warn( + '[KeychainIntegrityCheck]: declaring selected wallet unhealthy...' + ); + await dispatch(walletsSetSelected(wallets![wallet.id])); + } + logger.info('[KeychainIntegrityCheck]: done updating wallets'); } - logger.info('[KeychainIntegrityCheck]: done updating wallets'); } + if (!healthyKeychain) { + captureMessage('Keychain Integrity is not OK'); + } + logger.info('[KeychainIntegrityCheck]: check completed'); + await saveKeychainIntegrityState('done'); + } catch (e) { + logger.error( + new RainbowError("[KeychainIntegrityCheck]: error thrown'"), + { + message: (e as Error)?.message, + } + ); + captureMessage('Error running keychain integrity checks'); } - if (!healthyKeychain) { - captureMessage('Keychain Integrity is not OK'); - } - logger.info('[KeychainIntegrityCheck]: check completed'); - await saveKeychainIntegrityState('done'); - } catch (e) { - logger.error(new RainbowError("[KeychainIntegrityCheck]: error thrown'"), { - message: (e as Error)?.message, - }); - captureMessage('Error running keychain integrity checks'); - } -}; + }; // -- Reducer ----------------------------------------- // const INITIAL_STATE: WalletsState = { diff --git a/src/references/rainbow-token-list/index.ts b/src/references/rainbow-token-list/index.ts index 60d29dc617c..00b99e450f4 100644 --- a/src/references/rainbow-token-list/index.ts +++ b/src/references/rainbow-token-list/index.ts @@ -209,12 +209,12 @@ class RainbowTokenList extends EventEmitter { `Token list update: new update loaded, generated on ${newTokenList?.timestamp}` ) : status === 304 - ? logger.debug( - `Token list update: no change since last update, skipping update.` - ) - : logger.debug( - `Token list update: Token list did not update. (Status: ${status}, CurrentListDate: ${this._tokenListData?.timestamp})` - ); + ? logger.debug( + `Token list update: no change since last update, skipping update.` + ) + : logger.debug( + `Token list update: Token list did not update. (Status: ${status}, CurrentListDate: ${this._tokenListData?.timestamp})` + ); if (newTokenList) { this._tokenListData = newTokenList; diff --git a/src/references/swap/bridges.ts b/src/references/swap/bridges.ts index fa9ab9a37d1..bead5382c2c 100644 --- a/src/references/swap/bridges.ts +++ b/src/references/swap/bridges.ts @@ -40,8 +40,7 @@ export const SocketBridges = { displayName: 'Across', }, 'optimism-bridge': { - icon: - 'https://raw.githubusercontent.com/ethereum-optimism/brand-kit/main/assets/images/Profile-Logo.png', + icon: 'https://raw.githubusercontent.com/ethereum-optimism/brand-kit/main/assets/images/Profile-Logo.png', serviceTime: 1200, displayName: 'Optimism', }, diff --git a/src/resources/assets/UserAssetsQuery.ts b/src/resources/assets/UserAssetsQuery.ts index de3817a68d0..7f06413abdf 100644 --- a/src/resources/assets/UserAssetsQuery.ts +++ b/src/resources/assets/UserAssetsQuery.ts @@ -89,10 +89,8 @@ async function userAssetsQueryFunction({ network => network.enabled && network.networkType !== 'testnet' ).map(network => network.id); - const { - erroredChainIds, - results, - } = await fetchAndParseUserAssetsForChainIds(address, currency, chainIds); + const { erroredChainIds, results } = + await fetchAndParseUserAssetsForChainIds(address, currency, chainIds); let parsedSuccessResults = results; // grab cached data for chain IDs with errors diff --git a/src/resources/assets/assetSelectors.ts b/src/resources/assets/assetSelectors.ts index 55b86307ce9..0d2b1aeb871 100644 --- a/src/resources/assets/assetSelectors.ts +++ b/src/resources/assets/assetSelectors.ts @@ -27,10 +27,8 @@ const sortAssetsByNativeAmount = ( if (!isEmpty(assetsNativePrices)) { assetsNativePrices = parseAssetsNative(assetsNativePrices, nativeCurrency); } - const { - hasValue = EMPTY_ARRAY, - noValue = EMPTY_ARRAY, - } = groupAssetsByMarketValue(assetsNativePrices); + const { hasValue = EMPTY_ARRAY, noValue = EMPTY_ARRAY } = + groupAssetsByMarketValue(assetsNativePrices); const sortedAssetsNoShitcoins = hasValue.sort((a: any, b: any) => { const itemA = Number(a.native?.balance?.amount) ?? 0; diff --git a/src/resources/assets/hardhatAssets.ts b/src/resources/assets/hardhatAssets.ts index 770235091e6..56a9be3bf10 100644 --- a/src/resources/assets/hardhatAssets.ts +++ b/src/resources/assets/hardhatAssets.ts @@ -60,12 +60,11 @@ export const fetchHardhatBalances = async ( ({ asset }) => `${asset.asset_code}_${asset.network}` ); - const tokenAddresses = Object.values( - chainAssetsMap - ).map(({ asset: { asset_code } }) => - asset_code === ETH_ADDRESS - ? ETHEREUM_ADDRESS_FOR_BALANCE_CONTRACT - : asset_code.toLowerCase() + const tokenAddresses = Object.values(chainAssetsMap).map( + ({ asset: { asset_code } }) => + asset_code === ETH_ADDRESS + ? ETHEREUM_ADDRESS_FOR_BALANCE_CONTRACT + : asset_code.toLowerCase() ); const balances = await fetchHardhatBalancesWithBalanceChecker( tokenAddresses, diff --git a/src/resources/cards/cardCollectionQuery.ts b/src/resources/cards/cardCollectionQuery.ts index efb6d10ac9c..e2cfae8cf5b 100644 --- a/src/resources/cards/cardCollectionQuery.ts +++ b/src/resources/cards/cardCollectionQuery.ts @@ -32,7 +32,7 @@ export const TRIMMED_CARD_KEYS = [ 'primaryButton', ] as const; -export type TrimmedCard = Pick & { +export type TrimmedCard = Pick & { sys: Pick; imageCollection: { items: { diff --git a/src/resources/nfts/index.ts b/src/resources/nfts/index.ts index 25e23ac8c96..b457b1906d9 100644 --- a/src/resources/nfts/index.ts +++ b/src/resources/nfts/index.ts @@ -115,12 +115,15 @@ export function useLegacyNFTs({ address }: { address: string }) { const nftsMap = useMemo( () => - nfts.reduce((acc, nft) => { - // index by both uniqueId and fullUniqueId bc why not - acc[nft.uniqueId] = nft; - acc[nft.fullUniqueId] = nft; - return acc; - }, {} as { [key: string]: UniqueAsset }), + nfts.reduce( + (acc, nft) => { + // index by both uniqueId and fullUniqueId bc why not + acc[nft.uniqueId] = nft; + acc[nft.fullUniqueId] = nft; + return acc; + }, + {} as { [key: string]: UniqueAsset } + ), [nfts] ); diff --git a/src/resources/nfts/utils.ts b/src/resources/nfts/utils.ts index 2cc4292e010..57f58930772 100644 --- a/src/resources/nfts/utils.ts +++ b/src/resources/nfts/utils.ts @@ -26,7 +26,8 @@ type ErrorResponse = { }[]; }; -type SuccessResponse = paths['/collections/v6']['get']['responses']['200']['schema']; +type SuccessResponse = + paths['/collections/v6']['get']['responses']['200']['schema']; export async function fetchReservoirNFTFloorPrice( nft: UniqueAsset diff --git a/src/resources/transactions/consolidatedTransactions.ts b/src/resources/transactions/consolidatedTransactions.ts index 25e6a15a7bf..231173e6972 100644 --- a/src/resources/transactions/consolidatedTransactions.ts +++ b/src/resources/transactions/consolidatedTransactions.ts @@ -48,7 +48,7 @@ type ConsolidatedTransactionsQueryKey = ReturnType< // Query Fetcher export async function fetchConsolidatedTransactions< - ConsolidatedTransactionsResult + ConsolidatedTransactionsResult, >( { address, currency, chainIds }: ConsolidatedTransactionsArgs, config: QueryConfig< diff --git a/src/resources/transactions/types.ts b/src/resources/transactions/types.ts index e8219a0027c..977c25ebd5a 100644 --- a/src/resources/transactions/types.ts +++ b/src/resources/transactions/types.ts @@ -181,8 +181,10 @@ const transactionTypes = { ], } as const; -export type TransactionWithChangesType = typeof transactionTypes.withChanges[number]; -export type TransactionWithoutChangesType = typeof transactionTypes.withoutChanges[number]; +export type TransactionWithChangesType = + (typeof transactionTypes.withChanges)[number]; +export type TransactionWithoutChangesType = + (typeof transactionTypes.withoutChanges)[number]; export type TransactionType = | TransactionWithChangesType diff --git a/src/screens/AddCash/index.tsx b/src/screens/AddCash/index.tsx index 4cd88867639..d9e27e3e795 100644 --- a/src/screens/AddCash/index.tsx +++ b/src/screens/AddCash/index.tsx @@ -51,7 +51,11 @@ export function AddCashSheet() { ? deviceHeight - insets.top : deviceHeight + statusBarHeight; - const { isLoading, data: providers, error } = useQuery( + const { + isLoading, + data: providers, + error, + } = useQuery( ['f2c', 'providers'], async () => { const [{ data, error }] = await wait(1000, [await getProviders()]); diff --git a/src/screens/ChangeWalletSheet.tsx b/src/screens/ChangeWalletSheet.tsx index 5da48857731..1b8378a56e2 100644 --- a/src/screens/ChangeWalletSheet.tsx +++ b/src/screens/ChangeWalletSheet.tsx @@ -98,8 +98,9 @@ const getWalletRowCount = (wallets: any) => { if (wallets) { Object.keys(wallets).forEach(key => { // Addresses - count += wallets[key].addresses.filter((account: any) => account.visible) - .length; + count += wallets[key].addresses.filter( + (account: any) => account.visible + ).length; }); } return count; @@ -129,9 +130,8 @@ export default function ChangeWalletSheet() { const [currentAddress, setCurrentAddress] = useState( currentAccountAddress || accountAddress ); - const [currentSelectedWallet, setCurrentSelectedWallet] = useState( - selectedWallet - ); + const [currentSelectedWallet, setCurrentSelectedWallet] = + useState(selectedWallet); const walletRowCount = useMemo(() => getWalletRowCount(wallets), [wallets]); @@ -261,9 +261,8 @@ export default function ChangeWalletSheet() { label: args.name, }; const updatedWalletAddresses = [...walletAddresses]; - updatedWalletAddresses[ - walletAddressIndex - ] = updatedWalletAddress; + updatedWalletAddresses[walletAddressIndex] = + updatedWalletAddress; const updatedWallet = { ...wallets[walletId], @@ -323,9 +322,8 @@ export default function ChangeWalletSheet() { const onPressNotifications = useCallback( (walletName: string, address: string) => { analytics.track('Tapped "Notification Settings"'); - const walletNotificationSettings = getNotificationSettingsForWalletWithAddress( - address - ); + const walletNotificationSettings = + getNotificationSettingsForWalletWithAddress(address); if (walletNotificationSettings) { navigate(Routes.SETTINGS_SHEET, { params: { diff --git a/src/screens/CurrencySelectModal.tsx b/src/screens/CurrencySelectModal.tsx index f568925d9d8..7bae90ead78 100644 --- a/src/screens/CurrencySelectModal.tsx +++ b/src/screens/CurrencySelectModal.tsx @@ -168,16 +168,12 @@ export default function CurrencySelectModal() { const { inputCurrency, outputCurrency } = useSwapCurrencies(); - const { - crosschainExactMatches, - swapCurrencyList, - swapCurrencyListLoading, - } = useSwapCurrencyList(searchQueryForSearch, currentChainId, false); + const { crosschainExactMatches, swapCurrencyList, swapCurrencyListLoading } = + useSwapCurrencyList(searchQueryForSearch, currentChainId, false); - const { - swappableUserAssets, - unswappableUserAssets, - } = useSwappableUserAssets({ outputCurrency }); + const { swappableUserAssets, unswappableUserAssets } = useSwappableUserAssets( + { outputCurrency } + ); const checkForSameNetwork = useCallback( (newAsset: any, selectAsset: any, type: any) => { @@ -289,9 +285,11 @@ export default function CurrencySelectModal() { }, [crosschainExactMatches, swapCurrencyList]); const currencyList = useMemo(() => { - let list = (type === CurrencySelectionTypes.input - ? getWalletCurrencyList() - : activeSwapCurrencyList) as { + let list = ( + type === CurrencySelectionTypes.input + ? getWalletCurrencyList() + : activeSwapCurrencyList + ) as { data: EnrichedExchangeAsset[]; title: string; }[]; @@ -394,9 +392,8 @@ export default function CurrencySelectModal() { currentChainId && currentChainId !== ChainId.mainnet ) { - const currentL2Name = ethereumUtils.getNetworkNameFromChainId( - currentChainId - ); + const currentL2Name = + ethereumUtils.getNetworkNameFromChainId(currentChainId); const currentL2WalletAssets = assetsInWallet.filter( ({ network }) => network && network?.toLowerCase() === currentL2Name?.toLowerCase() diff --git a/src/screens/Diagnostics/DiagnosticsItemRow.tsx b/src/screens/Diagnostics/DiagnosticsItemRow.tsx index f8665fc2a95..9640bdaeccf 100644 --- a/src/screens/Diagnostics/DiagnosticsItemRow.tsx +++ b/src/screens/Diagnostics/DiagnosticsItemRow.tsx @@ -13,11 +13,8 @@ import { DiagnosticsSecretInput } from '@/screens/Diagnostics/DiagnosticsSecretI export const DiagnosticsItemRow = ({ data }: any) => { const { colors } = useTheme(); - const { - busy, - handleSetSeedPhrase, - handlePressImportButton, - } = useImportingWallet(); + const { busy, handleSetSeedPhrase, handlePressImportButton } = + useImportingWallet(); const handlePressRestore = useCallback(async () => { if (busy) return; diff --git a/src/screens/Diagnostics/index.tsx b/src/screens/Diagnostics/index.tsx index 82c5c5bf0fb..7a13785b902 100644 --- a/src/screens/Diagnostics/index.tsx +++ b/src/screens/Diagnostics/index.tsx @@ -71,9 +71,8 @@ export const WalletDiagnosticsSheet = () => { if (userPin) { secret = await encryptor.decrypt(userPin, secret); } - const { address, type } = await deriveAccountFromWalletInput( - secret - ); + const { address, type } = + await deriveAccountFromWalletInput(secret); let createdAt = null; let label = null; Object.keys(walletsWithBalancesAndNames).some(k => { diff --git a/src/screens/ENSAdditionalRecordsSheet.tsx b/src/screens/ENSAdditionalRecordsSheet.tsx index 09dec072b69..058874b020d 100644 --- a/src/screens/ENSAdditionalRecordsSheet.tsx +++ b/src/screens/ENSAdditionalRecordsSheet.tsx @@ -23,11 +23,8 @@ export const getENSAdditionalRecordsSheetHeight = () => { export default function ENSAdditionalRecordsSheet() { const { params } = useRoute(); const [accentColor] = useRecoilState(accentColorAtom); - const { - selectedFields, - onAddField, - onRemoveField, - } = useENSRegistrationForm(); + const { selectedFields, onAddField, onRemoveField } = + useENSRegistrationForm(); const { height: deviceHeight } = useWindowDimensions(); const boxStyle = useMemo( diff --git a/src/screens/ENSConfirmRegisterSheet.tsx b/src/screens/ENSConfirmRegisterSheet.tsx index 31cdf630890..8dc86d4e209 100644 --- a/src/screens/ENSConfirmRegisterSheet.tsx +++ b/src/screens/ENSConfirmRegisterSheet.tsx @@ -151,9 +151,8 @@ export default function ENSConfirmRegisterSheet() { accountProfile.accountENS !== ensName && (!isEmpty(changedRecords) || mode === REGISTRATION_MODES.EDIT) ); - const { step, secondsSinceCommitConfirmed } = useENSRegistrationStepHandler( - false - ); + const { step, secondsSinceCommitConfirmed } = + useENSRegistrationStepHandler(false); const { action } = useENSRegistrationActionHandler({ sendReverseRecord, step, diff --git a/src/screens/ENSSearchSheet.tsx b/src/screens/ENSSearchSheet.tsx index 2ccaa048519..a9546c4d77f 100644 --- a/src/screens/ENSSearchSheet.tsx +++ b/src/screens/ENSSearchSheet.tsx @@ -144,8 +144,8 @@ export default function ENSSearchSheet() { isAvailable ? colors.green : isRegistered - ? colors.yellowOrange - : colors.appleBlue + ? colors.yellowOrange + : colors.appleBlue } state={state} testID="ens-search-input" diff --git a/src/screens/ExchangeModal.tsx b/src/screens/ExchangeModal.tsx index 5df45b6866a..25d39b59564 100644 --- a/src/screens/ExchangeModal.tsx +++ b/src/screens/ExchangeModal.tsx @@ -118,8 +118,7 @@ export const DEFAULT_SLIPPAGE_BIPS = { }; export const getDefaultSlippageFromConfig = (network: Network) => { - const configSlippage = (getRemoteConfig() - .default_slippage_bips as unknown) as { + const configSlippage = getRemoteConfig().default_slippage_bips as unknown as { [network: string]: number; }; const slippage = @@ -149,11 +148,8 @@ export default function ExchangeModal({ }: ExchangeModalProps) { const { isHardwareWallet } = useWallets(); const dispatch = useDispatch(); - const { - slippageInBips, - maxInputUpdate, - flipCurrenciesUpdate, - } = useSwapSettings(); + const { slippageInBips, maxInputUpdate, flipCurrenciesUpdate } = + useSwapSettings(); const { params: { inputAsset: defaultInputAsset, outputAsset: defaultOutputAsset }, } = useRoute<{ @@ -190,12 +186,8 @@ export default function ExchangeModal({ txNetwork, isGasReady, } = useGas(); - const { - accountAddress, - flashbotsEnabled, - nativeCurrency, - network, - } = useAccountSettings(); + const { accountAddress, flashbotsEnabled, nativeCurrency, network } = + useAccountSettings(); const [isAuthorizing, setIsAuthorizing] = useState(false); const prevGasFeesParamsBySpeed = usePrevious(gasFeeParamsBySpeed); @@ -350,8 +342,8 @@ export default function ExchangeModal({ ); // For a limited period after the merge we need to block the use of flashbots. // This line should be removed after reenabling flashbots in remote config. - const swapSupportsFlashbots = getNetworkObj(currentNetwork).features - .flashbots; + const swapSupportsFlashbots = + getNetworkObj(currentNetwork).features.flashbots; const flashbots = swapSupportsFlashbots && flashbotsEnabled; const isDismissing = useRef(false); @@ -359,7 +351,7 @@ export default function ExchangeModal({ if (ios) { return; } - ((dismissingScreenListener.current as unknown) as () => void) = () => { + (dismissingScreenListener.current as unknown as () => void) = () => { Keyboard.dismiss(); isDismissing.current = true; }; @@ -372,7 +364,9 @@ export default function ExchangeModal({ ({ data: { closing } }) => { if (!closing && isDismissing.current) { isDismissing.current = false; - ((lastFocusedInputHandle as unknown) as MutableRefObject)?.current?.focus(); + ( + lastFocusedInputHandle as unknown as MutableRefObject + )?.current?.focus(); } } ); @@ -384,7 +378,7 @@ export default function ExchangeModal({ useEffect(() => { let slippage = DEFAULT_SLIPPAGE_BIPS?.[currentNetwork]; - const configSlippage = (default_slippage_bips as unknown) as { + const configSlippage = default_slippage_bips as unknown as { [network: string]: number; }; if (configSlippage?.[currentNetwork]) { @@ -404,15 +398,14 @@ export default function ExchangeModal({ const updateGasLimit = useCallback(async () => { try { const provider = await getProviderForNetwork(currentNetwork); - const swapParams: - | SwapActionParameters - | CrosschainSwapActionParameters = { - chainId, - inputAmount: inputAmount!, - outputAmount: outputAmount!, - provider, - tradeDetails: tradeDetails!, - }; + const swapParams: SwapActionParameters | CrosschainSwapActionParameters = + { + chainId, + inputAmount: inputAmount!, + outputAmount: outputAmount!, + provider, + tradeDetails: tradeDetails!, + }; const rapType = getSwapRapTypeByExchangeType(isCrosschainSwap); const gasLimit = await getSwapRapEstimationByType(rapType, swapParams); @@ -599,12 +592,8 @@ export default function ExchangeModal({ }; logger.log('[exchange - handle submit] rap'); const nonce = await getNextNonce(); - const { - independentField, - independentValue, - slippageInBips, - source, - } = store.getState().swap; + const { independentField, independentValue, slippageInBips, source } = + store.getState().swap; const swapParameters = { chainId, flashbots, @@ -652,7 +641,7 @@ export default function ExchangeModal({ isHardwareWallet, isHighPriceImpact: debouncedIsHighPriceImpact, legacyGasPrice: - ((selectedGasFee?.gasFeeParams as unknown) as LegacyGasFeeParams) + (selectedGasFee?.gasFeeParams as unknown as LegacyGasFeeParams) ?.gasPrice?.amount || '', liquiditySources: JSON.stringify(tradeDetails?.protocols || []), maxNetworkFee: @@ -736,7 +725,7 @@ export default function ExchangeModal({ isHardwareWallet, isHighPriceImpact: debouncedIsHighPriceImpact, legacyGasPrice: - ((selectedGasFee?.gasFeeParams as unknown) as LegacyGasFeeParams) + (selectedGasFee?.gasFeeParams as unknown as LegacyGasFeeParams) ?.gasPrice?.amount || '', liquiditySources: JSON.stringify(tradeDetails?.protocols || []), maxNetworkFee: @@ -883,7 +872,8 @@ export default function ExchangeModal({ isRefuelTx, restoreFocusOnSwapModal: () => { android && - (lastFocusedInputHandle.current = lastFocusedInputHandleTemporary); + (lastFocusedInputHandle.current = + lastFocusedInputHandleTemporary); setParams({ focused: true }); }, type: 'swap_details', @@ -928,7 +918,8 @@ export default function ExchangeModal({ ); const handleTapWhileDisabled = useCallback(() => { - const lastFocusedInput = (lastFocusedInputHandle?.current as unknown) as TextInput; + const lastFocusedInput = + lastFocusedInputHandle?.current as unknown as TextInput; lastFocusedInput?.blur(); navigate(Routes.EXPLAIN_SHEET, { inputToken: inputCurrency?.symbol, diff --git a/src/screens/ExplainSheet.js b/src/screens/ExplainSheet.js index ad1f14a3b46..819c7d29da2 100644 --- a/src/screens/ExplainSheet.js +++ b/src/screens/ExplainSheet.js @@ -958,8 +958,7 @@ export const explainers = (params, colors) => ({ onPress={() => Linking.openURL( buildRainbowLearnUrl({ - url: - 'https://learn.rainbow.me/a-beginners-guide-to-liquidity-providing', + url: 'https://learn.rainbow.me/a-beginners-guide-to-liquidity-providing', query: { campaign: 'explain', }, @@ -994,8 +993,7 @@ export const explainers = (params, colors) => ({ onPress={() => Linking.openURL( buildRainbowLearnUrl({ - url: - 'https://support.rainbow.me/en/articles/8324868-fee-on-transfer-tokens', + url: 'https://support.rainbow.me/en/articles/8324868-fee-on-transfer-tokens', query: { campaign: 'explain', }, @@ -1076,8 +1074,8 @@ export const explainers = (params, colors) => ({ index > 0 ? -12 : params?.networks?.length % 2 === 0 - ? -2 - : -30, + ? -2 + : -30, }} style={{ borderColor: colors.transparent, @@ -1131,8 +1129,7 @@ export const explainers = (params, colors) => ({ onPress={() => Linking.openURL( buildRainbowLearnUrl({ - url: - 'https://learn.rainbow.me/a-beginners-guide-to-layer-2-networks', + url: 'https://learn.rainbow.me/a-beginners-guide-to-layer-2-networks', query: { campaign: 'explain', }, @@ -1173,8 +1170,7 @@ export const explainers = (params, colors) => ({ onPress={() => Linking.openURL( buildRainbowLearnUrl({ - url: - 'https://learn.rainbow.me/protecting-transactions-with-flashbots', + url: 'https://learn.rainbow.me/protecting-transactions-with-flashbots', query: { campaign: 'explain', }, @@ -1204,8 +1200,7 @@ export const explainers = (params, colors) => ({ onPress={() => Linking.openURL( buildRainbowLearnUrl({ - url: - 'https://learn.rainbow.me/swap-with-confidence-with-rainbow', + url: 'https://learn.rainbow.me/swap-with-confidence-with-rainbow', query: { campaign: 'explain', }, diff --git a/src/screens/ImportOrWatchWalletSheet.tsx b/src/screens/ImportOrWatchWalletSheet.tsx index 145be323e5d..10d7b14a66b 100644 --- a/src/screens/ImportOrWatchWalletSheet.tsx +++ b/src/screens/ImportOrWatchWalletSheet.tsx @@ -31,9 +31,8 @@ type RouteParams = { }; export const ImportOrWatchWalletSheet = () => { - const { params: { type = 'watch' } = {} } = useRoute< - RouteProp - >(); + const { params: { type = 'watch' } = {} } = + useRoute>(); const { busy, @@ -161,8 +160,8 @@ export const ImportOrWatchWalletSheet = () => { buttonDisabled ? 'labelSecondary' : seedPhrase - ? 'label' - : { custom: globalColors.purple60 } + ? 'label' + : { custom: globalColors.purple60 } } size="15pt" testID="import-sheet-button-label" diff --git a/src/screens/MintsSheet/MintsSheet.tsx b/src/screens/MintsSheet/MintsSheet.tsx index a88751b734a..83bbb5d524d 100644 --- a/src/screens/MintsSheet/MintsSheet.tsx +++ b/src/screens/MintsSheet/MintsSheet.tsx @@ -32,12 +32,8 @@ import * as i18n from '@/languages'; const LoadingSpinner = IS_ANDROID ? Spinner : ActivityIndicator; export function MintsSheet() { - const { - accountAddress, - accountImage, - accountColor, - accountSymbol, - } = useAccountProfile(); + const { accountAddress, accountImage, accountColor, accountSymbol } = + useAccountProfile(); const { data: { mints }, isFetching, diff --git a/src/screens/NFTOffersSheet/index.tsx b/src/screens/NFTOffersSheet/index.tsx index fac04fa5a81..4375fc74ed1 100644 --- a/src/screens/NFTOffersSheet/index.tsx +++ b/src/screens/NFTOffersSheet/index.tsx @@ -33,12 +33,8 @@ const PROFILE_AVATAR_SIZE = 36; export const NFTOffersSheet = () => { const separatorSecondary = useForegroundColor('separatorSecondary'); - const { - accountColor, - accountImage, - accountSymbol, - accountAddress, - } = useAccountProfile(); + const { accountColor, accountImage, accountSymbol, accountAddress } = + useAccountProfile(); const { isDarkMode } = useTheme(); const { width: deviceWidth, height: deviceHeight } = useDimensions(); diff --git a/src/screens/NotificationsPromoSheet/index.tsx b/src/screens/NotificationsPromoSheet/index.tsx index 4a35d45abf0..554cc131922 100644 --- a/src/screens/NotificationsPromoSheet/index.tsx +++ b/src/screens/NotificationsPromoSheet/index.tsx @@ -161,10 +161,8 @@ export function NotificationsPromoSheetInner({ export default function NotificationsPromoSheet() { const { justBecameActive } = useAppState(); - const [ - permissionsCheckResult, - setPermissionsCheckResult, - ] = React.useState(); + const [permissionsCheckResult, setPermissionsCheckResult] = + React.useState(); const checkPermissions = React.useCallback(async () => { const result = await perms.checkNotifications(); diff --git a/src/screens/PinAuthenticationScreen.js b/src/screens/PinAuthenticationScreen.js index f7716acb73d..0fe91f2440b 100644 --- a/src/screens/PinAuthenticationScreen.js +++ b/src/screens/PinAuthenticationScreen.js @@ -227,8 +227,8 @@ const PinAuthenticationScreen = () => { {actionType === 'authentication' ? lang.t('wallet.pin_authentication.type_your_pin') : actionType === 'creation' - ? lang.t('wallet.pin_authentication.choose_your_pin') - : lang.t('wallet.pin_authentication.confirm_your_pin')} + ? lang.t('wallet.pin_authentication.choose_your_pin') + : lang.t('wallet.pin_authentication.confirm_your_pin')} diff --git a/src/screens/ProfileSheet.tsx b/src/screens/ProfileSheet.tsx index 16d22050548..706cffa1c29 100644 --- a/src/screens/ProfileSheet.tsx +++ b/src/screens/ProfileSheet.tsx @@ -51,17 +51,14 @@ export default function ProfileSheet() { const isPreview = name === Routes.PROFILE_PREVIEW_SHEET; // Prefetch first transaction timestamp unless already fetched for intro marquee - const { - isSuccess: hasFirstTxTimestampFetched, - } = useFirstTransactionTimestamp({ addressOrName: ensName }); + const { isSuccess: hasFirstTxTimestampFetched } = + useFirstTransactionTimestamp({ addressOrName: ensName }); // Prefetch asset list - const { - isSuccess: hasListFetched, - briefSectionsData, - } = useExternalWalletSectionsData({ - address: profileAddress || undefined, - }); + const { isSuccess: hasListFetched, briefSectionsData } = + useExternalWalletSectionsData({ + address: profileAddress || undefined, + }); const colorIndex = useMemo( () => (profileAddress ? addressHashedColorIndex(profileAddress) : 0), @@ -70,9 +67,10 @@ export default function ProfileSheet() { const dominantColor = usePersistentDominantColorFromImage(avatar?.imageUrl); - const wrapperStyle = useMemo(() => ({ height: contentHeight }), [ - contentHeight, - ]); + const wrapperStyle = useMemo( + () => ({ height: contentHeight }), + [contentHeight] + ); const accentColor = // Set accent color when ENS images have fetched & dominant diff --git a/src/screens/ReceiveModal.js b/src/screens/ReceiveModal.js index 79dde2744b2..916992d0928 100644 --- a/src/screens/ReceiveModal.js +++ b/src/screens/ReceiveModal.js @@ -78,9 +78,10 @@ export default function ReceiveModal() { setCopyCount(count => count + 1); }, []); - const checksummedAddress = useMemo(() => toChecksumAddress(accountAddress), [ - accountAddress, - ]); + const checksummedAddress = useMemo( + () => toChecksumAddress(accountAddress), + [accountAddress] + ); return ( diff --git a/src/screens/RestoreSheet.js b/src/screens/RestoreSheet.js index 8386b7293af..f4a89b80210 100644 --- a/src/screens/RestoreSheet.js +++ b/src/screens/RestoreSheet.js @@ -8,9 +8,8 @@ import { IS_ANDROID } from '@/env'; import { useDimensions } from '@/hooks'; export function RestoreSheet() { - const { - params: { userData, backupSelected, fromSettings } = {}, - } = useRoute(); + const { params: { userData, backupSelected, fromSettings } = {} } = + useRoute(); const { height: deviceHeight } = useDimensions(); return ( diff --git a/src/screens/SelectENSSheet.tsx b/src/screens/SelectENSSheet.tsx index a357ec319f2..ec14f2b6797 100644 --- a/src/screens/SelectENSSheet.tsx +++ b/src/screens/SelectENSSheet.tsx @@ -38,11 +38,8 @@ const rowPadding = 19; const maxListHeight = deviceHeight - 220; export default function SelectENSSheet() { - const { - isSuccess, - nonPrimaryDomains, - primaryDomain, - } = useAccountENSDomains(); + const { isSuccess, nonPrimaryDomains, primaryDomain } = + useAccountENSDomains(); const secondary06 = useForegroundColor('secondary06 (Deprecated)'); diff --git a/src/screens/SendConfirmationSheet.tsx b/src/screens/SendConfirmationSheet.tsx index 1cf13ecb129..668ac0c0687 100644 --- a/src/screens/SendConfirmationSheet.tsx +++ b/src/screens/SendConfirmationSheet.tsx @@ -251,10 +251,8 @@ export const SendConfirmationSheet = () => { // eslint-disable-next-line @typescript-eslint/no-explicit-any } = useRoute(); - const [ - alreadySentTransactionsTotal, - setAlreadySentTransactionsTotal, - ] = useState(0); + const [alreadySentTransactionsTotal, setAlreadySentTransactionsTotal] = + useState(0); const [ alreadySentTransactionsCurrentNetwork, setAlreadySentTransactionsCurrentNetwork, diff --git a/src/screens/SendSheet.js b/src/screens/SendSheet.js index 56c93295ef8..ba04a9ed1bd 100644 --- a/src/screens/SendSheet.js +++ b/src/screens/SendSheet.js @@ -183,11 +183,8 @@ export default function SendSheet(props) { const theme = useTheme(); const { colors, isDarkMode } = theme; - const { - nativeCurrencyInputRef, - setLastFocusedInputHandle, - assetInputRef, - } = useSendSheetInputRefs(); + const { nativeCurrencyInputRef, setLastFocusedInputHandle, assetInputRef } = + useSendSheetInputRefs(); const showEmptyState = !isValidAddress; const showAssetList = isValidAddress && isEmpty(selected); @@ -221,13 +218,12 @@ export default function SendSheet(props) { let _nativeAmount = ''; if (_assetAmount.length) { const priceUnit = selected?.price?.value ?? 0; - const { - amount: convertedNativeAmount, - } = convertAmountAndPriceToNativeDisplay( - _assetAmount, - priceUnit, - nativeCurrency - ); + const { amount: convertedNativeAmount } = + convertAmountAndPriceToNativeDisplay( + _assetAmount, + priceUnit, + nativeCurrency + ); _nativeAmount = formatInputDecimals( convertedNativeAmount, _assetAmount @@ -413,9 +409,8 @@ export default function SendSheet(props) { useEffect(() => { const resolveAddressIfNeeded = async () => { let realAddress = debouncedRecipient; - const isValid = await checkIsValidAddressOrDomainFormat( - debouncedRecipient - ); + const isValid = + await checkIsValidAddressOrDomainFormat(debouncedRecipient); if (isValid) { realAddress = await resolveNameOrAddress(debouncedRecipient); setToAddress(realAddress); diff --git a/src/screens/SettingsSheet/components/BackupSection.android.tsx b/src/screens/SettingsSheet/components/BackupSection.android.tsx index 10c809d37ff..e8033595967 100644 --- a/src/screens/SettingsSheet/components/BackupSection.android.tsx +++ b/src/screens/SettingsSheet/components/BackupSection.android.tsx @@ -117,12 +117,12 @@ const BackupSection = () => { }) : lang.t('wallet.back_ups.and_1_more_wallet') : wallet.backedUp - ? wallet.backupType === WalletBackupTypes.cloud - ? lang.t('wallet.back_ups.backed_up') - : lang.t('wallet.back_ups.backed_up_manually') - : wallet.imported - ? lang.t('wallet.back_ups.imported') - : lang.t('back_up.needs_backup.not_backed_up') + ? wallet.backupType === WalletBackupTypes.cloud + ? lang.t('wallet.back_ups.backed_up') + : lang.t('wallet.back_ups.backed_up_manually') + : wallet.imported + ? lang.t('wallet.back_ups.imported') + : lang.t('back_up.needs_backup.not_backed_up') } warn={ numAccounts <= 1 && @@ -154,8 +154,8 @@ const BackupSection = () => { wallet.backupType === WalletBackupTypes.cloud ? 'complete' : wallet.backedUp || wallet.imported - ? 'incomplete' - : 'warning' + ? 'incomplete' + : 'warning' } /> } diff --git a/src/screens/SettingsSheet/components/BackupSection.tsx b/src/screens/SettingsSheet/components/BackupSection.tsx index 51a34436112..b322057ebf1 100644 --- a/src/screens/SettingsSheet/components/BackupSection.tsx +++ b/src/screens/SettingsSheet/components/BackupSection.tsx @@ -104,12 +104,12 @@ const BackupSection = () => { }) : lang.t('wallet.back_ups.and_1_more_wallet') : wallet.backedUp - ? wallet.backupType === WalletBackupTypes.cloud - ? lang.t('wallet.back_ups.backed_up') - : lang.t('wallet.back_ups.backed_up_manually') - : wallet.imported - ? lang.t('wallet.back_ups.imported') - : lang.t('back_up.needs_backup.not_backed_up') + ? wallet.backupType === WalletBackupTypes.cloud + ? lang.t('wallet.back_ups.backed_up') + : lang.t('wallet.back_ups.backed_up_manually') + : wallet.imported + ? lang.t('wallet.back_ups.imported') + : lang.t('back_up.needs_backup.not_backed_up') } warn={ numAccounts <= 1 && !wallet.backedUp && !wallet.imported @@ -139,8 +139,8 @@ const BackupSection = () => { wallet.backupType === WalletBackupTypes.cloud ? 'complete' : wallet.backedUp || wallet.imported - ? 'incomplete' - : 'warning' + ? 'incomplete' + : 'warning' } /> } diff --git a/src/screens/SettingsSheet/components/DevSection.android.tsx b/src/screens/SettingsSheet/components/DevSection.android.tsx index 23f85d2d103..a31cd4e71cd 100644 --- a/src/screens/SettingsSheet/components/DevSection.android.tsx +++ b/src/screens/SettingsSheet/components/DevSection.android.tsx @@ -65,14 +65,10 @@ const DevSection = () => { const { navigate } = useNavigation(); const { config, setConfig } = useContext(RainbowContext) as any; const { wallets } = useWallets(); - const { - accountAddress, - testnetsEnabled, - settingsChangeTestnetsEnabled, - } = useAccountSettings(); - const { - walletNotificationSettings, - } = useAllNotificationSettingsFromStorage(); + const { accountAddress, testnetsEnabled, settingsChangeTestnetsEnabled } = + useAccountSettings(); + const { walletNotificationSettings } = + useAllNotificationSettingsFromStorage(); const dispatch = useDispatch(); const resetAccountState = useResetAccountState(); const loadAccountData = useLoadAccountData(); @@ -526,7 +522,8 @@ const DevSection = () => { } onPress={async () => { - const publicKey = await getPublicKeyOfTheSigningWalletAndCreateWalletIfNeeded(); + const publicKey = + await getPublicKeyOfTheSigningWalletAndCreateWalletIfNeeded(); if (publicKey) { Clipboard.setString(publicKey); diff --git a/src/screens/SettingsSheet/components/DevSection.tsx b/src/screens/SettingsSheet/components/DevSection.tsx index 2d5d0adf284..0cde442c605 100644 --- a/src/screens/SettingsSheet/components/DevSection.tsx +++ b/src/screens/SettingsSheet/components/DevSection.tsx @@ -64,14 +64,10 @@ const DevSection = () => { const { navigate } = useNavigation(); const { config, setConfig } = useContext(RainbowContext) as any; const { wallets } = useWallets(); - const { - accountAddress, - testnetsEnabled, - settingsChangeTestnetsEnabled, - } = useAccountSettings(); - const { - walletNotificationSettings, - } = useAllNotificationSettingsFromStorage(); + const { accountAddress, testnetsEnabled, settingsChangeTestnetsEnabled } = + useAccountSettings(); + const { walletNotificationSettings } = + useAllNotificationSettingsFromStorage(); const dispatch = useDispatch(); const resetAccountState = useResetAccountState(); const loadAccountData = useLoadAccountData(); @@ -494,7 +490,8 @@ const DevSection = () => { } onPress={async () => { - const publicKey = await getPublicKeyOfTheSigningWalletAndCreateWalletIfNeeded(); + const publicKey = + await getPublicKeyOfTheSigningWalletAndCreateWalletIfNeeded(); if (publicKey) { Clipboard.setString(publicKey); diff --git a/src/screens/SettingsSheet/components/MenuItem.tsx b/src/screens/SettingsSheet/components/MenuItem.tsx index 2180f809c6e..d84528b51aa 100644 --- a/src/screens/SettingsSheet/components/MenuItem.tsx +++ b/src/screens/SettingsSheet/components/MenuItem.tsx @@ -50,10 +50,10 @@ const TextIcon = ({ colorOverride ? { custom: colorOverride } : disabled - ? 'secondary60 (Deprecated)' - : isLink - ? 'action (Deprecated)' - : 'primary (Deprecated)' + ? 'secondary60 (Deprecated)' + : isLink + ? 'action (Deprecated)' + : 'primary (Deprecated)' } containsEmoji size="18px / 27px (Deprecated)" @@ -125,8 +125,8 @@ const Title = ({ text, weight = 'semibold', disabled, isLink }: TitleProps) => ( disabled ? 'secondary60 (Deprecated)' : isLink - ? 'action (Deprecated)' - : 'primary (Deprecated)' + ? 'action (Deprecated)' + : 'primary (Deprecated)' } containsEmoji size="18px / 27px (Deprecated)" diff --git a/src/screens/SettingsSheet/components/NotificationsSection.android.tsx b/src/screens/SettingsSheet/components/NotificationsSection.android.tsx index f26c22da431..153c2793993 100644 --- a/src/screens/SettingsSheet/components/NotificationsSection.android.tsx +++ b/src/screens/SettingsSheet/components/NotificationsSection.android.tsx @@ -78,7 +78,7 @@ const WalletRowLabel = ({ notifications, groupOff }: WalletRowLabelProps) => { const allTopicsDisabled = groupOff || Object.values(notifications.topics).every(topic => !topic); const enabledTopics = Object.keys(notifications.topics).filter( - topic => notifications.topics[(topic as unknown) as number] + topic => notifications.topics[topic as unknown as number] ); if (allTopicsDisabled) { @@ -140,9 +140,8 @@ const WalletRow = ({ const navigateToWalletSettings = useCallback( (name: string, address: string) => { - const settingsForWallet = getNotificationSettingsForWalletWithAddress( - address - ); + const settingsForWallet = + getNotificationSettingsForWalletWithAddress(address); if (settingsForWallet) { navigate(Routes.WALLET_NOTIFICATIONS_SETTINGS, { @@ -234,10 +233,8 @@ const NotificationsSection = () => { updateGroupSettingsAndSubscriptions, watcherEnabled: storedWatcherEnabled, } = useWalletGroupNotificationSettings(); - const { - globalNotificationSettings, - walletNotificationSettings, - } = useAllNotificationSettingsFromStorage(); + const { globalNotificationSettings, walletNotificationSettings } = + useAllNotificationSettingsFromStorage(); const [topicState, setTopicState] = useState( globalNotificationSettings @@ -257,10 +254,8 @@ const NotificationsSection = () => { // We allow only one subscription in progress // this states controls which we are currently updating - const [ - topicSubscriptionInProgress, - setTopicSubscriptionInProgress, - ] = useState(null); + const [topicSubscriptionInProgress, setTopicSubscriptionInProgress] = + useState(null); const { ownedWallets, watchedWallets } = useMemo(() => { const ownedWallets: RainbowAccount[] = []; diff --git a/src/screens/SettingsSheet/components/NotificationsSection.tsx b/src/screens/SettingsSheet/components/NotificationsSection.tsx index c4e79c903be..f6f651b8a69 100644 --- a/src/screens/SettingsSheet/components/NotificationsSection.tsx +++ b/src/screens/SettingsSheet/components/NotificationsSection.tsx @@ -79,7 +79,7 @@ const WalletRowLabel = ({ notifications, groupOff }: WalletRowLabelProps) => { const allTopicsDisabled = groupOff || Object.values(notifications.topics).every(topic => !topic); const enabledTopics = Object.keys(notifications.topics).filter( - topic => notifications.topics[(topic as unknown) as number] + topic => notifications.topics[topic as unknown as number] ); if (allTopicsDisabled) { @@ -141,9 +141,8 @@ const WalletRow = ({ const navigateToWalletSettings = useCallback( (name: string, address: string) => { - const settingsForWallet = getNotificationSettingsForWalletWithAddress( - address - ); + const settingsForWallet = + getNotificationSettingsForWalletWithAddress(address); if (settingsForWallet) { navigate(Routes.WALLET_NOTIFICATIONS_SETTINGS, { @@ -235,10 +234,8 @@ const NotificationsSection = () => { updateGroupSettingsAndSubscriptions, watcherEnabled: storedWatcherEnabled, } = useWalletGroupNotificationSettings(); - const { - globalNotificationSettings, - walletNotificationSettings, - } = useAllNotificationSettingsFromStorage(); + const { globalNotificationSettings, walletNotificationSettings } = + useAllNotificationSettingsFromStorage(); const [topicState, setTopicState] = useState( globalNotificationSettings @@ -257,10 +254,8 @@ const NotificationsSection = () => { }); // We allow only one subscription in progress // this states controls which we are currently updating - const [ - topicSubscriptionInProgress, - setTopicSubscriptionInProgress, - ] = useState(null); + const [topicSubscriptionInProgress, setTopicSubscriptionInProgress] = + useState(null); const { ownedWallets, watchedWallets } = useMemo(() => { const ownedWallets: RainbowAccount[] = []; diff --git a/src/screens/SettingsSheet/components/PrivacySection.android.tsx b/src/screens/SettingsSheet/components/PrivacySection.android.tsx index dff7a9bc6ef..b443e3cbcd0 100644 --- a/src/screens/SettingsSheet/components/PrivacySection.android.tsx +++ b/src/screens/SettingsSheet/components/PrivacySection.android.tsx @@ -26,23 +26,26 @@ const PrivacySection = () => { publicShowCase => !publicShowCase, webDataEnabled ); - const [analyticsEnabled, toggleAnalytics] = useReducer(analyticsEnabled => { - if (analyticsEnabled) { - device.set(['doNotTrack'], true); - logger.debug(`Analytics tracking disabled`); - analyticsV2.track(analyticsV2.event.analyticsTrackingDisabled); - logger.disable(); - analyticsV2.disable(); - return false; - } else { - device.set(['doNotTrack'], false); - logger.enable(); - analyticsV2.enable(); - logger.debug(`Analytics tracking enabled`); - analyticsV2.track(analyticsV2.event.analyticsTrackingEnabled); - return true; - } - }, !device.get(['doNotTrack'])); + const [analyticsEnabled, toggleAnalytics] = useReducer( + analyticsEnabled => { + if (analyticsEnabled) { + device.set(['doNotTrack'], true); + logger.debug(`Analytics tracking disabled`); + analyticsV2.track(analyticsV2.event.analyticsTrackingDisabled); + logger.disable(); + analyticsV2.disable(); + return false; + } else { + device.set(['doNotTrack'], false); + logger.enable(); + analyticsV2.enable(); + logger.debug(`Analytics tracking enabled`); + analyticsV2.track(analyticsV2.event.analyticsTrackingEnabled); + return true; + } + }, + !device.get(['doNotTrack']) + ); const profilesEnabled = useExperimentalFlag(PROFILES); diff --git a/src/screens/SettingsSheet/components/PrivacySection.tsx b/src/screens/SettingsSheet/components/PrivacySection.tsx index b5ba51266a7..af5c9a98737 100644 --- a/src/screens/SettingsSheet/components/PrivacySection.tsx +++ b/src/screens/SettingsSheet/components/PrivacySection.tsx @@ -24,23 +24,26 @@ const PrivacySection = () => { publicShowCase => !publicShowCase, webDataEnabled ); - const [analyticsEnabled, toggleAnalytics] = useReducer(analyticsEnabled => { - if (analyticsEnabled) { - device.set(['doNotTrack'], true); - logger.debug(`Analytics tracking disabled`); - analyticsV2.track(analyticsV2.event.analyticsTrackingDisabled); - logger.disable(); - analyticsV2.disable(); - return false; - } else { - device.set(['doNotTrack'], false); - logger.enable(); - analyticsV2.enable(); - logger.debug(`Analytics tracking enabled`); - analyticsV2.track(analyticsV2.event.analyticsTrackingEnabled); - return true; - } - }, !device.get(['doNotTrack'])); + const [analyticsEnabled, toggleAnalytics] = useReducer( + analyticsEnabled => { + if (analyticsEnabled) { + device.set(['doNotTrack'], true); + logger.debug(`Analytics tracking disabled`); + analyticsV2.track(analyticsV2.event.analyticsTrackingDisabled); + logger.disable(); + analyticsV2.disable(); + return false; + } else { + device.set(['doNotTrack'], false); + logger.enable(); + analyticsV2.enable(); + logger.debug(`Analytics tracking enabled`); + analyticsV2.track(analyticsV2.event.analyticsTrackingEnabled); + return true; + } + }, + !device.get(['doNotTrack']) + ); const profilesEnabled = useExperimentalFlag(PROFILES); diff --git a/src/screens/SettingsSheet/components/SettingsSection.tsx b/src/screens/SettingsSheet/components/SettingsSection.tsx index a1c14770ae5..d7db4c4cab0 100644 --- a/src/screens/SettingsSheet/components/SettingsSection.tsx +++ b/src/screens/SettingsSheet/components/SettingsSection.tsx @@ -115,12 +115,8 @@ const SettingsSection = ({ onPressNotifications, }: SettingsSectionProps) => { const { wallets, isReadOnlyWallet } = useWallets(); - const { - language, - nativeCurrency, - network, - testnetsEnabled, - } = useAccountSettings(); + const { language, nativeCurrency, network, testnetsEnabled } = + useAccountSettings(); const isLanguageSelectionEnabled = useExperimentalFlag(LANGUAGE_SETTINGS); const isNotificationsEnabled = useExperimentalFlag(NOTIFICATIONS); @@ -250,8 +246,8 @@ const SettingsSection = ({ allBackedUp ? 'complete' : areBackedUp - ? 'incomplete' - : 'warning' + ? 'incomplete' + : 'warning' } /> } diff --git a/src/screens/SettingsSheet/components/WalletNotificationsSettings.android.tsx b/src/screens/SettingsSheet/components/WalletNotificationsSettings.android.tsx index 7ff53e7dbf3..cf67284bcf2 100644 --- a/src/screens/SettingsSheet/components/WalletNotificationsSettings.android.tsx +++ b/src/screens/SettingsSheet/components/WalletNotificationsSettings.android.tsx @@ -97,9 +97,8 @@ type RouteParams = { const WalletNotificationsSettings = () => { const { colors } = useTheme(); const topicRowsData = useMemo(() => makeTopicRowsData(colors), [colors]); - const route = useRoute< - RouteProp - >(); + const route = + useRoute>(); const { isConnected } = useNetInfo(); const { wallets, walletNames } = useWallets(); const { address, notificationSettings } = route.params; @@ -110,10 +109,8 @@ const WalletNotificationsSettings = () => { address ).accountName; - const [ - notifications, - setNotificationSettings, - ] = useState(notificationSettings); + const [notifications, setNotificationSettings] = + useState(notificationSettings); const updateSettings = useCallback( (options: Partial) => { const newSettingsForWallet = updateSettingsForWalletWithAddress( @@ -175,10 +172,8 @@ const WalletNotificationsSettings = () => { // We allow only one subscription in progress // this states controls which we are currently updating - const [ - topicSubscriptionInProgress, - setTopicSubscriptionInProgress, - ] = useState(null); + const [topicSubscriptionInProgress, setTopicSubscriptionInProgress] = + useState(null); const toggleAllowNotifications = useCallback(() => { if (!isConnected) { diff --git a/src/screens/SettingsSheet/components/WalletNotificationsSettings.tsx b/src/screens/SettingsSheet/components/WalletNotificationsSettings.tsx index b86c3c234ea..bc8761da14d 100644 --- a/src/screens/SettingsSheet/components/WalletNotificationsSettings.tsx +++ b/src/screens/SettingsSheet/components/WalletNotificationsSettings.tsx @@ -91,16 +91,13 @@ type RouteParams = { const WalletNotificationsSettings = () => { const { colors } = useTheme(); const topicRowsData = useMemo(() => makeTopicRowsData(colors), [colors]); - const route = useRoute< - RouteProp - >(); + const route = + useRoute>(); const { isConnected } = useNetInfo(); const { address, notificationSettings } = route.params; - const [ - notifications, - setNotificationSettings, - ] = useState(notificationSettings); + const [notifications, setNotificationSettings] = + useState(notificationSettings); const updateSettings = useCallback( (options: Partial) => { const newSettingsForWallet = updateSettingsForWalletWithAddress( @@ -162,10 +159,8 @@ const WalletNotificationsSettings = () => { // We allow only one subscription in progress // this states controls which we are currently updating - const [ - topicSubscriptionInProgress, - setTopicSubscriptionInProgress, - ] = useState(null); + const [topicSubscriptionInProgress, setTopicSubscriptionInProgress] = + useState(null); const toggleAllowNotifications = useCallback(() => { if (!isConnected) { diff --git a/src/screens/ShowcaseSheet.js b/src/screens/ShowcaseSheet.js index c2ed24496b0..5187a8386f3 100644 --- a/src/screens/ShowcaseSheet.js +++ b/src/screens/ShowcaseSheet.js @@ -44,9 +44,8 @@ const LoadingWrapper = styled.View({ }); export default function ShowcaseScreen() { - const { - params: { address: addressOrDomain, setIsSearchModeEnabled } = {}, - } = useRoute(); + const { params: { address: addressOrDomain, setIsSearchModeEnabled } = {} } = + useRoute(); const theme = useTheme(); diff --git a/src/screens/SignTransactionSheet.tsx b/src/screens/SignTransactionSheet.tsx index e920e303850..569aa60a0e1 100644 --- a/src/screens/SignTransactionSheet.tsx +++ b/src/screens/SignTransactionSheet.tsx @@ -1695,8 +1695,8 @@ const SimulationCard = ({ simulationScanResult !== TransactionScanResultType.Ok ? simulationScanResult : simulationError - ? 'failed' - : 'insufficientBalance' + ? 'failed' + : 'insufficientBalance' } /> ) : ( @@ -1719,8 +1719,8 @@ const SimulationCard = ({ isLoading ? 'label' : simulationUnavailable - ? 'labelQuaternary' - : 'label' + ? 'labelQuaternary' + : 'label' } size="icon 15px" weight="bold" @@ -2210,8 +2210,8 @@ const DetailRow = ({ value === 'VERIFIED' ? 'verified' : value === 'UNVERIFIED' - ? 'unverified' - : 'unknown' + ? 'unverified' + : 'unknown' } value={value} /> diff --git a/src/screens/TransactionConfirmationScreen.js b/src/screens/TransactionConfirmationScreen.js index 78b6cbbb28a..3e614e5ffb6 100644 --- a/src/screens/TransactionConfirmationScreen.js +++ b/src/screens/TransactionConfirmationScreen.js @@ -211,11 +211,8 @@ export default function TransactionConfirmationScreen() { ({ walletconnect }) => walletconnect.walletConnectors ); - const { - dataAddNewTransaction, - removeRequest, - walletConnectSendStatus, - } = useTransactionConfirmation(); + const { dataAddNewTransaction, removeRequest, walletConnectSendStatus } = + useTransactionConfirmation(); const { callback, @@ -1130,8 +1127,8 @@ export default function TransactionConfirmationScreen() { (isMessageRequest ? MessageSheetHeight : (amount && amount !== '0.00') || !isBalanceEnough - ? TallSheetHeight - : ShortSheetHeight) * (android ? 1.5 : 1); + ? TallSheetHeight + : ShortSheetHeight) * (android ? 1.5 : 1); let marginTop = android ? deviceHeight - sheetHeight + 275 : null; diff --git a/src/screens/discover/components/DiscoverHome.js b/src/screens/discover/components/DiscoverHome.js index 6aee0a72619..bb8239b0df2 100644 --- a/src/screens/discover/components/DiscoverHome.js +++ b/src/screens/discover/components/DiscoverHome.js @@ -34,11 +34,8 @@ import { import { useRoute } from '@react-navigation/native'; export default function DiscoverHome() { - const { - profiles_enabled, - mints_enabled, - op_rewards_enabled, - } = useRemoteConfig(); + const { profiles_enabled, mints_enabled, op_rewards_enabled } = + useRemoteConfig(); const { accountAddress, network } = useAccountSettings(); const { getCardsForPlacement } = useRemoteCardContext(); const { name } = useRoute(); @@ -65,10 +62,10 @@ export default function DiscoverHome() { key => wallets[key].type === walletTypes.bluetooth ).length > 0; - const cards = useMemo(() => getCardsForPlacement(name), [ - name, - getCardsForPlacement, - ]); + const cards = useMemo( + () => getCardsForPlacement(name), + [name, getCardsForPlacement] + ); return ( diff --git a/src/screens/discover/components/DiscoverSearchContainer.js b/src/screens/discover/components/DiscoverSearchContainer.js index 0405fa07912..8b8dbb4346f 100644 --- a/src/screens/discover/components/DiscoverSearchContainer.js +++ b/src/screens/discover/components/DiscoverSearchContainer.js @@ -60,9 +60,8 @@ export default forwardRef(function DiscoverSearchContainer( const [isFetchingEns, setIsFetchingEns] = useState(false); const delayedShowSearch = useDelayedValueWithLayoutAnimation(showSearch); - const { setIsSearchModeEnabled, isSearchModeEnabled } = useContext( - DiscoverSheetContext - ); + const { setIsSearchModeEnabled, isSearchModeEnabled } = + useContext(DiscoverSheetContext); const setIsInputFocused = useCallback( value => { diff --git a/src/screens/hardware-wallets/PairHardwareWalletAgainSheet.tsx b/src/screens/hardware-wallets/PairHardwareWalletAgainSheet.tsx index 57d03b96127..20795d35021 100644 --- a/src/screens/hardware-wallets/PairHardwareWalletAgainSheet.tsx +++ b/src/screens/hardware-wallets/PairHardwareWalletAgainSheet.tsx @@ -186,16 +186,16 @@ export const PairHardwareWalletAgainSheet = () => { hardwareTXError ? 'red' : isReady - ? 'green' - : 'surfaceSecondary' + ? 'green' + : 'surfaceSecondary' } shadow={ IS_IOS ? hardwareTXError ? '30px red' : isReady - ? '30px green' - : undefined + ? '30px green' + : undefined : undefined } borderRadius={INDICATOR_SIZE / 2} diff --git a/src/screens/hardware-wallets/PairHardwareWalletErrorSheet.tsx b/src/screens/hardware-wallets/PairHardwareWalletErrorSheet.tsx index 8a63c5e4417..9a159630025 100644 --- a/src/screens/hardware-wallets/PairHardwareWalletErrorSheet.tsx +++ b/src/screens/hardware-wallets/PairHardwareWalletErrorSheet.tsx @@ -27,9 +27,8 @@ type RouteParams = { }; export const PairHardwareWalletErrorSheet = () => { - const route = useRoute< - RouteProp - >(); + const route = + useRoute>(); const { width: deviceWidth } = useDimensions(); const { goBack, navigate } = useNavigation(); diff --git a/src/screens/hardware-wallets/PairHardwareWalletSigningSheet.tsx b/src/screens/hardware-wallets/PairHardwareWalletSigningSheet.tsx index bed8b1488a4..221816973dd 100644 --- a/src/screens/hardware-wallets/PairHardwareWalletSigningSheet.tsx +++ b/src/screens/hardware-wallets/PairHardwareWalletSigningSheet.tsx @@ -93,17 +93,13 @@ type RouteParams = { }; export function PairHardwareWalletSigningSheet() { - const route = useRoute< - RouteProp - >(); + const route = + useRoute>(); const { navigate, goBack } = useNavigation(); const { isSmallPhone } = useDimensions(); const deviceId = useRecoilValue(LedgerImportDeviceIdAtom); - const { - busy, - handleSetSeedPhrase, - handlePressImportButton, - } = useImportingWallet({ showImportModal: true }); + const { busy, handleSetSeedPhrase, handlePressImportButton } = + useImportingWallet({ showImportModal: true }); const items: ItemDetails[] = [ { diff --git a/src/screens/mints/MintSheet.tsx b/src/screens/mints/MintSheet.tsx index b623bc387cf..43461e84d89 100644 --- a/src/screens/mints/MintSheet.tsx +++ b/src/screens/mints/MintSheet.tsx @@ -731,8 +731,8 @@ const MintSheet = () => { {isZero(mintPriceAmount) ? i18n.t(i18n.l.minting.free) : showNativePrice - ? nativeMintPriceDisplay - : mintPriceDisplay} + ? nativeMintPriceDisplay + : mintPriceDisplay} diff --git a/src/screens/mints/PoapSheet.tsx b/src/screens/mints/PoapSheet.tsx index 6956ad526aa..e4cea5c8c8a 100644 --- a/src/screens/mints/PoapSheet.tsx +++ b/src/screens/mints/PoapSheet.tsx @@ -344,10 +344,10 @@ const PoapSheet = () => { {claimStatus === 'claimed' ? i18n.t(i18n.l.poaps.minted) : claimStatus === 'claiming' - ? i18n.t(i18n.l.poaps.minting) - : claimStatus === 'none' - ? i18n.t(i18n.l.poaps.mint_poap) - : i18n.t(i18n.l.poaps.error)} + ? i18n.t(i18n.l.poaps.minting) + : claimStatus === 'none' + ? i18n.t(i18n.l.poaps.mint_poap) + : i18n.t(i18n.l.poaps.error)} diff --git a/src/screens/points/PointsScreen.tsx b/src/screens/points/PointsScreen.tsx index 686ff83590b..dc461d615e7 100644 --- a/src/screens/points/PointsScreen.tsx +++ b/src/screens/points/PointsScreen.tsx @@ -36,12 +36,8 @@ export const POINTS_ROUTES = { const Swipe = createMaterialTopTabNavigator(); export default function PointsScreen() { - const { - accountAddress, - accountImage, - accountColor, - accountSymbol, - } = useAccountProfile(); + const { accountAddress, accountImage, accountColor, accountSymbol } = + useAccountProfile(); const { points_enabled, points_notifications_toggle } = useRemoteConfig(); const pointsEnabled = useExperimentalFlag(POINTS) || points_enabled || IS_TEST; @@ -52,10 +48,8 @@ export default function PointsScreen() { const { data } = usePoints({ walletAddress: accountAddress, }); - const { - data: referralCode, - refetch: resetReferralCode, - } = usePointsReferralCode(); + const { data: referralCode, refetch: resetReferralCode } = + usePointsReferralCode(); const isOnboarded = data?.points?.error?.type !== PointsErrorType.NonExistingUser; diff --git a/src/screens/points/components/AnimatedText.tsx b/src/screens/points/components/AnimatedText.tsx index cd9380e5ad5..ea34377b58e 100644 --- a/src/screens/points/components/AnimatedText.tsx +++ b/src/screens/points/components/AnimatedText.tsx @@ -63,11 +63,8 @@ export const AnimatedText = ({ weight = 'bold', }: AnimatedTextProps) => { const { colors } = useTheme(); - const { - currentSequenceIndex, - getNextAnimationIndex, - incrementSequence, - } = useAnimationContext(); + const { currentSequenceIndex, getNextAnimationIndex, incrementSequence } = + useAnimationContext(); const index = useRef(getNextAnimationIndex()).current; const displayedCharacters = useSharedValue( skipAnimation ? textContent.length : 0 @@ -89,8 +86,8 @@ export const AnimatedText = ({ textShadowColor: disableShadow ? 'transparent' : shadowOpacity && rainbowTextColors?.[i]?.shadow - ? colors.alpha(rainbowTextColors?.[i]?.shadow, shadowOpacity) - : rainbowTextColors?.[i]?.shadow, + ? colors.alpha(rainbowTextColors?.[i]?.shadow, shadowOpacity) + : rainbowTextColors?.[i]?.shadow, }), [ colors, @@ -111,10 +108,10 @@ export const AnimatedText = ({ textShadowColor: disableShadow ? 'transparent' : rainbowText - ? undefined - : shadowOpacity && color?.shadow - ? colors.alpha(color?.shadow, shadowOpacity) - : color?.shadow, + ? undefined + : shadowOpacity && color?.shadow + ? colors.alpha(color?.shadow, shadowOpacity) + : color?.shadow, }), [ color, diff --git a/src/screens/points/components/LeaderboardRow.tsx b/src/screens/points/components/LeaderboardRow.tsx index c58d653736d..b436298fa28 100644 --- a/src/screens/points/components/LeaderboardRow.tsx +++ b/src/screens/points/components/LeaderboardRow.tsx @@ -65,9 +65,10 @@ export const LeaderboardRow = ({ const contact = address ? contacts[address.toLowerCase()] : undefined; - const formattedAddress = useMemo(() => formatAddress(address, 4, 5), [ - address, - ]); + const formattedAddress = useMemo( + () => formatAddress(address, 4, 5), + [address] + ); const menuItems = useMemo(() => { return [ diff --git a/src/screens/points/components/NotificationToggleContextMenu.tsx b/src/screens/points/components/NotificationToggleContextMenu.tsx index 7b08e7f41b3..c375a53e3a4 100644 --- a/src/screens/points/components/NotificationToggleContextMenu.tsx +++ b/src/screens/points/components/NotificationToggleContextMenu.tsx @@ -30,14 +30,11 @@ export const NotificationToggleContextMenu = () => { const separatorTertiary = useForegroundColor('separatorTertiary'); const { colorMode } = useColorMode(); const { isConnected } = useNetInfo(); - const { - globalNotificationSettings, - } = useAllNotificationSettingsFromStorage(); + const { globalNotificationSettings } = + useAllNotificationSettingsFromStorage(); - const [ - topicSubscriptionInProgress, - setTopicSubscriptionInProgress, - ] = useState(false); + const [topicSubscriptionInProgress, setTopicSubscriptionInProgress] = + useState(false); const toggleNotifications = useCallback(() => { if (!isConnected) { @@ -52,9 +49,8 @@ export const NotificationToggleContextMenu = () => { .then(() => { setAllGlobalNotificationSettingsToStorage({ ...globalNotificationSettings, - [GlobalNotificationTopic.POINTS]: !globalNotificationSettings[ - GlobalNotificationTopic.POINTS - ], + [GlobalNotificationTopic.POINTS]: + !globalNotificationSettings[GlobalNotificationTopic.POINTS], }); }) .catch(() => { diff --git a/src/screens/points/content/PointsContent.tsx b/src/screens/points/content/PointsContent.tsx index 453eeffa817..70f7c7d89b1 100644 --- a/src/screens/points/content/PointsContent.tsx +++ b/src/screens/points/content/PointsContent.tsx @@ -62,14 +62,19 @@ export default function PointsContent() { const { setClipboard } = useClipboard(); const { isReadOnlyWallet } = useWallets(); - const { data: points, isFetching, dataUpdatedAt, refetch } = usePoints({ + const { + data: points, + isFetching, + dataUpdatedAt, + refetch, + } = usePoints({ walletAddress: accountAddress, }); - const cards = useMemo(() => getCardsForPlacement(name as string), [ - getCardsForPlacement, - name, - ]); + const cards = useMemo( + () => getCardsForPlacement(name as string), + [getCardsForPlacement, name] + ); useFocusEffect( useCallback(() => { @@ -121,9 +126,8 @@ export default function PointsContent() { }, [dataUpdatedAt, refetch]); const nextDistributionSeconds = points?.points?.meta?.distribution?.next; - const totalPointsString = points?.points?.user?.earnings?.total.toLocaleString( - 'en-US' - ); + const totalPointsString = + points?.points?.user?.earnings?.total.toLocaleString('en-US'); const totalPointsMaskSize = 60 * Math.max(totalPointsString?.length ?? 0, 4); const totalUsers = points?.points?.leaderboard.stats.total_users; diff --git a/src/screens/points/content/console/calculate.tsx b/src/screens/points/content/console/calculate.tsx index 21b2b277e43..aabaeaac043 100644 --- a/src/screens/points/content/console/calculate.tsx +++ b/src/screens/points/content/console/calculate.tsx @@ -37,9 +37,8 @@ export const Calculate = () => { const { accountENS, accountAddress } = useAccountProfile(); const [isCalculationComplete, setIsCalculationComplete] = useState(false); - const [shouldShowContinueButton, setShouldShowContinueButton] = useState( - false - ); + const [shouldShowContinueButton, setShouldShowContinueButton] = + useState(false); const accountName = (abbreviateEnsForDisplay(accountENS, 10) || formatAddress(accountAddress, 4, 5)) as string; diff --git a/src/screens/points/content/console/initialize.tsx b/src/screens/points/content/console/initialize.tsx index 126878e8f60..874b79df2e7 100644 --- a/src/screens/points/content/console/initialize.tsx +++ b/src/screens/points/content/console/initialize.tsx @@ -20,12 +20,8 @@ import { Bleed, Box, Stack } from '@/design-system'; export const Initialize = () => { const [showSignInButton, setShowSignInButton] = useState(false); - const { - profile, - setStep, - setAnimationKey, - signIn, - } = usePointsProfileContext(); + const { profile, setStep, setAnimationKey, signIn } = + usePointsProfileContext(); const { accountENS, accountAddress } = useAccountProfile(); const accountName = (abbreviateEnsForDisplay(accountENS, 10) || diff --git a/src/screens/points/content/console/share.tsx b/src/screens/points/content/console/share.tsx index 06ff01a47e5..024f5580901 100644 --- a/src/screens/points/content/console/share.tsx +++ b/src/screens/points/content/console/share.tsx @@ -19,12 +19,8 @@ import { metadataPOSTClient } from '@/graphql'; import { analyticsV2 } from '@/analytics'; export const Share = () => { - const { - intent, - setAnimationKey, - setShareBonusPoints, - setStep, - } = usePointsProfileContext(); + const { intent, setAnimationKey, setShareBonusPoints, setStep } = + usePointsProfileContext(); const { accountENS, accountAddress } = useAccountProfile(); const { width: deviceWidth } = useDimensions(); @@ -113,12 +109,11 @@ export const Share = () => { const beginNextPhase = setTimeout(async () => { if (intent) { Linking.openURL(intent); - const shareBonusPointsResponse = await metadataPOSTClient.redeemCodeForPoints( - { + const shareBonusPointsResponse = + await metadataPOSTClient.redeemCodeForPoints({ address: accountAddress, redemptionCode: 'TWITTERSHARED', - } - ); + }); if (shareBonusPointsResponse?.redeemCode?.earnings?.total) { setShareBonusPoints( shareBonusPointsResponse?.redeemCode?.earnings?.total diff --git a/src/screens/points/contexts/PointsProfileContext.tsx b/src/screens/points/contexts/PointsProfileContext.tsx index 632af1baf05..cd109e1f823 100644 --- a/src/screens/points/contexts/PointsProfileContext.tsx +++ b/src/screens/points/contexts/PointsProfileContext.tsx @@ -119,21 +119,26 @@ export const PointsProfileProvider = ({ const [animationKey, setAnimationKey] = useState(0); const [shareBonusPoints, setShareBonusPoints] = useState(0); - const rainbowSwaps = profile?.onboardPoints?.user?.onboarding?.categories?.find( - ({ type }) => type === PointsOnboardingCategoryType.RainbowSwaps - ); - const metamaskSwaps = profile?.onboardPoints?.user?.onboarding?.categories?.find( - ({ type }) => type === PointsOnboardingCategoryType.MetamaskSwaps - ); - const rainbowBridges = profile?.onboardPoints?.user?.onboarding?.categories?.find( - ({ type }) => type === PointsOnboardingCategoryType.RainbowBridges - ); - const nftCollections = profile?.onboardPoints?.user?.onboarding?.categories?.find( - ({ type }) => type === PointsOnboardingCategoryType.NFTCollections - ); - const historicBalance = profile?.onboardPoints?.user?.onboarding?.categories?.find( - ({ type }) => type === PointsOnboardingCategoryType.HistoricBalance - ); + const rainbowSwaps = + profile?.onboardPoints?.user?.onboarding?.categories?.find( + ({ type }) => type === PointsOnboardingCategoryType.RainbowSwaps + ); + const metamaskSwaps = + profile?.onboardPoints?.user?.onboarding?.categories?.find( + ({ type }) => type === PointsOnboardingCategoryType.MetamaskSwaps + ); + const rainbowBridges = + profile?.onboardPoints?.user?.onboarding?.categories?.find( + ({ type }) => type === PointsOnboardingCategoryType.RainbowBridges + ); + const nftCollections = + profile?.onboardPoints?.user?.onboarding?.categories?.find( + ({ type }) => type === PointsOnboardingCategoryType.NFTCollections + ); + const historicBalance = + profile?.onboardPoints?.user?.onboarding?.categories?.find( + ({ type }) => type === PointsOnboardingCategoryType.HistoricBalance + ); const bonus = profile?.onboardPoints?.user?.onboarding?.categories?.find( ({ type }) => type === PointsOnboardingCategoryType.Bonus ); @@ -156,12 +161,11 @@ export const PointsProfileProvider = ({ ); try { - const challengeResponse = await metadataPOSTClient.getPointsOnboardChallenge( - { + const challengeResponse = + await metadataPOSTClient.getPointsOnboardChallenge({ address: accountAddress, referral: referralCode, - } - ); + }); const challenge = challengeResponse?.pointsOnboardChallenge; if (!challenge) { Alert.alert(i18n.t(i18n.l.points.console.generic_alert)); diff --git a/src/screens/rewards/RewardsSheet.tsx b/src/screens/rewards/RewardsSheet.tsx index ecae5ffc387..8f27ef8990a 100644 --- a/src/screens/rewards/RewardsSheet.tsx +++ b/src/screens/rewards/RewardsSheet.tsx @@ -19,7 +19,11 @@ export const RewardsSheet: React.FC = () => { (state: AppState) => state.settings.accountAddress ); const [isLoading, setIsLoading] = useState(true); - const { data, isLoading: queryIsLoading, isLoadingError } = useRewards({ + const { + data, + isLoading: queryIsLoading, + isLoadingError, + } = useRewards({ address: accountAddress, }); diff --git a/src/screens/transaction-details/TransactionDetails.tsx b/src/screens/transaction-details/TransactionDetails.tsx index 04eabcb1c3c..dec0c59938e 100644 --- a/src/screens/transaction-details/TransactionDetails.tsx +++ b/src/screens/transaction-details/TransactionDetails.tsx @@ -41,10 +41,10 @@ export const TransactionDetails = () => { const { height: deviceHeight } = useDimensions(); // Dynamic sheet height based on content height - useEffect(() => setParams({ longFormHeight: sheetHeight }), [ - setParams, - sheetHeight, - ]); + useEffect( + () => setParams({ longFormHeight: sheetHeight }), + [setParams, sheetHeight] + ); const onSheetContentLayout = (event: LayoutChangeEvent) => { const contentHeight = event.nativeEvent.layout.height; diff --git a/src/screens/transaction-details/components/TransactionDetailsAddressRow.tsx b/src/screens/transaction-details/components/TransactionDetailsAddressRow.tsx index 4ac68935326..3f457b8b143 100644 --- a/src/screens/transaction-details/components/TransactionDetailsAddressRow.tsx +++ b/src/screens/transaction-details/components/TransactionDetailsAddressRow.tsx @@ -217,9 +217,10 @@ export const TransactionDetailsAddressRow: React.FC = ({ easing: Easing.linear, }); - const accountEmoji = useMemo(() => returnStringFirstEmoji(account?.label), [ - account, - ]); + const accountEmoji = useMemo( + () => returnStringFirstEmoji(account?.label), + [account] + ); const accountName = useMemo( () => removeFirstEmojiFromString(account?.label), [] diff --git a/src/screens/transaction-details/components/TransactionDetailsStatusActionsAndTimestampSection.tsx b/src/screens/transaction-details/components/TransactionDetailsStatusActionsAndTimestampSection.tsx index 77ab340146a..52c8b079ea9 100644 --- a/src/screens/transaction-details/components/TransactionDetailsStatusActionsAndTimestampSection.tsx +++ b/src/screens/transaction-details/components/TransactionDetailsStatusActionsAndTimestampSection.tsx @@ -24,10 +24,9 @@ type Props = { hideIcon?: boolean; }; -export const TransactionDetailsStatusActionsAndTimestampSection: React.FC = ({ - transaction, - hideIcon, -}) => { +export const TransactionDetailsStatusActionsAndTimestampSection: React.FC< + Props +> = ({ transaction, hideIcon }) => { const { minedAt, status, pending, from } = transaction; const dispatch = useDispatch(); const { navigate, goBack } = useNavigation(); diff --git a/src/state/internal/createStore.ts b/src/state/internal/createStore.ts index 4e48af9b675..59c77627265 100644 --- a/src/state/internal/createStore.ts +++ b/src/state/internal/createStore.ts @@ -11,17 +11,15 @@ export type StoreWithPersist = Mutate< initializer: Initializer; }; -export function createStore( - initializer: Initializer -) { +export function createStore(initializer: Initializer) { const name = `rainbow.zustand`; return Object.assign( create( persist(initializer, { name, - getStorage: () => (persistStorage), - }), + getStorage: () => persistStorage, + }) ), - { initializer }, + { initializer } ); } diff --git a/src/styled-thing/hoist.ts b/src/styled-thing/hoist.ts index 62bb2ef67a1..d202b8aa01c 100644 --- a/src/styled-thing/hoist.ts +++ b/src/styled-thing/hoist.ts @@ -74,7 +74,7 @@ function getStatics(component: OmniComponent) { // React v16.12 and above return '$$typeof' in component - ? TYPE_STATICS[(component['$$typeof'] as unknown) as string] + ? TYPE_STATICS[component['$$typeof'] as unknown as string] : REACT_STATICS; } @@ -91,22 +91,22 @@ type ExcludeList = { type NonReactStatics< S extends OmniComponent, - C extends ExcludeList = Record + C extends ExcludeList = Record, > = { [key in Exclude< keyof S, S extends React.MemoExoticComponent ? keyof typeof MEMO_STATICS | keyof C : S extends React.ForwardRefExoticComponent - ? keyof typeof FORWARD_REF_STATICS | keyof C - : keyof typeof REACT_STATICS | keyof typeof KNOWN_STATICS | keyof C + ? keyof typeof FORWARD_REF_STATICS | keyof C + : keyof typeof REACT_STATICS | keyof typeof KNOWN_STATICS | keyof C >]: S[key]; }; export default function hoistNonReactStatics< T extends OmniComponent, S extends OmniComponent, - C extends ExcludeList = Record + C extends ExcludeList = Record, >(targetComponent: T, sourceComponent: S, excludelist?: C) { if (typeof sourceComponent !== 'string') { // don't hoist over string (html) components @@ -128,7 +128,7 @@ export default function hoistNonReactStatics< const sourceStatics = getStatics(sourceComponent); for (const item of keys) { - const key = (item as unknown) as string; + const key = item as unknown as string; if ( !(key in KNOWN_STATICS) && !excludelist?.[key] && diff --git a/src/theme/ThemeContext.tsx b/src/theme/ThemeContext.tsx index 859d04631b1..07165c14f20 100644 --- a/src/theme/ThemeContext.tsx +++ b/src/theme/ThemeContext.tsx @@ -26,7 +26,7 @@ export const Themes = { SYSTEM: 'system', } as const; -export type ThemesType = typeof Themes[keyof typeof Themes]; +export type ThemesType = (typeof Themes)[keyof typeof Themes]; export interface ThemeContextProps { colors: Colors; diff --git a/src/utils/__mocks__/delay.ts b/src/utils/__mocks__/delay.ts index b58fcec3502..b21c26d67bd 100644 --- a/src/utils/__mocks__/delay.ts +++ b/src/utils/__mocks__/delay.ts @@ -1,8 +1,8 @@ /** * @desc Promise that will resolve after the ms interval */ -export const delay = jest.fn().mockImplementation( - (ms: number): Promise => { +export const delay = jest + .fn() + .mockImplementation((ms: number): Promise => { return new Promise(resolve => setTimeout(resolve, ms)); - } -); + }); diff --git a/src/utils/ens.ts b/src/utils/ens.ts index 3840d1e9728..ebc4aa33fcc 100644 --- a/src/utils/ens.ts +++ b/src/utils/ens.ts @@ -111,7 +111,7 @@ export function validateENS( ): { valid: boolean; hint?: string; - code?: typeof ERROR_CODES[keyof typeof ERROR_CODES]; + code?: (typeof ERROR_CODES)[keyof typeof ERROR_CODES]; } { const splitDomain = domain.split('.'); diff --git a/src/utils/ethereumUtils.ts b/src/utils/ethereumUtils.ts index 836a532ec78..9fe9ca9120f 100644 --- a/src/utils/ethereumUtils.ts +++ b/src/utils/ethereumUtils.ts @@ -553,9 +553,9 @@ const calculateL1FeeOptimism = async ( newTx.data === '0x' ? ethUnits.basic_tx : ethUnits.basic_transfer ); } - // @ts-expect-error ts-migrate(2551) FIXME: Property 'selectedGasPrice' does not exist on type... Remove this comment to see the full error message - const currentGasPrice = store.getState().gas.selectedGasPrice?.value - ?.amount; + const currentGasPrice = + // @ts-expect-error ts-migrate(2551) FIXME: Property 'selectedGasPrice' does not exist on type... Remove this comment to see the full error message + store.getState().gas.selectedGasPrice?.value?.amount; if (currentGasPrice) newTx.gasPrice = toHex(currentGasPrice); // @ts-expect-error ts-migrate(100005) FIXME: Remove this comment to see the full error message const serializedTx = serialize(newTx); diff --git a/src/utils/haptics.ts b/src/utils/haptics.ts index e56c3921aae..1cfd440957f 100644 --- a/src/utils/haptics.ts +++ b/src/utils/haptics.ts @@ -12,7 +12,8 @@ export const HapticFeedback = { selection: 'selection', } as const; -export type HapticFeedbackType = typeof HapticFeedback[keyof typeof HapticFeedback]; +export type HapticFeedbackType = + (typeof HapticFeedback)[keyof typeof HapticFeedback]; const hapticToTrigger = (haptic: HapticFeedbackType) => ({ [haptic]: () => ReactNativeHapticFeedback.trigger(haptic), diff --git a/src/utils/profileUtils.ts b/src/utils/profileUtils.ts index f8029b45e9c..9c0f460fd4d 100644 --- a/src/utils/profileUtils.ts +++ b/src/utils/profileUtils.ts @@ -76,9 +76,10 @@ export function hashCode(text: string) { return hash; } -export function getNextEmojiWithColor( - prevEmoji: string -): { emoji: string; colorIndex: number } { +export function getNextEmojiWithColor(prevEmoji: string): { + emoji: string; + colorIndex: number; +} { const prevIndex = avatars.findIndex(({ emoji }) => emoji === prevEmoji); // if not matched, we get -1, what's fine return avatars[(prevIndex + 1) % avatars.length]; } diff --git a/src/utils/recompactAdapters.tsx b/src/utils/recompactAdapters.tsx index df9b60bb5fa..8a023fe329e 100644 --- a/src/utils/recompactAdapters.tsx +++ b/src/utils/recompactAdapters.tsx @@ -20,5 +20,9 @@ export function compose(...funcs: any[]) { return funcs[0]; } - return funcs.reduce((a, b) => (...args: any[]) => a(b(...args))); + return funcs.reduce( + (a, b) => + (...args: any[]) => + a(b(...args)) + ); } diff --git a/src/walletConnect/index.tsx b/src/walletConnect/index.tsx index 3211f3bc4af..4fb9ef0b2ff 100644 --- a/src/walletConnect/index.tsx +++ b/src/walletConnect/index.tsx @@ -108,7 +108,7 @@ export function maybeGoBackAndClearHasPendingRedirect({ * MAY BE UNDEFINED if WC v2 hasn't been instantiated yet */ let syncWeb3WalletClient: - | Awaited> + | Awaited> | undefined; const walletConnectCore = new Core({ projectId: WC_PROJECT_ID }); @@ -132,10 +132,7 @@ export const web3WalletClient = Web3Wallet.init({ * return { address, message } and JSON.parse the value if it's from a typed * data request */ -export function parseRPCParams({ - method, - params, -}: RPCPayload): { +export function parseRPCParams({ method, params }: RPCPayload): { address?: string; message?: string; } { @@ -463,11 +460,8 @@ export async function onSessionProposal( const verifiedData = proposal.verifyContext.verified; const receivedTimestamp = Date.now(); - const { - proposer, - requiredNamespaces, - optionalNamespaces, - } = proposal.params; + const { proposer, requiredNamespaces, optionalNamespaces } = + proposal.params; const requiredChains = requiredNamespaces?.eip155?.chains || []; const optionalChains = optionalNamespaces?.eip155?.chains || []; @@ -1069,9 +1063,8 @@ export async function addAccountToSession( try { const client = await web3WalletClient; - const namespaces: Parameters< - typeof client.updateSession - >[0]['namespaces'] = {}; + const namespaces: Parameters[0]['namespaces'] = + {}; for (const [key, value] of Object.entries(session.requiredNamespaces)) { /** diff --git a/src/walletConnect/types.ts b/src/walletConnect/types.ts index 053a6f18766..ad8e6bad02a 100644 --- a/src/walletConnect/types.ts +++ b/src/walletConnect/types.ts @@ -29,7 +29,7 @@ export type RPCPayload = | RPCMethod.SignTypedDataV4; params: [ string, // address - string // stringify typed object + string, // stringify typed object ]; } | { @@ -42,7 +42,7 @@ export type RPCPayload = gasPrice: string; gasLimit: string; value: string; - } + }, ]; } | { diff --git a/yarn.lock b/yarn.lock index ddafa87bc79..2458e6de6db 100644 --- a/yarn.lock +++ b/yarn.lock @@ -14732,10 +14732,10 @@ prelude-ls@^1.2.1: resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== -prettier@2.2.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.2.1.tgz#795a1a78dd52f073da0cd42b21f9c91381923ff5" - integrity sha512-PqyhM2yCjg/oKkFPtTGUojv7gnZAoG80ttl45O6x2Ug/rMJw4wcc9k6aaf2hibP7BGVCCM33gZoGjyvt9mm16Q== +prettier@3.2.5: + version "3.2.5" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.2.5.tgz#e52bc3090586e824964a8813b09aba6233b28368" + integrity sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A== prettier@^1.17.1: version "1.19.1" @@ -19165,9 +19165,9 @@ zod@^1.11.11: resolved "https://registry.yarnpkg.com/zod/-/zod-1.11.17.tgz#2aae9e91fc66128116ae9844e8f416a95f453f8e" integrity sha512-UzIwO92D0dSFwIRyyqAfRXICITLjF0IP8tRbEK/un7adirMssWZx8xF/1hZNE7t61knWZ+lhEuUvxlu2MO8qqA== -zustand@4.1.5: - version "4.1.5" - resolved "https://registry.yarnpkg.com/zustand/-/zustand-4.1.5.tgz#7402b511f5b23ccb0f9ba6d20ae01ec817e16eb6" - integrity sha512-PsdRT8Bvq22Yyh1tvpgdHNE7OAeFKqJXUxtJvj1Ixw2B9O2YZ1M34ImQ+xyZah4wZrR4lENMoDUutKPpyXCQ/Q== +zustand@4.3.1: + version "4.3.1" + resolved "https://registry.yarnpkg.com/zustand/-/zustand-4.3.1.tgz#76c47ef713c43763953f7a9e518f89efd898e3bb" + integrity sha512-EVyo/eLlOTcJm/X5M00rwtbYFXwRVTaRteSvhtbTZUCQFJkNfIyHPiJ6Ke68MSWzcKHpPzvqNH4gC2ZS/sbNqw== dependencies: use-sync-external-store "1.2.0" From 820a461df4e1fd8e3c68814f5c949b75a83ff488 Mon Sep 17 00:00:00 2001 From: skylarbarrera Date: Mon, 5 Feb 2024 22:47:31 -0500 Subject: [PATCH 12/38] Revert "fix prettier" This reverts commit 0ead5a0e866ccbb63cc93d8735107235be3f0926. --- audit-ci.jsonc | 4 +- e2e/registerENSFlow.spec.js | 12 +- lint-staged.config.js | 3 - metro.transform.js | 3 +- package.json | 10 +- src/components/EdgeFade.js | 28 +- .../ButtonPressAnimation.android.tsx | 7 +- .../ButtonPressAnimation/NativeButton.tsx | 45 +- .../animations/ButtonPressAnimation/types.ts | 3 +- .../asset-list/RecyclerAssetList/index.tsx | 19 +- .../FastCurrencySelectionRow.tsx | 9 +- .../WrappedPositionsListHeader.tsx | 6 +- .../core/ExternalENSProfileScrollView.tsx | 10 +- .../core/RawRecyclerList.tsx | 19 +- .../asset-list/RecyclerAssetList2/index.tsx | 14 +- .../ProfileActionButtonsRow.tsx | 6 +- .../profile-header/ProfileAvatarRow.tsx | 7 +- .../backup/BackupConfirmPasswordStep.js | 7 +- src/components/buttons/MiniButton.js | 8 +- src/components/buttons/PasteAddressButton.js | 8 +- .../HoldToAuthorizeButtonContent.tsx | 4 +- .../rainbow-button/RainbowButtonBackground.js | 8 +- src/components/cards/ActionCard.tsx | 8 +- .../cards/MintsCard/CollectionCell.tsx | 5 +- .../cards/remote-cards/RemoteCard.tsx | 9 +- .../cards/remote-cards/RemoteCardCarousel.tsx | 8 +- src/components/cards/utils/constants.ts | 4 +- src/components/change-wallet/AddressRow.tsx | 7 +- src/components/coin-divider/CoinDivider.js | 13 +- src/components/coin-icon/CoinIcon.tsx | 7 +- src/components/coin-icon/CoinIconFallback.js | 12 +- .../coin-row/CollectiblesSendRow.tsx | 4 +- src/components/coin-row/SendCoinRow.js | 8 +- src/components/contacts/ContactAvatar.js | 8 +- src/components/contacts/ContactRow.js | 11 +- .../contacts/SwipeableContactRow.js | 8 +- .../copy-tooltip/CopyTooltip.ios.js | 7 +- .../ens-profile/ProfileCover/ProfileCover.tsx | 12 +- .../ens-profile/RecordTags/RecordTags.tsx | 2 +- .../IntroMarquee/IntroMarquee.tsx | 5 +- .../RegistrationAvatar/RegistrationAvatar.tsx | 82 +- .../RegistrationCover/RegistrationCover.tsx | 13 +- .../exchange/ConfirmExchangeButton.js | 22 +- src/components/exchange/ExchangeAssetList.tsx | 7 +- .../exchange/ExchangeNativeField.tsx | 5 +- src/components/exchange/ExchangeTokenRow.tsx | 3 +- .../expanded-state/SwapDetailsState.js | 32 +- .../UniqueTokenExpandedState.tsx | 20 +- .../asset/ChartExpandedState.js | 23 +- .../chart/ChartContextButton.js | 7 +- .../ChartChangeDirectionArrow.js | 4 +- .../chart/chart-data-labels/ChartDateLabel.js | 4 +- .../ChartPercentChangeLabel.js | 13 +- .../expanded-state/custom-gas/FeesPanel.tsx | 10 +- src/components/expanded-state/ens/InfoRow.tsx | 8 +- .../expanded-state/ens/ProfileInfoSection.tsx | 31 +- .../expanded-state/profile/ProfileModal.tsx | 7 +- .../swap-details/SwapDetailsContent.js | 5 +- .../swap-details/SwapDetailsContractRow.js | 12 +- .../swap-settings/MaxToleranceInput.tsx | 4 +- .../swap-settings/SwapSettingsState.js | 6 +- .../UniqueTokenExpandedStateHeader.tsx | 2 +- .../unique-token/ZoomableWrapper.android.js | 40 +- .../unique-token/ZoomableWrapper.js | 40 +- src/components/fields/BubbleField.js | 8 +- src/components/fields/SmallBubbleField.js | 12 +- .../floating-emojis/FloatingEmojis.js | 4 +- src/components/gas/GasSpeedButton.js | 26 +- src/components/images/ImagePreviewOverlay.tsx | 4 +- src/components/inputs/InlineField.tsx | 12 +- src/components/layout/LayoutWithDividers.js | 7 +- src/components/qrcode-scanner/CameraDimmer.js | 5 +- .../remote-promo-sheet/RemotePromoSheet.tsx | 5 +- .../remote-promo-sheet/checkForCampaign.ts | 11 +- .../notificationsPromoCampaign.ts | 47 +- src/components/secret-display/states.ts | 3 +- src/components/send/SendAssetFormField.js | 4 +- src/components/send/SendAssetFormToken.js | 6 +- src/components/send/SendButton.js | 4 +- src/components/send/SendHeader.js | 8 +- src/components/sheet/SlackSheet.js | 4 +- src/components/unique-token/Tag.js | 5 +- .../unique-token/UniqueTokenCard.js | 7 +- src/components/value-chart/Chart.js | 7 +- .../WalletConnectV2ListItem.tsx | 81 +- .../color/AccentColorContext.tsx | 2 +- src/design-system/color/palettes.docs.tsx | 20 +- src/design-system/color/palettes.ts | 8 +- src/design-system/components/Box/Box.tsx | 2 +- .../components/Box/polymorphic.ts | 7 +- .../components/Heading/Heading.examples.tsx | 6 +- .../components/Heading/useHeadingStyle.ts | 2 +- .../components/Inline/Inline.tsx | 7 +- .../components/MarkdownText/MarkdownText.tsx | 17 +- .../components/Text/useTextStyle.ts | 2 +- src/design-system/docs/.playroom/fonts.css | 30 +- src/design-system/docs/styles/fonts.css | 36 +- .../docs/system/typography.css.ts | 4 +- src/design-system/playground/Playground.tsx | 7 +- src/ens-avatar/src/index.ts | 5 +- .../unlockableAppIconCheck.ts | 9 +- src/graphql/utils/getFetchRequester.ts | 2 +- src/handlers/LedgerSigner.ts | 5 +- src/handlers/ens.ts | 16 +- src/handlers/nftOffers.ts | 6 +- src/handlers/swap.ts | 43 +- src/handlers/web3.ts | 8 +- .../buildTransactionsSectionsSelector.tsx | 64 +- src/helpers/buildWalletSections.tsx | 6 +- src/helpers/chartTypes.ts | 2 +- src/helpers/emojiHandler.ts | 3 +- src/helpers/ens.ts | 23 +- src/helpers/signingWallet.ts | 6 +- src/helpers/time.ts | 6 +- ...ansformUniqueAssetTraitsForPresentation.ts | 3 +- src/helpers/utilities.ts | 15 +- src/hooks/charts/useChartInfo.ts | 2 +- src/hooks/charts/useChartThrottledPoints.ts | 5 +- src/hooks/useAccountENSDomains.ts | 43 +- src/hooks/useAccountTransactions.ts | 5 +- src/hooks/useAnimatedPageScrollHandler.ts | 4 +- src/hooks/useCoinListEditOptions.ts | 7 +- src/hooks/useCoinListEdited.ts | 5 +- src/hooks/useDeleteWallet.ts | 22 +- src/hooks/useENSModifiedRegistration.ts | 6 +- src/hooks/useENSRegistrationActionHandler.ts | 6 +- src/hooks/useENSRegistrationCosts.ts | 7 +- src/hooks/useENSRegistrationForm.ts | 5 +- src/hooks/useENSRegistrationStepHandler.tsx | 20 +- src/hooks/useExpandedStateNavigation.ts | 2 +- src/hooks/useInteraction.ts | 2 +- src/hooks/useInterval.ts | 2 +- src/hooks/useInvalidPaste.ts | 7 +- src/hooks/useLatestCallback.ts | 4 +- src/hooks/useOnAvatarPress.ts | 22 +- src/hooks/useParamsForExchangeModal.ts | 7 +- src/hooks/usePortfolios.ts | 7 +- src/hooks/usePriceImpactDetails.ts | 5 +- src/hooks/useRouteExistsInNavigationState.ts | 8 +- src/hooks/useSearchCurrencyList.ts | 29 +- src/hooks/useSendSheetInputRefs.ts | 7 +- src/hooks/useSwapCurrencyHandlers.ts | 7 +- src/hooks/useSwapCurrencyList.ts | 29 +- src/hooks/useSwapDerivedOutputs.ts | 12 +- src/hooks/useSwapInputRefs.ts | 7 +- src/hooks/useSwapRefuel.ts | 49 +- src/hooks/useSwappableUserAssets.ts | 10 +- src/hooks/useTimeout.ts | 2 +- src/hooks/useWalletSectionsData.ts | 20 +- src/hooks/useWatchPendingTxs.ts | 40 +- src/hooks/useWatchWallet.ts | 11 +- src/keychain/index.ts | 2 +- src/model/backup.ts | 6 +- src/model/migrations.ts | 12 +- src/model/preferences.ts | 11 +- src/model/wallet.ts | 70 +- src/navigation/HardwareWalletTxNavigator.tsx | 5 +- .../PairHardwareWalletNavigator.tsx | 5 +- .../RecyclerListViewScrollToTopContext.tsx | 12 +- src/navigation/RegisterENSNavigator.tsx | 14 +- src/navigation/Routes.android.tsx | 2 +- src/navigation/Routes.ios.tsx | 2 +- .../bottom-sheet/contexts/internal.ts | 5 +- src/navigation/bottom-sheet/types.d.ts | 4 +- src/navigation/config.tsx | 55 +- src/navigation/effects.tsx | 100 +- src/navigation/onNavigationStateChange.js | 4 +- src/notifications/NotificationsHandler.tsx | 10 +- src/notifications/analytics.ts | 33 +- src/notifications/settings/hooks.ts | 24 +- src/notifications/settings/initialization.ts | 49 +- src/notifications/settings/types.ts | 9 +- src/notifications/types.ts | 6 +- src/parsers/accounts.js | 6 +- .../tracking/types/PerformanceMetrics.ts | 3 +- .../tracking/types/PerformanceTags.ts | 3 +- src/raps/actions/crosschainSwap.ts | 8 +- src/raps/actions/ens.ts | 11 +- src/raps/actions/swap.ts | 9 +- src/raps/actions/unlock.ts | 13 +- src/raps/registerENS.ts | 9 +- .../Example/src/BasicExample/index.js | 6 +- .../Example/src/GenericExample/index.js | 137 +- .../src/charts/linear/ChartLabels.tsx | 9 +- .../src/charts/linear/ChartPath.tsx | 97 +- .../src/helpers/d3Interpolate.js | 3 +- src/react-query/types.ts | 40 +- src/redux/appState.ts | 16 +- src/redux/charts.ts | 57 +- src/redux/contacts.ts | 102 +- src/redux/data.ts | 1185 ++++++++-------- src/redux/editOptions.ts | 16 +- src/redux/ensRegistration.ts | 613 ++++---- src/redux/explorer.ts | 441 +++--- src/redux/gas.ts | 691 +++++---- src/redux/hiddenTokens.ts | 178 ++- src/redux/imageMetadata.ts | 47 +- src/redux/keyboardHeight.ts | 59 +- src/redux/nonceManager.ts | 103 +- src/redux/requests.ts | 202 ++- src/redux/settings.ts | 339 +++-- src/redux/showcaseTokens.ts | 188 +-- src/redux/swap.ts | 242 ++-- src/redux/transactionSignatures.ts | 56 +- src/redux/walletconnect.ts | 1259 ++++++++--------- src/redux/wallets.ts | 872 ++++++------ src/references/rainbow-token-list/index.ts | 12 +- src/references/swap/bridges.ts | 3 +- src/resources/assets/UserAssetsQuery.ts | 6 +- src/resources/assets/assetSelectors.ts | 6 +- src/resources/assets/hardhatAssets.ts | 11 +- src/resources/cards/cardCollectionQuery.ts | 2 +- src/resources/nfts/index.ts | 15 +- src/resources/nfts/utils.ts | 3 +- .../transactions/consolidatedTransactions.ts | 2 +- src/resources/transactions/types.ts | 6 +- src/screens/AddCash/index.tsx | 6 +- src/screens/ChangeWalletSheet.tsx | 20 +- src/screens/CurrencySelectModal.tsx | 27 +- .../Diagnostics/DiagnosticsItemRow.tsx | 7 +- src/screens/Diagnostics/index.tsx | 5 +- src/screens/ENSAdditionalRecordsSheet.tsx | 7 +- src/screens/ENSConfirmRegisterSheet.tsx | 5 +- src/screens/ENSSearchSheet.tsx | 4 +- src/screens/ExchangeModal.tsx | 65 +- src/screens/ExplainSheet.js | 19 +- src/screens/ImportOrWatchWalletSheet.tsx | 9 +- src/screens/MintsSheet/MintsSheet.tsx | 8 +- src/screens/NFTOffersSheet/index.tsx | 8 +- src/screens/NotificationsPromoSheet/index.tsx | 6 +- src/screens/PinAuthenticationScreen.js | 4 +- src/screens/ProfileSheet.tsx | 22 +- src/screens/ReceiveModal.js | 7 +- src/screens/RestoreSheet.js | 5 +- src/screens/SelectENSSheet.tsx | 7 +- src/screens/SendConfirmationSheet.tsx | 6 +- src/screens/SendSheet.js | 25 +- .../components/BackupSection.android.tsx | 16 +- .../components/BackupSection.tsx | 16 +- .../components/DevSection.android.tsx | 15 +- .../SettingsSheet/components/DevSection.tsx | 15 +- .../SettingsSheet/components/MenuItem.tsx | 12 +- .../NotificationsSection.android.tsx | 19 +- .../components/NotificationsSection.tsx | 19 +- .../components/PrivacySection.android.tsx | 37 +- .../components/PrivacySection.tsx | 37 +- .../components/SettingsSection.tsx | 12 +- .../WalletNotificationsSettings.android.tsx | 17 +- .../WalletNotificationsSettings.tsx | 17 +- src/screens/ShowcaseSheet.js | 5 +- src/screens/SignTransactionSheet.tsx | 12 +- src/screens/TransactionConfirmationScreen.js | 11 +- .../discover/components/DiscoverHome.js | 15 +- .../components/DiscoverSearchContainer.js | 5 +- .../PairHardwareWalletAgainSheet.tsx | 8 +- .../PairHardwareWalletErrorSheet.tsx | 5 +- .../PairHardwareWalletSigningSheet.tsx | 12 +- src/screens/mints/MintSheet.tsx | 4 +- src/screens/mints/PoapSheet.tsx | 8 +- src/screens/points/PointsScreen.tsx | 14 +- .../points/components/AnimatedText.tsx | 19 +- .../points/components/LeaderboardRow.tsx | 7 +- .../NotificationToggleContextMenu.tsx | 16 +- src/screens/points/content/PointsContent.tsx | 20 +- .../points/content/console/calculate.tsx | 5 +- .../points/content/console/initialize.tsx | 8 +- src/screens/points/content/console/share.tsx | 15 +- .../points/contexts/PointsProfileContext.tsx | 42 +- src/screens/rewards/RewardsSheet.tsx | 6 +- .../TransactionDetails.tsx | 8 +- .../TransactionDetailsAddressRow.tsx | 7 +- ...etailsStatusActionsAndTimestampSection.tsx | 7 +- src/state/internal/createStore.ts | 10 +- src/styled-thing/hoist.ts | 12 +- src/theme/ThemeContext.tsx | 2 +- src/utils/__mocks__/delay.ts | 8 +- src/utils/ens.ts | 2 +- src/utils/ethereumUtils.ts | 6 +- src/utils/haptics.ts | 3 +- src/utils/profileUtils.ts | 7 +- src/utils/recompactAdapters.tsx | 6 +- src/walletConnect/index.tsx | 19 +- src/walletConnect/types.ts | 4 +- yarn.lock | 16 +- 284 files changed, 5225 insertions(+), 5005 deletions(-) delete mode 100644 lint-staged.config.js diff --git a/audit-ci.jsonc b/audit-ci.jsonc index 2fcd75461f2..3a1cd024405 100644 --- a/audit-ci.jsonc +++ b/audit-ci.jsonc @@ -15,6 +15,6 @@ "GHSA-cchq-frgv-rjh5", // https://github.com/advisories/GHSA-cchq-frgv-rjh5 "GHSA-g644-9gfx-q4q4", // https://github.com/advisories/GHSA-g644-9gfx-q4q4 "GHSA-m95q-7qp3-xv42", // https://github.com/advisories/GHSA-m95q-7qp3-xv42 - "GHSA-gxpj-cx7g-858c", // https://github.com/advisories/GHSA-gxpj-cx7g-858c - ], + "GHSA-gxpj-cx7g-858c" // https://github.com/advisories/GHSA-gxpj-cx7g-858c + ] } diff --git a/e2e/registerENSFlow.spec.js b/e2e/registerENSFlow.spec.js index 70118cf5773..77f755cbbaf 100644 --- a/e2e/registerENSFlow.spec.js +++ b/e2e/registerENSFlow.spec.js @@ -133,10 +133,14 @@ const resolveName = async ensName => { }; const validatePrimaryName = async name => { - const { address: rainbowAddress, primaryName: rainbowPrimaryName } = - await resolveName(RAINBOW_TEST_WALLET_NAME); - const { address: randomAddress, primaryName: randomPrimaryName } = - await resolveName(RANDOM_NAME_ETH); + const { + address: rainbowAddress, + primaryName: rainbowPrimaryName, + } = await resolveName(RAINBOW_TEST_WALLET_NAME); + const { + address: randomAddress, + primaryName: randomPrimaryName, + } = await resolveName(RANDOM_NAME_ETH); if ( rainbowAddress !== randomAddress || diff --git a/lint-staged.config.js b/lint-staged.config.js deleted file mode 100644 index 64148218a63..00000000000 --- a/lint-staged.config.js +++ /dev/null @@ -1,3 +0,0 @@ -module.exports = { - '*.{js,jsx,ts,tsx,graphql}': ['prettier --write', 'eslint --cache'], -}; diff --git a/metro.transform.js b/metro.transform.js index 4eff389db94..cf91d9b9d3f 100644 --- a/metro.transform.js +++ b/metro.transform.js @@ -10,8 +10,7 @@ module.exports.transform = function applyRainbowTransform({ const opts = merge(options, { customTransformOptions: { 'metro-plugin-anisotropic-transform': { - cyclicDependents: - /.+\/node_modules\/react-native\/Libraries\/BatchedBridge\/NativeModules\.js$/, + cyclicDependents: /.+\/node_modules\/react-native\/Libraries\/BatchedBridge\/NativeModules\.js$/, globalScopeFilter: { '@react-native-community/clipboard': {}, 'react-native-keychain': {}, diff --git a/package.json b/package.json index dc11d53a367..3d89f9b8039 100644 --- a/package.json +++ b/package.json @@ -307,7 +307,7 @@ "viem": "1.6.0", "vm-browserify": "0.0.4", "w2t": "3.0.2", - "zustand": "4.3.1" + "zustand": "4.1.5" }, "devDependencies": { "@babel/core": "7.22.0", @@ -361,7 +361,7 @@ "metro-plugin-anisotropic-transform": "https://github.com/rainbow-me/metro-plugin-anisotropic-transform#eaf2a2db95eeedd2f63ce8032c102a12c5a88802", "metro-react-native-babel-preset": "0.76.7", "node-vibrant": "3.2.1-alpha.1", - "prettier": "3.2.5", + "prettier": "2.2.1", "react-test-renderer": "18.1.0", "resolve": "1.22.8", "rn-nodeify": "10.2.0", @@ -531,5 +531,11 @@ "react-native-storage": false, "react-native-storage>opencollective>babel-polyfill>core-js": false } + }, + "lint-staged": { + "*.{js,jsx,ts,tsx,graphql}": [ + "prettier --write", + "eslint --cache" + ] } } diff --git a/src/components/EdgeFade.js b/src/components/EdgeFade.js index 374f80e61ec..f947c9b2797 100644 --- a/src/components/EdgeFade.js +++ b/src/components/EdgeFade.js @@ -20,7 +20,19 @@ const LeftFade = styled(LinearGradient).attrs(({ theme: { colors } }) => ({ ], end: { x: 1, y: 0.5 }, locations: [ - 0, 0.19, 0.34, 0.47, 0.565, 0.65, 0.73, 0.802, 0.861, 0.91, 0.952, 0.982, 1, + 0, + 0.19, + 0.34, + 0.47, + 0.565, + 0.65, + 0.73, + 0.802, + 0.861, + 0.91, + 0.952, + 0.982, + 1, ], pointerEvents: 'none', start: { x: 0, y: 0.5 }, @@ -49,7 +61,19 @@ const RightFade = styled(LinearGradient).attrs(({ theme: { colors } }) => ({ ], end: { x: 0, y: 0.5 }, locations: [ - 0, 0.19, 0.34, 0.47, 0.565, 0.65, 0.73, 0.802, 0.861, 0.91, 0.952, 0.982, 1, + 0, + 0.19, + 0.34, + 0.47, + 0.565, + 0.65, + 0.73, + 0.802, + 0.861, + 0.91, + 0.952, + 0.982, + 1, ], pointerEvents: 'none', start: { x: 1, y: 0.5 }, diff --git a/src/components/animations/ButtonPressAnimation/ButtonPressAnimation.android.tsx b/src/components/animations/ButtonPressAnimation/ButtonPressAnimation.android.tsx index 8762e1a84b2..c57e0724ff6 100644 --- a/src/components/animations/ButtonPressAnimation/ButtonPressAnimation.android.tsx +++ b/src/components/animations/ButtonPressAnimation/ButtonPressAnimation.android.tsx @@ -126,8 +126,8 @@ const ScaleButton = ({ onPress, }); - const gestureHandler = - useAnimatedGestureHandler({ + const gestureHandler = useAnimatedGestureHandler( + { onActive: () => { runOnJS(handleStartPress)(); if (hasScaledDown.value === 0) { @@ -148,7 +148,8 @@ const ScaleButton = ({ onFail: () => { runOnJS(handleCancel)(); }, - }); + } + ); return ( diff --git a/src/components/animations/ButtonPressAnimation/NativeButton.tsx b/src/components/animations/ButtonPressAnimation/NativeButton.tsx index 96cf0772523..672b3fc4234 100644 --- a/src/components/animations/ButtonPressAnimation/NativeButton.tsx +++ b/src/components/animations/ButtonPressAnimation/NativeButton.tsx @@ -21,32 +21,31 @@ interface SpecificRawNativeButtonProps extends Props { transformOrigin?: TransformOrigin; } -const RawNativeButton = - requireNativeComponent('Button'); +const RawNativeButton = requireNativeComponent( + 'Button' +); -const ButtonWithTransformOrigin = styled(RawNativeButton)(({ - transformOrigin, -}: { - transformOrigin: TransformOrigin; -}) => { - if (!transformOrigin) return {}; - const [x, y] = transformOrigin; - // 👇️ Here we want to set the button's top / left - // properties (relative to the parent wrapper view) to - // values opposite of the provided transformOrigin. - // This is necessary to do in order for the `transformOrigin` prop to - // work with NativeButton without effecting NativeButton's layout. - const styles: ViewStyle = {}; +const ButtonWithTransformOrigin = styled(RawNativeButton)( + ({ transformOrigin }: { transformOrigin: TransformOrigin }) => { + if (!transformOrigin) return {}; + const [x, y] = transformOrigin; + // 👇️ Here we want to set the button's top / left + // properties (relative to the parent wrapper view) to + // values opposite of the provided transformOrigin. + // This is necessary to do in order for the `transformOrigin` prop to + // work with NativeButton without effecting NativeButton's layout. + const styles: ViewStyle = {}; - if (x !== 0.5) { - styles.left = `${x + 0.5 * (x > 0.5 ? 100 : -100)}%`; - } - if (y !== 0.5) { - styles.top = `${y + 0.5 * (y > 0.5 ? 100 : -100)}%`; - } + if (x !== 0.5) { + styles.left = `${x + 0.5 * (x > 0.5 ? 100 : -100)}%`; + } + if (y !== 0.5) { + styles.top = `${y + 0.5 * (y > 0.5 ? 100 : -100)}%`; + } - return styles; -}); + return styles; + } +); export function normalizeTransformOrigin( transformOrigin: TransformOrigin | string | undefined diff --git a/src/components/animations/ButtonPressAnimation/types.ts b/src/components/animations/ButtonPressAnimation/types.ts index 3963c393adc..b4973c3786a 100644 --- a/src/components/animations/ButtonPressAnimation/types.ts +++ b/src/components/animations/ButtonPressAnimation/types.ts @@ -7,8 +7,7 @@ import { export type TransformOrigin = [number, number]; export type Direction = 'bottom' | 'left' | 'right' | 'top'; -export type ButtonPressAnimationTouchEvent = - NativeSyntheticEvent; +export type ButtonPressAnimationTouchEvent = NativeSyntheticEvent; export interface BaseButtonAnimationProps extends Pick, diff --git a/src/components/asset-list/RecyclerAssetList/index.tsx b/src/components/asset-list/RecyclerAssetList/index.tsx index 009701115de..aabb4e9167f 100644 --- a/src/components/asset-list/RecyclerAssetList/index.tsx +++ b/src/components/asset-list/RecyclerAssetList/index.tsx @@ -225,8 +225,9 @@ function RecyclerAssetList({ const { openFamilies: openFamilyTabs } = useOpenFamilies(); const { ref, handleRef } = useRecyclerListViewRef(); const stickyCoinDividerRef = React.useRef() as React.RefObject; - const [globalDeviceDimensions, setGlobalDeviceDimensions] = - useState(0); + const [globalDeviceDimensions, setGlobalDeviceDimensions] = useState( + 0 + ); const { areSmallCollectibles, items, @@ -352,8 +353,9 @@ function RecyclerAssetList({ } if (type.index === ViewTypes.HEADER.index) { - return ( - showcase ? ViewTypes.SHOWCASE_HEADER : ViewTypes.HEADER + return (showcase + ? ViewTypes.SHOWCASE_HEADER + : ViewTypes.HEADER ).renderComponent({ data, isCoinListEdited, @@ -522,7 +524,7 @@ function RecyclerAssetList({ }; }, (type, dim) => { - const element = type as unknown as { + const element = (type as unknown) as { readonly height: number; readonly visibleDuringCoinEdit: boolean; }; @@ -581,8 +583,7 @@ function RecyclerAssetList({ useEffect(() => { let collectibles: RecyclerAssetListSection = {} as RecyclerAssetListSection; - let prevCollectibles: RecyclerAssetListSection = - {} as RecyclerAssetListSection; + let prevCollectibles: RecyclerAssetListSection = {} as RecyclerAssetListSection; let balances: RecyclerAssetListSection = {} as RecyclerAssetListSection; let smallBalances: any = {}; @@ -686,8 +687,8 @@ function RecyclerAssetList({ disableStickyHeaders ? [] : isCoinListEdited - ? defaultIndices - : stickyComponentsIndices + ? defaultIndices + : stickyComponentsIndices } > {/* @ts-ignore */} diff --git a/src/components/asset-list/RecyclerAssetList2/FastComponents/FastCurrencySelectionRow.tsx b/src/components/asset-list/RecyclerAssetList2/FastComponents/FastCurrencySelectionRow.tsx index 0a1d2d08458..06a2dd5a033 100644 --- a/src/components/asset-list/RecyclerAssetList2/FastComponents/FastCurrencySelectionRow.tsx +++ b/src/components/asset-list/RecyclerAssetList2/FastComponents/FastCurrencySelectionRow.tsx @@ -19,9 +19,9 @@ import { useAccountAsset } from '@/hooks'; import { colors, fonts, fontWithWidth, getFontSize } from '@/styles'; import { deviceUtils } from '@/utils'; -const SafeRadialGradient = ( - IS_TESTING === 'true' ? View : RadialGradient -) as typeof RadialGradient; +const SafeRadialGradient = (IS_TESTING === 'true' + ? View + : RadialGradient) as typeof RadialGradient; interface FastCurrencySelectionRowProps { item: any; @@ -261,7 +261,8 @@ export default React.memo(function FastCurrencySelectionRow({ )} ); -}, isEqual); +}, +isEqual); const sx = StyleSheet.create({ addGradient: { diff --git a/src/components/asset-list/RecyclerAssetList2/WrappedPositionsListHeader.tsx b/src/components/asset-list/RecyclerAssetList2/WrappedPositionsListHeader.tsx index 05e3ca48626..6c8a3a3f6dc 100644 --- a/src/components/asset-list/RecyclerAssetList2/WrappedPositionsListHeader.tsx +++ b/src/components/asset-list/RecyclerAssetList2/WrappedPositionsListHeader.tsx @@ -14,8 +14,10 @@ const TokenFamilyHeaderHeight = 48; const PositionListHeader = ({ total, ...props }: { total: string }) => { const { colors } = useTheme(); - const { isPositionCardsOpen, toggleOpenPositionCards } = - useOpenPositionCards(); + const { + isPositionCardsOpen, + toggleOpenPositionCards, + } = useOpenPositionCards(); const toValue = Number(!!isPositionCardsOpen); diff --git a/src/components/asset-list/RecyclerAssetList2/core/ExternalENSProfileScrollView.tsx b/src/components/asset-list/RecyclerAssetList2/core/ExternalENSProfileScrollView.tsx index 5d0f230b5f7..ff3b3d2da63 100644 --- a/src/components/asset-list/RecyclerAssetList2/core/ExternalENSProfileScrollView.tsx +++ b/src/components/asset-list/RecyclerAssetList2/core/ExternalENSProfileScrollView.tsx @@ -111,10 +111,12 @@ const ExternalENSProfileScrollViewWithRefFactory = (type: string) => ); }); -const ExternalENSProfileScrollViewWithRef = - ExternalENSProfileScrollViewWithRefFactory('ens-profile'); -const ExternalSelectNFTScrollViewWithRef = - ExternalENSProfileScrollViewWithRefFactory('select-nft'); +const ExternalENSProfileScrollViewWithRef = ExternalENSProfileScrollViewWithRefFactory( + 'ens-profile' +); +const ExternalSelectNFTScrollViewWithRef = ExternalENSProfileScrollViewWithRefFactory( + 'select-nft' +); export { ExternalSelectNFTScrollViewWithRef, ExternalENSProfileScrollViewWithRef, diff --git a/src/components/asset-list/RecyclerAssetList2/core/RawRecyclerList.tsx b/src/components/asset-list/RecyclerAssetList2/core/RawRecyclerList.tsx index b87abbc1087..7a371de025d 100644 --- a/src/components/asset-list/RecyclerAssetList2/core/RawRecyclerList.tsx +++ b/src/components/asset-list/RecyclerAssetList2/core/RawRecyclerList.tsx @@ -79,10 +79,10 @@ const RawMemoRecyclerAssetList = React.memo(function RawRecyclerAssetList({ const { getCardsForPlacement } = useRemoteCardContext(); const { isReadOnlyWallet } = useWallets(); - const cards = useMemo( - () => getCardsForPlacement(name as string), - [getCardsForPlacement, name] - ); + const cards = useMemo(() => getCardsForPlacement(name as string), [ + getCardsForPlacement, + name, + ]); const layoutProvider = useMemo( () => @@ -134,10 +134,9 @@ const RawMemoRecyclerAssetList = React.memo(function RawRecyclerAssetList({ }, [ref, setScrollToTopRef]); const onLayout = useCallback( - () => - ({ nativeEvent }: LayoutChangeEvent) => { - topMarginRef.current = nativeEvent.layout.y; - }, + () => ({ nativeEvent }: LayoutChangeEvent) => { + topMarginRef.current = nativeEvent.layout.y; + }, [] ); @@ -189,8 +188,8 @@ const RawMemoRecyclerAssetList = React.memo(function RawRecyclerAssetList({ type === 'ens-profile' ? ExternalENSProfileScrollViewWithRef : type === 'select-nft' - ? ExternalSelectNFTScrollViewWithRef - : ExternalScrollViewWithRef + ? ExternalSelectNFTScrollViewWithRef + : ExternalScrollViewWithRef } itemAnimator={layoutItemAnimator} layoutProvider={layoutProvider} diff --git a/src/components/asset-list/RecyclerAssetList2/index.tsx b/src/components/asset-list/RecyclerAssetList2/index.tsx index 389ed45fe99..07eb44cc75e 100644 --- a/src/components/asset-list/RecyclerAssetList2/index.tsx +++ b/src/components/asset-list/RecyclerAssetList2/index.tsx @@ -39,12 +39,14 @@ function RecyclerAssetList({ type?: AssetListType; walletBriefSectionsData: any[]; }) { - const { memoizedResult: briefSectionsData, additionalData } = - useMemoBriefSectionData({ - briefSectionsData: walletBriefSectionsData, - externalAddress, - type, - }); + const { + memoizedResult: briefSectionsData, + additionalData, + } = useMemoBriefSectionData({ + briefSectionsData: walletBriefSectionsData, + externalAddress, + type, + }); const insets = useSafeAreaInsets(); diff --git a/src/components/asset-list/RecyclerAssetList2/profile-header/ProfileActionButtonsRow.tsx b/src/components/asset-list/RecyclerAssetList2/profile-header/ProfileActionButtonsRow.tsx index 356b750767f..38b6e148a05 100644 --- a/src/components/asset-list/RecyclerAssetList2/profile-header/ProfileActionButtonsRow.tsx +++ b/src/components/asset-list/RecyclerAssetList2/profile-header/ProfileActionButtonsRow.tsx @@ -58,8 +58,10 @@ export function ProfileActionButtonsRow() { ], })); - const { f2c_enabled: addCashEnabled, swagg_enabled: swapEnabled } = - useRemoteConfig(); + const { + f2c_enabled: addCashEnabled, + swagg_enabled: swapEnabled, + } = useRemoteConfig(); if (!accentColorLoaded) return null; diff --git a/src/components/asset-list/RecyclerAssetList2/profile-header/ProfileAvatarRow.tsx b/src/components/asset-list/RecyclerAssetList2/profile-header/ProfileAvatarRow.tsx index e284edfe3cd..b69e75ecd70 100644 --- a/src/components/asset-list/RecyclerAssetList2/profile-header/ProfileAvatarRow.tsx +++ b/src/components/asset-list/RecyclerAssetList2/profile-header/ProfileAvatarRow.tsx @@ -39,8 +39,11 @@ export function ProfileAvatarRow({ const { accountSymbol, accountColor, accountImage } = useAccountProfile(); - const { avatarContextMenuConfig, onAvatarPressProfile, onSelectionCallback } = - useOnAvatarPress({ screenType: 'wallet' }); + const { + avatarContextMenuConfig, + onAvatarPressProfile, + onSelectionCallback, + } = useOnAvatarPress({ screenType: 'wallet' }); const dominantColor = usePersistentDominantColorFromImage(accountImage); diff --git a/src/components/backup/BackupConfirmPasswordStep.js b/src/components/backup/BackupConfirmPasswordStep.js index 3cf7e65318b..06e70f4daf7 100644 --- a/src/components/backup/BackupConfirmPasswordStep.js +++ b/src/components/backup/BackupConfirmPasswordStep.js @@ -72,8 +72,11 @@ export default function BackupConfirmPasswordStep() { const walletCloudBackup = useWalletCloudBackup(); const [isKeyboardOpen, setIsKeyboardOpen] = useState(false); const [validPassword, setValidPassword] = useState(false); - const [passwordFocused, setPasswordFocused, setPasswordBlurred] = - useBooleanState(true); + const [ + passwordFocused, + setPasswordFocused, + setPasswordBlurred, + ] = useBooleanState(true); const [password, setPassword] = useState(''); const [label, setLabel] = useState( `􀎽 ${lang.t('back_up.confirm_password.confirm_backup')}` diff --git a/src/components/buttons/MiniButton.js b/src/components/buttons/MiniButton.js index a1161a455c4..e9707603cec 100644 --- a/src/components/buttons/MiniButton.js +++ b/src/components/buttons/MiniButton.js @@ -118,8 +118,8 @@ export default function MiniButton({ android ? 'none' : disabled - ? colors.lightGrey - : backgroundColor || colors.appleBlue + ? colors.lightGrey + : backgroundColor || colors.appleBlue } borderRadius={borderRadius} height={height} @@ -127,8 +127,8 @@ export default function MiniButton({ hideShadow ? shadows.none : disabled - ? shadows.disabled - : shadows.default + ? shadows.disabled + : shadows.default } width={width} /> diff --git a/src/components/buttons/PasteAddressButton.js b/src/components/buttons/PasteAddressButton.js index bbb59509a9a..103ef908e55 100644 --- a/src/components/buttons/PasteAddressButton.js +++ b/src/components/buttons/PasteAddressButton.js @@ -10,8 +10,12 @@ export default function PasteAddressButton({ onPress }) { const [isValid, setIsValid] = useState(false); const { colors } = useTheme(); const { onInvalidPaste } = useInvalidPaste(); - const { clipboard, enablePaste, getClipboard, hasClipboardData } = - useClipboard(); + const { + clipboard, + enablePaste, + getClipboard, + hasClipboardData, + } = useClipboard(); useEffect(() => { async function validate() { diff --git a/src/components/buttons/hold-to-authorize/HoldToAuthorizeButtonContent.tsx b/src/components/buttons/hold-to-authorize/HoldToAuthorizeButtonContent.tsx index 1185b658c21..fb18aa23b38 100644 --- a/src/components/buttons/hold-to-authorize/HoldToAuthorizeButtonContent.tsx +++ b/src/components/buttons/hold-to-authorize/HoldToAuthorizeButtonContent.tsx @@ -158,8 +158,8 @@ function HoldToAuthorizeButtonContent2({ const height = tinyButton ? TINY_BUTTON_HEIGHT : smallButton - ? SMALL_BUTTON_HEIGHT - : BUTTON_HEIGHT; + ? SMALL_BUTTON_HEIGHT + : BUTTON_HEIGHT; const width = deviceDimensions.width - parentHorizontalPadding * 2; diff --git a/src/components/buttons/rainbow-button/RainbowButtonBackground.js b/src/components/buttons/rainbow-button/RainbowButtonBackground.js index d32e1a027b6..6529fa5d599 100644 --- a/src/components/buttons/rainbow-button/RainbowButtonBackground.js +++ b/src/components/buttons/rainbow-button/RainbowButtonBackground.js @@ -63,8 +63,8 @@ const InnerGradient = styled(RainbowButtonGradient).attrs( colors: disabled ? gradientColors.inner.disabled : type === RainbowButtonTypes.addCash - ? gradientColors.inner.addCash - : gradientColors.inner.default, + ? gradientColors.inner.addCash + : gradientColors.inner.default, }) )(({ width, height }) => ({ height: width, @@ -77,8 +77,8 @@ const OuterGradient = styled(RainbowButtonGradient).attrs( colors: disabled ? gradientColors.outer.disabled : type === RainbowButtonTypes.addCash - ? gradientColors.outer.addCash - : gradientColors.outer.default, + ? gradientColors.outer.addCash + : gradientColors.outer.default, }) )(({ width, height }) => ({ height: width * 2, diff --git a/src/components/cards/ActionCard.tsx b/src/components/cards/ActionCard.tsx index 966b3c7fb99..d31f28a0575 100644 --- a/src/components/cards/ActionCard.tsx +++ b/src/components/cards/ActionCard.tsx @@ -21,8 +21,12 @@ export const ActionCard = ({ }: ActionCardProps) => { const { isDarkMode } = useTheme(); const cardColorways = getCardColorways(isDarkMode); - const { gradient, shadowColor, orbColorDark, primaryTextColor } = - cardColorways[colorway]; + const { + gradient, + shadowColor, + orbColorDark, + primaryTextColor, + } = cardColorways[colorway]; return ( = ({ const { width } = useDimensions(); const { dismissCard } = useRemoteCardContext(); - const { cardKey, accentColor, backgroundColor, primaryButton, imageIcon } = - card; + const { + cardKey, + accentColor, + backgroundColor, + primaryButton, + imageIcon, + } = card; const accent = useForegroundColor(getColorFromString(accentColor)); const border = useForegroundColor('separatorSecondary'); diff --git a/src/components/cards/remote-cards/RemoteCardCarousel.tsx b/src/components/cards/remote-cards/RemoteCardCarousel.tsx index 00011029ff5..b9059b46373 100644 --- a/src/components/cards/remote-cards/RemoteCardCarousel.tsx +++ b/src/components/cards/remote-cards/RemoteCardCarousel.tsx @@ -37,10 +37,10 @@ export const RemoteCardCarousel = () => { const { getCardsForPlacement } = useRemoteCardContext(); const { width } = useDimensions(); - const data = useMemo( - () => getCardsForPlacement(name as string), - [getCardsForPlacement, name] - ); + const data = useMemo(() => getCardsForPlacement(name as string), [ + getCardsForPlacement, + name, + ]); const gutterSize = getGutterSizeForCardAmount(data.length); diff --git a/src/components/cards/utils/constants.ts b/src/components/cards/utils/constants.ts index ccbe94c5787..d87524a14eb 100644 --- a/src/components/cards/utils/constants.ts +++ b/src/components/cards/utils/constants.ts @@ -6,7 +6,9 @@ import { LearnCategory, } from './types'; -export const getCardColorways: (isDarkMode: boolean) => { +export const getCardColorways: ( + isDarkMode: boolean +) => { [key in CardColor]: CardColorway; } = (isDarkMode: boolean) => { return { diff --git a/src/components/change-wallet/AddressRow.tsx b/src/components/change-wallet/AddressRow.tsx index bcbf2c87f3f..a5af90c724b 100644 --- a/src/components/change-wallet/AddressRow.tsx +++ b/src/components/change-wallet/AddressRow.tsx @@ -151,10 +151,9 @@ export default function AddressRow({ cleanedUpBalance = '0'; } - const cleanedUpLabel = useMemo( - () => removeFirstEmojiFromString(label), - [label] - ); + const cleanedUpLabel = useMemo(() => removeFirstEmojiFromString(label), [ + label, + ]); const emoji = useMemo( () => diff --git a/src/components/coin-divider/CoinDivider.js b/src/components/coin-divider/CoinDivider.js index 7ba4357e24f..4984df7b549 100644 --- a/src/components/coin-divider/CoinDivider.js +++ b/src/components/coin-divider/CoinDivider.js @@ -106,11 +106,16 @@ export default function CoinDivider({ const { clearSelectedCoins } = useCoinListEditOptions(); - const { currentAction, setHiddenCoins, setPinnedCoins } = - useCoinListFinishEditingOptions(); + const { + currentAction, + setHiddenCoins, + setPinnedCoins, + } = useCoinListFinishEditingOptions(); - const { isSmallBalancesOpen, toggleOpenSmallBalances } = - useOpenSmallBalances(); + const { + isSmallBalancesOpen, + toggleOpenSmallBalances, + } = useOpenSmallBalances(); const handlePressEdit = useCallback(() => { setIsCoinListEdited(prev => !prev); diff --git a/src/components/coin-icon/CoinIcon.tsx b/src/components/coin-icon/CoinIcon.tsx index aa982f80fe4..d7c083f6bd2 100644 --- a/src/components/coin-icon/CoinIcon.tsx +++ b/src/components/coin-icon/CoinIcon.tsx @@ -61,10 +61,9 @@ const CoinIcon: React.FC = ({ }); const { colors, isDarkMode } = useTheme(); const forceFallback = !isETH(mainnet_address || address); - const isNotContractInteraction = useMemo( - () => symbol !== 'contract', - [symbol] - ); + const isNotContractInteraction = useMemo(() => symbol !== 'contract', [ + symbol, + ]); const theme = useTheme(); diff --git a/src/components/coin-icon/CoinIconFallback.js b/src/components/coin-icon/CoinIconFallback.js index befb798c3a4..11fdcca5535 100644 --- a/src/components/coin-icon/CoinIconFallback.js +++ b/src/components/coin-icon/CoinIconFallback.js @@ -29,8 +29,16 @@ const fallbackIconStyle = size => { }; export const CoinIconFallback = fallbackProps => { - const { address, height, network, symbol, shadowColor, theme, size, width } = - fallbackProps; + const { + address, + height, + network, + symbol, + shadowColor, + theme, + size, + width, + } = fallbackProps; const { colors } = theme; const imageUrl = getUrlForTrustIconFallback(address, network); diff --git a/src/components/coin-row/CollectiblesSendRow.tsx b/src/components/coin-row/CollectiblesSendRow.tsx index 9e86c7110bc..56d450cf73d 100644 --- a/src/components/coin-row/CollectiblesSendRow.tsx +++ b/src/components/coin-row/CollectiblesSendRow.tsx @@ -24,8 +24,8 @@ const selectedStyles = { ...(isTinyPhone ? padding.object(10, 0, 0) : isSmallPhone - ? padding.object(12) - : padding.object(15)), + ? padding.object(12) + : padding.object(15)), }; const BottomRow = ({ diff --git a/src/components/coin-row/SendCoinRow.js b/src/components/coin-row/SendCoinRow.js index ed9f6c062bd..e2f53e26e9b 100644 --- a/src/components/coin-row/SendCoinRow.js +++ b/src/components/coin-row/SendCoinRow.js @@ -66,8 +66,8 @@ const BottomRow = ({ {showNativeValue ? `${fiatValue} available` : balance?.display - ? `${balance?.display}${selected ? ' available' : ''}` - : 'Fetching balances...'} + ? `${balance?.display}${selected ? ' available' : ''}` + : 'Fetching balances...'} ); }; @@ -130,8 +130,8 @@ const SendCoinRow = ({ ...(isTinyPhone ? padding.object(10, 0, 0) : isSmallPhone - ? padding.object(12, 12, 12, isL2 ? 17 : 12) - : padding.object(15, 15, 15, isL2 ? 19 : 15)), + ? padding.object(12, 12, 12, isL2 ? 17 : 12) + : padding.object(15, 15, 15, isL2 ? 19 : 15)), }; return ( diff --git a/src/components/contacts/ContactAvatar.js b/src/components/contacts/ContactAvatar.js index d4691b88d73..7c7c33b77eb 100644 --- a/src/components/contacts/ContactAvatar.js +++ b/src/components/contacts/ContactAvatar.js @@ -129,10 +129,10 @@ const sizeConfigs = colors => ({ const ContactAvatar = ({ color, size = 'medium', value, ...props }) => { const { colors } = useTheme(); - const { dimensions, textSize } = useMemo( - () => sizeConfigs(colors)[size], - [colors, size] - ); + const { dimensions, textSize } = useMemo(() => sizeConfigs(colors)[size], [ + colors, + size, + ]); const { isDarkMode } = useTheme(); const shadows = useMemo( diff --git a/src/components/contacts/ContactRow.js b/src/components/contacts/ContactRow.js index 23936266ea9..1e1d06c09d5 100644 --- a/src/components/contacts/ContactRow.js +++ b/src/components/contacts/ContactRow.js @@ -97,8 +97,8 @@ const ContactRow = ( typeof ens === 'string' ? ens : nickname?.includes(ENS_DOMAIN) - ? nickname - : ''; + ? nickname + : ''; const [ensName, setENSName] = useState(initialENSName); @@ -154,10 +154,9 @@ const ContactRow = ( const imageAvatar = profilesEnabled ? ensAvatar?.imageUrl : image; - const emoji = useMemo( - () => (address ? addressHashedEmoji(address) : ''), - [address] - ); + const emoji = useMemo(() => (address ? addressHashedEmoji(address) : ''), [ + address, + ]); const emojiAvatar = avatar || emoji || nickname || label; const colorIndex = useMemo( diff --git a/src/components/contacts/SwipeableContactRow.js b/src/components/contacts/SwipeableContactRow.js index 06328a68609..2a6c5a55111 100644 --- a/src/components/contacts/SwipeableContactRow.js +++ b/src/components/contacts/SwipeableContactRow.js @@ -96,10 +96,10 @@ const SwipeableContactRow = ( [] ); - const handlePressStart = useCallback( - () => onTouch(address), - [address, onTouch] - ); + const handlePressStart = useCallback(() => onTouch(address), [ + address, + onTouch, + ]); const renderRightActions = useCallback( progress => ( diff --git a/src/components/copy-tooltip/CopyTooltip.ios.js b/src/components/copy-tooltip/CopyTooltip.ios.js index 8e0bf6893ec..9c83ca84b73 100644 --- a/src/components/copy-tooltip/CopyTooltip.ios.js +++ b/src/components/copy-tooltip/CopyTooltip.ios.js @@ -3,10 +3,9 @@ import React, { useCallback, useEffect, useRef } from 'react'; import ToolTip from 'react-native-tooltip'; function CopyTooltip({ textToCopy, activeOpacity, tooltipText, ...props }) { - const handleCopy = useCallback( - () => Clipboard.setString(textToCopy), - [textToCopy] - ); + const handleCopy = useCallback(() => Clipboard.setString(textToCopy), [ + textToCopy, + ]); const { colors } = useTheme(); const ref = useRef(); useEffect(() => ref.current.hideMenu, []); diff --git a/src/components/ens-profile/ProfileCover/ProfileCover.tsx b/src/components/ens-profile/ProfileCover/ProfileCover.tsx index 0d3e4199293..51e79f284f5 100644 --- a/src/components/ens-profile/ProfileCover/ProfileCover.tsx +++ b/src/components/ens-profile/ProfileCover/ProfileCover.tsx @@ -58,12 +58,12 @@ export default function ProfileCover({ ...(showSkeleton ? {} : coverUrl - ? { - background: 'body (Deprecated)', - } - : { - style: { backgroundColor: accentColor }, - }), + ? { + background: 'body (Deprecated)', + } + : { + style: { backgroundColor: accentColor }, + }), })} > { - onRemoveField({ key: ENS_RECORDS.avatar }); - onChangeAvatarUrl(''); - setAvatarMetadata(undefined); - setDisabled(false); - setTimeout(() => { - setAvatarUrl(''); - }, 100); - }, - onUploadError: () => { - onBlurField({ key: 'avatar', value: '' }); + const { + ContextMenu, + handleSelectImage, + handleSelectNFT, + } = useSelectImageMenu({ + imagePickerOptions: { + cropperCircleOverlay: true, + cropping: true, + height: 400, + width: 400, + }, + menuItems: enableNFTs ? ['library', 'nft'] : ['library'], + onChangeImage, + onRemoveImage: () => { + onRemoveField({ key: ENS_RECORDS.avatar }); + onChangeAvatarUrl(''); + setAvatarMetadata(undefined); + setDisabled(false); + setTimeout(() => { setAvatarUrl(''); - }, - onUploading: () => setDisabled(true), - onUploadSuccess: ({ data }: { data: UploadImageReturnData }) => { - onBlurField({ key: 'avatar', value: data.url }); - setDisabled(false); - }, - showRemove: Boolean(avatarUrl), - testID: 'avatar', - uploadToIPFS: true, - }); + }, 100); + }, + onUploadError: () => { + onBlurField({ key: 'avatar', value: '' }); + setAvatarUrl(''); + }, + onUploading: () => setDisabled(true), + onUploadSuccess: ({ data }: { data: UploadImageReturnData }) => { + onBlurField({ key: 'avatar', value: data.url }); + setDisabled(false); + }, + showRemove: Boolean(avatarUrl), + testID: 'avatar', + uploadToIPFS: true, + }); return ( @@ -177,10 +185,10 @@ const RegistrationAvatar = ({ !hasSeenExplainSheet ? onShowExplainSheet : isTesting - ? handleSelectNFT - : enableNFTs - ? undefined - : handleSelectImage + ? handleSelectNFT + : enableNFTs + ? undefined + : handleSelectImage } testID="use-select-image-avatar" > diff --git a/src/components/ens-registration/RegistrationCover/RegistrationCover.tsx b/src/components/ens-registration/RegistrationCover/RegistrationCover.tsx index ba87fe76e22..f93c0f3fcb6 100644 --- a/src/components/ens-registration/RegistrationCover/RegistrationCover.tsx +++ b/src/components/ens-registration/RegistrationCover/RegistrationCover.tsx @@ -37,8 +37,13 @@ const RegistrationCover = ({ const { images: { coverUrl: initialCoverUrl }, } = useENSModifiedRegistration(); - const { isLoading, onBlurField, onRemoveField, setDisabled, values } = - useENSRegistrationForm(); + const { + isLoading, + onBlurField, + onRemoveField, + setDisabled, + values, + } = useENSRegistrationForm(); const { name } = useENSRegistration(); const [coverUpdateAllowed, setCoverUpdateAllowed] = useState(true); const [coverUrl, setCoverUrl] = useState(initialCoverUrl || values?.header); @@ -156,8 +161,8 @@ const RegistrationCover = ({ !hasSeenExplainSheet ? onShowExplainSheet : enableNFTs - ? undefined - : handleSelectImage + ? undefined + : handleSelectImage } scaleTo={1} > diff --git a/src/components/exchange/ConfirmExchangeButton.js b/src/components/exchange/ConfirmExchangeButton.js index edf79735be8..17ed7c4a579 100644 --- a/src/components/exchange/ConfirmExchangeButton.js +++ b/src/components/exchange/ConfirmExchangeButton.js @@ -80,13 +80,13 @@ export default function ConfirmExchangeButton({ const color = quoteError ? disabledButtonColor : asset.address === ETH_ADDRESS - ? colors.appleBlue - : isSwapDetailsRoute - ? colorForAsset - : makeColorMoreChill( - colorForAsset, - (isSwapDetailsRoute ? colors : darkModeThemeColors).light - ); + ? colors.appleBlue + : isSwapDetailsRoute + ? colorForAsset + : makeColorMoreChill( + colorForAsset, + (isSwapDetailsRoute ? colors : darkModeThemeColors).light + ); return { buttonColor: color, @@ -193,10 +193,10 @@ export default function ConfirmExchangeButton({ loading || isSwapSubmitting ? NOOP : explainerType - ? handleExplainer - : shouldOpenSwapDetails - ? onPressViewDetails - : onSwap + ? handleExplainer + : shouldOpenSwapDetails + ? onPressViewDetails + : onSwap } shadows={ isSwapDetailsRoute diff --git a/src/components/exchange/ExchangeAssetList.tsx b/src/components/exchange/ExchangeAssetList.tsx index ea4e51fb598..8cf58bf89d5 100644 --- a/src/components/exchange/ExchangeAssetList.tsx +++ b/src/components/exchange/ExchangeAssetList.tsx @@ -144,8 +144,11 @@ const ExchangeAssetList: ForwardRefRenderFunction< useImperativeHandle(ref, () => sectionListRef.current as SectionList); const prevQuery = usePrevious(query); const { getParent: dangerouslyGetParent, navigate } = useNavigation(); - const { copiedText, copyCount, onCopySwapDetailsText } = - useSwapDetailsClipboardState(); + const { + copiedText, + copyCount, + onCopySwapDetailsText, + } = useSwapDetailsClipboardState(); // Scroll to top once the query is cleared if (prevQuery && prevQuery.length && !query.length) { diff --git a/src/components/exchange/ExchangeNativeField.tsx b/src/components/exchange/ExchangeNativeField.tsx index 139931f3bf1..19f06bb978f 100644 --- a/src/components/exchange/ExchangeNativeField.tsx +++ b/src/components/exchange/ExchangeNativeField.tsx @@ -59,8 +59,9 @@ const ExchangeNativeField: ForwardRefRenderFunction< const [value, setValue] = useState(nativeAmount); - const { mask, placeholder, symbol } = - supportedNativeCurrencies[nativeCurrency as NativeCurrencyKey]; + const { mask, placeholder, symbol } = supportedNativeCurrencies[ + nativeCurrency as NativeCurrencyKey + ]; const handleFocusNativeField = useCallback( () => nativeFieldRef?.current?.focus(), diff --git a/src/components/exchange/ExchangeTokenRow.tsx b/src/components/exchange/ExchangeTokenRow.tsx index 4b29e31edaa..5857561c64a 100644 --- a/src/components/exchange/ExchangeTokenRow.tsx +++ b/src/components/exchange/ExchangeTokenRow.tsx @@ -174,4 +174,5 @@ export default React.memo(function ExchangeTokenRow({ ); -}, isEqual); +}, +isEqual); diff --git a/src/components/expanded-state/SwapDetailsState.js b/src/components/expanded-state/SwapDetailsState.js index 2b451d3f3a6..6ca404aa4bc 100644 --- a/src/components/expanded-state/SwapDetailsState.js +++ b/src/components/expanded-state/SwapDetailsState.js @@ -104,16 +104,22 @@ export default function SwapDetailsState({ tradeDetails, } = useSelector(state => state.swap); - const { priceImpact, inputNativeAmount, outputNativeAmount } = - usePriceImpactDetails( - inputCurrency, - outputCurrency, - tradeDetails, - currentNetwork - ); + const { + priceImpact, + inputNativeAmount, + outputNativeAmount, + } = usePriceImpactDetails( + inputCurrency, + outputCurrency, + tradeDetails, + currentNetwork + ); - const { copiedText, copyCount, onCopySwapDetailsText } = - useSwapDetailsClipboardState(); + const { + copiedText, + copyCount, + onCopySwapDetailsText, + } = useSwapDetailsClipboardState(); const [footerHeight, setFooterHeight] = useHeight(FOOTER_MIN_HEIGHT); const [slippageMessageHeight, setSlippageMessageHeight] = useHeight(); @@ -121,8 +127,12 @@ export default function SwapDetailsState({ FOOTER_CONTENT_MIN_HEIGHT ); - const { onHeightChange, wrapperStyle, onPressMore, onWrapperLayout } = - useSwapDetailsButtonPosition({ contentHeight }); + const { + onHeightChange, + wrapperStyle, + onPressMore, + onWrapperLayout, + } = useSwapDetailsButtonPosition({ contentHeight }); const onContentHeightChange = useCallback( event => { diff --git a/src/components/expanded-state/UniqueTokenExpandedState.tsx b/src/components/expanded-state/UniqueTokenExpandedState.tsx index 67111383f57..ecb80b27d3a 100644 --- a/src/components/expanded-state/UniqueTokenExpandedState.tsx +++ b/src/components/expanded-state/UniqueTokenExpandedState.tsx @@ -253,8 +253,10 @@ const UniqueTokenExpandedState = ({ const { colors, isDarkMode } = useTheme(); const { isReadOnlyWallet } = useWallets(); - const [isRefreshMetadataToastActive, setIsRefreshMetadataToastActive] = - useState(false); + const [ + isRefreshMetadataToastActive, + setIsRefreshMetadataToastActive, + ] = useState(false); const activateRefreshMetadataToast = useCallback(() => { if (!isRefreshMetadataToastActive) { @@ -323,12 +325,18 @@ const UniqueTokenExpandedState = ({ return available; }, [ensData?.records]); - const { addShowcaseToken, removeShowcaseToken, showcaseTokens } = - useShowcaseTokens(); + const { + addShowcaseToken, + removeShowcaseToken, + showcaseTokens, + } = useShowcaseTokens(); const { hiddenTokens, removeHiddenToken } = useHiddenTokens(); - const [contentFocused, handleContentFocus, handleContentBlur] = - useBooleanState(); + const [ + contentFocused, + handleContentFocus, + handleContentBlur, + ] = useBooleanState(); const animationProgress = useSharedValue(0); const ensCoverAnimationProgress = useSharedValue(0); // TODO(jxom): This is temporary until `ZoomableWrapper` refactor diff --git a/src/components/expanded-state/asset/ChartExpandedState.js b/src/components/expanded-state/asset/ChartExpandedState.js index 345e6cd9fc6..3199f4aaa57 100644 --- a/src/components/expanded-state/asset/ChartExpandedState.js +++ b/src/components/expanded-state/asset/ChartExpandedState.js @@ -199,14 +199,14 @@ export default function ChartExpandedState({ asset }) { return hasBalance ? { ...asset } : genericAsset - ? asset?.networks - ? { - ...ethereumUtils.formatGenericAsset(genericAsset, nativeCurrency), - network: asset.network, - colors: asset?.colors, - } - : ethereumUtils.formatGenericAsset(genericAsset, nativeCurrency) - : { ...asset }; + ? asset?.networks + ? { + ...ethereumUtils.formatGenericAsset(genericAsset, nativeCurrency), + network: asset.network, + colors: asset?.colors, + } + : ethereumUtils.formatGenericAsset(genericAsset, nativeCurrency) + : { ...asset }; }, [asset, genericAsset, hasBalance, nativeCurrency]); if (assetWithPrice?.mainnet_address) { @@ -214,10 +214,9 @@ export default function ChartExpandedState({ asset }) { assetWithPrice.address = assetWithPrice.mainnet_address; } - const isL2 = useMemo( - () => isL2Network(assetWithPrice.network), - [assetWithPrice.network] - ); + const isL2 = useMemo(() => isL2Network(assetWithPrice.network), [ + assetWithPrice.network, + ]); const isTestnet = isTestnetNetwork(currentNetwork); const { diff --git a/src/components/expanded-state/chart/ChartContextButton.js b/src/components/expanded-state/chart/ChartContextButton.js index 33f10003303..5a3c420aa9c 100644 --- a/src/components/expanded-state/chart/ChartContextButton.js +++ b/src/components/expanded-state/chart/ChartContextButton.js @@ -14,8 +14,11 @@ const emojiSpacing = ios ? '' : ' '; export default function ChartContextButton({ asset, color }) { const { clearSelectedCoins, pushSelectedCoin } = useCoinListEditOptions(); - const { currentAction, setHiddenCoins, setPinnedCoins } = - useCoinListFinishEditingOptions(); + const { + currentAction, + setHiddenCoins, + setPinnedCoins, + } = useCoinListFinishEditingOptions(); useEffect(() => { // Ensure this expanded state's asset is always actively inside diff --git a/src/components/expanded-state/chart/chart-data-labels/ChartChangeDirectionArrow.js b/src/components/expanded-state/chart/chart-data-labels/ChartChangeDirectionArrow.js index c605d9fea25..ea40c175772 100644 --- a/src/components/expanded-state/chart/chart-data-labels/ChartChangeDirectionArrow.js +++ b/src/components/expanded-state/chart/chart-data-labels/ChartChangeDirectionArrow.js @@ -31,8 +31,8 @@ export default function ChartChangeDirectionArrow({ ratio, sharedRatio }) { realRatio === 1 ? colors.blueGreyDark : realRatio < 1 - ? colors.red - : colors.green, + ? colors.red + : colors.green, }; }, [ratio]); diff --git a/src/components/expanded-state/chart/chart-data-labels/ChartDateLabel.js b/src/components/expanded-state/chart/chart-data-labels/ChartDateLabel.js index 5eb2d2a7ee9..e3d9d7fba94 100644 --- a/src/components/expanded-state/chart/chart-data-labels/ChartDateLabel.js +++ b/src/components/expanded-state/chart/chart-data-labels/ChartDateLabel.js @@ -94,8 +94,8 @@ export default function ChartDateLabel({ chartTimeDefaultValue, ratio }) { realRatio === 1 ? colors.blueGreyDark : realRatio < 1 - ? colors.red - : colors.green, + ? colors.red + : colors.green, }; }, [ratio]); diff --git a/src/components/expanded-state/chart/chart-data-labels/ChartPercentChangeLabel.js b/src/components/expanded-state/chart/chart-data-labels/ChartPercentChangeLabel.js index ac1d1d5314b..bf653eb45af 100644 --- a/src/components/expanded-state/chart/chart-data-labels/ChartPercentChangeLabel.js +++ b/src/components/expanded-state/chart/chart-data-labels/ChartPercentChangeLabel.js @@ -63,10 +63,11 @@ export default function ChartPercentChangeLabel({ ratio, latestChange }) { const { colors } = useTheme(); // we don't need to format on latestChange changes - const defaultValue = useMemo( - () => format(originalY, data, latestChange), - [originalY, data, latestChange] - ); + const defaultValue = useMemo(() => format(originalY, data, latestChange), [ + originalY, + data, + latestChange, + ]); const textProps = useAnimatedStyle( () => ({ @@ -86,8 +87,8 @@ export default function ChartPercentChangeLabel({ ratio, latestChange }) { realRatio === 1 ? colors.blueGreyDark : realRatio < 1 - ? colors.red - : colors.green, + ? colors.red + : colors.green, }; }, [ratio]); diff --git a/src/components/expanded-state/custom-gas/FeesPanel.tsx b/src/components/expanded-state/custom-gas/FeesPanel.tsx index 9d8dff51918..5847a109c20 100644 --- a/src/components/expanded-state/custom-gas/FeesPanel.tsx +++ b/src/components/expanded-state/custom-gas/FeesPanel.tsx @@ -120,10 +120,12 @@ export default function FeesPanel({ const isL2 = getNetworkObj(txNetwork)?.networkType === 'layer2'; - const [maxPriorityFeeWarning, setMaxPriorityFeeWarning] = - useState(null); - const [maxPriorityFeeError, setMaxPriorityFeeError] = - useState(null); + const [maxPriorityFeeWarning, setMaxPriorityFeeWarning] = useState( + null + ); + const [maxPriorityFeeError, setMaxPriorityFeeError] = useState( + null + ); const [maxBaseFeeWarning, setMaxBaseFeeWarning] = useState(null); const [maxBaseFeeError, setMaxBaseFeeError] = useState(null); diff --git a/src/components/expanded-state/ens/InfoRow.tsx b/src/components/expanded-state/ens/InfoRow.tsx index 13e94e258bc..8896912f262 100644 --- a/src/components/expanded-state/ens/InfoRow.tsx +++ b/src/components/expanded-state/ens/InfoRow.tsx @@ -148,15 +148,15 @@ export default function InfoRow({ isSwitch ? undefined : isMultiline - ? ('15px (Deprecated)' as const) - : ('10px' as const) + ? ('15px (Deprecated)' as const) + : ('10px' as const) } style={{ backgroundColor: isSwitch ? 'transparent' : useAccentColor - ? accentColor + '10' - : 'rgba(255, 255, 255, 0.08)', + ? accentColor + '10' + : 'rgba(255, 255, 255, 0.08)', maxWidth: android ? 250 : undefined, opacity: show ? 1 : 0, }} diff --git a/src/components/expanded-state/ens/ProfileInfoSection.tsx b/src/components/expanded-state/ens/ProfileInfoSection.tsx index 8bb15f5bd5a..77e10e261be 100644 --- a/src/components/expanded-state/ens/ProfileInfoSection.tsx +++ b/src/components/expanded-state/ens/ProfileInfoSection.tsx @@ -57,10 +57,9 @@ export default function ProfileInfoSection({ .filter(Boolean) as [ENS_RECORDS, string][]; return [orderedTopRecords, otherRecords as [ENS_RECORDS, string][]]; }, [recordsArray]); - const coinAddresses = useMemo( - () => Object.entries(coinAddressMap || {}), - [coinAddressMap] - ); + const coinAddresses = useMemo(() => Object.entries(coinAddressMap || {}), [ + coinAddressMap, + ]); return ( @@ -131,15 +130,21 @@ function ProfileInfoRow({ recordValue: string; type: 'address' | 'record'; }) { - const { ContextMenuButton, icon, isImageValue, label, url, value } = - useENSRecordDisplayProperties({ - allowEdit, - ensName, - images, - key: recordKey, - type, - value: recordValue, - }); + const { + ContextMenuButton, + icon, + isImageValue, + label, + url, + value, + } = useENSRecordDisplayProperties({ + allowEdit, + ensName, + images, + key: recordKey, + type, + value: recordValue, + }); return ( (null); - const handleTriggerFocusInput = useCallback( - () => inputRef.current?.focus(), - [inputRef] - ); + const handleTriggerFocusInput = useCallback(() => inputRef.current?.focus(), [ + inputRef, + ]); return ( diff --git a/src/components/expanded-state/swap-details/SwapDetailsContent.js b/src/components/expanded-state/swap-details/SwapDetailsContent.js index 8eb8d0f8a71..503e85452b6 100644 --- a/src/components/expanded-state/swap-details/SwapDetailsContent.js +++ b/src/components/expanded-state/swap-details/SwapDetailsContent.js @@ -42,8 +42,9 @@ export default function SwapDetailsContent({ ...props }) { const { inputCurrency, outputCurrency } = useSwapCurrencies(); - const { amountReceivedSold, receivedSoldLabel } = - useSwapAdjustedAmounts(tradeDetails); + const { amountReceivedSold, receivedSoldLabel } = useSwapAdjustedAmounts( + tradeDetails + ); const { navigate } = useNavigation(); const { flashbotsEnabled } = useAccountSettings(); const inputAsExact = useSelector( diff --git a/src/components/expanded-state/swap-details/SwapDetailsContractRow.js b/src/components/expanded-state/swap-details/SwapDetailsContractRow.js index 82176ef34c6..1aaaf224b0d 100644 --- a/src/components/expanded-state/swap-details/SwapDetailsContractRow.js +++ b/src/components/expanded-state/swap-details/SwapDetailsContractRow.js @@ -31,8 +31,9 @@ export const SwapDetailsValue = styled(SwapDetailsText).attrs( }) )(fontWithWidth(fonts.weight.bold)); -const AnimatedTruncatedAddress = - Animated.createAnimatedComponent(TruncatedAddress); +const AnimatedTruncatedAddress = Animated.createAnimatedComponent( + TruncatedAddress +); const AnimatedText = Animated.createAnimatedComponent(Text); const ContractActionsEnum = { @@ -74,10 +75,9 @@ function SwapDetailsContractRowContent({ const { colors } = useTheme(); const colorForAsset = useColorForAsset(asset); const animation = useSharedValue(menuVisible ? 1 : 0); - const startingColor = useMemo( - () => colors.alpha(colors.blueGreyDark, 0.8), - [colors] - ); + const startingColor = useMemo(() => colors.alpha(colors.blueGreyDark, 0.8), [ + colors, + ]); useLayoutEffect(() => { animation.value = withTiming(menuVisible ? 1 : 0, { duration: 150 }); diff --git a/src/components/expanded-state/swap-settings/MaxToleranceInput.tsx b/src/components/expanded-state/swap-settings/MaxToleranceInput.tsx index 6d5af12b506..4f83fbfc2a7 100644 --- a/src/components/expanded-state/swap-settings/MaxToleranceInput.tsx +++ b/src/components/expanded-state/swap-settings/MaxToleranceInput.tsx @@ -64,9 +64,9 @@ export const MaxToleranceInput = forwardRef( slippageRef?.current?.blur(); }, reset: () => { - const slippage = getDefaultSlippageFromConfig( + const slippage = (getDefaultSlippageFromConfig( currentNetwork - ) as unknown as number; + ) as unknown) as number; onSlippageChange(convertBipsToPercent(slippage)); }, })); diff --git a/src/components/expanded-state/swap-settings/SwapSettingsState.js b/src/components/expanded-state/swap-settings/SwapSettingsState.js index 74ceac98d28..a7766e9d4f1 100644 --- a/src/components/expanded-state/swap-settings/SwapSettingsState.js +++ b/src/components/expanded-state/swap-settings/SwapSettingsState.js @@ -44,8 +44,10 @@ function useAndroidDisableGesturesOnFocus() { } export default function SwapSettingsState({ asset }) { - const { flashbotsEnabled, settingsChangeFlashbotsEnabled } = - useAccountSettings(); + const { + flashbotsEnabled, + settingsChangeFlashbotsEnabled, + } = useAccountSettings(); const { params: { swapSupportsFlashbots = false, network }, } = useRoute(); diff --git a/src/components/expanded-state/unique-token/UniqueTokenExpandedStateHeader.tsx b/src/components/expanded-state/unique-token/UniqueTokenExpandedStateHeader.tsx index 028766e1335..057f1846d0a 100644 --- a/src/components/expanded-state/unique-token/UniqueTokenExpandedStateHeader.tsx +++ b/src/components/expanded-state/unique-token/UniqueTokenExpandedStateHeader.tsx @@ -121,7 +121,7 @@ const getAssetActions = (network: Network) => iconValue: 'looksrare', }, }, - }) as const; + } as const); const FamilyActionsEnum = { collectionWebsite: 'collectionWebsite', diff --git a/src/components/expanded-state/unique-token/ZoomableWrapper.android.js b/src/components/expanded-state/unique-token/ZoomableWrapper.android.js index e5277c52484..cadb6787a45 100644 --- a/src/components/expanded-state/unique-token/ZoomableWrapper.android.js +++ b/src/components/expanded-state/unique-token/ZoomableWrapper.android.js @@ -98,28 +98,30 @@ export const ZoomableWrapper = ({ const maxImageWidth = width || deviceWidth - horizontalPadding * 2; const maxImageHeight = height || deviceHeight / 2; - const [containerWidth = maxImageWidth, containerHeight = maxImageWidth] = - useMemo(() => { - const isSquare = aspectRatio === 1; - const isLandscape = aspectRatio > 1; - const isPortrait = aspectRatio < 1; - - if (isSquare) { - return [maxImageWidth, maxImageWidth]; - } + const [ + containerWidth = maxImageWidth, + containerHeight = maxImageWidth, + ] = useMemo(() => { + const isSquare = aspectRatio === 1; + const isLandscape = aspectRatio > 1; + const isPortrait = aspectRatio < 1; + + if (isSquare) { + return [maxImageWidth, maxImageWidth]; + } - if (isLandscape) { - return [maxImageWidth, maxImageWidth / aspectRatio]; - } + if (isLandscape) { + return [maxImageWidth, maxImageWidth / aspectRatio]; + } - if (isPortrait) { - if (maxImageWidth / aspectRatio > maxImageHeight) { - return [aspectRatio * maxImageHeight, maxImageHeight]; - } else { - return [maxImageWidth, maxImageWidth / aspectRatio]; - } + if (isPortrait) { + if (maxImageWidth / aspectRatio > maxImageHeight) { + return [aspectRatio * maxImageHeight, maxImageHeight]; + } else { + return [maxImageWidth, maxImageWidth / aspectRatio]; } - }, [aspectRatio, maxImageHeight, maxImageWidth]); + } + }, [aspectRatio, maxImageHeight, maxImageWidth]); const containerWidthValue = useReactiveSharedValue( containerWidth || maxImageWidth diff --git a/src/components/expanded-state/unique-token/ZoomableWrapper.js b/src/components/expanded-state/unique-token/ZoomableWrapper.js index 9cac904efce..ab125896300 100644 --- a/src/components/expanded-state/unique-token/ZoomableWrapper.js +++ b/src/components/expanded-state/unique-token/ZoomableWrapper.js @@ -116,28 +116,30 @@ export const ZoomableWrapper = ({ const maxImageWidth = width || deviceWidth - horizontalPadding * 2; const maxImageHeight = height || deviceHeightWithMaybeHiddenStatusBar / 2; - const [containerWidth = maxImageWidth, containerHeight = maxImageWidth] = - useMemo(() => { - const isSquare = aspectRatio === 1; - const isLandscape = aspectRatio > 1; - const isPortrait = aspectRatio < 1; - - if (isSquare) { - return [maxImageWidth, maxImageWidth]; - } + const [ + containerWidth = maxImageWidth, + containerHeight = maxImageWidth, + ] = useMemo(() => { + const isSquare = aspectRatio === 1; + const isLandscape = aspectRatio > 1; + const isPortrait = aspectRatio < 1; + + if (isSquare) { + return [maxImageWidth, maxImageWidth]; + } - if (isLandscape) { - return [maxImageWidth, maxImageWidth / aspectRatio]; - } + if (isLandscape) { + return [maxImageWidth, maxImageWidth / aspectRatio]; + } - if (isPortrait) { - if (maxImageWidth / aspectRatio > maxImageHeight) { - return [aspectRatio * maxImageHeight, maxImageHeight]; - } else { - return [maxImageWidth, maxImageWidth / aspectRatio]; - } + if (isPortrait) { + if (maxImageWidth / aspectRatio > maxImageHeight) { + return [aspectRatio * maxImageHeight, maxImageHeight]; + } else { + return [maxImageWidth, maxImageWidth / aspectRatio]; } - }, [aspectRatio, maxImageHeight, maxImageWidth]); + } + }, [aspectRatio, maxImageHeight, maxImageWidth]); const containerWidthValue = useReactiveSharedValue( containerWidth || maxImageWidth diff --git a/src/components/fields/BubbleField.js b/src/components/fields/BubbleField.js index f6d7de79b74..1a2026ce854 100644 --- a/src/components/fields/BubbleField.js +++ b/src/components/fields/BubbleField.js @@ -49,10 +49,10 @@ const BubbleField = ( const [value, setValue] = useState(valueProp); const [wasButtonPressed, setWasButtonPressed] = useState(false); - const formattedValue = useMemo( - () => format(String(value || '')), - [format, value] - ); + const formattedValue = useMemo(() => format(String(value || '')), [ + format, + value, + ]); const handleBlur = useCallback( event => { diff --git a/src/components/fields/SmallBubbleField.js b/src/components/fields/SmallBubbleField.js index 4299539d786..5e5f31f000d 100644 --- a/src/components/fields/SmallBubbleField.js +++ b/src/components/fields/SmallBubbleField.js @@ -21,8 +21,8 @@ const BubbleInput = styled(ExchangeInput).attrs( ? isTinyPhone ? 27 : android || isSmallPhone - ? 31 - : 38 + ? 31 + : 38 : undefined, size: isTinyPhone ? 'big' : isSmallPhone ? 'bigger' : 'h3', weight: 'semibold', @@ -65,10 +65,10 @@ const BubbleField = ( const ref = useRef(); useImperativeHandle(forwardedRef, () => ref.current); - const formattedValue = useMemo( - () => format(String(value || '')), - [format, value] - ); + const formattedValue = useMemo(() => format(String(value || '')), [ + format, + value, + ]); const handleBlur = useCallback( event => { diff --git a/src/components/floating-emojis/FloatingEmojis.js b/src/components/floating-emojis/FloatingEmojis.js index c430fb278fc..9fca2c356f9 100644 --- a/src/components/floating-emojis/FloatingEmojis.js +++ b/src/components/floating-emojis/FloatingEmojis.js @@ -56,8 +56,8 @@ const FloatingEmojis = ({ (existingEmojis.length + 1) % 7 === 0 && !disableRainbow ? 'rainbow' : emojisArray.length === 1 - ? emojisArray[0] - : emojisArray[getEmoji(emojisArray)], + ? emojisArray[0] + : emojisArray[getEmoji(emojisArray)], x: x ? x - getRandomNumber(-20, 20) : getRandomNumber(...range) + '%', y: y || 0, }; diff --git a/src/components/gas/GasSpeedButton.js b/src/components/gas/GasSpeedButton.js index 3c2df0ab2eb..11425af3523 100644 --- a/src/components/gas/GasSpeedButton.js +++ b/src/components/gas/GasSpeedButton.js @@ -365,8 +365,9 @@ const GasSpeedButton = ({ type: 'crossChainGas', }); } else { - const nativeAsset = - await ethereumUtils.getNativeAssetForNetwork(networkName); + const nativeAsset = await ethereumUtils.getNativeAssetForNetwork( + networkName + ); navigate(Routes.EXPLAIN_SHEET, { network: networkName, type: 'gas', @@ -444,13 +445,13 @@ const GasSpeedButton = ({ const gweiDisplay = !shouldRoundGwei ? gasFeeParamsBySpeed[gasOption]?.gasPrice?.display : gasOption === 'custom' && selectedGasFeeOption !== 'custom' - ? '' - : greaterThan(estimatedGwei, totalGwei) - ? `${toFixedDecimals(totalGwei, isL2 ? 4 : 0)} Gwei` - : `${toFixedDecimals(estimatedGwei, isL2 ? 4 : 0)}–${toFixedDecimals( - totalGwei, - isL2 ? 4 : 0 - )} Gwei`; + ? '' + : greaterThan(estimatedGwei, totalGwei) + ? `${toFixedDecimals(totalGwei, isL2 ? 4 : 0)} Gwei` + : `${toFixedDecimals(estimatedGwei, isL2 ? 4 : 0)}–${toFixedDecimals( + totalGwei, + isL2 ? 4 : 0 + )} Gwei`; return { actionKey: gasOption, actionTitle: @@ -476,10 +477,9 @@ const GasSpeedButton = ({ isL2, ]); - const gasOptionsAvailable = useMemo( - () => speedOptions.length > 1, - [speedOptions.length] - ); + const gasOptionsAvailable = useMemo(() => speedOptions.length > 1, [ + speedOptions.length, + ]); const onDonePress = useCallback(() => { if (canGoBack) { diff --git a/src/components/images/ImagePreviewOverlay.tsx b/src/components/images/ImagePreviewOverlay.tsx index bdcd7917cda..096fd331772 100644 --- a/src/components/images/ImagePreviewOverlay.tsx +++ b/src/components/images/ImagePreviewOverlay.tsx @@ -591,8 +591,8 @@ export function ImagePreviewOverlayTarget({ givenHeight ? givenHeight : height - ? { custom: height } - : { custom: 0 } + ? { custom: height } + : { custom: 0 } } onLayout={handleLayout} ref={zoomableWrapperRef} diff --git a/src/components/inputs/InlineField.tsx b/src/components/inputs/InlineField.tsx index 171618e26ba..9f83a0c08ec 100644 --- a/src/components/inputs/InlineField.tsx +++ b/src/components/inputs/InlineField.tsx @@ -100,18 +100,18 @@ export default function InlineField({ ? 11 : 15 : android - ? valueRef.current - ? 16 - : 11 - : 0, + ? valueRef.current + ? 16 + : 11 + : 0, textAlignVertical: 'top', width: startsWith ? ios ? 0.55 * width : 0.56 * width : ios - ? 0.6 * width - : 0.61 * width, + ? 0.6 * width + : 0.61 * width, }), [textStyle, inputHeight, inputProps?.multiline, startsWith, width] ); diff --git a/src/components/layout/LayoutWithDividers.js b/src/components/layout/LayoutWithDividers.js index 68304226d86..fd82f238c36 100644 --- a/src/components/layout/LayoutWithDividers.js +++ b/src/components/layout/LayoutWithDividers.js @@ -6,10 +6,9 @@ const LayoutWithDividers = ( { children, dividerHorizontal, dividerRenderer = Divider, ...props }, ref ) => { - const dividerProps = useMemo( - () => ({ horizontal: dividerHorizontal }), - [dividerHorizontal] - ); + const dividerProps = useMemo(() => ({ horizontal: dividerHorizontal }), [ + dividerHorizontal, + ]); return ( diff --git a/src/components/qrcode-scanner/CameraDimmer.js b/src/components/qrcode-scanner/CameraDimmer.js index 19a638d79d3..affef4c4b2d 100644 --- a/src/components/qrcode-scanner/CameraDimmer.js +++ b/src/components/qrcode-scanner/CameraDimmer.js @@ -10,8 +10,9 @@ const Dim = styled(Animated.View)({ }); export default function CameraDimmer({ children, cameraVisible }) { - const delayedCameraVisible = - useDelayedValueWithLayoutAnimation(cameraVisible); + const delayedCameraVisible = useDelayedValueWithLayoutAnimation( + cameraVisible + ); return ( diff --git a/src/components/remote-promo-sheet/RemotePromoSheet.tsx b/src/components/remote-promo-sheet/RemotePromoSheet.tsx index 239c348072d..bcb3b71efb7 100644 --- a/src/components/remote-promo-sheet/RemotePromoSheet.tsx +++ b/src/components/remote-promo-sheet/RemotePromoSheet.tsx @@ -58,8 +58,9 @@ const getKeyForLanguage = ( export function RemotePromoSheet() { const { colors } = useTheme(); const { goBack, navigate } = useNavigation(); - const { params } = - useRoute>(); + const { params } = useRoute< + RouteProp + >(); const { campaignId, campaignKey } = params; const { language } = useAccountSettings(); diff --git a/src/components/remote-promo-sheet/checkForCampaign.ts b/src/components/remote-promo-sheet/checkForCampaign.ts index ccd8aca8045..76eacbc1d20 100644 --- a/src/components/remote-promo-sheet/checkForCampaign.ts +++ b/src/components/remote-promo-sheet/checkForCampaign.ts @@ -146,10 +146,7 @@ export const shouldPromptCampaign = async ( export const __INTERNAL_ACTION_CHECKS: { [key: string]: ActionFn; -} = Object.keys(fns).reduce( - (acc, fnKey) => { - acc[fnKey] = fns[fnKey as keyof typeof fns]; - return acc; - }, - {} as { [key: string]: ActionFn } -); +} = Object.keys(fns).reduce((acc, fnKey) => { + acc[fnKey] = fns[fnKey as keyof typeof fns]; + return acc; +}, {} as { [key: string]: ActionFn }); diff --git a/src/components/remote-promo-sheet/notificationsPromoCampaign.ts b/src/components/remote-promo-sheet/notificationsPromoCampaign.ts index 8060dd1f27d..ad46a99c731 100644 --- a/src/components/remote-promo-sheet/notificationsPromoCampaign.ts +++ b/src/components/remote-promo-sheet/notificationsPromoCampaign.ts @@ -26,36 +26,35 @@ export const notificationsCampaignAction = async () => { }, 1000); }; -export const notificationsCampaignCheck = - async (): Promise => { - const hasShownCampaign = mmkv.getBoolean(CampaignKey.notificationsLaunch); - const isFirstLaunch = mmkv.getBoolean(STORAGE_IDS.FIRST_APP_LAUNCH); +export const notificationsCampaignCheck = async (): Promise => { + const hasShownCampaign = mmkv.getBoolean(CampaignKey.notificationsLaunch); + const isFirstLaunch = mmkv.getBoolean(STORAGE_IDS.FIRST_APP_LAUNCH); - logger.debug(`Notifications promo`, { hasShownCampaign }); + logger.debug(`Notifications promo`, { hasShownCampaign }); - const { - selected: currentWallet, - }: { - selected: RainbowWallet | undefined; - } = store.getState().wallets; + const { + selected: currentWallet, + }: { + selected: RainbowWallet | undefined; + } = store.getState().wallets; - /** - * stop if: - * there's no wallet - * the campaign has already been activated - * the user is launching Rainbow for the first time - */ - if (!currentWallet || hasShownCampaign || isFirstLaunch) { - logger.debug(`Notifications promo: not activating`); - return GenericCampaignCheckResponse.nonstarter; - } + /** + * stop if: + * there's no wallet + * the campaign has already been activated + * the user is launching Rainbow for the first time + */ + if (!currentWallet || hasShownCampaign || isFirstLaunch) { + logger.debug(`Notifications promo: not activating`); + return GenericCampaignCheckResponse.nonstarter; + } - logger.debug(`Notifications promo: activating`); + logger.debug(`Notifications promo: activating`); - NotificationsPromoCampaign.action(); + NotificationsPromoCampaign.action(); - return GenericCampaignCheckResponse.activated; - }; + return GenericCampaignCheckResponse.activated; +}; export const NotificationsPromoCampaign: Campaign = { action: async () => await notificationsCampaignAction(), diff --git a/src/components/secret-display/states.ts b/src/components/secret-display/states.ts index 6617e2d0fb8..8928f8c93b0 100644 --- a/src/components/secret-display/states.ts +++ b/src/components/secret-display/states.ts @@ -5,5 +5,4 @@ export const SecretDisplayStates = { securedWithBiometrics: 'securedWithBiometrics', } as const; -export type SecretDisplayStatesType = - (typeof SecretDisplayStates)[keyof typeof SecretDisplayStates]; +export type SecretDisplayStatesType = typeof SecretDisplayStates[keyof typeof SecretDisplayStates]; diff --git a/src/components/send/SendAssetFormField.js b/src/components/send/SendAssetFormField.js index 600c6779c70..ebbe344cd8f 100644 --- a/src/components/send/SendAssetFormField.js +++ b/src/components/send/SendAssetFormField.js @@ -124,8 +124,8 @@ const SendAssetFormField = ( ? isTinyPhone ? 27 : android || isSmallPhone - ? 31 - : 38 + ? 31 + : 38 : null } size={isTinyPhone ? 'big' : android || isSmallPhone ? 'bigger' : 'h3'} diff --git a/src/components/send/SendAssetFormToken.js b/src/components/send/SendAssetFormToken.js index 7bb9d966cab..eb9c0780665 100644 --- a/src/components/send/SendAssetFormToken.js +++ b/src/components/send/SendAssetFormToken.js @@ -52,8 +52,10 @@ export default function SendAssetFormToken({ const { isSmallPhone, isTinyPhone } = useDimensions(); const { colors } = useTheme(); - const { mask: nativeMask, placeholder: nativePlaceholder } = - supportedNativeCurrencies[nativeCurrency]; + const { + mask: nativeMask, + placeholder: nativePlaceholder, + } = supportedNativeCurrencies[nativeCurrency]; return ( diff --git a/src/components/send/SendButton.js b/src/components/send/SendButton.js index 99fb461e045..2d3e1ca7e33 100644 --- a/src/components/send/SendButton.js +++ b/src/components/send/SendButton.js @@ -41,8 +41,8 @@ export default function SendButton({ disabled && requiresChecks ? `􀄨 ${lang.t('wallet.transaction.complete_checks')}` : insufficientEth - ? lang.t('button.confirm_exchange.insufficient_funds') - : lang.t('button.hold_to_send') + ? lang.t('button.confirm_exchange.insufficient_funds') + : lang.t('button.hold_to_send') } onLongPress={onLongPress} parentHorizontalPadding={19} diff --git a/src/components/send/SendHeader.js b/src/components/send/SendHeader.js index 300ba7868a8..a9c45153cae 100644 --- a/src/components/send/SendHeader.js +++ b/src/components/send/SendHeader.js @@ -28,10 +28,10 @@ const AddressInputContainer = styled(Row).attrs({ align: 'center' })( ...(android ? padding.object(0, 19) : isTinyPhone - ? padding.object(23, 15, 10) - : isSmallPhone - ? padding.object(11, 19, 15) - : padding.object(18, 19, 19)), + ? padding.object(23, 15, 10) + : isSmallPhone + ? padding.object(11, 19, 15) + : padding.object(18, 19, 19)), backgroundColor: colors.white, overflow: 'hidden', width: '100%', diff --git a/src/components/sheet/SlackSheet.js b/src/components/sheet/SlackSheet.js index 5e772573e11..2329026d2b2 100644 --- a/src/components/sheet/SlackSheet.js +++ b/src/components/sheet/SlackSheet.js @@ -46,8 +46,8 @@ const Container = styled(Centered).attrs({ direction: 'column' })( typeof additionalTopPadding === 'number' ? additionalTopPadding : contentHeight && additionalTopPadding - ? deviceHeight - contentHeight - : 0, + ? deviceHeight - contentHeight + : 0, }), ...(IS_ANDROID ? { borderTopLeftRadius: 30, borderTopRightRadius: 30 } diff --git a/src/components/unique-token/Tag.js b/src/components/unique-token/Tag.js index bfee605339b..f46c042b3dd 100644 --- a/src/components/unique-token/Tag.js +++ b/src/components/unique-token/Tag.js @@ -115,8 +115,9 @@ const Tag = ({ typeof originalValue === 'string' && originalValue.toLowerCase().startsWith('https://'); - const viewTraitOnNftMarketplaceAction = - getViewTraitOnNftMarketplaceAction(marketplaceName); + const viewTraitOnNftMarketplaceAction = getViewTraitOnNftMarketplaceAction( + marketplaceName + ); const handlePressMenuItem = useCallback( ({ nativeEvent: { actionKey } }) => { diff --git a/src/components/unique-token/UniqueTokenCard.js b/src/components/unique-token/UniqueTokenCard.js index 8a13bffda2b..a4e1d58c2cd 100644 --- a/src/components/unique-token/UniqueTokenCard.js +++ b/src/components/unique-token/UniqueTokenCard.js @@ -50,10 +50,9 @@ const UniqueTokenCard = ({ const { colors } = useTheme(); - const defaultShadow = useMemo( - () => UniqueTokenCardShadowFactory(colors), - [colors] - ); + const defaultShadow = useMemo(() => UniqueTokenCardShadowFactory(colors), [ + colors, + ]); return ( ChartTimespans.indexOf(chartType), - [chartType] - ); + const timespanIndex = useMemo(() => ChartTimespans.indexOf(chartType), [ + chartType, + ]); const { progress } = useChartData(); const spinnerRotation = useSharedValue(0); diff --git a/src/components/walletconnect-list/WalletConnectV2ListItem.tsx b/src/components/walletconnect-list/WalletConnectV2ListItem.tsx index 419401b0b2d..fd0b5ac8071 100644 --- a/src/components/walletconnect-list/WalletConnectV2ListItem.tsx +++ b/src/components/walletconnect-list/WalletConnectV2ListItem.tsx @@ -77,50 +77,55 @@ export function WalletConnectV2ListItem({ }, }; - const { dappName, dappUrl, dappLogo, address, chainIds } = - React.useMemo(() => { - const { namespaces, requiredNamespaces, peer } = session; - const { metadata } = peer; - const { chains } = requiredNamespaces.eip155; - const eip155Account = namespaces.eip155?.accounts?.[0] || undefined; + const { + dappName, + dappUrl, + dappLogo, + address, + chainIds, + } = React.useMemo(() => { + const { namespaces, requiredNamespaces, peer } = session; + const { metadata } = peer; + const { chains } = requiredNamespaces.eip155; + const eip155Account = namespaces.eip155?.accounts?.[0] || undefined; - if (!eip155Account || !chains || !chains.length) { - const e = new RainbowError( - `WalletConnectV2ListItem: unsupported namespace` - ); - logger.error(e); + if (!eip155Account || !chains || !chains.length) { + const e = new RainbowError( + `WalletConnectV2ListItem: unsupported namespace` + ); + logger.error(e); - // defensive, just for types, should never happen - throw e; - } + // defensive, just for types, should never happen + throw e; + } - const [ns, rawChainId, address] = eip155Account?.split(':') as [ - string, - string, - string, - ]; - const chainIds = chains - .map(chain => parseInt(chain.split(':')[1])) - .filter(isSupportedChain); + const [ns, rawChainId, address] = eip155Account?.split(':') as [ + string, + string, + string + ]; + const chainIds = chains + .map(chain => parseInt(chain.split(':')[1])) + .filter(isSupportedChain); - if (!address) { - const e = new RainbowError( - `WalletConnectV2ListItem: could not parse address` - ); - logger.error(e); + if (!address) { + const e = new RainbowError( + `WalletConnectV2ListItem: could not parse address` + ); + logger.error(e); - // defensive, just for types, should never happen - throw e; - } + // defensive, just for types, should never happen + throw e; + } - return { - dappName: metadata.name || 'Unknown Dapp', - dappUrl: metadata.url || 'Unknown URL', - dappLogo: metadata && metadata.icons ? metadata.icons[0] : undefined, - address, - chainIds, - }; - }, [session]); + return { + dappName: metadata.name || 'Unknown Dapp', + dappUrl: metadata.url || 'Unknown URL', + dappLogo: metadata && metadata.icons ? metadata.icons[0] : undefined, + address, + chainIds, + }; + }, [session]); const availableNetworks = useMemo(() => { return chainIds diff --git a/src/design-system/color/AccentColorContext.tsx b/src/design-system/color/AccentColorContext.tsx index 237c45e6643..4fb7c01dacc 100644 --- a/src/design-system/color/AccentColorContext.tsx +++ b/src/design-system/color/AccentColorContext.tsx @@ -34,7 +34,7 @@ export function AccentColorProvider({ color, mode: chroma.contrast(color, '#fff') > 2.125 ? 'darkTinted' : 'lightTinted', - }) as const, + } as const), [color] ); diff --git a/src/design-system/color/palettes.docs.tsx b/src/design-system/color/palettes.docs.tsx index 05d3efe9569..6b33ea44ddf 100644 --- a/src/design-system/color/palettes.docs.tsx +++ b/src/design-system/color/palettes.docs.tsx @@ -22,15 +22,17 @@ const BackgroundColors = ({ mode }: { mode: ColorMode }) => ( - {( - Object.keys(backgroundColors) as (keyof typeof backgroundColors)[] - ).map((color: BackgroundColor) => ( - - - {color} - - - ))} + {(Object.keys( + backgroundColors + ) as (keyof typeof backgroundColors)[]).map( + (color: BackgroundColor) => ( + + + {color} + + + ) + )} diff --git a/src/design-system/color/palettes.ts b/src/design-system/color/palettes.ts index a29b9960a19..6edd3d3c44b 100644 --- a/src/design-system/color/palettes.ts +++ b/src/design-system/color/palettes.ts @@ -676,7 +676,7 @@ export const palettes: Record = { }; function selectForegroundColors< - SelectedColors extends readonly (ForegroundColor | 'accent')[], + SelectedColors extends readonly (ForegroundColor | 'accent')[] >(...colors: SelectedColors): SelectedColors { return colors; } @@ -707,7 +707,7 @@ export const textColors = selectForegroundColors( 'secondary70 (Deprecated)', 'secondary80 (Deprecated)' ); -export type TextColor = (typeof textColors)[number]; +export type TextColor = typeof textColors[number]; export const shadowColors = selectForegroundColors( 'accent', @@ -719,7 +719,7 @@ export const shadowColors = selectForegroundColors( 'orange', 'yellow' ); -export type ShadowColor = (typeof shadowColors)[number]; +export type ShadowColor = typeof shadowColors[number]; export const separatorColors = selectForegroundColors( 'separator', @@ -731,4 +731,4 @@ export const separatorColors = selectForegroundColors( 'divider80 (Deprecated)', 'divider100 (Deprecated)' ); -export type SeparatorColor = (typeof separatorColors)[number]; +export type SeparatorColor = typeof separatorColors[number]; diff --git a/src/design-system/components/Box/Box.tsx b/src/design-system/components/Box/Box.tsx index 4373cd9bdf9..02364d831c7 100644 --- a/src/design-system/components/Box/Box.tsx +++ b/src/design-system/components/Box/Box.tsx @@ -23,7 +23,7 @@ import { ApplyShadow } from '../private/ApplyShadow/ApplyShadow'; import type * as Polymorphic from './polymorphic'; const positions = ['absolute'] as const; -type Position = (typeof positions)[number]; +type Position = typeof positions[number]; export function resolveToken( scale: Record, diff --git a/src/design-system/components/Box/polymorphic.ts b/src/design-system/components/Box/polymorphic.ts index 15c9fba053f..c82958bc076 100644 --- a/src/design-system/components/Box/polymorphic.ts +++ b/src/design-system/components/Box/polymorphic.ts @@ -44,8 +44,9 @@ type OwnProps = E extends ForwardRefComponent ? P : {}; /** * Infers the JSX.IntrinsicElement if E is a ForwardRefExoticComponentWithAs */ -type IntrinsicElement = - E extends ForwardRefComponent ? I : never; +type IntrinsicElement = E extends ForwardRefComponent + ? I + : never; type ForwardRefExoticComponent = React.ForwardRefExoticComponent< Merge< @@ -60,7 +61,7 @@ type ForwardRefExoticComponent = React.ForwardRefExoticComponent< interface ForwardRefComponent< DefaultComponentType, - OwnProps = {}, + OwnProps = {} /** * Extends original type to ensure built in React types play nice * with polymorphic components still e.g. `React.ElementRef` etc. diff --git a/src/design-system/components/Heading/Heading.examples.tsx b/src/design-system/components/Heading/Heading.examples.tsx index f8dbcc5f41c..e1571db546f 100644 --- a/src/design-system/components/Heading/Heading.examples.tsx +++ b/src/design-system/components/Heading/Heading.examples.tsx @@ -13,9 +13,9 @@ import { Heading } from './Heading'; const loremIpsum = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.'; -export const sizes: Example[] = ( - Object.keys(typeHierarchy.heading) as HeadingSize[] -).map(size => ({ +export const sizes: Example[] = (Object.keys( + typeHierarchy.heading +) as HeadingSize[]).map(size => ({ name: size, Example: () => source( diff --git a/src/design-system/components/Heading/useHeadingStyle.ts b/src/design-system/components/Heading/useHeadingStyle.ts index cca61eb2e8a..8ff617f57f3 100644 --- a/src/design-system/components/Heading/useHeadingStyle.ts +++ b/src/design-system/components/Heading/useHeadingStyle.ts @@ -32,7 +32,7 @@ export function useHeadingStyle({ textAlign, ...sizeStyles, ...weightStyles, - }) as const, + } as const), [colorValue, textAlign, sizeStyles, weightStyles] ); diff --git a/src/design-system/components/Inline/Inline.tsx b/src/design-system/components/Inline/Inline.tsx index 3fb44b9cb6f..d356684f6af 100644 --- a/src/design-system/components/Inline/Inline.tsx +++ b/src/design-system/components/Inline/Inline.tsx @@ -44,10 +44,9 @@ export function Inline({ const verticalSpace = verticalSpaceProp ?? space; const horizontalSpace = horizontalSpaceProp ?? space; - const flattenedChildren = useMemo( - () => flattenChildren(children), - [children] - ); + const flattenedChildren = useMemo(() => flattenChildren(children), [ + children, + ]); return ( ({ depth, listSpace, paragraphSpace }), - [depth, paragraphSpace, listSpace] - )} + value={useMemo(() => ({ depth, listSpace, paragraphSpace }), [ + depth, + paragraphSpace, + listSpace, + ])} > {children} @@ -142,10 +143,10 @@ export const MarkdownText = memo(function MarkdownText({ const heading1Color = heading1ColorProp ?? color; const heading2Color = heading2ColorProp ?? heading1ColorProp ?? color; - const spaceProps = useMemo( - () => ({ listSpace, paragraphSpace }), - [paragraphSpace, listSpace] - ); + const spaceProps = useMemo(() => ({ listSpace, paragraphSpace }), [ + paragraphSpace, + listSpace, + ]); const rules: RenderRules = useMemo(() => { return { diff --git a/src/design-system/components/Text/useTextStyle.ts b/src/design-system/components/Text/useTextStyle.ts index d80cd47b5df..05191e33994 100644 --- a/src/design-system/components/Text/useTextStyle.ts +++ b/src/design-system/components/Text/useTextStyle.ts @@ -50,7 +50,7 @@ export function useTextStyle({ ...weightStyles, ...(uppercase ? { textTransform: 'uppercase' as const } : null), ...(tabularNumbers ? { fontVariant: ['tabular-nums' as const] } : null), - }) as const, + } as const), [sizeStyles, weightStyles, textAlign, colorValue, tabularNumbers, uppercase] ); diff --git a/src/design-system/docs/.playroom/fonts.css b/src/design-system/docs/.playroom/fonts.css index 893834b4fa2..609ee7d5e6e 100644 --- a/src/design-system/docs/.playroom/fonts.css +++ b/src/design-system/docs/.playroom/fonts.css @@ -3,8 +3,7 @@ @font-face { font-family: 'SFRounded'; src: url('../public/fonts/subset-SFRounded-Regular.eot'); - src: - url('../public/fonts/subset-SFRounded-Regular.eot?#iefix') + src: url('../public/fonts/subset-SFRounded-Regular.eot?#iefix') format('embedded-opentype'), url('../public/fonts/subset-SFRounded-Regular.woff2') format('woff2'), url('../public/fonts/subset-SFRounded-Regular.woff') format('woff'), @@ -18,8 +17,7 @@ @font-face { font-family: 'SFRounded'; src: url('../public/fonts/subset-SFRounded-Medium.eot'); - src: - url('../public/fonts/subset-SFRounded-Medium.eot?#iefix') + src: url('../public/fonts/subset-SFRounded-Medium.eot?#iefix') format('embedded-opentype'), url('../public/fonts/subset-SFRounded-Medium.woff2') format('woff2'), url('../public/fonts/subset-SFRounded-Medium.woff') format('woff'), @@ -33,8 +31,7 @@ @font-face { font-family: 'SFRounded'; src: url('../public/fonts/subset-SFRounded-Semibold.eot'); - src: - url('../public/fonts/subset-SFRounded-Semibold.eot?#iefix') + src: url('../public/fonts/subset-SFRounded-Semibold.eot?#iefix') format('embedded-opentype'), url('../public/fonts/subset-SFRounded-Semibold.woff2') format('woff2'), url('../public/fonts/subset-SFRounded-Semibold.woff') format('woff'), @@ -48,8 +45,7 @@ @font-face { font-family: 'SFRounded'; src: url('../public/fonts/subset-SFRounded-Bold.eot'); - src: - url('../public/fonts/subset-SFRounded-Bold.eot?#iefix') + src: url('../public/fonts/subset-SFRounded-Bold.eot?#iefix') format('embedded-opentype'), url('../public/fonts/subset-SFRounded-Bold.woff2') format('woff2'), url('../public/fonts/subset-SFRounded-Bold.woff') format('woff'), @@ -63,8 +59,7 @@ @font-face { font-family: 'SFRounded'; src: url('../public/fonts/subset-SFRounded-Heavy.eot'); - src: - url('../public/fonts/subset-SFRounded-Heavy.eot?#iefix') + src: url('../public/fonts/subset-SFRounded-Heavy.eot?#iefix') format('embedded-opentype'), url('../public/fonts/subset-SFRounded-Heavy.woff2') format('woff2'), url('../public/fonts/subset-SFRounded-Heavy.woff') format('woff'), @@ -78,8 +73,7 @@ @font-face { font-family: 'SF-Pro-Rounded-Regular'; src: url('../public/fonts/subset-SFRounded-Regular.eot'); - src: - url('../public/fonts/subset-SFRounded-Regular.eot?#iefix') + src: url('../public/fonts/subset-SFRounded-Regular.eot?#iefix') format('embedded-opentype'), url('../public/fonts/subset-SFRounded-Regular.woff2') format('woff2'), url('../public/fonts/subset-SFRounded-Regular.woff') format('woff'), @@ -93,8 +87,7 @@ @font-face { font-family: 'SF-Pro-Rounded-Bold'; src: url('../public/fonts/subset-SFRounded-Bold.eot'); - src: - url('../public/fonts/subset-SFRounded-Bold.eot?#iefix') + src: url('../public/fonts/subset-SFRounded-Bold.eot?#iefix') format('embedded-opentype'), url('../public/fonts/subset-SFRounded-Bold.woff2') format('woff2'), url('../public/fonts/subset-SFRounded-Bold.woff') format('woff'), @@ -108,8 +101,7 @@ @font-face { font-family: 'SF-Pro-Rounded-Medium'; src: url('../public/fonts/subset-SFRounded-Medium.eot'); - src: - url('../public/fonts/subset-SFRounded-Medium.eot?#iefix') + src: url('../public/fonts/subset-SFRounded-Medium.eot?#iefix') format('embedded-opentype'), url('../public/fonts/subset-SFRounded-Medium.woff2') format('woff2'), url('../public/fonts/subset-SFRounded-Medium.woff') format('woff'), @@ -123,8 +115,7 @@ @font-face { font-family: 'SF-Pro-Rounded-Semibold'; src: url('../public/fonts/subset-SFRounded-Semibold.eot'); - src: - url('../public/fonts/subset-SFRounded-Semibold.eot?#iefix') + src: url('../public/fonts/subset-SFRounded-Semibold.eot?#iefix') format('embedded-opentype'), url('../public/fonts/subset-SFRounded-Semibold.woff2') format('woff2'), url('../public/fonts/subset-SFRounded-Semibold.woff') format('woff'), @@ -138,8 +129,7 @@ @font-face { font-family: 'SF-Pro-Rounded-Heavy'; src: url('../public/fonts/subset-SFRounded-Heavy.eot'); - src: - url('../public/fonts/subset-SFRounded-Heavy.eot?#iefix') + src: url('../public/fonts/subset-SFRounded-Heavy.eot?#iefix') format('embedded-opentype'), url('../public/fonts/subset-SFRounded-Heavy.woff2') format('woff2'), url('../public/fonts/subset-SFRounded-Heavy.woff') format('woff'), diff --git a/src/design-system/docs/styles/fonts.css b/src/design-system/docs/styles/fonts.css index 4a2d4b37483..22e805bc443 100644 --- a/src/design-system/docs/styles/fonts.css +++ b/src/design-system/docs/styles/fonts.css @@ -3,8 +3,7 @@ @font-face { font-family: 'SFRounded'; src: url('/fonts/subset-SFRounded-Regular.eot'); - src: - url('/fonts/subset-SFRounded-Regular.eot?#iefix') + src: url('/fonts/subset-SFRounded-Regular.eot?#iefix') format('embedded-opentype'), url('/fonts/subset-SFRounded-Regular.woff2') format('woff2'), url('/fonts/subset-SFRounded-Regular.woff') format('woff'), @@ -17,8 +16,8 @@ @font-face { font-family: 'SFRounded'; src: url('/fonts/subset-SFRounded-Medium.eot'); - src: - url('/fonts/subset-SFRounded-Medium.eot?#iefix') format('embedded-opentype'), + src: url('/fonts/subset-SFRounded-Medium.eot?#iefix') + format('embedded-opentype'), url('/fonts/subset-SFRounded-Medium.woff2') format('woff2'), url('/fonts/subset-SFRounded-Medium.woff') format('woff'), url('/fonts/subset-SFRounded-Medium.svg#SFRounded-Medium') format('svg'); @@ -30,8 +29,7 @@ @font-face { font-family: 'SFRounded'; src: url('/fonts/subset-SFRounded-Semibold.eot'); - src: - url('/fonts/subset-SFRounded-Semibold.eot?#iefix') + src: url('/fonts/subset-SFRounded-Semibold.eot?#iefix') format('embedded-opentype'), url('/fonts/subset-SFRounded-Semibold.woff2') format('woff2'), url('/fonts/subset-SFRounded-Semibold.woff') format('woff'), @@ -44,8 +42,8 @@ @font-face { font-family: 'SFRounded'; src: url('/fonts/subset-SFRounded-Bold.eot'); - src: - url('/fonts/subset-SFRounded-Bold.eot?#iefix') format('embedded-opentype'), + src: url('/fonts/subset-SFRounded-Bold.eot?#iefix') + format('embedded-opentype'), url('/fonts/subset-SFRounded-Bold.woff2') format('woff2'), url('/fonts/subset-SFRounded-Bold.woff') format('woff'), url('/fonts/subset-SFRounded-Bold.svg#SFRounded-Bold') format('svg'); @@ -57,8 +55,8 @@ @font-face { font-family: 'SFRounded'; src: url('/fonts/subset-SFRounded-Heavy.eot'); - src: - url('/fonts/subset-SFRounded-Heavy.eot?#iefix') format('embedded-opentype'), + src: url('/fonts/subset-SFRounded-Heavy.eot?#iefix') + format('embedded-opentype'), url('/fonts/subset-SFRounded-Heavy.woff2') format('woff2'), url('/fonts/subset-SFRounded-Heavy.woff') format('woff'), url('/fonts/subset-SFRounded-Heavy.svg#SFRounded-Heavy') format('svg'); @@ -70,8 +68,7 @@ @font-face { font-family: 'SF-Pro-Rounded-Regular'; src: url('/fonts/subset-SFRounded-Regular.eot'); - src: - url('/fonts/subset-SFRounded-Regular.eot?#iefix') + src: url('/fonts/subset-SFRounded-Regular.eot?#iefix') format('embedded-opentype'), url('/fonts/subset-SFRounded-Regular.woff2') format('woff2'), url('/fonts/subset-SFRounded-Regular.woff') format('woff'), @@ -84,8 +81,8 @@ @font-face { font-family: 'SF-Pro-Rounded-Bold'; src: url('/fonts/subset-SFRounded-Bold.eot'); - src: - url('/fonts/subset-SFRounded-Bold.eot?#iefix') format('embedded-opentype'), + src: url('/fonts/subset-SFRounded-Bold.eot?#iefix') + format('embedded-opentype'), url('/fonts/subset-SFRounded-Bold.woff2') format('woff2'), url('/fonts/subset-SFRounded-Bold.woff') format('woff'), url('/fonts/subset-SFRounded-Bold.svg#SFRounded-Bold') format('svg'); @@ -97,8 +94,8 @@ @font-face { font-family: 'SF-Pro-Rounded-Medium'; src: url('/fonts/subset-SFRounded-Medium.eot'); - src: - url('/fonts/subset-SFRounded-Medium.eot?#iefix') format('embedded-opentype'), + src: url('/fonts/subset-SFRounded-Medium.eot?#iefix') + format('embedded-opentype'), url('/fonts/subset-SFRounded-Medium.woff2') format('woff2'), url('/fonts/subset-SFRounded-Medium.woff') format('woff'), url('/fonts/subset-SFRounded-Medium.svg#SFRounded-Medium') format('svg'); @@ -110,8 +107,7 @@ @font-face { font-family: 'SF-Pro-Rounded-Semibold'; src: url('/fonts/subset-SFRounded-Semibold.eot'); - src: - url('/fonts/subset-SFRounded-Semibold.eot?#iefix') + src: url('/fonts/subset-SFRounded-Semibold.eot?#iefix') format('embedded-opentype'), url('/fonts/subset-SFRounded-Semibold.woff2') format('woff2'), url('/fonts/subset-SFRounded-Semibold.woff') format('woff'), @@ -124,8 +120,8 @@ @font-face { font-family: 'SF-Pro-Rounded-Heavy'; src: url('/fonts/subset-SFRounded-Heavy.eot'); - src: - url('/fonts/subset-SFRounded-Heavy.eot?#iefix') format('embedded-opentype'), + src: url('/fonts/subset-SFRounded-Heavy.eot?#iefix') + format('embedded-opentype'), url('/fonts/subset-SFRounded-Heavy.woff2') format('woff2'), url('/fonts/subset-SFRounded-Heavy.woff') format('woff'), url('/fonts/subset-SFRounded-Heavy.svg#SFRounded-Heavy') format('svg'); diff --git a/src/design-system/docs/system/typography.css.ts b/src/design-system/docs/system/typography.css.ts index d511f7eb4ed..2525b5654af 100644 --- a/src/design-system/docs/system/typography.css.ts +++ b/src/design-system/docs/system/typography.css.ts @@ -36,8 +36,8 @@ export const sizes = { text: mapValues(typeHierarchy.text, createTextSize), }; -export type HeadingSizes = keyof (typeof sizes)['heading']; -export type TextSizes = keyof (typeof sizes)['text']; +export type HeadingSizes = keyof typeof sizes['heading']; +export type TextSizes = keyof typeof sizes['text']; export const letterSpacings = { heading: mapValues( diff --git a/src/design-system/playground/Playground.tsx b/src/design-system/playground/Playground.tsx index 49bcd12cbde..669911968b6 100644 --- a/src/design-system/playground/Playground.tsx +++ b/src/design-system/playground/Playground.tsx @@ -72,10 +72,9 @@ const CodePreview = ({ wrapper: Example['wrapper']; Example: Example['Example']; }) => { - const { element } = React.useMemo( - () => getSourceFromExample({ Example }), - [Example] - ); + const { element } = React.useMemo(() => getSourceFromExample({ Example }), [ + Example, + ]); // @ts-expect-error Argument of type 'Source...' is not assignable to parameter of type 'ReactNode'. return <>{wrapper(element)}; }; diff --git a/src/ens-avatar/src/index.ts b/src/ens-avatar/src/index.ts index ad39dbad96b..ff7518df9c0 100644 --- a/src/ens-avatar/src/index.ts +++ b/src/ens-avatar/src/index.ts @@ -64,8 +64,9 @@ export class AvatarResolver implements IAvatarResolver { } // parse retrieved avatar uri - const { chainID, namespace, contractAddress, tokenID } = - parseNFT(avatarURI); + const { chainID, namespace, contractAddress, tokenID } = parseNFT( + avatarURI + ); // detect avatar spec by namespace const spec = new specs[namespace](); if (!spec) return null; diff --git a/src/featuresToUnlock/unlockableAppIconCheck.ts b/src/featuresToUnlock/unlockableAppIconCheck.ts index 7b06db4a15c..1fb62662724 100644 --- a/src/featuresToUnlock/unlockableAppIconCheck.ts +++ b/src/featuresToUnlock/unlockableAppIconCheck.ts @@ -20,8 +20,13 @@ export const unlockableAppIconCheck = async ( appIconFeature: UnlockableAppIcon, walletsToCheck: EthereumAddress[] ) => { - const { key, explainSheetType, network, unlockKey, unlockingNfts } = - appIconFeature; + const { + key, + explainSheetType, + network, + unlockKey, + unlockingNfts, + } = appIconFeature; const handled = mmkv.getBoolean(unlockKey); diff --git a/src/graphql/utils/getFetchRequester.ts b/src/graphql/utils/getFetchRequester.ts index b08b7938367..d51effd20d6 100644 --- a/src/graphql/utils/getFetchRequester.ts +++ b/src/graphql/utils/getFetchRequester.ts @@ -60,7 +60,7 @@ export function getFetchRequester(config: Config) { return async function requester< TResponse = unknown, - TVariables = Record, + TVariables = Record >( node: DocumentNode, variables?: TVariables, diff --git a/src/handlers/LedgerSigner.ts b/src/handlers/LedgerSigner.ts index ee2130f954d..56ab4e74766 100644 --- a/src/handlers/LedgerSigner.ts +++ b/src/handlers/LedgerSigner.ts @@ -129,8 +129,9 @@ export class LedgerSigner extends Signer { async signTypedDataMessage(data: any, legacy: boolean): Promise { const version = legacy === false ? SignTypedDataVersion.V4 : SignTypedDataVersion.V3; - const { domain, types, primaryType, message } = - TypedDataUtils.sanitizeData(data); + const { domain, types, primaryType, message } = TypedDataUtils.sanitizeData( + data + ); const domainSeparatorHex = TypedDataUtils.hashStruct( 'EIP712Domain', diff --git a/src/handlers/ens.ts b/src/handlers/ens.ts index 1e6cebb9d58..1ce0070b86d 100644 --- a/src/handlers/ens.ts +++ b/src/handlers/ens.ts @@ -940,8 +940,12 @@ export const formatRecordsForTransaction = ( export const recordsForTransactionAreValid = ( registrationRecords: ENSRegistrationRecords ) => { - const { coinAddress, contenthash, ensAssociatedAddress, text } = - registrationRecords; + const { + coinAddress, + contenthash, + ensAssociatedAddress, + text, + } = registrationRecords; if ( !coinAddress?.length && typeof contenthash !== 'string' && @@ -956,8 +960,12 @@ export const recordsForTransactionAreValid = ( export const getTransactionTypeForRecords = ( registrationRecords: ENSRegistrationRecords ) => { - const { coinAddress, contenthash, ensAssociatedAddress, text } = - registrationRecords; + const { + coinAddress, + contenthash, + ensAssociatedAddress, + text, + } = registrationRecords; if ( ensAssociatedAddress || diff --git a/src/handlers/nftOffers.ts b/src/handlers/nftOffers.ts index ce3737597e7..d3b7df3f7a6 100644 --- a/src/handlers/nftOffers.ts +++ b/src/handlers/nftOffers.ts @@ -22,9 +22,9 @@ const getStateDiff = async ( provider: StaticJsonRpcProvider, approval: TxData ): Promise => { - const { number: blockNumber } = await ( - provider.getBlock as () => Promise - )(); + const { + number: blockNumber, + } = await (provider.getBlock as () => Promise)(); const { trace_call_block_number_offset } = getRemoteConfig(); // trace_call default params diff --git a/src/handlers/swap.ts b/src/handlers/swap.ts index 85fccc15317..4c576da0b67 100644 --- a/src/handlers/swap.ts +++ b/src/handlers/swap.ts @@ -141,9 +141,9 @@ export const getStateDiff = async ( const fromAddr = tradeDetails.from; const toAddr = RAINBOW_ROUTER_CONTRACT_ADDRESS; const tokenContract = new Contract(tokenAddress, erc20ABI, provider); - const { number: blockNumber } = await ( - provider.getBlock as () => Promise - )(); + const { + number: blockNumber, + } = await (provider.getBlock as () => Promise)(); // Get data const { data } = await tokenContract.populateTransaction.approve( @@ -337,12 +337,11 @@ export const estimateSwapGasLimit = async ({ IS_TESTING !== 'true' ) { try { - const gasLimitWithFakeApproval = - await getSwapGasLimitWithFakeApproval( - chainId, - provider, - tradeDetails - ); + const gasLimitWithFakeApproval = await getSwapGasLimitWithFakeApproval( + chainId, + provider, + tradeDetails + ); logger.debug( ' ✅ Got gasLimitWithFakeApproval!', gasLimitWithFakeApproval @@ -391,12 +390,11 @@ export const estimateCrosschainSwapGasLimit = async ({ IS_TESTING !== 'true' ) { try { - const gasLimitWithFakeApproval = - await getSwapGasLimitWithFakeApproval( - chainId, - provider, - tradeDetails - ); + const gasLimitWithFakeApproval = await getSwapGasLimitWithFakeApproval( + chainId, + provider, + tradeDetails + ); logger.debug( ' ✅ Got gasLimitWithFakeApproval!', gasLimitWithFakeApproval @@ -408,8 +406,9 @@ export const estimateCrosschainSwapGasLimit = async ({ } const routeGasLimit = getCrosschainSwapDefaultGasLimit(tradeDetails); - const rainbowDefaultGasLimit = - getCrosschainSwapRainbowDefaultGasLimit(chainId); + const rainbowDefaultGasLimit = getCrosschainSwapRainbowDefaultGasLimit( + chainId + ); if (routeGasLimit && lessThan(rainbowDefaultGasLimit, routeGasLimit)) { return routeGasLimit; } @@ -429,8 +428,9 @@ export const estimateCrosschainSwapGasLimit = async ({ SWAP_GAS_PADDING ); const routeGasLimit = getCrosschainSwapDefaultGasLimit(tradeDetails); - const rainbowDefaultGasLimit = - getCrosschainSwapRainbowDefaultGasLimit(chainId); + const rainbowDefaultGasLimit = getCrosschainSwapRainbowDefaultGasLimit( + chainId + ); let fallbackGasLimit: BigNumberish = rainbowDefaultGasLimit; if (routeGasLimit && lessThan(rainbowDefaultGasLimit, routeGasLimit)) { @@ -439,8 +439,9 @@ export const estimateCrosschainSwapGasLimit = async ({ return gasLimit || fallbackGasLimit; } catch (error) { const routeGasLimit = getCrosschainSwapDefaultGasLimit(tradeDetails); - const rainbowDefaultGasLimit = - getCrosschainSwapRainbowDefaultGasLimit(chainId); + const rainbowDefaultGasLimit = getCrosschainSwapRainbowDefaultGasLimit( + chainId + ); let fallbackGasLimit: BigNumberish = rainbowDefaultGasLimit; if (routeGasLimit && lessThan(rainbowDefaultGasLimit, routeGasLimit)) { diff --git a/src/handlers/web3.ts b/src/handlers/web3.ts index de58a72d506..ab91dc87232 100644 --- a/src/handlers/web3.ts +++ b/src/handlers/web3.ts @@ -149,8 +149,7 @@ type NewTransactionNonNullable = { /** * @desc web3 http instance */ -export let web3Provider: StaticJsonRpcProvider = - null as unknown as StaticJsonRpcProvider; +export let web3Provider: StaticJsonRpcProvider = (null as unknown) as StaticJsonRpcProvider; /** * @desc Checks whether or not a `Network | string` union type should be @@ -414,8 +413,9 @@ export async function estimateGasWithPadding( const saferGasLimit = fraction(gasLimit.toString(), 19, 20); logger.info('⛽ safer gas limit for last block is', { saferGasLimit }); - txPayloadToEstimate[contractCallEstimateGas ? 'gasLimit' : 'gas'] = - toHex(saferGasLimit); + txPayloadToEstimate[contractCallEstimateGas ? 'gasLimit' : 'gas'] = toHex( + saferGasLimit + ); // safety precaution: we want to ensure these properties are not used for gas estimation const cleanTxPayload = omitFlatten(txPayloadToEstimate, [ diff --git a/src/helpers/buildTransactionsSectionsSelector.tsx b/src/helpers/buildTransactionsSectionsSelector.tsx index 33cd348724e..e656db21e52 100644 --- a/src/helpers/buildTransactionsSectionsSelector.tsx +++ b/src/helpers/buildTransactionsSectionsSelector.tsx @@ -19,11 +19,10 @@ type RainbowTransactionWithContact = RainbowTransaction & { contact: Contact | null; }; -type RainbowTransactionWithContactAndMainnetAddress = - RainbowTransactionWithContact & { - mainnetAddress: string; - accountAddress: string; - }; +type RainbowTransactionWithContactAndMainnetAddress = RainbowTransactionWithContact & { + mainnetAddress: string; + accountAddress: string; +}; // bad news const groupTransactionByDate = ({ pending, @@ -52,22 +51,20 @@ const groupTransactionByDate = ({ } }; -const addContactInfo = - (contacts: { [address: string]: Contact }) => - ( - txn: RainbowTransaction - ): RainbowTransaction & { - contact: Contact | null; - } => { - const { from, to, status } = txn; - const isSent = status === TransactionStatusTypes.sent; - const contactAddress = (isSent ? to : from) || ''; - const contact = contacts?.[contactAddress?.toLowerCase()] ?? null; - return { - ...txn, - contact, - }; +const addContactInfo = (contacts: { [address: string]: Contact }) => ( + txn: RainbowTransaction +): RainbowTransaction & { + contact: Contact | null; +} => { + const { from, to, status } = txn; + const isSent = status === TransactionStatusTypes.sent; + const contactAddress = (isSent ? to : from) || ''; + const contact = contacts?.[contactAddress?.toLowerCase()] ?? null; + return { + ...txn, + contact, }; +}; export const buildTransactionsSections = ({ accountAddress, @@ -120,20 +117,21 @@ export const buildTransactionsSections = ({ item: RainbowTransactionWithContactAndMainnetAddress; }) => JSX.Element; }[] = filter.map((section: string) => { - const sectionData: RainbowTransactionWithContactAndMainnetAddress[] = - transactionsByDate[section].map(txn => { - const typeTxn = txn as RainbowTransactionWithContact; - const res = { - ...typeTxn, - to: typeTxn.to || '', - from: typeTxn.from || '', - accountAddress, - mainnetAddress: - mainnetAddresses[`${typeTxn.address}_${typeTxn.network}`], - }; + const sectionData: RainbowTransactionWithContactAndMainnetAddress[] = transactionsByDate[ + section + ].map(txn => { + const typeTxn = txn as RainbowTransactionWithContact; + const res = { + ...typeTxn, + to: typeTxn.to || '', + from: typeTxn.from || '', + accountAddress, + mainnetAddress: + mainnetAddresses[`${typeTxn.address}_${typeTxn.network}`], + }; - return res; - }); + return res; + }); return { data: sectionData, diff --git a/src/helpers/buildWalletSections.tsx b/src/helpers/buildWalletSections.tsx index 5184a4a081a..b1c9010d6bf 100644 --- a/src/helpers/buildWalletSections.tsx +++ b/src/helpers/buildWalletSections.tsx @@ -78,8 +78,10 @@ const withPositionsSection = (isLoadingUserAssets: boolean) => { const positionsEnabled = getExperimetalFlag(DEFI_POSITIONS); if (!positionsEnabled) return []; - const { accountAddress: address, nativeCurrency: currency } = - store.getState().settings; + const { + accountAddress: address, + nativeCurrency: currency, + } = store.getState().settings; const positionsObj: RainbowPositions | undefined = queryClient.getQueryData( positionsQueryKey({ address, currency }) ); diff --git a/src/helpers/chartTypes.ts b/src/helpers/chartTypes.ts index 0b1b8c1929d..cef4cdcd027 100644 --- a/src/helpers/chartTypes.ts +++ b/src/helpers/chartTypes.ts @@ -8,4 +8,4 @@ const chartTypes = { } as const; export default chartTypes; -export type ChartType = (typeof chartTypes)[keyof typeof chartTypes]; +export type ChartType = typeof chartTypes[keyof typeof chartTypes]; diff --git a/src/helpers/emojiHandler.ts b/src/helpers/emojiHandler.ts index 04cb1a88d61..1a5f22d6fa0 100644 --- a/src/helpers/emojiHandler.ts +++ b/src/helpers/emojiHandler.ts @@ -1,8 +1,7 @@ import GraphemeSplitter from 'grapheme-splitter'; import { memoFn } from '../utils/memoFn'; -const regex = - /(?:[\u2700-\u27bf]|(?:\ud83c[\udde6-\uddff]){2}|[\ud800-\udbff][\udc00-\udfff]|[\u0023-\u0039]\ufe0f?\u20e3|\u3299|\u3297|\u303d|\u3030|\u24c2|\ud83c[\udd70-\udd71]|\ud83c[\udd7e-\udd7f]|\ud83c\udd8e|\ud83c[\udd91-\udd9a]|\ud83c[\udde6-\uddff]|\ud83c[\ude01-\ude02]|\ud83c\ude1a|\ud83c\ude2f|\ud83c[\ude32-\ude3a]|\ud83c[\ude50-\ude51]|\u203c|\u2049|[\u25aa-\u25ab]|\u25b6|\u25c0|[\u25fb-\u25fe]|\u00a9|\u00ae|\u2122|\u2139|\ud83c\udc04|[\u2600-\u26FF]|\u2b05|\u2b06|\u2b07|\u2b1b|\u2b1c|\u2b50|\u2b55|\u231a|\u231b|\u2328|\u23cf|[\u23e9-\u23f3]|[\u23f8-\u23fa]|\ud83c\udccf|\u2934|\u2935|[\u2190-\u21ff])/g; +const regex = /(?:[\u2700-\u27bf]|(?:\ud83c[\udde6-\uddff]){2}|[\ud800-\udbff][\udc00-\udfff]|[\u0023-\u0039]\ufe0f?\u20e3|\u3299|\u3297|\u303d|\u3030|\u24c2|\ud83c[\udd70-\udd71]|\ud83c[\udd7e-\udd7f]|\ud83c\udd8e|\ud83c[\udd91-\udd9a]|\ud83c[\udde6-\uddff]|\ud83c[\ude01-\ude02]|\ud83c\ude1a|\ud83c\ude2f|\ud83c[\ude32-\ude3a]|\ud83c[\ude50-\ude51]|\u203c|\u2049|[\u25aa-\u25ab]|\u25b6|\u25c0|[\u25fb-\u25fe]|\u00a9|\u00ae|\u2122|\u2139|\ud83c\udc04|[\u2600-\u26FF]|\u2b05|\u2b06|\u2b07|\u2b1b|\u2b1c|\u2b50|\u2b55|\u231a|\u231b|\u2328|\u23cf|[\u23e9-\u23f3]|[\u23f8-\u23fa]|\ud83c\udccf|\u2934|\u2935|[\u2190-\u21ff])/g; export const removeFirstEmojiFromString = memoFn(string => { if (!string) return ''; diff --git a/src/helpers/ens.ts b/src/helpers/ens.ts index 24adeccf4ac..b39be23716d 100644 --- a/src/helpers/ens.ts +++ b/src/helpers/ens.ts @@ -581,8 +581,9 @@ const getENSExecutionDetails = async ({ switch (type) { case ENSRegistrationTransactionType.COMMIT: { if (!name || !ownerAddress) throw new Error('Bad arguments for commit'); - const registrarController = - await getENSRegistrarControllerContract(wallet); + const registrarController = await getENSRegistrarControllerContract( + wallet + ); const commitment = await registrarController.makeCommitmentWithConfig( name.replace(ENS_DOMAIN, ''), ownerAddress, @@ -770,14 +771,16 @@ const formatRentPrice = ( undefined, true ); - const { display: displayPerYear, amount: amountPerYear } = - convertAmountAndPriceToNativeDisplay( - rentPricePerYear, - nativeAssetPrice, - nativeCurrency, - undefined, - true - ); + const { + display: displayPerYear, + amount: amountPerYear, + } = convertAmountAndPriceToNativeDisplay( + rentPricePerYear, + nativeAssetPrice, + nativeCurrency, + undefined, + true + ); return { perYear: { diff --git a/src/helpers/signingWallet.ts b/src/helpers/signingWallet.ts index b505dd62aa4..4eb400308fe 100644 --- a/src/helpers/signingWallet.ts +++ b/src/helpers/signingWallet.ts @@ -65,8 +65,7 @@ export async function getSignatureForSigningWalletAndCreateSignatureIfNeeded( publicAccessControlOptions ); if (alreadyExistingEncodedSignature) { - const publicKeyForTheSigningWallet = - await getPublicKeyOfTheSigningWalletAndCreateWalletIfNeeded(); + const publicKeyForTheSigningWallet = await getPublicKeyOfTheSigningWalletAndCreateWalletIfNeeded(); const encryptor = new AesEncryptor(); const decryptedSignature = await encryptor.decrypt( RAINBOW_MASTER_KEY, @@ -110,8 +109,7 @@ export async function createSignature( privateKey: string | null = null ) { logger.log('Creating a signature'); - const publicKeyForTheSigningWallet = - await getPublicKeyOfTheSigningWalletAndCreateWalletIfNeeded(); + const publicKeyForTheSigningWallet = await getPublicKeyOfTheSigningWalletAndCreateWalletIfNeeded(); const mainWallet = privateKey ? new Wallet(privateKey) diff --git a/src/helpers/time.ts b/src/helpers/time.ts index e02c8960f81..80459f4ca22 100644 --- a/src/helpers/time.ts +++ b/src/helpers/time.ts @@ -40,8 +40,10 @@ export const getMinimalTimeUnitStringForMs = ( const { days, hours, minutes, seconds } = parseMilliseconds(Number(ms)); const parsedMs = omitBy({ days, hours, minutes, seconds }, isZero); - const { unit: highestResolutionUnit, value: highestResolutionValue } = - getHighestResolutionUnit(parsedMs); + const { + unit: highestResolutionUnit, + value: highestResolutionValue, + } = getHighestResolutionUnit(parsedMs); const label = buildLocalizedTimeUnitString({ plural, diff --git a/src/helpers/transformUniqueAssetTraitsForPresentation.ts b/src/helpers/transformUniqueAssetTraitsForPresentation.ts index 1c02c955b09..8fd089a5da1 100644 --- a/src/helpers/transformUniqueAssetTraitsForPresentation.ts +++ b/src/helpers/transformUniqueAssetTraitsForPresentation.ts @@ -12,8 +12,7 @@ type MappedTrait = UniqueAssetTrait & { disableMenu?: boolean; } & AdditionalProperties; -const poapDateRegex = - /\d\d-(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)-\d\d\d\d/; +const poapDateRegex = /\d\d-(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)-\d\d\d\d/; const poapDateFormatString = 'dd-MMM-y'; const targetDateFormatString = 'MMM do, y'; diff --git a/src/helpers/utilities.ts b/src/helpers/utilities.ts index ca23037637d..311a34cea08 100644 --- a/src/helpers/utilities.ts +++ b/src/helpers/utilities.ts @@ -575,16 +575,13 @@ export const pickShallow = ( obj: T, paths: K[] ): Pick => { - return paths.reduce( - (acc, key) => { - if (obj.hasOwnProperty(key)) { - acc[key] = obj[key]; - return acc; - } + return paths.reduce((acc, key) => { + if (obj.hasOwnProperty(key)) { + acc[key] = obj[key]; return acc; - }, - {} as Pick - ); + } + return acc; + }, {} as Pick); }; /** diff --git a/src/hooks/charts/useChartInfo.ts b/src/hooks/charts/useChartInfo.ts index c1d37bff602..cd3751dac0e 100644 --- a/src/hooks/charts/useChartInfo.ts +++ b/src/hooks/charts/useChartInfo.ts @@ -15,7 +15,7 @@ import { NetworkProperties } from '@/networks/types'; import { Network } from '@/helpers'; const chartTimes = ['hour', 'day', 'week', 'month', 'year'] as const; -type ChartTime = (typeof chartTimes)[number]; +type ChartTime = typeof chartTimes[number]; type PriceChartTimeData = { points?: [x: number, y: number][] }; const getChartTimeArg = (selected: ChartTime) => diff --git a/src/hooks/charts/useChartThrottledPoints.ts b/src/hooks/charts/useChartThrottledPoints.ts index 5a860c143f1..d24ab49a76c 100644 --- a/src/hooks/charts/useChartThrottledPoints.ts +++ b/src/hooks/charts/useChartThrottledPoints.ts @@ -174,9 +174,8 @@ export default function useChartThrottledPoints({ smoothingStrategy: 'bezier', }); - const debouncedSetThrottledData = useRef( - debounce(setThrottledData, 30) - ).current; + const debouncedSetThrottledData = useRef(debounce(setThrottledData, 30)) + .current; useEffect(() => { if (throttledPoints.points && !fetchingCharts) { diff --git a/src/hooks/useAccountENSDomains.ts b/src/hooks/useAccountENSDomains.ts index 18d628aa6ec..097a53a5562 100644 --- a/src/hooks/useAccountENSDomains.ts +++ b/src/hooks/useAccountENSDomains.ts @@ -70,12 +70,9 @@ export async function prefetchAccountENSDomains({ export default function useAccountENSDomains() { const { accountAddress, accountENS } = useAccountProfile(); - const { - data: domains, - isLoading, - isFetched, - isSuccess, - } = useQuery( + const { data: domains, isLoading, isFetched, isSuccess } = useQuery< + BaseEnsDomainFragment[] + >( queryKey({ accountAddress }), async () => fetchENSDomainsWithCache({ accountAddress }), { @@ -83,28 +80,28 @@ export default function useAccountENSDomains() { } ); - const { controlledDomains, primaryDomain, nonPrimaryDomains } = - useMemo(() => { - const controlledDomains = domains?.filter( - ({ owner }) => - owner?.id?.toLowerCase() === accountAddress?.toLowerCase() - ); - return { - controlledDomains, - nonPrimaryDomains: - controlledDomains?.filter(({ name }) => accountENS !== name) || [], - primaryDomain: controlledDomains?.find( - ({ name }) => accountENS === name - ), - }; - }, [accountAddress, accountENS, domains]); + const { + controlledDomains, + primaryDomain, + nonPrimaryDomains, + } = useMemo(() => { + const controlledDomains = domains?.filter( + ({ owner }) => owner?.id?.toLowerCase() === accountAddress?.toLowerCase() + ); + return { + controlledDomains, + nonPrimaryDomains: + controlledDomains?.filter(({ name }) => accountENS !== name) || [], + primaryDomain: controlledDomains?.find(({ name }) => accountENS === name), + }; + }, [accountAddress, accountENS, domains]); const uniqueDomain = useMemo(() => { return primaryDomain ? primaryDomain : nonPrimaryDomains?.length === 1 - ? nonPrimaryDomains?.[0] - : null; + ? nonPrimaryDomains?.[0] + : null; }, [nonPrimaryDomains, primaryDomain]); return { diff --git a/src/hooks/useAccountTransactions.ts b/src/hooks/useAccountTransactions.ts index 3556086ac08..2405565cbf9 100644 --- a/src/hooks/useAccountTransactions.ts +++ b/src/hooks/useAccountTransactions.ts @@ -31,8 +31,9 @@ export default function useAccountTransactions() { connectedToHardhat, }); - const { pendingTransactions: storePendingTransactions } = - usePendingTransactionsStore(); + const { + pendingTransactions: storePendingTransactions, + } = usePendingTransactionsStore(); const pendingTransactions = useMemo(() => { const txs = storePendingTransactions[accountAddress] || []; diff --git a/src/hooks/useAnimatedPageScrollHandler.ts b/src/hooks/useAnimatedPageScrollHandler.ts index b7a2478f2fa..7441ab63841 100644 --- a/src/hooks/useAnimatedPageScrollHandler.ts +++ b/src/hooks/useAnimatedPageScrollHandler.ts @@ -6,8 +6,8 @@ import { NativeScrollEvent, Platform } from 'react-native'; // ts wants to lint reanimated codebase but it doesn't quite work // so let's just assume it's any for now /* eslint-disable import/no-commonjs */ -const WorkletEventHandlerClass = - require('react-native-reanimated/src/reanimated2/WorkletEventHandler').default; +const WorkletEventHandlerClass = require('react-native-reanimated/src/reanimated2/WorkletEventHandler') + .default; const { makeRemote } = require('react-native-reanimated/src/reanimated2/core'); /* eslint-enable import/no-commonjs */ diff --git a/src/hooks/useCoinListEditOptions.ts b/src/hooks/useCoinListEditOptions.ts index 8e855880fba..ec3cf1c9c3d 100644 --- a/src/hooks/useCoinListEditOptions.ts +++ b/src/hooks/useCoinListEditOptions.ts @@ -52,10 +52,9 @@ export default function useCoinListEditOptions() { [setSelectedItems] ); - const clearSelectedCoins = useCallback( - () => setSelectedItems([]), - [setSelectedItems] - ); + const clearSelectedCoins = useCallback(() => setSelectedItems([]), [ + setSelectedItems, + ]); return { clearSelectedCoins, diff --git a/src/hooks/useCoinListEdited.ts b/src/hooks/useCoinListEdited.ts index 6878f568345..3bd3ac1a654 100644 --- a/src/hooks/useCoinListEdited.ts +++ b/src/hooks/useCoinListEdited.ts @@ -6,8 +6,9 @@ const isCoinListEditedAtom = atom({ }); export default function useCoinListEdited() { - const [isCoinListEdited, setIsCoinListEdited] = - useRecoilState(isCoinListEditedAtom); + const [isCoinListEdited, setIsCoinListEdited] = useRecoilState( + isCoinListEditedAtom + ); return { isCoinListEdited, diff --git a/src/hooks/useDeleteWallet.ts b/src/hooks/useDeleteWallet.ts index 1b2191eb6d9..9e10c801233 100644 --- a/src/hooks/useDeleteWallet.ts +++ b/src/hooks/useDeleteWallet.ts @@ -16,11 +16,12 @@ export default function useDeleteWallet({ const [watchingWalletId] = useMemo(() => { return ( - Object.entries(wallets || {}).find( - ([_, wallet]: [string, RainbowWallet]) => - wallet.addresses.some( - ({ address }: RainbowAccount) => address === primaryAddress - ) + Object.entries( + wallets || {} + ).find(([_, wallet]: [string, RainbowWallet]) => + wallet.addresses.some( + ({ address }: RainbowAccount) => address === primaryAddress + ) ) || ['', ''] ); }, [primaryAddress, wallets]); @@ -30,11 +31,12 @@ export default function useDeleteWallet({ ...wallets, [watchingWalletId]: { ...wallets![watchingWalletId], - addresses: wallets![watchingWalletId].addresses.map( - (account: { address: string }) => - account.address.toLowerCase() === primaryAddress?.toLowerCase() - ? { ...(account as RainbowAccount), visible: false } - : (account as RainbowAccount) + addresses: wallets![ + watchingWalletId + ].addresses.map((account: { address: string }) => + account.address.toLowerCase() === primaryAddress?.toLowerCase() + ? { ...(account as RainbowAccount), visible: false } + : (account as RainbowAccount) ), }, }; diff --git a/src/hooks/useENSModifiedRegistration.ts b/src/hooks/useENSModifiedRegistration.ts index bd6a61a9080..31d3d0fd45c 100644 --- a/src/hooks/useENSModifiedRegistration.ts +++ b/src/hooks/useENSModifiedRegistration.ts @@ -153,9 +153,9 @@ export default function useENSModifiedRegistration({ {} ); - const recordKeysWithValue = ( - Object.keys(records) as (keyof Records)[] - ).filter((key: keyof Records) => { + const recordKeysWithValue = (Object.keys( + records + ) as (keyof Records)[]).filter((key: keyof Records) => { return Boolean(records[key]); }); diff --git a/src/hooks/useENSRegistrationActionHandler.ts b/src/hooks/useENSRegistrationActionHandler.ts index 7261de3ffb7..a358b9a1686 100644 --- a/src/hooks/useENSRegistrationActionHandler.ts +++ b/src/hooks/useENSRegistrationActionHandler.ts @@ -178,8 +178,10 @@ export default function useENSRegistrationActionHandler( const registerAction = useCallback( async (callback: () => void = NOOP) => { - const { name, duration } = - registrationParameters as RegistrationParameters; + const { + name, + duration, + } = registrationParameters as RegistrationParameters; const provider = await getProviderForNetwork(); const wallet = await loadWallet(undefined, false, provider); diff --git a/src/hooks/useENSRegistrationCosts.ts b/src/hooks/useENSRegistrationCosts.ts index 4042eb91e96..0590ff1f7c0 100644 --- a/src/hooks/useENSRegistrationCosts.ts +++ b/src/hooks/useENSRegistrationCosts.ts @@ -124,8 +124,8 @@ export default function useENSRegistrationCosts({ }, [accountAddress, duration, name, rentPriceInWei]); const getRegisterRapGasLimit = useCallback(async () => { - const newRegisterRapGasLimit = - await estimateENSRegisterSetRecordsAndNameGasLimit({ + const newRegisterRapGasLimit = await estimateENSRegisterSetRecordsAndNameGasLimit( + { duration, name, ownerAddress: accountAddress, @@ -133,7 +133,8 @@ export default function useENSRegistrationCosts({ rentPrice: registrationParameters?.rentPrice, salt: registrationParameters?.salt, setReverseRecord: sendReverseRecord, - }); + } + ); return newRegisterRapGasLimit || ''; }, [ accountAddress, diff --git a/src/hooks/useENSRegistrationForm.ts b/src/hooks/useENSRegistrationForm.ts index bc889067af2..4b38a93cd28 100644 --- a/src/hooks/useENSRegistrationForm.ts +++ b/src/hooks/useENSRegistrationForm.ts @@ -120,8 +120,9 @@ export default function useENSRegistrationForm({ setDisabled(mode === REGISTRATION_MODES.EDIT && isEmpty(changedRecords)); }, [changedRecords, mode, setDisabled]); - const [selectedFields, setSelectedFields] = - useRecoilState(selectedFieldsAtom); + const [selectedFields, setSelectedFields] = useRecoilState( + selectedFieldsAtom + ); useEffect(() => { if (!initializeForm) return; // If there are existing records in the global state, then we diff --git a/src/hooks/useENSRegistrationStepHandler.tsx b/src/hooks/useENSRegistrationStepHandler.tsx index 7cc331b48c3..cefe8c228b6 100644 --- a/src/hooks/useENSRegistrationStepHandler.tsx +++ b/src/hooks/useENSRegistrationStepHandler.tsx @@ -63,15 +63,17 @@ export default function useENSRegistrationStepHandler(observer = true) { const timeout = useRef(); - const [secondsSinceCommitConfirmed, setSecondsSinceCommitConfirmed] = - useState( - (registrationParameters?.commitTransactionConfirmedAt && - differenceInSeconds( - Date.now(), - registrationParameters?.commitTransactionConfirmedAt - )) || - -1 - ); + const [ + secondsSinceCommitConfirmed, + setSecondsSinceCommitConfirmed, + ] = useState( + (registrationParameters?.commitTransactionConfirmedAt && + differenceInSeconds( + Date.now(), + registrationParameters?.commitTransactionConfirmedAt + )) || + -1 + ); const isTestingHardhat = useMemo( () => isHardHat(web3Provider.connection.url), diff --git a/src/hooks/useExpandedStateNavigation.ts b/src/hooks/useExpandedStateNavigation.ts index 322ce42eeff..b70260d51bc 100644 --- a/src/hooks/useExpandedStateNavigation.ts +++ b/src/hooks/useExpandedStateNavigation.ts @@ -9,7 +9,7 @@ import { useNavigation } from '@/navigation'; import { watchingAlert } from '@/utils'; export default function useExpandedStateNavigation( - inputType: (typeof AssetInputTypes)[keyof typeof AssetInputTypes], + inputType: typeof AssetInputTypes[keyof typeof AssetInputTypes], fromDiscover = false ) { const { goBack, navigate } = useNavigation(); diff --git a/src/hooks/useInteraction.ts b/src/hooks/useInteraction.ts index e1d131053fd..b6a835efac3 100644 --- a/src/hooks/useInteraction.ts +++ b/src/hooks/useInteraction.ts @@ -8,7 +8,7 @@ type HandleType = Handle | null; export default function useInteraction(): [ CreateHandleType, RemoveHandleType, - MutableRefObject, + MutableRefObject ] { const interactionHandle = useRef(null); diff --git a/src/hooks/useInterval.ts b/src/hooks/useInterval.ts index 8ab9bc38f40..2f14b99bcb4 100644 --- a/src/hooks/useInterval.ts +++ b/src/hooks/useInterval.ts @@ -3,7 +3,7 @@ import { MutableRefObject, useCallback, useEffect, useRef } from 'react'; export default function useInterval(): [ (func: () => void, ms?: number) => void, () => void, - MutableRefObject, + MutableRefObject ] { const handle = useRef(null); diff --git a/src/hooks/useInvalidPaste.ts b/src/hooks/useInvalidPaste.ts index eb6055bdda2..e80dc528415 100644 --- a/src/hooks/useInvalidPaste.ts +++ b/src/hooks/useInvalidPaste.ts @@ -21,10 +21,9 @@ export default function useInvalidPaste() { }, [isInvalidPaste, setGlobalState, startTimeout, stopTimeout]); // 🚪️ Reset isInvalidPaste when we leave the screen - useEffect( - () => () => setGlobalState({ isInvalidPaste: false }), - [setGlobalState] - ); + useEffect(() => () => setGlobalState({ isInvalidPaste: false }), [ + setGlobalState, + ]); return { isInvalidPaste, diff --git a/src/hooks/useLatestCallback.ts b/src/hooks/useLatestCallback.ts index 6852fa57b71..1a15d7f3678 100644 --- a/src/hooks/useLatestCallback.ts +++ b/src/hooks/useLatestCallback.ts @@ -10,12 +10,12 @@ const useIsomorphicLayoutEffect = export default function useLatestCallback(callback: T): T { const ref = React.useRef(callback); - const latestCallback = React.useRef(function latestCallback( + const latestCallback = React.useRef((function latestCallback( this: unknown, ...args: unknown[] ) { return ref.current.apply(this, args); - } as unknown as T).current; + } as unknown) as T).current; useIsomorphicLayoutEffect(() => { ref.current = callback; diff --git a/src/hooks/useOnAvatarPress.ts b/src/hooks/useOnAvatarPress.ts index 0c2513f6826..f4f05fedf11 100644 --- a/src/hooks/useOnAvatarPress.ts +++ b/src/hooks/useOnAvatarPress.ts @@ -77,11 +77,12 @@ export default ({ screenType = 'transaction' }: UseOnAvatarPressProps = {}) => { ...wallets, [selectedWallet.id]: { ...wallets![selectedWallet.id], - addresses: wallets![selectedWallet.id].addresses.map( - (account: RainbowAccount) => - account.address.toLowerCase() === accountAddress?.toLowerCase() - ? { ...account, image: null } - : account + addresses: wallets![ + selectedWallet.id + ].addresses.map((account: RainbowAccount) => + account.address.toLowerCase() === accountAddress?.toLowerCase() + ? { ...account, image: null } + : account ), }, }; @@ -100,11 +101,12 @@ export default ({ screenType = 'transaction' }: UseOnAvatarPressProps = {}) => { ...wallets, [selectedWallet.id]: { ...wallets![selectedWallet.id], - addresses: wallets![selectedWallet.id].addresses.map( - (account: RainbowAccount) => - account.address.toLowerCase() === accountAddress?.toLowerCase() - ? { ...account, image: imagePath } - : account + addresses: wallets![ + selectedWallet.id + ].addresses.map((account: RainbowAccount) => + account.address.toLowerCase() === accountAddress?.toLowerCase() + ? { ...account, image: imagePath } + : account ), }, }; diff --git a/src/hooks/useParamsForExchangeModal.ts b/src/hooks/useParamsForExchangeModal.ts index 70b7d0e6781..46bd4e356db 100644 --- a/src/hooks/useParamsForExchangeModal.ts +++ b/src/hooks/useParamsForExchangeModal.ts @@ -32,8 +32,11 @@ export default function ({ }>(); const dispatch = useDispatch(); - const { updateInputAmount, updateNativeAmount, updateOutputAmount } = - useSwapInputHandlers(); + const { + updateInputAmount, + updateNativeAmount, + updateOutputAmount, + } = useSwapInputHandlers(); const [isFillingParams, setIsFillingParams] = useState(false); diff --git a/src/hooks/usePortfolios.ts b/src/hooks/usePortfolios.ts index f87922ce0fa..7b49c0c70b9 100644 --- a/src/hooks/usePortfolios.ts +++ b/src/hooks/usePortfolios.ts @@ -30,10 +30,9 @@ export default function usePortfolios() { keys(portfolios).forEach(address => { keys(portfolios[address]).forEach(key => { if (!isNil(total[key as keyof typeof total])) { - total[key as keyof typeof total] += - portfolios[address][ - key as keyof (typeof portfolios)[typeof address] - ]!; + total[key as keyof typeof total] += portfolios[address][ + key as keyof typeof portfolios[typeof address] + ]!; } }); }); diff --git a/src/hooks/usePriceImpactDetails.ts b/src/hooks/usePriceImpactDetails.ts index e547c5c6367..7443dc7c85d 100644 --- a/src/hooks/usePriceImpactDetails.ts +++ b/src/hooks/usePriceImpactDetails.ts @@ -125,8 +125,9 @@ export default function usePriceImpactDetails( const { impactDisplay, priceImpact, percentDisplay } = useMemo(() => { const nativeAmountImpact = subtract(inputNativeAmount, outputNativeAmount); const priceImpact = divide(nativeAmountImpact, inputNativeAmount); - const percentDisplay = - convertAmountToPercentageDisplayWithThreshold(priceImpact); + const percentDisplay = convertAmountToPercentageDisplayWithThreshold( + priceImpact + ); const impactDisplay = convertAmountToNativeDisplay( nativeAmountImpact, nativeCurrency diff --git a/src/hooks/useRouteExistsInNavigationState.ts b/src/hooks/useRouteExistsInNavigationState.ts index 4a1a43f4531..5e7ada4f808 100644 --- a/src/hooks/useRouteExistsInNavigationState.ts +++ b/src/hooks/useRouteExistsInNavigationState.ts @@ -3,8 +3,8 @@ import { useMemo } from 'react'; export default function useRouteExistsInNavigationState(routeName: string) { const routes = useNavigationState(state => state.routes); - return useMemo( - () => routes.find(route => route.name === routeName), - [routeName, routes] - ); + return useMemo(() => routes.find(route => route.name === routeName), [ + routeName, + routes, + ]); } diff --git a/src/hooks/useSearchCurrencyList.ts b/src/hooks/useSearchCurrencyList.ts index fdf07fb2ddf..db0b178f1b1 100644 --- a/src/hooks/useSearchCurrencyList.ts +++ b/src/hooks/useSearchCurrencyList.ts @@ -103,8 +103,10 @@ const useSearchCurrencyList = ( [searchChainId, searchQuery] ); - const { favorites: favoriteAddresses, favoritesMetadata: favoriteMap } = - useFavorites(); + const { + favorites: favoriteAddresses, + favoritesMetadata: favoriteMap, + } = useFavorites(); const curatedMap = rainbowTokenList.CURATED_TOKENS; const unfilteredFavorites = Object.values(favoriteMap); @@ -115,16 +117,19 @@ const useSearchCurrencyList = ( const [highLiquidityAssets, setHighLiquidityAssets] = useState([]); const [lowLiquidityAssets, setLowLiquidityAssets] = useState([]); const [verifiedAssets, setVerifiedAssets] = useState([]); - const [fetchingCrosschainAssets, setFetchingCrosschainAssets] = - useState(false); - const [crosschainVerifiedAssets, setCrosschainVerifiedAssets] = - useState({ - [Network.mainnet]: [], - [Network.optimism]: [], - [Network.polygon]: [], - [Network.bsc]: [], - [Network.arbitrum]: [], - }); + const [fetchingCrosschainAssets, setFetchingCrosschainAssets] = useState( + false + ); + const [ + crosschainVerifiedAssets, + setCrosschainVerifiedAssets, + ] = useState({ + [Network.mainnet]: [], + [Network.optimism]: [], + [Network.polygon]: [], + [Network.bsc]: [], + [Network.arbitrum]: [], + }); const crosschainSwapsEnabled = useExperimentalFlag(CROSSCHAIN_SWAPS); diff --git a/src/hooks/useSendSheetInputRefs.ts b/src/hooks/useSendSheetInputRefs.ts index a45fa37c5a9..b14179c5293 100644 --- a/src/hooks/useSendSheetInputRefs.ts +++ b/src/hooks/useSendSheetInputRefs.ts @@ -6,8 +6,11 @@ export default function useSendSheetInputRefs() { const assetInputRef = useRef(); const nativeCurrencyInputRef = useRef(); - const { handleFocus, lastFocusedInputHandle, setLastFocusedInputHandle } = - useMagicAutofocus(nativeCurrencyInputRef, null, true); + const { + handleFocus, + lastFocusedInputHandle, + setLastFocusedInputHandle, + } = useMagicAutofocus(nativeCurrencyInputRef, null, true); return { assetInputRef, diff --git a/src/hooks/useSwapCurrencyHandlers.ts b/src/hooks/useSwapCurrencyHandlers.ts index 500425fe13f..bb0f7f42b63 100644 --- a/src/hooks/useSwapCurrencyHandlers.ts +++ b/src/hooks/useSwapCurrencyHandlers.ts @@ -44,8 +44,11 @@ export default function useSwapCurrencyHandlers({ const { derivedValues } = useSwapDerivedValues(); - const { updateInputAmount, updateNativeAmount, updateOutputAmount } = - useSwapInputHandlers(); + const { + updateInputAmount, + updateNativeAmount, + updateOutputAmount, + } = useSwapInputHandlers(); const { defaultInputItemInWallet, defaultOutputItem } = useMemo(() => { if (type === ExchangeModalTypes.swap) { diff --git a/src/hooks/useSwapCurrencyList.ts b/src/hooks/useSwapCurrencyList.ts index 7f70d6af687..3ac4e67ff5e 100644 --- a/src/hooks/useSwapCurrencyList.ts +++ b/src/hooks/useSwapCurrencyList.ts @@ -101,8 +101,10 @@ const useSwapCurrencyList = ( [searchChainId, searchQuery] ); - const { favorites: favoriteAddresses, favoritesMetadata: favoriteMap } = - useFavorites(); + const { + favorites: favoriteAddresses, + favoritesMetadata: favoriteMap, + } = useFavorites(); const curatedMap = rainbowTokenList.CURATED_TOKENS; const unfilteredFavorites = Object.values(favoriteMap); @@ -113,16 +115,19 @@ const useSwapCurrencyList = ( const [highLiquidityAssets, setHighLiquidityAssets] = useState([]); const [lowLiquidityAssets, setLowLiquidityAssets] = useState([]); const [verifiedAssets, setVerifiedAssets] = useState([]); - const [fetchingCrosschainAssets, setFetchingCrosschainAssets] = - useState(false); - const [crosschainVerifiedAssets, setCrosschainVerifiedAssets] = - useState({ - [Network.mainnet]: [], - [Network.optimism]: [], - [Network.polygon]: [], - [Network.bsc]: [], - [Network.arbitrum]: [], - }); + const [fetchingCrosschainAssets, setFetchingCrosschainAssets] = useState( + false + ); + const [ + crosschainVerifiedAssets, + setCrosschainVerifiedAssets, + ] = useState({ + [Network.mainnet]: [], + [Network.optimism]: [], + [Network.polygon]: [], + [Network.bsc]: [], + [Network.arbitrum]: [], + }); const crosschainSwapsEnabled = useExperimentalFlag(CROSSCHAIN_SWAPS); const { inputCurrency } = useSwapCurrencies(); diff --git a/src/hooks/useSwapDerivedOutputs.ts b/src/hooks/useSwapDerivedOutputs.ts index 93d7c08faa8..2124676a61d 100644 --- a/src/hooks/useSwapDerivedOutputs.ts +++ b/src/hooks/useSwapDerivedOutputs.ts @@ -131,7 +131,7 @@ const getInputAmount = async ( // if no quote, if quote is error or there's no sell amount if (!quote || (quote as QuoteError).error || !(quote as Quote).sellAmount) { if ((quote as QuoteError).error) { - const quoteError = quote as unknown as QuoteError; + const quoteError = (quote as unknown) as QuoteError; logger.error(new RainbowError('[getInputAmount]: Quote error'), { code: quoteError.error_code, msg: quoteError.message, @@ -238,9 +238,13 @@ const getOutputAmount = async ( logger.debug('[getOutputAmount]: Getting quote', { rand, quoteParams }); // Do not deleeeet the comment below 😤 // @ts-ignore About to get quote - const quote: Quote | CrosschainQuote | QuoteError | null = await ( - isCrosschainSwap ? getCrosschainQuote : getQuote - )(quoteParams); + const quote: + | Quote + | CrosschainQuote + | QuoteError + | null = await (isCrosschainSwap ? getCrosschainQuote : getQuote)( + quoteParams + ); logger.debug('[getOutputAmount]: Got quote', { rand, quote }); if ( diff --git a/src/hooks/useSwapInputRefs.ts b/src/hooks/useSwapInputRefs.ts index c9eb3f5a107..67b43f63832 100644 --- a/src/hooks/useSwapInputRefs.ts +++ b/src/hooks/useSwapInputRefs.ts @@ -35,8 +35,11 @@ export default function useSwapInputRefs() { [inputCurrency, outputCurrency] ); - const { handleFocus, lastFocusedInputHandle, setLastFocusedInputHandle } = - useMagicAutofocus(inputFieldRef, findNextInput, true); + const { + handleFocus, + lastFocusedInputHandle, + setLastFocusedInputHandle, + } = useMagicAutofocus(inputFieldRef, findNextInput, true); return { handleFocus, diff --git a/src/hooks/useSwapRefuel.ts b/src/hooks/useSwapRefuel.ts index 0a51792bec9..29a0035811b 100644 --- a/src/hooks/useSwapRefuel.ts +++ b/src/hooks/useSwapRefuel.ts @@ -36,29 +36,38 @@ export default function useSwapRefuel({ const { accountAddress } = useAccountSettings(); const { selectedGasFee } = useGas(); - const [outputNativeAsset, setOutputNativeAsset] = - useState(); - const [inputNativeAsset, setInputNativeAsset] = - useState(); + const [ + outputNativeAsset, + setOutputNativeAsset, + ] = useState(); + const [ + inputNativeAsset, + setInputNativeAsset, + ] = useState(); - const { inputNetwork, outputNetwork, chainId, toChainId, isCrosschainSwap } = - useMemo(() => { - const inputNetwork = inputCurrency.network; - const outputNetwork = outputCurrency.network; - const chainId = ethereumUtils.getChainIdFromNetwork(inputNetwork); + const { + inputNetwork, + outputNetwork, + chainId, + toChainId, + isCrosschainSwap, + } = useMemo(() => { + const inputNetwork = inputCurrency.network; + const outputNetwork = outputCurrency.network; + const chainId = ethereumUtils.getChainIdFromNetwork(inputNetwork); - const toChainId = ethereumUtils.getChainIdFromNetwork(outputNetwork); - const isCrosschainSwap = - crosschainSwapsEnabled && inputNetwork !== outputNetwork; + const toChainId = ethereumUtils.getChainIdFromNetwork(outputNetwork); + const isCrosschainSwap = + crosschainSwapsEnabled && inputNetwork !== outputNetwork; - return { - inputNetwork, - outputNetwork, - chainId, - toChainId, - isCrosschainSwap, - }; - }, [crosschainSwapsEnabled, inputCurrency.network, outputCurrency.network]); + return { + inputNetwork, + outputNetwork, + chainId, + toChainId, + isCrosschainSwap, + }; + }, [crosschainSwapsEnabled, inputCurrency.network, outputCurrency.network]); const { data: minRefuelAmount } = useMinRefuelAmount( { diff --git a/src/hooks/useSwappableUserAssets.ts b/src/hooks/useSwappableUserAssets.ts index bee2d2b4e10..f642f4c8665 100644 --- a/src/hooks/useSwappableUserAssets.ts +++ b/src/hooks/useSwappableUserAssets.ts @@ -105,8 +105,9 @@ export const useSwappableUserAssets = (params: { ? ETH_ADDRESS_AGGREGATORS : asset?.address; - const isSwappable = - swappableAssetsRef.current[assetNetwork]?.includes(assetAddress); + const isSwappable = swappableAssetsRef.current[assetNetwork]?.includes( + assetAddress + ); return isSwappable; }), [filteredAssetsInWallet] @@ -122,8 +123,9 @@ export const useSwappableUserAssets = (params: { : asset?.address; // we place our testnets (goerli) in the Network type which creates this type issue // @ts-ignore - const isNotSwappable = - !swappableAssetsRef.current[assetNetwork]?.includes(assetAddress); + const isNotSwappable = !swappableAssetsRef.current[ + assetNetwork + ]?.includes(assetAddress); return isNotSwappable; }), [filteredAssetsInWallet] diff --git a/src/hooks/useTimeout.ts b/src/hooks/useTimeout.ts index e856b1bf31a..ab945cd5b30 100644 --- a/src/hooks/useTimeout.ts +++ b/src/hooks/useTimeout.ts @@ -3,7 +3,7 @@ import { MutableRefObject, useCallback, useEffect, useRef } from 'react'; export default function useTimeout(): [ (func: () => void, ms?: number) => void, () => void, - MutableRefObject, + MutableRefObject ] { const handle = useRef(null); diff --git a/src/hooks/useWalletSectionsData.ts b/src/hooks/useWalletSectionsData.ts index 6011e7ae1fe..c538fb8cc10 100644 --- a/src/hooks/useWalletSectionsData.ts +++ b/src/hooks/useWalletSectionsData.ts @@ -17,12 +17,18 @@ export default function useWalletSectionsData({ }: { type?: string; } = {}) { - const { isLoading: isLoadingUserAssets, data: sortedAssets = [] } = - useSortedUserAssets(); + const { + isLoading: isLoadingUserAssets, + data: sortedAssets = [], + } = useSortedUserAssets(); const isWalletEthZero = useIsWalletEthZero(); - const { accountAddress, language, network, nativeCurrency } = - useAccountSettings(); + const { + accountAddress, + language, + network, + nativeCurrency, + } = useAccountSettings(); const { sendableUniqueTokens } = useSendableUniqueTokens(); const { data: { nfts: allUniqueTokens }, @@ -33,8 +39,10 @@ export default function useWalletSectionsData({ const { hiddenTokens } = useHiddenTokens(); const { isReadOnlyWallet } = useWallets(); - const { hiddenCoinsObj: hiddenCoins, pinnedCoinsObj: pinnedCoins } = - useCoinListEditOptions(); + const { + hiddenCoinsObj: hiddenCoins, + pinnedCoinsObj: pinnedCoins, + } = useCoinListEditOptions(); const { isCoinListEdited } = useCoinListEdited(); diff --git a/src/hooks/useWatchPendingTxs.ts b/src/hooks/useWatchPendingTxs.ts index c91c067791e..32b0fbcc2ff 100644 --- a/src/hooks/useWatchPendingTxs.ts +++ b/src/hooks/useWatchPendingTxs.ts @@ -95,12 +95,14 @@ export const useWatchPendingTransactions = ({ let updatedTransaction: RainbowTransaction = { ...tx }; try { if (tx.network && tx.hash && address) { - updatedTransaction = - await processSupportedNetworkTransaction(updatedTransaction); + updatedTransaction = await processSupportedNetworkTransaction( + updatedTransaction + ); // if flashbots tx and no blockNumber, check if it failed if (!(tx as any).blockNumber && tx.flashbots) { - updatedTransaction = - await processFlashbotsTransaction(updatedTransaction); + updatedTransaction = await processFlashbotsTransaction( + updatedTransaction + ); } } else { throw new Error('Pending transaction missing chain id'); @@ -209,21 +211,23 @@ export const useWatchPendingTransactions = ({ processNonces(updatedPendingTransactions); - const { newPendingTransactions, minedTransactions } = - updatedPendingTransactions.reduce( - (acc, tx) => { - if (tx?.status === 'pending') { - acc.newPendingTransactions.push(tx); - } else { - acc.minedTransactions.push(tx as MinedTransaction); - } - return acc; - }, - { - newPendingTransactions: [] as RainbowTransaction[], - minedTransactions: [] as MinedTransaction[], + const { + newPendingTransactions, + minedTransactions, + } = updatedPendingTransactions.reduce( + (acc, tx) => { + if (tx?.status === 'pending') { + acc.newPendingTransactions.push(tx); + } else { + acc.minedTransactions.push(tx as MinedTransaction); } - ); + return acc; + }, + { + newPendingTransactions: [] as RainbowTransaction[], + minedTransactions: [] as MinedTransaction[], + } + ); if (minedTransactions.length) { console.log('we mined a transaction'); diff --git a/src/hooks/useWatchWallet.ts b/src/hooks/useWatchWallet.ts index d156fc63698..63eb03348da 100644 --- a/src/hooks/useWatchWallet.ts +++ b/src/hooks/useWatchWallet.ts @@ -57,10 +57,13 @@ export default function useWatchWallet({ ); const { accountAddress } = useAccountProfile(); - const { isImporting, handleSetSeedPhrase, handlePressImportButton } = - useImportingWallet({ - showImportModal, - }); + const { + isImporting, + handleSetSeedPhrase, + handlePressImportButton, + } = useImportingWallet({ + showImportModal, + }); const watchWallet = useCallback(async () => { if (!isWatching) { handleSetSeedPhrase(ensName ?? ''); diff --git a/src/keychain/index.ts b/src/keychain/index.ts index 799ac3306ab..240b5a1fce4 100644 --- a/src/keychain/index.ts +++ b/src/keychain/index.ts @@ -274,7 +274,7 @@ export async function set( * JSON. */ export async function getObject< - T extends Record = Record, + T extends Record = Record >(key: string, options: KeychainOptions = {}): Promise> { logger.debug(`keychain: getObject`, { key }, logger.DebugContext.keychain); diff --git a/src/model/backup.ts b/src/model/backup.ts index 92eb0d2b4df..8a8b66127b9 100644 --- a/src/model/backup.ts +++ b/src/model/backup.ts @@ -233,8 +233,7 @@ export const RestoreCloudBackupResultStates = { incorrectPinCode: 'incorrectPinCode', } as const; -type RestoreCloudBackupResultStatesType = - (typeof RestoreCloudBackupResultStates)[keyof typeof RestoreCloudBackupResultStates]; +type RestoreCloudBackupResultStatesType = typeof RestoreCloudBackupResultStates[keyof typeof RestoreCloudBackupResultStates]; /** * Restores a cloud backup. @@ -369,8 +368,7 @@ async function restoreCurrentBackupIntoKeychain( ): Promise { try { // Access control config per each type of key - const privateAccessControlOptions = - await keychain.getPrivateAccessControlOptions(); + const privateAccessControlOptions = await keychain.getPrivateAccessControlOptions(); const encryptedBackupPinData = backedUpData[pinKey]; const backupPIN = await decryptPIN(encryptedBackupPinData); diff --git a/src/model/migrations.ts b/src/model/migrations.ts index fbbb22cfc4d..019c412af77 100644 --- a/src/model/migrations.ts +++ b/src/model/migrations.ts @@ -387,9 +387,9 @@ export default async function runMigrations() { color: isNumber(contact.color) ? newColorIndexes[contact.color] : typeof contact.color === 'string' && - colors.avatarBackgrounds.includes(contact.color) - ? colors.avatarBackgrounds.indexOf(contact.color) - : getRandomColor(), + colors.avatarBackgrounds.includes(contact.color) + ? colors.avatarBackgrounds.indexOf(contact.color) + : getRandomColor(), }; } logger.log('update contacts to index new colors'); @@ -688,8 +688,10 @@ export default async function runMigrations() { ); if (favoritesMetadata) { - const lowercasedFavoritesMetadata: Record = - {}; + const lowercasedFavoritesMetadata: Record< + EthereumAddress, + RainbowToken + > = {}; Object.keys(favoritesMetadata).forEach((address: string) => { lowercasedFavoritesMetadata[address.toLowerCase()] = favoritesMetadata[address]; diff --git a/src/model/preferences.ts b/src/model/preferences.ts index f718fd657a1..46a1437f9e1 100644 --- a/src/model/preferences.ts +++ b/src/model/preferences.ts @@ -36,8 +36,9 @@ export async function setPreference( value?: any | undefined ): Promise { try { - const signature = - await getSignatureForSigningWalletAndCreateSignatureIfNeeded(address); + const signature = await getSignatureForSigningWalletAndCreateSignatureIfNeeded( + address + ); if (!signature) { return false; } @@ -55,8 +56,7 @@ export async function setPreference( signature, signature2, }); - const responseData: PreferencesResponse = - response.data as PreferencesResponse; + const responseData: PreferencesResponse = response.data as PreferencesResponse; logger.debug('☁️ RESPONSE', { reason: responseData?.reason, success: responseData?.success, @@ -78,8 +78,7 @@ export async function getPreference( const response = await preferencesAPI.get(`${PREFS_ENDPOINT}/${key}`, { params: { address }, }); - const responseData: PreferencesResponse = - response.data as PreferencesResponse; + const responseData: PreferencesResponse = response.data as PreferencesResponse; logger.debug('☁️ RESPONSE', { reason: responseData?.reason, success: responseData?.success, diff --git a/src/model/wallet.ts b/src/model/wallet.ts index 2b3c3753c7f..f0166e362f4 100644 --- a/src/model/wallet.ts +++ b/src/model/wallet.ts @@ -552,13 +552,12 @@ export const signTypedDataMessage = async ( } }; -export const oldLoadSeedPhrase = - async (): Promise => { - const seedPhrase = await keychain.loadString(seedPhraseKey, { - authenticationPrompt, - }); - return seedPhrase as string | null; - }; +export const oldLoadSeedPhrase = async (): Promise => { + const seedPhrase = await keychain.loadString(seedPhraseKey, { + authenticationPrompt, + }); + return seedPhrase as string | null; +}; export const loadAddress = (): Promise => keychain.loadString(addressKey) as Promise; @@ -1082,8 +1081,7 @@ export const savePrivateKey = async ( androidEncryptionPin, }: Pick = {} ) => { - const privateAccessControlOptions = - await keychain.getPrivateAccessControlOptions(); + const privateAccessControlOptions = await keychain.getPrivateAccessControlOptions(); const key = `${address}_${privateKeyKey}`; const val = { @@ -1180,8 +1178,7 @@ export const saveSeedPhrase = async ( androidEncryptionPin, }: Pick = {} ): Promise => { - const privateAccessControlOptions = - await keychain.getPrivateAccessControlOptions(); + const privateAccessControlOptions = await keychain.getPrivateAccessControlOptions(); const key = `${keychain_id}_${seedPhraseKey}`; const val = { id: keychain_id, @@ -1243,19 +1240,18 @@ export const setSelectedWallet = async ( ); }; -export const getSelectedWallet = - async (): Promise => { - try { - const selectedWalletData = await keychain.loadObject(selectedWalletKey); - if (selectedWalletData) { - return selectedWalletData as RainbowSelectedWalletData; - } - return null; - } catch (error) { - logger.error(new RainbowError('Error in getSelectedWallet'), { error }); - return null; +export const getSelectedWallet = async (): Promise => { + try { + const selectedWalletData = await keychain.loadObject(selectedWalletKey); + if (selectedWalletData) { + return selectedWalletData as RainbowSelectedWalletData; } - }; + return null; + } catch (error) { + logger.error(new RainbowError('Error in getSelectedWallet'), { error }); + return null; + } +}; export const saveAllWallets = async (wallets: AllRainbowWallets) => { const val = { @@ -1270,19 +1266,18 @@ export const saveAllWallets = async (wallets: AllRainbowWallets) => { ); }; -export const getAllWallets = - async (): Promise => { - try { - const allWallets = await keychain.loadObject(allWalletsKey); - if (allWallets) { - return allWallets as AllRainbowWalletsData; - } - return null; - } catch (error) { - logger.error(new RainbowError('Error in getAllWallets'), { error }); - return null; +export const getAllWallets = async (): Promise => { + try { + const allWallets = await keychain.loadObject(allWalletsKey); + if (allWallets) { + return allWallets as AllRainbowWalletsData; } - }; + return null; + } catch (error) { + logger.error(new RainbowError('Error in getAllWallets'), { error }); + return null; + } +}; let callbackAfterSeeds: null | (() => void) = null; export function setCallbackAfterObtainingSeedsFromKeychainOrError( @@ -1406,8 +1401,9 @@ const migrateSecrets = async (): Promise => { break; case EthereumWalletType.mnemonic: { - const { wallet: ethereumJSWallet } = - await deriveAccountFromMnemonic(seedphrase); + const { wallet: ethereumJSWallet } = await deriveAccountFromMnemonic( + seedphrase + ); if (!ethereumJSWallet) return null; const walletPkey = addHexPrefix( ethereumJSWallet.getPrivateKey().toString('hex') diff --git a/src/navigation/HardwareWalletTxNavigator.tsx b/src/navigation/HardwareWalletTxNavigator.tsx index 98d43459fd6..183eabb164b 100644 --- a/src/navigation/HardwareWalletTxNavigator.tsx +++ b/src/navigation/HardwareWalletTxNavigator.tsx @@ -65,8 +65,9 @@ export const HardwareWalletTxNavigator = () => { const deviceId = selectedWallet?.deviceId; const [isReady, setIsReady] = useRecoilState(LedgerIsReadyAtom); - const [readyForPolling, setReadyForPolling] = - useRecoilState(readyForPollingAtom); + const [readyForPolling, setReadyForPolling] = useRecoilState( + readyForPollingAtom + ); const [triggerPollerCleanup, setTriggerPollerCleanup] = useRecoilState( triggerPollerCleanupAtom ); diff --git a/src/navigation/PairHardwareWalletNavigator.tsx b/src/navigation/PairHardwareWalletNavigator.tsx index 8f9191ee8c5..87d52fbbc68 100644 --- a/src/navigation/PairHardwareWalletNavigator.tsx +++ b/src/navigation/PairHardwareWalletNavigator.tsx @@ -30,8 +30,9 @@ export const LedgerImportDeviceIdAtom = atom({ }); export function PairHardwareWalletNavigator() { - const { params } = - useRoute>(); + const { params } = useRoute< + RouteProp + >(); const { height, width } = useDimensions(); const [currentRouteName, setCurrentRouteName] = useState( diff --git a/src/navigation/RecyclerListViewScrollToTopContext.tsx b/src/navigation/RecyclerListViewScrollToTopContext.tsx index 7bcc13b2df4..aeb45bc46a5 100644 --- a/src/navigation/RecyclerListViewScrollToTopContext.tsx +++ b/src/navigation/RecyclerListViewScrollToTopContext.tsx @@ -14,13 +14,15 @@ type ScrollToTopProviderProps = { children: React.ReactNode; }; -const RecyclerListViewScrollToTopProvider: React.FC< - ScrollToTopProviderProps -> = ({ children }) => { +const RecyclerListViewScrollToTopProvider: React.FC = ({ + children, +}) => { const insets = useSafeAreaInsets(); - const [scrollToTopRef, setScrollToTopRef] = - useState(null); + const [ + scrollToTopRef, + setScrollToTopRef, + ] = useState(null); const scrollToTop = () => { scrollToTopRef?.scrollToOffset(0, -insets.top, true); diff --git a/src/navigation/RegisterENSNavigator.tsx b/src/navigation/RegisterENSNavigator.tsx index e4b96224aae..24c4c6f63f9 100644 --- a/src/navigation/RegisterENSNavigator.tsx +++ b/src/navigation/RegisterENSNavigator.tsx @@ -68,8 +68,11 @@ export default function RegisterENSNavigator() { const { clearValues } = useENSRegistrationForm(); - const { removeRecordByKey, clearCurrentRegistrationName, startRegistration } = - useENSRegistration(); + const { + removeRecordByKey, + clearCurrentRegistrationName, + startRegistration, + } = useENSRegistration(); const initialRouteName = useMemo(() => { const { ensName, mode } = params || { mode: REGISTRATION_MODES.CREATE }; @@ -90,10 +93,9 @@ export default function RegisterENSNavigator() { const [currentRouteName, setCurrentRouteName] = useState(initialRouteName); const previousRouteName = usePrevious(currentRouteName); - const screenOptions = useMemo( - () => defaultScreenOptions[currentRouteName], - [currentRouteName] - ); + const screenOptions = useMemo(() => defaultScreenOptions[currentRouteName], [ + currentRouteName, + ]); useEffect( () => () => { diff --git a/src/navigation/Routes.android.tsx b/src/navigation/Routes.android.tsx index 16c8ce162c8..65a72f857c5 100644 --- a/src/navigation/Routes.android.tsx +++ b/src/navigation/Routes.android.tsx @@ -93,7 +93,7 @@ const AuthStack = createStackNavigator(); const BSStack = createBottomSheetNavigator(); function MainNavigator() { - const initialRoute = useContext(InitialRouteContext) as unknown as string; + const initialRoute = (useContext(InitialRouteContext) as unknown) as string; return ( void; } -export const BottomSheetNavigatorContext = - createContext(null); +export const BottomSheetNavigatorContext = createContext( + null +); diff --git a/src/navigation/bottom-sheet/types.d.ts b/src/navigation/bottom-sheet/types.d.ts index 415ec86585a..6e8410d7f4b 100644 --- a/src/navigation/bottom-sheet/types.d.ts +++ b/src/navigation/bottom-sheet/types.d.ts @@ -41,7 +41,7 @@ export type BottomSheetNavigationHelpers = NavigationHelpers< export type BottomSheetNavigationProp< ParamList extends ParamListBase, - RouteName extends keyof ParamList = string, + RouteName extends keyof ParamList = string > = NavigationProp< ParamList, RouteName, @@ -53,7 +53,7 @@ export type BottomSheetNavigationProp< export type BottomSheetScreenProps< ParamList extends ParamListBase, - RouteName extends keyof ParamList = string, + RouteName extends keyof ParamList = string > = { navigation: BottomSheetNavigationProp; route: RouteProp; diff --git a/src/navigation/config.tsx b/src/navigation/config.tsx index 7e24f0e85c5..7a193411288 100644 --- a/src/navigation/config.tsx +++ b/src/navigation/config.tsx @@ -65,8 +65,8 @@ const buildCoolModalConfig = (params: any): CoolModalConfigOptions => ({ ? 30 : 0.666 // 0.666 gets the screen corner radius internally : params.cornerRadius === 0 - ? 0 - : params.cornerRadius || 39, + ? 0 + : params.cornerRadius || 39, customStack: true, disableShortFormAfterTransitionToLongForm: params.disableShortFormAfterTransitionToLongForm || @@ -294,18 +294,17 @@ export const qrScannerConfig: PartialNavigatorConfigOptions = { }), }; -export const pairHardwareWalletNavigatorConfig: PartialNavigatorConfigOptions = - { - options: ({ route: { params = {} } }) => ({ - ...buildCoolModalConfig({ - ...params, - backgroundOpacity: 1, - scrollEnabled: true, - springDamping: 1, - transitionDuration: 0.2, - }), +export const pairHardwareWalletNavigatorConfig: PartialNavigatorConfigOptions = { + options: ({ route: { params = {} } }) => ({ + ...buildCoolModalConfig({ + ...params, + backgroundOpacity: 1, + scrollEnabled: true, + springDamping: 1, + transitionDuration: 0.2, }), - }; + }), +}; export const hardwareWalletTxNavigatorConfig: PartialNavigatorConfigOptions = { options: ({ route: { params = {} } }) => ({ @@ -449,16 +448,15 @@ export const expandedAssetSheetConfig: PartialNavigatorConfigOptions = { }), }; -export const expandedAssetSheetConfigWithLimit: PartialNavigatorConfigOptions = - { - options: ({ route: { params = {} } }) => ({ - ...buildCoolModalConfig({ - ...params, - scrollEnabled: true, - }), - limitActiveModals: true, +export const expandedAssetSheetConfigWithLimit: PartialNavigatorConfigOptions = { + options: ({ route: { params = {} } }) => ({ + ...buildCoolModalConfig({ + ...params, + scrollEnabled: true, }), - }; + limitActiveModals: true, + }), +}; export const restoreSheetConfig: PartialNavigatorConfigOptions = { // @ts-ignore @@ -523,13 +521,12 @@ export const nativeStackDefaultConfig: CoolModalConfigOptions = { transitionDuration: 0.3, }; -export const nativeStackDefaultConfigWithoutStatusBar: CoolModalConfigOptions = - { - ...nativeStackDefaultConfig, - onWillDismiss: () => { - onWillPop(); - }, - }; +export const nativeStackDefaultConfigWithoutStatusBar: CoolModalConfigOptions = { + ...nativeStackDefaultConfig, + onWillDismiss: () => { + onWillPop(); + }, +}; export const exchangeTabNavigatorConfig = { initialLayout: deviceUtils.dimensions, diff --git a/src/navigation/effects.tsx b/src/navigation/effects.tsx index e0178cd9d7d..70c4941da2d 100644 --- a/src/navigation/effects.tsx +++ b/src/navigation/effects.tsx @@ -130,33 +130,34 @@ const exchangeStyleInterpolator = ({ }; }; -export const expandStyleInterpolator = - (targetOpacity: number) => - ({ current: { progress: current }, layouts: { screen } }: any) => { - const backgroundOpacity = current.interpolate({ - inputRange: [-1, 0, 0.975, 2], - outputRange: [0, 0, targetOpacity, targetOpacity], - }); +export const expandStyleInterpolator = (targetOpacity: number) => ({ + current: { progress: current }, + layouts: { screen }, +}: any) => { + const backgroundOpacity = current.interpolate({ + inputRange: [-1, 0, 0.975, 2], + outputRange: [0, 0, targetOpacity, targetOpacity], + }); - const translateY = current.interpolate({ - inputRange: [0, 1, 2], - outputRange: [screen.height, 0, -screen.height / 3], - }); + const translateY = current.interpolate({ + inputRange: [0, 1, 2], + outputRange: [screen.height, 0, -screen.height / 3], + }); - return { - cardStyle: { - shadowColor: colors.themedColors?.shadow, - shadowOffset: { height: 10, width: 0 }, - shadowOpacity: 0.5, - shadowRadius: 25, - transform: [{ translateY }], - }, - overlayStyle: { - backgroundColor: lightModeThemeColors.blueGreyDarker, - opacity: backgroundOpacity, - }, - }; + return { + cardStyle: { + shadowColor: colors.themedColors?.shadow, + shadowOffset: { height: 10, width: 0 }, + shadowOpacity: 0.5, + shadowRadius: 25, + transform: [{ translateY }], + }, + overlayStyle: { + backgroundColor: lightModeThemeColors.blueGreyDarker, + opacity: backgroundOpacity, + }, }; +}; const savingsStyleInterpolator = ({ current: { progress: current }, @@ -188,34 +189,35 @@ const savingsStyleInterpolator = ({ }; }; -const sheetStyleInterpolator = - (targetOpacity = 1) => - ({ current: { progress: current }, layouts: { screen } }: any) => { - const backgroundOpacity = current.interpolate({ - inputRange: [-1, 0, 0.975, 2], - outputRange: [0, 0, targetOpacity, targetOpacity], - }); +const sheetStyleInterpolator = (targetOpacity = 1) => ({ + current: { progress: current }, + layouts: { screen }, +}: any) => { + const backgroundOpacity = current.interpolate({ + inputRange: [-1, 0, 0.975, 2], + outputRange: [0, 0, targetOpacity, targetOpacity], + }); - const translateY = current.interpolate({ - extrapolate: 'clamp', - inputRange: [0, 1], - outputRange: [screen.height, 0], - }); + const translateY = current.interpolate({ + extrapolate: 'clamp', + inputRange: [0, 1], + outputRange: [screen.height, 0], + }); - return { - cardStyle: { - shadowColor: colors.themedColors?.shadowBlack, - shadowOffset: { height: 10, width: 0 }, - shadowOpacity: 0.6, - shadowRadius: 25, - transform: [{ translateY }], - }, - overlayStyle: { - backgroundColor: lightModeThemeColors.shadowBlack, - opacity: backgroundOpacity, - }, - }; + return { + cardStyle: { + shadowColor: colors.themedColors?.shadowBlack, + shadowOffset: { height: 10, width: 0 }, + shadowOpacity: 0.6, + shadowRadius: 25, + transform: [{ translateY }], + }, + overlayStyle: { + backgroundColor: lightModeThemeColors.shadowBlack, + opacity: backgroundOpacity, + }, }; +}; const swapDetailInterpolator = ({ current: { progress: current }, diff --git a/src/navigation/onNavigationStateChange.js b/src/navigation/onNavigationStateChange.js index 51507d8eb04..8c11e49e73a 100644 --- a/src/navigation/onNavigationStateChange.js +++ b/src/navigation/onNavigationStateChange.js @@ -34,8 +34,8 @@ export function onHandleStatusBar(currentState, prevState) { StatusBarHelper.setLightContent(); return; } - const isFromWalletScreen = - Navigation.getActiveRoute()?.params?.isFromWalletScreen; + const isFromWalletScreen = Navigation.getActiveRoute()?.params + ?.isFromWalletScreen; const isRoutesLengthDecrease = prevState?.routes.length > currentState?.routes.length; diff --git a/src/notifications/NotificationsHandler.tsx b/src/notifications/NotificationsHandler.tsx index b36e244a048..25621f65243 100644 --- a/src/notifications/NotificationsHandler.tsx +++ b/src/notifications/NotificationsHandler.tsx @@ -70,8 +70,7 @@ export const NotificationsHandler = ({ walletReady }: Props) => { const dispatch: ThunkDispatch = useDispatch(); const walletsRef = useRef(wallets); const prevWalletReady = usePrevious(walletReady); - const subscriptionChangesListener = - useRef(); + const subscriptionChangesListener = useRef(); const onTokenRefreshListener = useRef(); const foregroundNotificationListener = useRef(); const notificationOpenedListener = useRef(); @@ -180,7 +179,7 @@ export const NotificationsHandler = ({ walletReady }: Props) => { } // casting data payload to type that was agreed on with backend - const data = notification.data as unknown as TransactionNotificationData; + const data = (notification.data as unknown) as TransactionNotificationData; const wallets = walletsRef.current; const { accountAddress, nativeCurrency } = store.getState().settings; @@ -308,7 +307,7 @@ export const NotificationsHandler = ({ walletReady }: Props) => { logger.info(`NotificationsHandler: handling marketing notification`, { notification, }); - const data = notification.data as unknown as MarketingNotificationData; + const data = (notification.data as unknown) as MarketingNotificationData; if (data?.route) { const parsedProps = JSON.parse(data?.routeProps || '{}'); Navigation.handleAction((Routes as any)[data.route], { @@ -326,8 +325,7 @@ export const NotificationsHandler = ({ walletReady }: Props) => { setupAndroidChannels(); saveFCMToken(); trackWalletsSubscribedForNotifications(); - subscriptionChangesListener.current = - registerNotificationSubscriptionChangesListener(); + subscriptionChangesListener.current = registerNotificationSubscriptionChangesListener(); onTokenRefreshListener.current = registerTokenRefreshListener(); foregroundNotificationListener.current = messaging().onMessage( onForegroundRemoteNotification diff --git a/src/notifications/analytics.ts b/src/notifications/analytics.ts index 6d1c679fe63..59fd786a49d 100644 --- a/src/notifications/analytics.ts +++ b/src/notifications/analytics.ts @@ -89,24 +89,23 @@ export type NotificationSubscriptionChangesListener = { remove: () => void; }; -export const registerNotificationSubscriptionChangesListener = - (): NotificationSubscriptionChangesListener => { - return notificationSettingsStorage.addOnValueChangedListener(key => { - if (key === WALLET_GROUPS_STORAGE_KEY) { - const stringValue = notificationSettingsStorage.getString(key); - if (stringValue) { - const value = JSON.parse(stringValue) as GroupSettings; - onGroupStateChange(value); - } - } else if (key === WALLET_TOPICS_STORAGE_KEY) { - const stringValue = notificationSettingsStorage.getString(key); - if (stringValue) { - const value = JSON.parse(stringValue); - onTopicsStateChange(value); - } +export const registerNotificationSubscriptionChangesListener = (): NotificationSubscriptionChangesListener => { + return notificationSettingsStorage.addOnValueChangedListener(key => { + if (key === WALLET_GROUPS_STORAGE_KEY) { + const stringValue = notificationSettingsStorage.getString(key); + if (stringValue) { + const value = JSON.parse(stringValue) as GroupSettings; + onGroupStateChange(value); } - }); - }; + } else if (key === WALLET_TOPICS_STORAGE_KEY) { + const stringValue = notificationSettingsStorage.getString(key); + if (stringValue) { + const value = JSON.parse(stringValue); + onTopicsStateChange(value); + } + } + }); +}; const onGroupStateChange = (state: GroupSettings) => { const stringValue = notificationSettingsStorage.getString( diff --git a/src/notifications/settings/hooks.ts b/src/notifications/settings/hooks.ts index 1580e38a595..cd8a90cc3f0 100644 --- a/src/notifications/settings/hooks.ts +++ b/src/notifications/settings/hooks.ts @@ -24,19 +24,21 @@ import { Hook to constantly listen to notification settings. */ export const useAllNotificationSettingsFromStorage = () => { - const walletNotificationSettingsData = - getAllWalletNotificationSettingsFromStorage(); - const globalNotificationSettingsData = - getAllGlobalNotificationSettingsFromStorage(); + const walletNotificationSettingsData = getAllWalletNotificationSettingsFromStorage(); + const globalNotificationSettingsData = getAllGlobalNotificationSettingsFromStorage(); const existingGroupSettingsData = getExistingGroupSettingsFromStorage(); const [walletNotificationSettings, setWalletNotificationSettings] = useState< WalletNotificationSettings[] >(walletNotificationSettingsData); - const [globalNotificationSettings, setGlobalNotificationSettings] = - useState(globalNotificationSettingsData); - const [existingGroupSettings, setExistingGroupSettings] = - useState(existingGroupSettingsData); + const [ + globalNotificationSettings, + setGlobalNotificationSettings, + ] = useState(globalNotificationSettingsData); + const [ + existingGroupSettings, + setExistingGroupSettings, + ] = useState(existingGroupSettingsData); const listener = notificationSettingsStorage.addOnValueChangedListener( changedKey => { if (changedKey === WALLET_TOPICS_STORAGE_KEY) { @@ -69,8 +71,10 @@ export const useAllNotificationSettingsFromStorage = () => { Provides a function for updating the group settings. */ export const useWalletGroupNotificationSettings = () => { - const { walletNotificationSettings, existingGroupSettings } = - useAllNotificationSettingsFromStorage(); + const { + walletNotificationSettings, + existingGroupSettings, + } = useAllNotificationSettingsFromStorage(); const ownerEnabled = existingGroupSettings[WalletNotificationRelationship.OWNER]; diff --git a/src/notifications/settings/initialization.ts b/src/notifications/settings/initialization.ts index 8cbc4ed84db..631dab3e076 100644 --- a/src/notifications/settings/initialization.ts +++ b/src/notifications/settings/initialization.ts @@ -69,34 +69,35 @@ export const initializeGlobalNotificationSettings = () => { * schedules subscribing to owned wallets that haven't been initialized yet * schedules removing settings for wallets that are no longer prersent but removal failed previously */ -export const initializeNotificationSettingsForAllAddressesAndCleanupSettingsForRemovedWallets = - (addresses: AddressWithRelationship[]) => { - const initializationState = _prepareInitializationState(); - // Set of wallet addresses we have in app (unrelated to notification settings entries) - const walletAddresses = new Set( - addresses.map(addressWithRelationship => addressWithRelationship.address) - ); - const removedWalletsThatWereNotUnsubscribedProperly: string[] = [ - ...initializationState.alreadySaved.keys(), - ].filter(address => !walletAddresses.has(address)); +export const initializeNotificationSettingsForAllAddressesAndCleanupSettingsForRemovedWallets = ( + addresses: AddressWithRelationship[] +) => { + const initializationState = _prepareInitializationState(); + // Set of wallet addresses we have in app (unrelated to notification settings entries) + const walletAddresses = new Set( + addresses.map(addressWithRelationship => addressWithRelationship.address) + ); + const removedWalletsThatWereNotUnsubscribedProperly: string[] = [ + ...initializationState.alreadySaved.keys(), + ].filter(address => !walletAddresses.has(address)); - const queue = _prepareSubscriptionQueueAndCreateInitialSettings( - addresses, - initializationState - ); + const queue = _prepareSubscriptionQueueAndCreateInitialSettings( + addresses, + initializationState + ); - InteractionManager.runAfterInteractions(() => { - _processSubscriptionQueue(queue); - }); + InteractionManager.runAfterInteractions(() => { + _processSubscriptionQueue(queue); + }); - if (removedWalletsThatWereNotUnsubscribedProperly.length) { - InteractionManager.runAfterInteractions(() => { - removedWalletsThatWereNotUnsubscribedProperly.forEach(address => { - removeNotificationSettingsForWallet(address); - }); + if (removedWalletsThatWereNotUnsubscribedProperly.length) { + InteractionManager.runAfterInteractions(() => { + removedWalletsThatWereNotUnsubscribedProperly.forEach(address => { + removeNotificationSettingsForWallet(address); }); - } - }; + }); + } +}; /** * Adds fresh disabled settings for all wallets that didn't have settings diff --git a/src/notifications/settings/types.ts b/src/notifications/settings/types.ts index 83ad972501b..25331590548 100644 --- a/src/notifications/settings/types.ts +++ b/src/notifications/settings/types.ts @@ -4,14 +4,11 @@ import { WalletNotificationTopic, } from '@/notifications/settings/constants'; -export type WalletNotificationTopicType = - (typeof WalletNotificationTopic)[keyof typeof WalletNotificationTopic]; +export type WalletNotificationTopicType = typeof WalletNotificationTopic[keyof typeof WalletNotificationTopic]; -export type GlobalNotificationTopicType = - (typeof GlobalNotificationTopic)[keyof typeof GlobalNotificationTopic]; +export type GlobalNotificationTopicType = typeof GlobalNotificationTopic[keyof typeof GlobalNotificationTopic]; -export type WalletNotificationRelationshipType = - (typeof WalletNotificationRelationship)[keyof typeof WalletNotificationRelationship]; +export type WalletNotificationRelationshipType = typeof WalletNotificationRelationship[keyof typeof WalletNotificationRelationship]; export type WalletNotificationTopics = { [key: WalletNotificationTopicType]: boolean; diff --git a/src/notifications/types.ts b/src/notifications/types.ts index 1ab6edb57c5..8d92896ced5 100644 --- a/src/notifications/types.ts +++ b/src/notifications/types.ts @@ -6,8 +6,7 @@ export const NotificationTypes = { marketing: 'marketing', } as const; -export type NotificationTypesType = - (typeof NotificationTypes)[keyof typeof NotificationTypes]; +export type NotificationTypesType = typeof NotificationTypes[keyof typeof NotificationTypes]; // FCM sends a different kind than the typings cover export interface FixedRemoteMessage @@ -45,8 +44,7 @@ export const NotificationTransactionTypes = { withdraw: 'withdraw', } as const; -export type NotificationTransactionTypesType = - (typeof NotificationTransactionTypes)[keyof typeof NotificationTransactionTypes]; +export type NotificationTransactionTypesType = typeof NotificationTransactionTypes[keyof typeof NotificationTransactionTypes]; export interface MarketingNotificationData { type: 'marketing'; diff --git a/src/parsers/accounts.js b/src/parsers/accounts.js index 55f947faf9b..d221e6eb2f5 100644 --- a/src/parsers/accounts.js +++ b/src/parsers/accounts.js @@ -73,10 +73,8 @@ export const parseAssetNative = (asset, nativeCurrency) => { change: isLowerCaseMatch(asset.symbol, nativeCurrency) ? null : assetNativePrice.relative_change_24h - ? convertAmountToPercentageDisplay( - assetNativePrice.relative_change_24h - ) - : '', + ? convertAmountToPercentageDisplay(assetNativePrice.relative_change_24h) + : '', price: { amount: priceUnit, display: convertAmountToNativeDisplay(priceUnit, nativeCurrency), diff --git a/src/performance/tracking/types/PerformanceMetrics.ts b/src/performance/tracking/types/PerformanceMetrics.ts index feda5714cd0..12b23a8f081 100644 --- a/src/performance/tracking/types/PerformanceMetrics.ts +++ b/src/performance/tracking/types/PerformanceMetrics.ts @@ -10,5 +10,4 @@ export const PerformanceMetrics = { useInitializeWallet: 'Performance Wallet Initialize Time', } as const; -export type PerformanceMetricsType = - (typeof PerformanceMetrics)[keyof typeof PerformanceMetrics]; +export type PerformanceMetricsType = typeof PerformanceMetrics[keyof typeof PerformanceMetrics]; diff --git a/src/performance/tracking/types/PerformanceTags.ts b/src/performance/tracking/types/PerformanceTags.ts index 9893221d5dc..5ee88f42fac 100644 --- a/src/performance/tracking/types/PerformanceTags.ts +++ b/src/performance/tracking/types/PerformanceTags.ts @@ -2,5 +2,4 @@ export const PerformanceTags = { lodash: 'lodash', } as const; -export type PerformanceTagsType = - (typeof PerformanceTags)[keyof typeof PerformanceTags]; +export type PerformanceTagsType = typeof PerformanceTags[keyof typeof PerformanceTags]; diff --git a/src/raps/actions/crosschainSwap.ts b/src/raps/actions/crosschainSwap.ts index 58d5f66a350..a00e8882f2b 100644 --- a/src/raps/actions/crosschainSwap.ts +++ b/src/raps/actions/crosschainSwap.ts @@ -82,8 +82,12 @@ const crosschainSwap = async ( baseNonce?: number ): Promise => { logger.log(`[${actionName}] base nonce`, baseNonce, 'index:', index); - const { inputAmount, tradeDetails, chainId, requiresApprove } = - parameters as CrosschainSwapActionParameters; + const { + inputAmount, + tradeDetails, + chainId, + requiresApprove, + } = parameters as CrosschainSwapActionParameters; const { dispatch } = store; const { accountAddress } = store.getState().settings; const { inputCurrency, outputCurrency } = store.getState().swap; diff --git a/src/raps/actions/ens.ts b/src/raps/actions/ens.ts index b16bfa4b158..fa66c1307d8 100644 --- a/src/raps/actions/ens.ts +++ b/src/raps/actions/ens.ts @@ -333,8 +333,15 @@ const ensAction = async ( const { accountAddress: ownerAddress } = store.getState().settings; const { selectedGasFee } = store.getState().gas; - const { name, duration, rentPrice, records, salt, toAddress, mode } = - parameters; + const { + name, + duration, + rentPrice, + records, + salt, + toAddress, + mode, + } = parameters; logger.log(`[${actionName}] rap for`, name); diff --git a/src/raps/actions/swap.ts b/src/raps/actions/swap.ts index 3d257291905..fd5fadb5b54 100644 --- a/src/raps/actions/swap.ts +++ b/src/raps/actions/swap.ts @@ -134,8 +134,13 @@ const swap = async ( baseNonce?: number ): Promise => { logger.log(`[${actionName}] base nonce`, baseNonce, 'index:', index); - const { inputAmount, tradeDetails, permit, chainId, requiresApprove } = - parameters as SwapActionParameters; + const { + inputAmount, + tradeDetails, + permit, + chainId, + requiresApprove, + } = parameters as SwapActionParameters; const { dispatch } = store; const { accountAddress } = store.getState().settings; const { inputCurrency, outputCurrency } = store.getState().swap; diff --git a/src/raps/actions/unlock.ts b/src/raps/actions/unlock.ts index ce9f1b07b86..6b061b4b7ea 100644 --- a/src/raps/actions/unlock.ts +++ b/src/raps/actions/unlock.ts @@ -131,8 +131,11 @@ const unlock = async ( const { dispatch } = store; const { accountAddress } = store.getState().settings; const { gasFeeParamsBySpeed, selectedGasFee } = store.getState().gas; - const { assetToUnlock, contractAddress, chainId } = - parameters as UnlockActionParameters; + const { + assetToUnlock, + contractAddress, + chainId, + } = parameters as UnlockActionParameters; const { address: assetAddress } = assetToUnlock; logger.log(`[${actionName}] rap for`, assetToUnlock); @@ -188,8 +191,7 @@ const unlock = async ( throw e; } const walletAddress = await wallet.getAddress(); - const cacheKey = - `${walletAddress}|${assetAddress}|${contractAddress}`.toLowerCase(); + const cacheKey = `${walletAddress}|${assetAddress}|${contractAddress}`.toLowerCase(); // Cache the approved value AllowancesCache.cache[cacheKey] = MaxUint256.toString(); @@ -230,8 +232,7 @@ export const assetNeedsUnlocking = async ( if (address === ETH_ADDRESS) return false; if (alwaysRequireApprove) return true; - const cacheKey = - `${accountAddress}|${address}|${contractAddress}`.toLowerCase(); + const cacheKey = `${accountAddress}|${address}|${contractAddress}`.toLowerCase(); const allowance = await getRawAllowance( accountAddress, diff --git a/src/raps/registerENS.ts b/src/raps/registerENS.ts index c3a513fffbc..0afc52076e1 100644 --- a/src/raps/registerENS.ts +++ b/src/raps/registerENS.ts @@ -131,8 +131,13 @@ export const createTransferENSRap = async ( ) => { let actions: RapENSAction[] = []; - const { clearRecords, records, setAddress, transferControl, toAddress } = - ensActionParameters; + const { + clearRecords, + records, + setAddress, + transferControl, + toAddress, + } = ensActionParameters; if (clearRecords) { const emptyRecords = Object.keys(records ?? {}).reduce( diff --git a/src/react-native-animated-charts/Example/src/BasicExample/index.js b/src/react-native-animated-charts/Example/src/BasicExample/index.js index 2ddf47f2df4..786df331da3 100644 --- a/src/react-native-animated-charts/Example/src/BasicExample/index.js +++ b/src/react-native-animated-charts/Example/src/BasicExample/index.js @@ -32,14 +32,12 @@ const BasicExample = () => ( + }}> + }}> + }}> {/**/} {/* Generic Example (swipe right for a real-life example)*/} @@ -148,8 +148,7 @@ function GenericExample() { + }}> Yes @@ -157,8 +156,7 @@ function GenericExample() { + }}> No @@ -168,28 +166,24 @@ function GenericExample() { setSmoothingWhileTransitioningEnabled(true)} - > + onPress={() => setSmoothingWhileTransitioningEnabled(true)}> + }}> Yes setSmoothingWhileTransitioningEnabled(false)} - > + onPress={() => setSmoothingWhileTransitioningEnabled(false)}> + }}> No @@ -200,8 +194,7 @@ function GenericExample() { + }}> 0 @@ -209,8 +202,7 @@ function GenericExample() { + }}> 30 @@ -218,8 +210,7 @@ function GenericExample() { + }}> 50 @@ -256,8 +247,7 @@ function GenericExample() { Pick range: + style={{flexDirection: 'row', justifyContent: 'space-around'}}> setPickRange(2)}> 2 @@ -270,15 +260,13 @@ function GenericExample() { setPickRange(10)}> + style={{color: pickRange === 10 ? 'lightgreen' : 'white'}}> 10 setPickRange(25)}> + style={{color: pickRange === 25 ? 'lightgreen' : 'white'}}> 25 @@ -287,8 +275,7 @@ function GenericExample() { Include extremes: + style={{flexDirection: 'row', justifyContent: 'space-around'}}> setIncludeExtremes(true)}> Yes @@ -296,8 +283,7 @@ function GenericExample() { setIncludeExtremes(false)}> + style={{color: !includeExtremes ? 'lightgreen' : 'white'}}> No @@ -313,8 +299,7 @@ function GenericExample() { style={{ color: interpolationStrategy === 'none' ? 'lightgreen' : 'white', - }} - > + }}> None @@ -322,8 +307,7 @@ function GenericExample() { + }}> B Spline @@ -332,8 +316,7 @@ function GenericExample() { style={{ color: interpolationStrategy === 'mono' ? 'lightgreen' : 'white', - }} - > + }}> Monotone Qubic Spline @@ -344,14 +327,12 @@ function GenericExample() { BSpline degree: + style={{flexDirection: 'row', justifyContent: 'space-around'}}> setBSplineDegree(2)}> + }}> 2 @@ -359,8 +340,7 @@ function GenericExample() { + }}> 3 @@ -368,8 +348,7 @@ function GenericExample() { + }}> 4 @@ -377,8 +356,7 @@ function GenericExample() { + }}> 5 @@ -391,61 +369,52 @@ function GenericExample() { Number of points Interpolated: + style={{flexDirection: 'row', justifyContent: 'space-around'}}> setNumberOfPointsInterpolated(30)} - > + onPress={() => setNumberOfPointsInterpolated(30)}> + }}> 30 setNumberOfPointsInterpolated(80)} - > + onPress={() => setNumberOfPointsInterpolated(80)}> + }}> 80 setNumberOfPointsInterpolated(120)} - > + onPress={() => setNumberOfPointsInterpolated(120)}> + }}> 120 setNumberOfPointsInterpolated(200)} - > + onPress={() => setNumberOfPointsInterpolated(200)}> + }}> 200 @@ -460,8 +429,7 @@ function GenericExample() { + }}> None @@ -469,8 +437,7 @@ function GenericExample() { + }}> Simple (Quadratic bezier with fixed points) @@ -480,8 +447,7 @@ function GenericExample() { + }}> Complex (Cubic bezier) @@ -489,8 +455,7 @@ function GenericExample() { + }}> Bezier @@ -501,14 +466,12 @@ function GenericExample() { Smoothing factor: + style={{flexDirection: 'row', justifyContent: 'space-around'}}> setSmoothingFactor(0.05)}> + }}> 0.05 @@ -516,8 +479,7 @@ function GenericExample() { + }}> 0.1 @@ -525,8 +487,7 @@ function GenericExample() { + }}> 0.2 @@ -534,8 +495,7 @@ function GenericExample() { + }}> 0.3 @@ -543,8 +503,7 @@ function GenericExample() { + }}> 0.5 @@ -552,8 +511,7 @@ function GenericExample() { + }}> 0.7 @@ -561,8 +519,7 @@ function GenericExample() { + }}> 0.9 diff --git a/src/react-native-animated-charts/src/charts/linear/ChartLabels.tsx b/src/react-native-animated-charts/src/charts/linear/ChartLabels.tsx index 7186a49ec83..2a5980bd835 100644 --- a/src/react-native-animated-charts/src/charts/linear/ChartLabels.tsx +++ b/src/react-native-animated-charts/src/charts/linear/ChartLabels.tsx @@ -16,10 +16,11 @@ const ChartLabelFactory = (fieldName: 'originalX' | 'originalY') => { // we need to recreate defaultValue on data change // eslint-disable-next-line react-hooks/exhaustive-deps - const defaultValue = useMemo( - () => format?.(val.value) ?? val.value, - [format, val, data] - ); + const defaultValue = useMemo(() => format?.(val.value) ?? val.value, [ + format, + val, + data, + ]); const textProps = useAnimatedProps( () => ({ diff --git a/src/react-native-animated-charts/src/charts/linear/ChartPath.tsx b/src/react-native-animated-charts/src/charts/linear/ChartPath.tsx index 06f66f8d610..7fa20ca46bf 100644 --- a/src/react-native-animated-charts/src/charts/linear/ChartPath.tsx +++ b/src/react-native-animated-charts/src/charts/linear/ChartPath.tsx @@ -305,63 +305,62 @@ const ChartPathInner = React.memo( return props; }, [currentPath]); - const onGestureEvent = - useAnimatedGestureHandler( - { - onActive: event => { - if (!isActive.value) { - isActive.value = true; - - pathOpacity.value = withTiming( - 0, - timingFeedbackConfig || timingFeedbackDefaultConfig - ); - - if (hapticsEnabled) { - impactHeavy(); - } - } + const onGestureEvent = useAnimatedGestureHandler( + { + onActive: event => { + if (!isActive.value) { + isActive.value = true; - state.value = event.state; - translationX.value = positionXWithMargin(event.x, hitSlop, width); - translationY.value = event.y; - }, - onCancel: event => { - state.value = event.state; - resetGestureState(); - }, - onEnd: event => { - state.value = event.state; - resetGestureState(); + pathOpacity.value = withTiming( + 0, + timingFeedbackConfig || timingFeedbackDefaultConfig + ); if (hapticsEnabled) { impactHeavy(); } - }, - onFail: event => { + } + + state.value = event.state; + translationX.value = positionXWithMargin(event.x, hitSlop, width); + translationY.value = event.y; + }, + onCancel: event => { + state.value = event.state; + resetGestureState(); + }, + onEnd: event => { + state.value = event.state; + resetGestureState(); + + if (hapticsEnabled) { + impactHeavy(); + } + }, + onFail: event => { + state.value = event.state; + resetGestureState(); + }, + onStart: event => { + // WARNING: the following code does not run on using iOS, but it does on Android. + // I use the same code from onActive + // platform is for safety + if (Platform.OS === 'android') { state.value = event.state; - resetGestureState(); - }, - onStart: event => { - // WARNING: the following code does not run on using iOS, but it does on Android. - // I use the same code from onActive - // platform is for safety - if (Platform.OS === 'android') { - state.value = event.state; - isActive.value = true; - pathOpacity.value = withTiming( - 0, - timingFeedbackConfig || timingFeedbackDefaultConfig - ); - - if (hapticsEnabled) { - impactHeavy(); - } + isActive.value = true; + pathOpacity.value = withTiming( + 0, + timingFeedbackConfig || timingFeedbackDefaultConfig + ); + + if (hapticsEnabled) { + impactHeavy(); } - }, + } }, - [width, height, hapticsEnabled, hitSlop, timingFeedbackConfig] - ); + }, + [width, height, hapticsEnabled, hitSlop, timingFeedbackConfig] + ); const pathAnimatedStyles = useAnimatedStyle(() => { return { diff --git a/src/react-native-animated-charts/src/helpers/d3Interpolate.js b/src/react-native-animated-charts/src/helpers/d3Interpolate.js index 44761b117a7..93b516176a9 100644 --- a/src/react-native-animated-charts/src/helpers/d3Interpolate.js +++ b/src/react-native-animated-charts/src/helpers/d3Interpolate.js @@ -610,7 +610,8 @@ export function d3Interpolate() { return extended.concat( splitSegment(commandsToExtend[i], commandsToExtend[i + 1], segmentCount) ); - }, []); // add in the very first point since splitSegment only adds in the ones after it + }, + []); // add in the very first point since splitSegment only adds in the ones after it extended.unshift(commandsToExtend[0]); return extended; diff --git a/src/react-query/types.ts b/src/react-query/types.ts index 2a9d0113def..822898a7f48 100644 --- a/src/react-query/types.ts +++ b/src/react-query/types.ts @@ -7,12 +7,14 @@ import { } from '@tanstack/react-query'; // Used to obtain argument types for query functions. -export type QueryFunctionArgs any> = - QueryFunctionContext>; +export type QueryFunctionArgs< + T extends (...args: any) => any +> = QueryFunctionContext>; // Used to obtain types for query function results. -export type QueryFunctionResult any> = - PromiseValue>; +export type QueryFunctionResult< + FnType extends (...args: any) => any +> = PromiseValue>; // Note: we probably want to restrict the amount of configuration // to the React Query hook. So we are picking out the only the @@ -22,7 +24,7 @@ export type QueryConfigWithSelect< TQueryFnData, TError, TData, - TQueryKey extends QueryKey, + TQueryKey extends QueryKey > = Pick< UseQueryOptions, | 'cacheTime' @@ -78,26 +80,28 @@ export type MutationConfig = Pick< >; // Used to obtain types for mutation function results. -export type MutationFunctionResult any> = - PromiseValue>; +export type MutationFunctionResult< + FnType extends (...args: any) => any +> = PromiseValue>; // ////////////////////////////////////////////////////////////////////////////////////// // Deprecated Types -type PromiseValue = - PromiseType extends PromiseLike - ? PromiseValue - : PromiseType; +type PromiseValue = PromiseType extends PromiseLike + ? PromiseValue + : PromiseType; type ExtractFnReturnType any> = PromiseValue< ReturnType >; -export type UseQueryData any> = - ExtractFnReturnType; +export type UseQueryData< + QueryFnType extends (...args: any) => any +> = ExtractFnReturnType; -export type QueryConfigDeprecated any> = - Omit< - UseQueryOptions>, - 'queryKey' | 'queryFn' - >; +export type QueryConfigDeprecated< + QueryFnType extends (...args: any) => any +> = Omit< + UseQueryOptions>, + 'queryKey' | 'queryFn' +>; diff --git a/src/redux/appState.ts b/src/redux/appState.ts index 4db93eb39b1..5969845b0bc 100644 --- a/src/redux/appState.ts +++ b/src/redux/appState.ts @@ -32,14 +32,14 @@ interface AppStateUpdateAction { * * @param stateToUpdate The updates to apply to the state. */ -export const appStateUpdate = - (stateToUpdate: Partial) => - (dispatch: Dispatch) => { - dispatch({ - payload: stateToUpdate, - type: APP_STATE_UPDATE, - }); - }; +export const appStateUpdate = (stateToUpdate: Partial) => ( + dispatch: Dispatch +) => { + dispatch({ + payload: stateToUpdate, + type: APP_STATE_UPDATE, + }); +}; // -- Reducer ----------------------------------------- // diff --git a/src/redux/charts.ts b/src/redux/charts.ts index 6cffcedd293..53ad0073dca 100644 --- a/src/redux/charts.ts +++ b/src/redux/charts.ts @@ -71,38 +71,39 @@ export interface ChartsReceivedMessage { * * @param message The `ChartsReceivedMessage`. */ -export const assetChartsReceived = - (message: ChartsReceivedMessage) => - (dispatch: Dispatch, getState: AppGetState) => { - const chartType = message?.meta?.charts_type; - const { charts: existingCharts } = getState().charts; - const assetCharts = message?.payload?.charts ?? {}; - const { nativeCurrency } = getState().settings; - - if (nativeCurrency.toLowerCase() === message?.meta?.currency) { - const newChartData = mapValues(assetCharts, (chartData, address) => { - if (chartType) { - return { - ...existingCharts[address], - // .slice to prevent mutation - [chartType]: reverse(chartData?.slice()), - }; - } +export const assetChartsReceived = (message: ChartsReceivedMessage) => ( + dispatch: Dispatch, + getState: AppGetState +) => { + const chartType = message?.meta?.charts_type; + const { charts: existingCharts } = getState().charts; + const assetCharts = message?.payload?.charts ?? {}; + const { nativeCurrency } = getState().settings; + + if (nativeCurrency.toLowerCase() === message?.meta?.currency) { + const newChartData = mapValues(assetCharts, (chartData, address) => { + if (chartType) { return { ...existingCharts[address], + // .slice to prevent mutation + [chartType]: reverse(chartData?.slice()), }; - }); - - const updatedCharts = { - ...existingCharts, - ...newChartData, + } + return { + ...existingCharts[address], }; - dispatch({ - payload: updatedCharts, - type: CHARTS_UPDATE, - }); - } - }; + }); + + const updatedCharts = { + ...existingCharts, + ...newChartData, + }; + dispatch({ + payload: updatedCharts, + type: CHARTS_UPDATE, + }); + } +}; // -- Reducer ----------------------------------------- // diff --git a/src/redux/contacts.ts b/src/redux/contacts.ts index 5c0b44d8283..ea24b0bc238 100644 --- a/src/redux/contacts.ts +++ b/src/redux/contacts.ts @@ -76,61 +76,61 @@ interface ContactsClearStateAction { } // -- Actions ---------------------------------------- // -export const contactsLoadState = - () => async (dispatch: Dispatch) => { - try { - const contacts = (await getContacts()) as ContactsState['contacts']; - dispatch({ - payload: contacts, - type: CONTACTS_LOAD, - }); - // eslint-disable-next-line no-empty - } catch (error) {} - }; - -export const contactsAddOrUpdate = - ( - address: string, - nickname: string, - color: number, - network: Network, - ens: string - ) => - (dispatch: Dispatch, getState: AppGetState) => { - const loweredAddress = address.toLowerCase(); - const { contacts } = getState().contacts; - const updatedContacts = { - ...contacts, - [loweredAddress]: { - address: loweredAddress, - color, - ens, - network, - nickname, - }, - }; - saveContacts(updatedContacts); - - setTimeout(() => { - handleReviewPromptAction(ReviewPromptAction.AddingContact); - }, 500); +export const contactsLoadState = () => async ( + dispatch: Dispatch +) => { + try { + const contacts = (await getContacts()) as ContactsState['contacts']; dispatch({ - payload: updatedContacts, - type: CONTACTS_UPDATE, + payload: contacts, + type: CONTACTS_LOAD, }); - }; + // eslint-disable-next-line no-empty + } catch (error) {} +}; -export const removeContact = - (address: string) => - (dispatch: Dispatch, getState: AppGetState) => { - const { contacts } = getState().contacts; - const updatedContacts = omitFlatten(contacts, address.toLowerCase()); - saveContacts(updatedContacts); - dispatch({ - payload: updatedContacts, - type: CONTACTS_UPDATE, - }); +export const contactsAddOrUpdate = ( + address: string, + nickname: string, + color: number, + network: Network, + ens: string +) => (dispatch: Dispatch, getState: AppGetState) => { + const loweredAddress = address.toLowerCase(); + const { contacts } = getState().contacts; + const updatedContacts = { + ...contacts, + [loweredAddress]: { + address: loweredAddress, + color, + ens, + network, + nickname, + }, }; + saveContacts(updatedContacts); + + setTimeout(() => { + handleReviewPromptAction(ReviewPromptAction.AddingContact); + }, 500); + dispatch({ + payload: updatedContacts, + type: CONTACTS_UPDATE, + }); +}; + +export const removeContact = (address: string) => ( + dispatch: Dispatch, + getState: AppGetState +) => { + const { contacts } = getState().contacts; + const updatedContacts = omitFlatten(contacts, address.toLowerCase()); + saveContacts(updatedContacts); + dispatch({ + payload: updatedContacts, + type: CONTACTS_UPDATE, + }); +}; // -- Reducer ----------------------------------------- // const INITIAL_STATE: ContactsState = { diff --git a/src/redux/data.ts b/src/redux/data.ts index 814cab7b9d2..0b0d164eae6 100644 --- a/src/redux/data.ts +++ b/src/redux/data.ts @@ -308,75 +308,75 @@ export const DISPERSION_SUCCESS_CODE = 'ok'; /** * Loads initial state from account local storage. */ -export const dataLoadState = - () => - async ( - dispatch: ThunkDispatch< - AppState, - unknown, - | DataLoadTransactionSuccessAction - | DataLoadTransactionsRequestAction - | DataLoadTransactionsFailureAction - | DataUpdatePendingTransactionSuccessAction - >, - getState: AppGetState - ) => { - const { accountAddress, network } = getState().settings; - - try { - dispatch({ type: DATA_LOAD_TRANSACTIONS_REQUEST }); - const transactions = await getLocalTransactions(accountAddress, network); - const pendingTransactions = await getLocalPendingTransactions( - accountAddress, - network - ); - const isCurrentAccountAddress = - accountAddress === getState().settings.accountAddress; - if (!isCurrentAccountAddress) return; +export const dataLoadState = () => async ( + dispatch: ThunkDispatch< + AppState, + unknown, + | DataLoadTransactionSuccessAction + | DataLoadTransactionsRequestAction + | DataLoadTransactionsFailureAction + | DataUpdatePendingTransactionSuccessAction + >, + getState: AppGetState +) => { + const { accountAddress, network } = getState().settings; + + try { + dispatch({ type: DATA_LOAD_TRANSACTIONS_REQUEST }); + const transactions = await getLocalTransactions(accountAddress, network); + const pendingTransactions = await getLocalPendingTransactions( + accountAddress, + network + ); + const isCurrentAccountAddress = + accountAddress === getState().settings.accountAddress; + if (!isCurrentAccountAddress) return; - dispatch({ - payload: pendingTransactions, - type: DATA_UPDATE_PENDING_TRANSACTIONS_SUCCESS, - }); - dispatch({ - payload: transactions, - type: DATA_LOAD_TRANSACTIONS_SUCCESS, - }); - } catch (error) { - dispatch({ type: DATA_LOAD_TRANSACTIONS_FAILURE }); - } - }; + dispatch({ + payload: pendingTransactions, + type: DATA_UPDATE_PENDING_TRANSACTIONS_SUCCESS, + }); + dispatch({ + payload: transactions, + type: DATA_LOAD_TRANSACTIONS_SUCCESS, + }); + } catch (error) { + dispatch({ type: DATA_LOAD_TRANSACTIONS_FAILURE }); + } +}; /** * Resets state, with the exception of generic asset prices, and unsubscribes * from listeners and timeouts. */ -export const dataResetState = - () => (dispatch: Dispatch) => { - // cancel any debounced updates so we won't override any new data with stale debounced ones - cancelDebouncedUpdateGenericAssets(); +export const dataResetState = () => ( + dispatch: Dispatch +) => { + // cancel any debounced updates so we won't override any new data with stale debounced ones + cancelDebouncedUpdateGenericAssets(); - pendingTransactionsHandle && clearTimeout(pendingTransactionsHandle); + pendingTransactionsHandle && clearTimeout(pendingTransactionsHandle); - dispatch({ type: DATA_CLEAR_STATE }); - }; + dispatch({ type: DATA_CLEAR_STATE }); +}; /** * Checks whether or not metadata received from Zerion is valid. * * @param message The message received from Zerion. */ -const checkMeta = - (message: DataMessage | undefined) => - (_: Dispatch, getState: AppGetState) => { - const { accountAddress, nativeCurrency } = getState().settings; - const address = message?.meta?.address || message?.meta?.addresses?.[0]; - const currency = message?.meta?.currency; - return ( - isLowerCaseMatch(address!, accountAddress) && - isLowerCaseMatch(currency!, nativeCurrency) - ); - }; +const checkMeta = (message: DataMessage | undefined) => ( + _: Dispatch, + getState: AppGetState +) => { + const { accountAddress, nativeCurrency } = getState().settings; + const address = message?.meta?.address || message?.meta?.addresses?.[0]; + const currency = message?.meta?.currency; + return ( + isLowerCaseMatch(address!, accountAddress) && + isLowerCaseMatch(currency!, nativeCurrency) + ); +}; /** * Checks to see if a network's nonce should be incremented for an acount @@ -384,32 +384,30 @@ const checkMeta = * * @param transactionData Incoming transaction data. */ -const checkForUpdatedNonce = - (transactionData: ZerionTransaction[]) => - ( - dispatch: ThunkDispatch, - getState: AppGetState - ) => { - if (transactionData.length) { - const { accountAddress, network } = getState().settings; - const txSortedByDescendingNonce = transactionData - .filter(tx => { - const addressFrom = tx?.address_from; - return ( - addressFrom && - addressFrom.toLowerCase() === accountAddress.toLowerCase() - ); - }) - .sort(({ nonce: n1 }, { nonce: n2 }) => (n2 ?? 0) - (n1 ?? 0)); - const [latestTx] = txSortedByDescendingNonce; - const addressFrom = latestTx?.address_from; - const nonce = latestTx?.nonce; - if (addressFrom && nonce) { - // @ts-ignore-next-line - dispatch(incrementNonce(addressFrom!, nonce, network)); - } +const checkForUpdatedNonce = (transactionData: ZerionTransaction[]) => ( + dispatch: ThunkDispatch, + getState: AppGetState +) => { + if (transactionData.length) { + const { accountAddress, network } = getState().settings; + const txSortedByDescendingNonce = transactionData + .filter(tx => { + const addressFrom = tx?.address_from; + return ( + addressFrom && + addressFrom.toLowerCase() === accountAddress.toLowerCase() + ); + }) + .sort(({ nonce: n1 }, { nonce: n2 }) => (n2 ?? 0) - (n1 ?? 0)); + const [latestTx] = txSortedByDescendingNonce; + const addressFrom = latestTx?.address_from; + const nonce = latestTx?.nonce; + if (addressFrom && nonce) { + // @ts-ignore-next-line + dispatch(incrementNonce(addressFrom!, nonce, network)); } - }; + } +}; /** * Handles an incoming portfolio data message from Zerion and updates state @@ -417,25 +415,25 @@ const checkForUpdatedNonce = * * @param message The `PortfolioReceivedMessage`, or undefined. */ -export const portfolioReceived = - (message: PortfolioReceivedMessage | undefined) => - async ( - dispatch: Dispatch, - getState: AppGetState - ) => { - if (message?.meta?.status !== DISPERSION_SUCCESS_CODE) return; - if (!message?.payload?.portfolio) return; - - const { portfolios } = getState().data; - - const newPortfolios = { ...portfolios }; - newPortfolios[message.meta.address!] = message.payload.portfolio; - - dispatch({ - payload: newPortfolios, - type: DATA_UPDATE_PORTFOLIOS, - }); - }; +export const portfolioReceived = ( + message: PortfolioReceivedMessage | undefined +) => async ( + dispatch: Dispatch, + getState: AppGetState +) => { + if (message?.meta?.status !== DISPERSION_SUCCESS_CODE) return; + if (!message?.payload?.portfolio) return; + + const { portfolios } = getState().data; + + const newPortfolios = { ...portfolios }; + newPortfolios[message.meta.address!] = message.payload.portfolio; + + dispatch({ + payload: newPortfolios, + type: DATA_UPDATE_PORTFOLIOS, + }); +}; /** * Handles a `TransactionsReceivedMessage` message from Zerion and updates @@ -444,122 +442,124 @@ export const portfolioReceived = * @param message The `TransactionsReceivedMessage`, or undefined. * @param appended Whether or not transactions are being appended. */ -export const transactionsReceived = - (message: TransactionsReceivedMessage | undefined, appended = false) => - async ( - dispatch: ThunkDispatch< - AppState, - unknown, - | DataLoadTransactionSuccessAction - | DataUpdatePendingTransactionSuccessAction - >, - getState: AppGetState - ) => { - return; - loggr.debug('transactionsReceived', { - message: { - ...message, - payload: { - transactions: message?.payload?.transactions?.length, - }, +export const transactionsReceived = ( + message: TransactionsReceivedMessage | undefined, + appended = false +) => async ( + dispatch: ThunkDispatch< + AppState, + unknown, + DataLoadTransactionSuccessAction | DataUpdatePendingTransactionSuccessAction + >, + getState: AppGetState +) => { + return; + loggr.debug('transactionsReceived', { + message: { + ...message, + payload: { + transactions: message?.payload?.transactions?.length, }, - appended, - }); - - const isValidMeta = dispatch(checkMeta(message)); - - if (!isValidMeta) { - loggr.debug('transactionsReceived: !isValidMeta', { message }); - return; - } + }, + appended, + }); - const transactionData = message?.payload?.transactions ?? []; + const isValidMeta = dispatch(checkMeta(message)); - const { network } = getState().settings; - let currentNetwork = network; - if (currentNetwork === Network.mainnet && message?.meta?.chain_id) { - currentNetwork = message?.meta?.chain_id; - } - if (transactionData.length && currentNetwork === Network.mainnet) { - loggr.debug('transactionsReceived: dispatching checkForUpdatedNonce'); - dispatch(checkForUpdatedNonce(transactionData)); - } - - const { accountAddress, nativeCurrency } = getState().settings; - const { pendingTransactions, transactions } = getState().data; - const { selected } = getState().wallets; - - loggr.debug('transactionsReceived: attempting to parse transactions'); - - const { parsedTransactions, potentialNftTransaction } = - await parseTransactions( - transactionData, - accountAddress, - nativeCurrency, - transactions, - pendingTransactions, - undefined, - currentNetwork, - appended - ); + if (!isValidMeta) { + loggr.debug('transactionsReceived: !isValidMeta', { message }); + return; + } - const isCurrentAccountAddress = - accountAddress === getState().settings.accountAddress; - if (!isCurrentAccountAddress) { - loggr.debug( - 'transactionsReceived: transaction accountAddress does not match current accountAddress', - { - transactionAccountAddress: accountAddress, - currentAccountAddress: getState().settings.accountAddress, - } - ); - return; - } + const transactionData = message?.payload?.transactions ?? []; - if (appended && potentialNftTransaction) { - setTimeout(() => { - queryClient.invalidateQueries({ - queryKey: nftsQueryKey({ address: accountAddress }), - }); - }, 60000); - } + const { network } = getState().settings; + let currentNetwork = network; + if (currentNetwork === Network.mainnet && message?.meta?.chain_id) { + currentNetwork = message?.meta?.chain_id; + } + if (transactionData.length && currentNetwork === Network.mainnet) { + loggr.debug('transactionsReceived: dispatching checkForUpdatedNonce'); + dispatch(checkForUpdatedNonce(transactionData)); + } - const txHashes = parsedTransactions.map(tx => ethereumUtils.getHash(tx)); - const updatedPendingTransactions = pendingTransactions.filter( - tx => !txHashes.includes(ethereumUtils.getHash(tx)) + const { accountAddress, nativeCurrency } = getState().settings; + const { pendingTransactions, transactions } = getState().data; + const { selected } = getState().wallets; + + loggr.debug('transactionsReceived: attempting to parse transactions'); + + const { + parsedTransactions, + potentialNftTransaction, + } = await parseTransactions( + transactionData, + accountAddress, + nativeCurrency, + transactions, + pendingTransactions, + undefined, + currentNetwork, + appended + ); + + const isCurrentAccountAddress = + accountAddress === getState().settings.accountAddress; + if (!isCurrentAccountAddress) { + loggr.debug( + 'transactionsReceived: transaction accountAddress does not match current accountAddress', + { + transactionAccountAddress: accountAddress, + currentAccountAddress: getState().settings.accountAddress, + } ); + return; + } - dispatch({ - payload: updatedPendingTransactions, - type: DATA_UPDATE_PENDING_TRANSACTIONS_SUCCESS, - }); - dispatch({ - payload: parsedTransactions, - type: DATA_LOAD_TRANSACTIONS_SUCCESS, - }); - saveLocalTransactions(parsedTransactions, accountAddress, network); - saveLocalPendingTransactions( - updatedPendingTransactions, - accountAddress, - network - ); + if (appended && potentialNftTransaction) { + setTimeout(() => { + queryClient.invalidateQueries({ + queryKey: nftsQueryKey({ address: accountAddress }), + }); + }, 60000); + } - if (appended && parsedTransactions.length) { - if ( - selected && - !selected.backedUp && - !selected.imported && - selected.type !== WalletTypes.readOnly && - selected.type !== WalletTypes.bluetooth - ) { - setTimeout(() => { - triggerOnSwipeLayout(() => - Navigation.handleAction(Routes.BACKUP_SHEET, { single: true }) - ); - }, BACKUP_SHEET_DELAY_MS); - } + const txHashes = parsedTransactions.map(tx => ethereumUtils.getHash(tx)); + const updatedPendingTransactions = pendingTransactions.filter( + tx => !txHashes.includes(ethereumUtils.getHash(tx)) + ); + + dispatch({ + payload: updatedPendingTransactions, + type: DATA_UPDATE_PENDING_TRANSACTIONS_SUCCESS, + }); + dispatch({ + payload: parsedTransactions, + type: DATA_LOAD_TRANSACTIONS_SUCCESS, + }); + saveLocalTransactions(parsedTransactions, accountAddress, network); + saveLocalPendingTransactions( + updatedPendingTransactions, + accountAddress, + network + ); + + if (appended && parsedTransactions.length) { + if ( + selected && + !selected.backedUp && + !selected.imported && + selected.type !== WalletTypes.readOnly && + selected.type !== WalletTypes.bluetooth + ) { + setTimeout(() => { + triggerOnSwipeLayout(() => + Navigation.handleAction(Routes.BACKUP_SHEET, { single: true }) + ); + }, BACKUP_SHEET_DELAY_MS); } - }; + } +}; const callbacksOnAssetReceived: { [address: string]: ((asset: ParsedAddressAsset) => unknown) | undefined; @@ -583,105 +583,103 @@ export function scheduleActionOnAssetReceived( * * @param message The message, or undefined. */ -export const assetPricesReceived = - (message: AssetPricesReceivedMessage | undefined) => - ( - dispatch: Dispatch, - getState: AppGetState - ) => { - const newAssetPrices = message?.payload?.prices ?? {}; - const { nativeCurrency } = getState().settings; - - if (nativeCurrency.toLowerCase() === message?.meta?.currency) { - if (isEmpty(newAssetPrices)) return; - const parsedAssets = mapValues(newAssetPrices, asset => - parseAsset(asset) - ) as { - [id: string]: ParsedAddressAsset; - }; - const { genericAssets } = getState().data; - - const updatedAssets = { - ...genericAssets, - ...parsedAssets, - }; +export const assetPricesReceived = ( + message: AssetPricesReceivedMessage | undefined +) => ( + dispatch: Dispatch, + getState: AppGetState +) => { + const newAssetPrices = message?.payload?.prices ?? {}; + const { nativeCurrency } = getState().settings; + + if (nativeCurrency.toLowerCase() === message?.meta?.currency) { + if (isEmpty(newAssetPrices)) return; + const parsedAssets = mapValues(newAssetPrices, asset => + parseAsset(asset) + ) as { + [id: string]: ParsedAddressAsset; + }; + const { genericAssets } = getState().data; - const assetAddresses = Object.keys(parsedAssets); + const updatedAssets = { + ...genericAssets, + ...parsedAssets, + }; - for (const address of assetAddresses) { - callbacksOnAssetReceived[address.toLowerCase()]?.( - parsedAssets[address] - ); - callbacksOnAssetReceived[address.toLowerCase()] = undefined; - } + const assetAddresses = Object.keys(parsedAssets); - dispatch({ - payload: updatedAssets, - type: DATA_UPDATE_GENERIC_ASSETS, - }); - } - if ( - message?.meta?.currency?.toLowerCase() === - NativeCurrencyKeys.USD.toLowerCase() && - newAssetPrices[ETH_ADDRESS] - ) { - const value = newAssetPrices[ETH_ADDRESS]?.price?.value; - dispatch({ - payload: value, - type: DATA_UPDATE_ETH_USD, - }); + for (const address of assetAddresses) { + callbacksOnAssetReceived[address.toLowerCase()]?.(parsedAssets[address]); + callbacksOnAssetReceived[address.toLowerCase()] = undefined; } - }; + + dispatch({ + payload: updatedAssets, + type: DATA_UPDATE_GENERIC_ASSETS, + }); + } + if ( + message?.meta?.currency?.toLowerCase() === + NativeCurrencyKeys.USD.toLowerCase() && + newAssetPrices[ETH_ADDRESS] + ) { + const value = newAssetPrices[ETH_ADDRESS]?.price?.value; + dispatch({ + payload: value, + type: DATA_UPDATE_ETH_USD, + }); + } +}; /** * Handles a `AssetPricesChangedMessage` from Zerion and updates state. * * @param message The message. */ -export const assetPricesChanged = - (message: AssetPricesChangedMessage | undefined) => - ( - dispatch: Dispatch, - getState: AppGetState - ) => { - const { nativeCurrency } = getState().settings; - - const price = message?.payload?.prices?.[0]?.price; - const assetAddress = message?.meta?.asset_code; - if (isNil(price) || isNil(assetAddress)) return; - - if (nativeCurrency?.toLowerCase() === message?.meta?.currency) { - const { genericAssets } = getState().data; - const genericAsset = { - ...genericAssets?.[assetAddress], - price, - }; - const updatedAssets = { - ...genericAssets, - [assetAddress]: genericAsset, - } as { - [address: string]: ParsedAddressAsset; - }; +export const assetPricesChanged = ( + message: AssetPricesChangedMessage | undefined +) => ( + dispatch: Dispatch, + getState: AppGetState +) => { + const { nativeCurrency } = getState().settings; + + const price = message?.payload?.prices?.[0]?.price; + const assetAddress = message?.meta?.asset_code; + if (isNil(price) || isNil(assetAddress)) return; + + if (nativeCurrency?.toLowerCase() === message?.meta?.currency) { + const { genericAssets } = getState().data; + const genericAsset = { + ...genericAssets?.[assetAddress], + price, + }; + const updatedAssets = { + ...genericAssets, + [assetAddress]: genericAsset, + } as { + [address: string]: ParsedAddressAsset; + }; - debouncedUpdateGenericAssets( - { - payload: updatedAssets, - type: DATA_UPDATE_GENERIC_ASSETS, - }, - dispatch - ); - } - if ( - message?.meta?.currency?.toLowerCase() === - NativeCurrencyKeys.USD.toLowerCase() && - assetAddress === ETH_ADDRESS - ) { - dispatch({ - payload: price?.value, - type: DATA_UPDATE_ETH_USD, - }); - } - }; + debouncedUpdateGenericAssets( + { + payload: updatedAssets, + type: DATA_UPDATE_GENERIC_ASSETS, + }, + dispatch + ); + } + if ( + message?.meta?.currency?.toLowerCase() === + NativeCurrencyKeys.USD.toLowerCase() && + assetAddress === ETH_ADDRESS + ) { + dispatch({ + payload: price?.value, + type: DATA_UPDATE_ETH_USD, + }); + } +}; /** * Updates state and account local storage with a new transaction. @@ -694,138 +692,129 @@ export const assetPricesChanged = * @param provider A `StaticJsonRpcProvider` to use for watching the pending * transaction, or null to use the default provider. */ -export const dataAddNewTransaction = - ( - txDetails: NewTransactionOrAddCashTransaction, - accountAddressToUpdate: string | null = null, - disableTxnWatcher = false, - provider: StaticJsonRpcProvider | null = null - ) => - async ( - dispatch: ThunkDispatch< - AppState, - unknown, - DataUpdatePendingTransactionSuccessAction - >, - getState: AppGetState - ) => { +export const dataAddNewTransaction = ( + txDetails: NewTransactionOrAddCashTransaction, + accountAddressToUpdate: string | null = null, + disableTxnWatcher = false, + provider: StaticJsonRpcProvider | null = null +) => async ( + dispatch: ThunkDispatch< + AppState, + unknown, + DataUpdatePendingTransactionSuccessAction + >, + getState: AppGetState +) => { + return; + loggr.debug('dataAddNewTransaction', {}, loggr.DebugContext.f2c); + + const { pendingTransactions } = getState().data; + const { accountAddress, nativeCurrency, network } = getState().settings; + + if ( + accountAddressToUpdate && + accountAddressToUpdate.toLowerCase() !== accountAddress.toLowerCase() + ) { + loggr.debug( + 'dataAddNewTransaction: accountAddressToUpdate does not match accountAddress', + {}, + loggr.DebugContext.f2c + ); return; - loggr.debug('dataAddNewTransaction', {}, loggr.DebugContext.f2c); + } - const { pendingTransactions } = getState().data; - const { accountAddress, nativeCurrency, network } = getState().settings; + try { + const parsedTransaction = await parseNewTransaction( + txDetails, + nativeCurrency + ); - if ( - accountAddressToUpdate && - accountAddressToUpdate.toLowerCase() !== accountAddress.toLowerCase() - ) { - loggr.debug( - 'dataAddNewTransaction: accountAddressToUpdate does not match accountAddress', - {}, - loggr.DebugContext.f2c - ); - return; - } + const _pendingTransactions = [parsedTransaction, ...pendingTransactions]; + dispatch({ + payload: _pendingTransactions, + type: DATA_UPDATE_PENDING_TRANSACTIONS_SUCCESS, + }); + saveLocalPendingTransactions(_pendingTransactions, accountAddress, network); - try { - const parsedTransaction = await parseNewTransaction( - txDetails, - nativeCurrency - ); + loggr.debug( + 'dataAddNewTransaction: adding pending transactions', + {}, + loggr.DebugContext.f2c + ); - const _pendingTransactions = [parsedTransaction, ...pendingTransactions]; - dispatch({ - payload: _pendingTransactions, - type: DATA_UPDATE_PENDING_TRANSACTIONS_SUCCESS, - }); - saveLocalPendingTransactions( - _pendingTransactions, - accountAddress, - network + if (parsedTransaction.from && parsedTransaction.nonce) { + dispatch( + // @ts-ignore-next-line + incrementNonce( + parsedTransaction.from, + parsedTransaction.nonce, + parsedTransaction.network + ) ); - + } + if ( + !disableTxnWatcher || + network !== Network.mainnet || + parsedTransaction?.network + ) { loggr.debug( - 'dataAddNewTransaction: adding pending transactions', + 'dataAddNewTransaction: watching new pending transactions', {}, loggr.DebugContext.f2c ); + dispatch( + watchPendingTransactions( + accountAddress, + parsedTransaction.network + ? TXN_WATCHER_MAX_TRIES_LAYER_2 + : TXN_WATCHER_MAX_TRIES, + null, + // @ts-expect-error `watchPendingTransactions` only takes 3 arguments. + provider + ) + ); + } - if (parsedTransaction.from && parsedTransaction.nonce) { - dispatch( - // @ts-ignore-next-line - incrementNonce( - parsedTransaction.from, - parsedTransaction.nonce, - parsedTransaction.network - ) - ); - } - if ( - !disableTxnWatcher || - network !== Network.mainnet || - parsedTransaction?.network - ) { - loggr.debug( - 'dataAddNewTransaction: watching new pending transactions', - {}, - loggr.DebugContext.f2c - ); - dispatch( - watchPendingTransactions( - accountAddress, - parsedTransaction.network - ? TXN_WATCHER_MAX_TRIES_LAYER_2 - : TXN_WATCHER_MAX_TRIES, - null, - // @ts-expect-error `watchPendingTransactions` only takes 3 arguments. - provider - ) - ); - } + loggr.debug('dataAddNewTransaction: complete', {}, loggr.DebugContext.f2c); - loggr.debug( - 'dataAddNewTransaction: complete', - {}, - loggr.DebugContext.f2c - ); + return parsedTransaction; + } catch (error) { + loggr.error(new Error('dataAddNewTransaction: failed'), { error }); + } +}; - return parsedTransaction; - } catch (error) { - loggr.error(new Error('dataAddNewTransaction: failed'), { error }); +export const dataRemovePendingTransaction = ( + txHash: string, + network: Network +) => async ( + dispatch: ThunkDispatch< + AppState, + unknown, + DataUpdatePendingTransactionSuccessAction + >, + getState: AppGetState +) => { + loggr.debug('dataRemovePendingTransaction', { txHash }); + + const { pendingTransactions } = getState().data; + const { accountAddress } = getState().settings; + + const _pendingTransactions = pendingTransactions.filter(tx => { + // if we find the pending tx, filter it out + if (tx.hash === txHash && tx.network === network) { + loggr.debug('dataRemovePendingTransaction: removed tx', { txHash }); + return false; + } else { + return true; } - }; + }); -export const dataRemovePendingTransaction = - (txHash: string, network: Network) => - async ( - dispatch: ThunkDispatch< - AppState, - unknown, - DataUpdatePendingTransactionSuccessAction - >, - getState: AppGetState - ) => { - loggr.debug('dataRemovePendingTransaction', { txHash }); - - const { pendingTransactions } = getState().data; - const { accountAddress } = getState().settings; - - const _pendingTransactions = pendingTransactions.filter(tx => { - // if we find the pending tx, filter it out - if (tx.hash === txHash && tx.network === network) { - loggr.debug('dataRemovePendingTransaction: removed tx', { txHash }); - return false; - } else { - return true; - } - }); - - dispatch({ - payload: _pendingTransactions, - type: DATA_UPDATE_PENDING_TRANSACTIONS_SUCCESS, - }); - saveLocalPendingTransactions(_pendingTransactions, accountAddress, network); - }; + dispatch({ + payload: _pendingTransactions, + type: DATA_UPDATE_PENDING_TRANSACTIONS_SUCCESS, + }); + saveLocalPendingTransactions(_pendingTransactions, accountAddress, network); +}; /** * Watches pending transactions and updates state and account local storage @@ -836,110 +825,110 @@ export const dataRemovePendingTransaction = * @param currentNonce The nonce of the last confirmed transaction, used to * determine if a transaction has been dropped. */ -export const dataWatchPendingTransactions = - (provider: StaticJsonRpcProvider | null = null, currentNonce = -1) => - async ( - dispatch: ThunkDispatch< - AppState, - unknown, - | DataLoadTransactionSuccessAction - | DataUpdatePendingTransactionSuccessAction - >, - getState: AppGetState - ) => { - const { pendingTransactions: pending } = getState().data; - if (isEmpty(pending)) { - return true; - } - let txStatusesDidChange = false; - const updatedPendingTransactions = await Promise.all( - pending.map(async tx => { - const updatedPendingTransaction: RainbowTransaction = { ...tx }; - const txHash = ethereumUtils.getHash(tx) || ''; - let pendingTransactionData: { - title: string; - minedAt: number | null; - pending: boolean; - status: TransactionStatus; - } | null = { - status: TransactionStatus.sending, - title: tx?.title || TransactionStatus.sending, - minedAt: null, - pending: true, - }; - return; - try { - logger.log('Checking pending tx with hash', txHash); - const p = - (await getProviderForNetwork(updatedPendingTransaction.network)) || - provider; - const txObj: TransactionResponse | undefined = - await p.getTransaction(txHash); - // if the nonce of last confirmed tx is higher than this pending tx then it got dropped - const nonceAlreadyIncluded = - currentNonce > (tx?.nonce ?? txObj.nonce); - if ( - (txObj && txObj?.blockNumber && txObj?.blockHash) || - nonceAlreadyIncluded - ) { - // When speeding up a non "normal tx" we need to resubscribe - // because zerion "append" event isn't reliable - logger.log('TX CONFIRMED!', txObj); - if (!nonceAlreadyIncluded) { +export const dataWatchPendingTransactions = ( + provider: StaticJsonRpcProvider | null = null, + currentNonce = -1 +) => async ( + dispatch: ThunkDispatch< + AppState, + unknown, + DataLoadTransactionSuccessAction | DataUpdatePendingTransactionSuccessAction + >, + getState: AppGetState +) => { + const { pendingTransactions: pending } = getState().data; + if (isEmpty(pending)) { + return true; + } + let txStatusesDidChange = false; + const updatedPendingTransactions = await Promise.all( + pending.map(async tx => { + const updatedPendingTransaction: RainbowTransaction = { ...tx }; + const txHash = ethereumUtils.getHash(tx) || ''; + let pendingTransactionData: { + title: string; + minedAt: number | null; + pending: boolean; + status: TransactionStatus; + } | null = { + status: TransactionStatus.sending, + title: tx?.title || TransactionStatus.sending, + minedAt: null, + pending: true, + }; + return; + try { + logger.log('Checking pending tx with hash', txHash); + const p = + (await getProviderForNetwork(updatedPendingTransaction.network)) || + provider; + const txObj: TransactionResponse | undefined = await p.getTransaction( + txHash + ); + // if the nonce of last confirmed tx is higher than this pending tx then it got dropped + const nonceAlreadyIncluded = currentNonce > (tx?.nonce ?? txObj.nonce); + if ( + (txObj && txObj?.blockNumber && txObj?.blockHash) || + nonceAlreadyIncluded + ) { + // When speeding up a non "normal tx" we need to resubscribe + // because zerion "append" event isn't reliable + logger.log('TX CONFIRMED!', txObj); + if (!nonceAlreadyIncluded) { + appEvents.emit('transactionConfirmed', { + ...txObj, + internalType: tx.type, + }); + } + if (tx?.ensRegistration) { + fetchWalletENSDataAfterRegistration(); + } + + if (updatedPendingTransaction?.swap?.type === SwapType.crossChain) { + pendingTransactionData = await getTransactionSocketStatus( + updatedPendingTransaction + ); + if (!pendingTransactionData.pending) { appEvents.emit('transactionConfirmed', { ...txObj, internalType: tx.type, }); - } - if (tx?.ensRegistration) { - fetchWalletENSDataAfterRegistration(); - } - - if (updatedPendingTransaction?.swap?.type === SwapType.crossChain) { - pendingTransactionData = await getTransactionSocketStatus( - updatedPendingTransaction - ); - if (!pendingTransactionData.pending) { - appEvents.emit('transactionConfirmed', { - ...txObj, - internalType: tx.type, - }); - txStatusesDidChange = true; - } - } else { - pendingTransactionData = getPendingTransactionData( - updatedPendingTransaction, - transactionStatus - ); txStatusesDidChange = true; } - } else if (tx.flashbots) { - pendingTransactionData = await getTransactionFlashbotStatus( + } else { + pendingTransactionData = getPendingTransactionData( updatedPendingTransaction, - txHash + transactionStatus ); - if (pendingTransactionData && !pendingTransactionData.pending) { - txStatusesDidChange = true; - // decrement the nonce since it was dropped - // @ts-ignore-next-line - dispatch(decrementNonce(tx.from!, tx.nonce!, Network.mainnet)); - } + txStatusesDidChange = true; } - if (pendingTransactionData) { - updatedPendingTransaction.title = pendingTransactionData.title; - updatedPendingTransaction.status = pendingTransactionData.status; - updatedPendingTransaction.pending = pendingTransactionData.pending; - updatedPendingTransaction.minedAt = pendingTransactionData.minedAt; + } else if (tx.flashbots) { + pendingTransactionData = await getTransactionFlashbotStatus( + updatedPendingTransaction, + txHash + ); + if (pendingTransactionData && !pendingTransactionData.pending) { + txStatusesDidChange = true; + // decrement the nonce since it was dropped + // @ts-ignore-next-line + dispatch(decrementNonce(tx.from!, tx.nonce!, Network.mainnet)); } - } catch (error) { - logger.log('Error watching pending txn', error); } - return updatedPendingTransaction; - }) - ); + if (pendingTransactionData) { + updatedPendingTransaction.title = pendingTransactionData.title; + updatedPendingTransaction.status = pendingTransactionData.status; + updatedPendingTransaction.pending = pendingTransactionData.pending; + updatedPendingTransaction.minedAt = pendingTransactionData.minedAt; + } + } catch (error) { + logger.log('Error watching pending txn', error); + } + return updatedPendingTransaction; + }) + ); - return false; - }; + return false; +}; /** * Updates a transaction in state and account local storage and watches it, @@ -951,44 +940,42 @@ export const dataWatchPendingTransactions = * @param provider A `StaticJsonRpcProvider`, or null to use the default * provider. */ -export const dataUpdateTransaction = - ( - txHash: string, - txObj: RainbowTransaction, - watch: boolean, - provider: StaticJsonRpcProvider | null = null - ) => - async ( - dispatch: ThunkDispatch< - AppState, - unknown, - DataUpdatePendingTransactionSuccessAction - >, - getState: AppGetState - ) => { - return; - const { pendingTransactions } = getState().data; - - const allOtherTx = pendingTransactions.filter(tx => tx.hash !== txHash); - const updatedTransactions = [txObj].concat(allOtherTx); - - dispatch({ - payload: updatedTransactions, - type: DATA_UPDATE_PENDING_TRANSACTIONS_SUCCESS, - }); - const { accountAddress, network } = getState().settings; - saveLocalPendingTransactions(updatedTransactions, accountAddress, network); - // Always watch cancellation and speed up - if (watch) { - dispatch( - watchPendingTransactions( - accountAddress, - txObj.network ? TXN_WATCHER_MAX_TRIES_LAYER_2 : TXN_WATCHER_MAX_TRIES, - provider - ) - ); - } - }; +export const dataUpdateTransaction = ( + txHash: string, + txObj: RainbowTransaction, + watch: boolean, + provider: StaticJsonRpcProvider | null = null +) => async ( + dispatch: ThunkDispatch< + AppState, + unknown, + DataUpdatePendingTransactionSuccessAction + >, + getState: AppGetState +) => { + return; + const { pendingTransactions } = getState().data; + + const allOtherTx = pendingTransactions.filter(tx => tx.hash !== txHash); + const updatedTransactions = [txObj].concat(allOtherTx); + + dispatch({ + payload: updatedTransactions, + type: DATA_UPDATE_PENDING_TRANSACTIONS_SUCCESS, + }); + const { accountAddress, network } = getState().settings; + saveLocalPendingTransactions(updatedTransactions, accountAddress, network); + // Always watch cancellation and speed up + if (watch) { + dispatch( + watchPendingTransactions( + accountAddress, + txObj.network ? TXN_WATCHER_MAX_TRIES_LAYER_2 : TXN_WATCHER_MAX_TRIES, + provider + ) + ); + } +}; /** * Checks the current account's transaction count and subscribes to pending @@ -999,36 +986,36 @@ export const dataUpdateTransaction = * @param provider A `StaticJsonRpcProvider`, or null to use the default * provider. */ -export const checkPendingTransactionsOnInitialize = - ( - accountAddressToWatch: string, - provider: StaticJsonRpcProvider | null = null - ) => - async ( - dispatch: ThunkDispatch, - getState: AppGetState - ) => { - return; - const { accountAddress: currentAccountAddress, network } = - getState().settings; - if (currentAccountAddress !== accountAddressToWatch) return; - const providerForNetwork = await getProviderForNetwork(network); - const currentNonce = await ( - provider || providerForNetwork - ).getTransactionCount(currentAccountAddress, 'latest'); - const notPendingTxs = await dispatch( - dataWatchPendingTransactions(provider, currentNonce) +export const checkPendingTransactionsOnInitialize = ( + accountAddressToWatch: string, + provider: StaticJsonRpcProvider | null = null +) => async ( + dispatch: ThunkDispatch, + getState: AppGetState +) => { + return; + const { + accountAddress: currentAccountAddress, + network, + } = getState().settings; + if (currentAccountAddress !== accountAddressToWatch) return; + const providerForNetwork = await getProviderForNetwork(network); + const currentNonce = await ( + provider || providerForNetwork + ).getTransactionCount(currentAccountAddress, 'latest'); + const notPendingTxs = await dispatch( + dataWatchPendingTransactions(provider, currentNonce) + ); + if (!notPendingTxs) { + dispatch( + watchPendingTransactions( + currentAccountAddress, + TXN_WATCHER_MAX_TRIES, + null + ) ); - if (!notPendingTxs) { - dispatch( - watchPendingTransactions( - currentAccountAddress, - TXN_WATCHER_MAX_TRIES, - null - ) - ); - } - }; + } +}; /** * Repeatedly attempts to subscribe to transaction updates using @@ -1041,37 +1028,35 @@ export const checkPendingTransactionsOnInitialize = * @param provider A `StaticJsonRpcProvider`, or null to use the default * provider. */ -export const watchPendingTransactions = - ( - accountAddressToWatch: string, - remainingTries: number = TXN_WATCHER_MAX_TRIES, - provider: StaticJsonRpcProvider | null = null - ) => - async ( - dispatch: ThunkDispatch, - getState: AppGetState - ) => { - return; - pendingTransactionsHandle && clearTimeout(pendingTransactionsHandle); - if (remainingTries === 0) return; - - const { accountAddress: currentAccountAddress } = getState().settings; - if (currentAccountAddress !== accountAddressToWatch) return; - - const done = await dispatch(dataWatchPendingTransactions(provider)); - - if (!done) { - pendingTransactionsHandle = setTimeout(() => { - dispatch( - watchPendingTransactions( - accountAddressToWatch, - remainingTries - 1, - provider - ) - ); - }, TXN_WATCHER_POLL_INTERVAL); - } - }; +export const watchPendingTransactions = ( + accountAddressToWatch: string, + remainingTries: number = TXN_WATCHER_MAX_TRIES, + provider: StaticJsonRpcProvider | null = null +) => async ( + dispatch: ThunkDispatch, + getState: AppGetState +) => { + return; + pendingTransactionsHandle && clearTimeout(pendingTransactionsHandle); + if (remainingTries === 0) return; + + const { accountAddress: currentAccountAddress } = getState().settings; + if (currentAccountAddress !== accountAddressToWatch) return; + + const done = await dispatch(dataWatchPendingTransactions(provider)); + + if (!done) { + pendingTransactionsHandle = setTimeout(() => { + dispatch( + watchPendingTransactions( + accountAddressToWatch, + remainingTries - 1, + provider + ) + ); + }, TXN_WATCHER_POLL_INTERVAL); + } +}; // -- Reducer ----------------------------------------- // const INITIAL_STATE: DataState = { diff --git a/src/redux/editOptions.ts b/src/redux/editOptions.ts index f5bb88b5599..d171cd1a2d0 100644 --- a/src/redux/editOptions.ts +++ b/src/redux/editOptions.ts @@ -37,14 +37,14 @@ type EditOptionsAction = EditOptionsSetHiddenCoinsAction; * * @param coins The `uniqueId`s of the new hidden coins. */ -export const setHiddenCoins = - (coins: EditOptionsState['hiddenCoins']) => - (dispatch: Dispatch) => { - dispatch({ - payload: coins, - type: SET_HIDDEN_COINS, - }); - }; +export const setHiddenCoins = (coins: EditOptionsState['hiddenCoins']) => ( + dispatch: Dispatch +) => { + dispatch({ + payload: coins, + type: SET_HIDDEN_COINS, + }); +}; // -- Reducer ----------------------------------------- // const INITIAL_STATE: EditOptionsState = { diff --git a/src/redux/ensRegistration.ts b/src/redux/ensRegistration.ts index 71a6a135344..e65ee6aad0b 100644 --- a/src/redux/ensRegistration.ts +++ b/src/redux/ensRegistration.ts @@ -132,353 +132,362 @@ export type EnsRegistrationActionTypes = /** * Loads initial state from account local storage. */ -export const ensRegistrationsLoadState = - () => - async ( - dispatch: Dispatch, - getState: AppGetState - ) => { - const { accountAddress, network } = getState().settings; - try { - const registrations = await getLocalENSRegistrations( - accountAddress, - network - ); - dispatch({ - payload: { registrations }, - type: ENS_LOAD_STATE, - }); - // eslint-disable-next-line no-empty - } catch (error) {} - }; - -export const startRegistration = - (name: string, mode: keyof typeof REGISTRATION_MODES) => - async (dispatch: AppDispatch, getState: AppGetState) => { - const { - ensRegistration: { registrations }, - settings: { accountAddress }, - } = getState(); - const lcAccountAddress = accountAddress.toLowerCase(); - const accountRegistrations = registrations?.[lcAccountAddress] || {}; - const registration = accountRegistrations[name] || {}; - - const updatedEnsRegistrationManager = { - currentRegistrationName: name, - registrations: { - ...registrations, - [lcAccountAddress]: { - ...accountRegistrations, - [name]: { ...registration, mode, name }, - }, - }, - }; +export const ensRegistrationsLoadState = () => async ( + dispatch: Dispatch, + getState: AppGetState +) => { + const { accountAddress, network } = getState().settings; + try { + const registrations = await getLocalENSRegistrations( + accountAddress, + network + ); dispatch({ - payload: updatedEnsRegistrationManager, - type: ENS_START_REGISTRATION, + payload: { registrations }, + type: ENS_LOAD_STATE, }); + // eslint-disable-next-line no-empty + } catch (error) {} +}; + +export const startRegistration = ( + name: string, + mode: keyof typeof REGISTRATION_MODES +) => async (dispatch: AppDispatch, getState: AppGetState) => { + const { + ensRegistration: { registrations }, + settings: { accountAddress }, + } = getState(); + const lcAccountAddress = accountAddress.toLowerCase(); + const accountRegistrations = registrations?.[lcAccountAddress] || {}; + const registration = accountRegistrations[name] || {}; + + const updatedEnsRegistrationManager = { + currentRegistrationName: name, + registrations: { + ...registrations, + [lcAccountAddress]: { + ...accountRegistrations, + [name]: { ...registration, mode, name }, + }, + }, }; + dispatch({ + payload: updatedEnsRegistrationManager, + type: ENS_START_REGISTRATION, + }); +}; -export const continueRegistration = - (name: string) => async (dispatch: AppDispatch) => { - const updatedEnsRegistrationManager = { - currentRegistrationName: name, - }; - dispatch({ - payload: updatedEnsRegistrationManager, - type: ENS_CONTINUE_REGISTRATION, - }); +export const continueRegistration = (name: string) => async ( + dispatch: AppDispatch +) => { + const updatedEnsRegistrationManager = { + currentRegistrationName: name, }; + dispatch({ + payload: updatedEnsRegistrationManager, + type: ENS_CONTINUE_REGISTRATION, + }); +}; -export const removeExpiredRegistrations = - () => async (dispatch: AppDispatch, getState: AppGetState) => { - const { - ensRegistration: { registrations }, - settings: { accountAddress }, - } = getState(); +export const removeExpiredRegistrations = () => async ( + dispatch: AppDispatch, + getState: AppGetState +) => { + const { + ensRegistration: { registrations }, + settings: { accountAddress }, + } = getState(); - const accountRegistrations = - registrations?.[accountAddress.toLowerCase()] || []; + const accountRegistrations = + registrations?.[accountAddress.toLowerCase()] || []; - const registrationsArray = Object.values(accountRegistrations); + const registrationsArray = Object.values(accountRegistrations); - const sevenDaysAgoMs = subDays(new Date(), 7).getTime(); + const sevenDaysAgoMs = subDays(new Date(), 7).getTime(); - const activeRegistrations = registrationsArray.filter(registration => - registration?.commitTransactionConfirmedAt - ? registration?.commitTransactionConfirmedAt >= sevenDaysAgoMs - : true - ); + const activeRegistrations = registrationsArray.filter(registration => + registration?.commitTransactionConfirmedAt + ? registration?.commitTransactionConfirmedAt >= sevenDaysAgoMs + : true + ); - dispatch({ - payload: activeRegistrations, - type: ENS_REMOVE_EXPIRED_REGISTRATIONS, - }); - }; + dispatch({ + payload: activeRegistrations, + type: ENS_REMOVE_EXPIRED_REGISTRATIONS, + }); +}; -export const setInitialRecords = - (records: Records) => - async (dispatch: AppDispatch, getState: AppGetState) => { - const { - ensRegistration: { registrations, currentRegistrationName }, - settings: { accountAddress }, - } = getState(); - const lcAccountAddress = accountAddress.toLowerCase(); - const accountRegistrations = registrations?.[lcAccountAddress] || {}; - const registration = accountRegistrations[currentRegistrationName] || {}; - - const updatedEnsRegistrationManagerForAccount = { - registrations: { - ...registrations, - [lcAccountAddress]: { - ...accountRegistrations, - [currentRegistrationName]: { - ...registration, - initialRecords: records, - records, - }, +export const setInitialRecords = (records: Records) => async ( + dispatch: AppDispatch, + getState: AppGetState +) => { + const { + ensRegistration: { registrations, currentRegistrationName }, + settings: { accountAddress }, + } = getState(); + const lcAccountAddress = accountAddress.toLowerCase(); + const accountRegistrations = registrations?.[lcAccountAddress] || {}; + const registration = accountRegistrations[currentRegistrationName] || {}; + + const updatedEnsRegistrationManagerForAccount = { + registrations: { + ...registrations, + [lcAccountAddress]: { + ...accountRegistrations, + [currentRegistrationName]: { + ...registration, + initialRecords: records, + records, }, }, - }; - dispatch({ - payload: updatedEnsRegistrationManagerForAccount, - type: ENS_REGISTRATION_SET_INITIAL_RECORDS, - }); + }, }; + dispatch({ + payload: updatedEnsRegistrationManagerForAccount, + type: ENS_REGISTRATION_SET_INITIAL_RECORDS, + }); +}; -export const setChangedRecords = - (changedRecords: Records) => - async (dispatch: AppDispatch, getState: AppGetState) => { - const { - ensRegistration: { registrations, currentRegistrationName }, - settings: { accountAddress }, - } = getState(); - const lcAccountAddress = accountAddress.toLowerCase(); - const accountRegistrations = registrations?.[lcAccountAddress] || {}; - const registration = accountRegistrations[currentRegistrationName] || {}; - - const updatedEnsRegistrationManagerForAccount = { - registrations: { - ...registrations, - [lcAccountAddress]: { - ...accountRegistrations, - [currentRegistrationName]: { - ...registration, - changedRecords, - }, +export const setChangedRecords = (changedRecords: Records) => async ( + dispatch: AppDispatch, + getState: AppGetState +) => { + const { + ensRegistration: { registrations, currentRegistrationName }, + settings: { accountAddress }, + } = getState(); + const lcAccountAddress = accountAddress.toLowerCase(); + const accountRegistrations = registrations?.[lcAccountAddress] || {}; + const registration = accountRegistrations[currentRegistrationName] || {}; + + const updatedEnsRegistrationManagerForAccount = { + registrations: { + ...registrations, + [lcAccountAddress]: { + ...accountRegistrations, + [currentRegistrationName]: { + ...registration, + changedRecords, }, }, - }; - dispatch({ - payload: updatedEnsRegistrationManagerForAccount, - type: ENS_REGISTRATION_SET_CHANGED_RECORDS, - }); + }, }; + dispatch({ + payload: updatedEnsRegistrationManagerForAccount, + type: ENS_REGISTRATION_SET_CHANGED_RECORDS, + }); +}; -export const updateRecords = - (records: Records) => - async (dispatch: AppDispatch, getState: AppGetState) => { - const { - ensRegistration: { registrations, currentRegistrationName }, - settings: { accountAddress }, - } = getState(); - const lcAccountAddress = accountAddress.toLowerCase(); - const accountRegistrations = registrations?.[lcAccountAddress] || {}; - const registration = accountRegistrations[currentRegistrationName] || {}; - - const updatedEnsRegistrationManagerForAccount = { - registrations: { - ...registrations, - [lcAccountAddress]: { - ...accountRegistrations, - [currentRegistrationName]: { ...registration, records }, - }, +export const updateRecords = (records: Records) => async ( + dispatch: AppDispatch, + getState: AppGetState +) => { + const { + ensRegistration: { registrations, currentRegistrationName }, + settings: { accountAddress }, + } = getState(); + const lcAccountAddress = accountAddress.toLowerCase(); + const accountRegistrations = registrations?.[lcAccountAddress] || {}; + const registration = accountRegistrations[currentRegistrationName] || {}; + + const updatedEnsRegistrationManagerForAccount = { + registrations: { + ...registrations, + [lcAccountAddress]: { + ...accountRegistrations, + [currentRegistrationName]: { ...registration, records }, }, - }; - dispatch({ - payload: updatedEnsRegistrationManagerForAccount, - type: ENS_REGISTRATION_UPDATE_RECORDS, - }); + }, }; + dispatch({ + payload: updatedEnsRegistrationManagerForAccount, + type: ENS_REGISTRATION_UPDATE_RECORDS, + }); +}; -export const updateRecordByKey = - (key: string, value: string) => - async (dispatch: AppDispatch, getState: AppGetState) => { - const { - ensRegistration: { registrations, currentRegistrationName }, - settings: { accountAddress }, - } = getState(); - const lcAccountAddress = accountAddress.toLowerCase(); - - const accountRegistrations = registrations?.[lcAccountAddress] || {}; - const registration = accountRegistrations[currentRegistrationName] || {}; - const registrationRecords = registration?.records || {}; - const updatedEnsRegistrationManagerForAccount = { - registrations: { - ...registrations, - [lcAccountAddress]: { - ...accountRegistrations, - [currentRegistrationName]: { - ...registration, - records: { ...registrationRecords, [key]: value }, - }, +export const updateRecordByKey = (key: string, value: string) => async ( + dispatch: AppDispatch, + getState: AppGetState +) => { + const { + ensRegistration: { registrations, currentRegistrationName }, + settings: { accountAddress }, + } = getState(); + const lcAccountAddress = accountAddress.toLowerCase(); + + const accountRegistrations = registrations?.[lcAccountAddress] || {}; + const registration = accountRegistrations[currentRegistrationName] || {}; + const registrationRecords = registration?.records || {}; + const updatedEnsRegistrationManagerForAccount = { + registrations: { + ...registrations, + [lcAccountAddress]: { + ...accountRegistrations, + [currentRegistrationName]: { + ...registration, + records: { ...registrationRecords, [key]: value }, }, }, - }; - dispatch({ - payload: updatedEnsRegistrationManagerForAccount, - type: ENS_REGISTRATION_UPDATE_RECORDS, - }); + }, }; + dispatch({ + payload: updatedEnsRegistrationManagerForAccount, + type: ENS_REGISTRATION_UPDATE_RECORDS, + }); +}; -export const removeRecordByKey = - (key: string) => async (dispatch: AppDispatch, getState: AppGetState) => { - const { - ensRegistration: { registrations, currentRegistrationName }, - settings: { accountAddress }, - } = getState(); - - const lcAccountAddress = accountAddress.toLowerCase(); - const accountRegistrations = registrations?.[lcAccountAddress] || {}; - const registration = accountRegistrations[currentRegistrationName] || {}; - const registrationRecords = registration?.records || {}; - - const newRecords = omitFlatten(registrationRecords, key as ENS_RECORDS); - - const updatedEnsRegistrationManagerForAccount = { - registrations: { - ...registrations, - [lcAccountAddress]: { - ...accountRegistrations, - [currentRegistrationName]: { - ...registration, - records: newRecords, - }, +export const removeRecordByKey = (key: string) => async ( + dispatch: AppDispatch, + getState: AppGetState +) => { + const { + ensRegistration: { registrations, currentRegistrationName }, + settings: { accountAddress }, + } = getState(); + + const lcAccountAddress = accountAddress.toLowerCase(); + const accountRegistrations = registrations?.[lcAccountAddress] || {}; + const registration = accountRegistrations[currentRegistrationName] || {}; + const registrationRecords = registration?.records || {}; + + const newRecords = omitFlatten(registrationRecords, key as ENS_RECORDS); + + const updatedEnsRegistrationManagerForAccount = { + registrations: { + ...registrations, + [lcAccountAddress]: { + ...accountRegistrations, + [currentRegistrationName]: { + ...registration, + records: newRecords, }, }, - }; - - dispatch({ - payload: updatedEnsRegistrationManagerForAccount, - type: ENS_REGISTRATION_REMOVE_RECORD_BY_KEY, - }); + }, }; -export const saveCommitRegistrationParameters = - ( - registrationParameters: - | RegistrationParameters - | TransactionRegistrationParameters - ) => - async (dispatch: AppDispatch, getState: AppGetState) => { - const { - ensRegistration: { registrations, currentRegistrationName }, - settings: { accountAddress }, - } = getState(); - const registrationName = - (registrationParameters as RegistrationParameters)?.name || - currentRegistrationName; - const lcAccountAddress = accountAddress.toLowerCase(); - const accountRegistrations = registrations?.[lcAccountAddress] || {}; - const registration = accountRegistrations[registrationName] || {}; - const updatedEnsRegistrationManager = { - registrations: { - ...registrations, - [lcAccountAddress]: { - ...accountRegistrations, - [registrationName]: { - ...registration, - ...registrationParameters, - }, + dispatch({ + payload: updatedEnsRegistrationManagerForAccount, + type: ENS_REGISTRATION_REMOVE_RECORD_BY_KEY, + }); +}; + +export const saveCommitRegistrationParameters = ( + registrationParameters: + | RegistrationParameters + | TransactionRegistrationParameters +) => async (dispatch: AppDispatch, getState: AppGetState) => { + const { + ensRegistration: { registrations, currentRegistrationName }, + settings: { accountAddress }, + } = getState(); + const registrationName = + (registrationParameters as RegistrationParameters)?.name || + currentRegistrationName; + const lcAccountAddress = accountAddress.toLowerCase(); + const accountRegistrations = registrations?.[lcAccountAddress] || {}; + const registration = accountRegistrations[registrationName] || {}; + const updatedEnsRegistrationManager = { + registrations: { + ...registrations, + [lcAccountAddress]: { + ...accountRegistrations, + [registrationName]: { + ...registration, + ...registrationParameters, }, }, - }; + }, + }; - saveLocalENSRegistrations( - updatedEnsRegistrationManager.registrations, - accountAddress, - NetworkTypes.mainnet - ); + saveLocalENSRegistrations( + updatedEnsRegistrationManager.registrations, + accountAddress, + NetworkTypes.mainnet + ); - dispatch({ - payload: updatedEnsRegistrationManager, - type: ENS_SAVE_COMMIT_REGISTRATION_PARAMETERS, - }); - }; + dispatch({ + payload: updatedEnsRegistrationManager, + type: ENS_SAVE_COMMIT_REGISTRATION_PARAMETERS, + }); +}; -export const clearCurrentRegistrationName = - () => async (dispatch: AppDispatch) => { - dispatch({ - type: ENS_CLEAR_CURRENT_REGISTRATION_NAME, - }); - }; +export const clearCurrentRegistrationName = () => async ( + dispatch: AppDispatch +) => { + dispatch({ + type: ENS_CLEAR_CURRENT_REGISTRATION_NAME, + }); +}; -export const updateTransactionRegistrationParameters = - (registrationParameters: TransactionRegistrationParameters) => - async (dispatch: AppDispatch, getState: AppGetState) => { - const { - ensRegistration: { registrations, currentRegistrationName }, - settings: { accountAddress }, - } = getState(); - - const lcAccountAddress = accountAddress.toLowerCase(); - const accountRegistrations = registrations?.[lcAccountAddress] || {}; - const registration = accountRegistrations[currentRegistrationName] || {}; - const updatedEnsRegistrationManager = { - registrations: { - ...registrations, - [lcAccountAddress]: { - ...accountRegistrations, - [currentRegistrationName]: { - ...registration, - ...registrationParameters, - }, +export const updateTransactionRegistrationParameters = ( + registrationParameters: TransactionRegistrationParameters +) => async (dispatch: AppDispatch, getState: AppGetState) => { + const { + ensRegistration: { registrations, currentRegistrationName }, + settings: { accountAddress }, + } = getState(); + + const lcAccountAddress = accountAddress.toLowerCase(); + const accountRegistrations = registrations?.[lcAccountAddress] || {}; + const registration = accountRegistrations[currentRegistrationName] || {}; + const updatedEnsRegistrationManager = { + registrations: { + ...registrations, + [lcAccountAddress]: { + ...accountRegistrations, + [currentRegistrationName]: { + ...registration, + ...registrationParameters, }, }, - }; + }, + }; - saveLocalENSRegistrations( - updatedEnsRegistrationManager.registrations, - accountAddress, - NetworkTypes.mainnet - ); + saveLocalENSRegistrations( + updatedEnsRegistrationManager.registrations, + accountAddress, + NetworkTypes.mainnet + ); - dispatch({ - payload: updatedEnsRegistrationManager, - type: ENS_UPDATE_REGISTRATION_PARAMETERS, - }); - }; + dispatch({ + payload: updatedEnsRegistrationManager, + type: ENS_UPDATE_REGISTRATION_PARAMETERS, + }); +}; -export const removeRegistrationByName = - (name: string) => async (dispatch: AppDispatch, getState: AppGetState) => { - const { - ensRegistration: { registrations }, - settings: { accountAddress }, - } = getState(); - - const lcAccountAddress = accountAddress.toLowerCase(); - const accountRegistrations = registrations?.[lcAccountAddress] || {}; - delete accountRegistrations?.[name]; - const updatedEnsRegistrationManager = { - registrations: { - ...registrations, - [lcAccountAddress]: { - ...accountRegistrations, - }, +export const removeRegistrationByName = (name: string) => async ( + dispatch: AppDispatch, + getState: AppGetState +) => { + const { + ensRegistration: { registrations }, + settings: { accountAddress }, + } = getState(); + + const lcAccountAddress = accountAddress.toLowerCase(); + const accountRegistrations = registrations?.[lcAccountAddress] || {}; + delete accountRegistrations?.[name]; + const updatedEnsRegistrationManager = { + registrations: { + ...registrations, + [lcAccountAddress]: { + ...accountRegistrations, }, - }; + }, + }; - saveLocalENSRegistrations( - updatedEnsRegistrationManager.registrations, - accountAddress, - NetworkTypes.mainnet - ); + saveLocalENSRegistrations( + updatedEnsRegistrationManager.registrations, + accountAddress, + NetworkTypes.mainnet + ); - dispatch({ - payload: updatedEnsRegistrationManager, - type: ENS_UPDATE_REGISTRATION_PARAMETERS, - }); - }; + dispatch({ + payload: updatedEnsRegistrationManager, + type: ENS_UPDATE_REGISTRATION_PARAMETERS, + }); +}; // -- Reducer ----------------------------------------- // const INITIAL_STATE: ENSRegistrationState = { diff --git a/src/redux/explorer.ts b/src/redux/explorer.ts index 5799b5ef2a9..aa6648fb292 100644 --- a/src/redux/explorer.ts +++ b/src/redux/explorer.ts @@ -193,22 +193,24 @@ const portfolioSubscription = ( * @param address The address to subscribe to. * @returns Arguments for an `emit` function call. */ -export const notificationsSubscription = - (address: string) => (_: Dispatch, getState: AppGetState) => { - const { addressSocket } = getState().explorer; - - const payload: SocketEmitArguments = [ - 'get', - { - payload: { - address, - action: 'subscribe', - }, - scope: ['notifications'], +export const notificationsSubscription = (address: string) => ( + _: Dispatch, + getState: AppGetState +) => { + const { addressSocket } = getState().explorer; + + const payload: SocketEmitArguments = [ + 'get', + { + payload: { + address, + action: 'subscribe', }, - ]; - addressSocket?.emit(...payload); - }; + scope: ['notifications'], + }, + ]; + addressSocket?.emit(...payload); +}; /** * Configures an asset price subscription. @@ -291,34 +293,39 @@ const l2AddressTransactionHistoryRequest = ( * * @param assetAddress The address or addresses to fetch. */ -export const fetchAssetPrices = - (assetAddress: string | string[]) => (_: Dispatch, getState: AppGetState) => { - const { assetsSocket } = getState().explorer; - const { nativeCurrency } = getState().settings; - - const assetCodes = Array.isArray(assetAddress) - ? assetAddress - : [assetAddress]; - - const payload: SocketEmitArguments = [ - 'get', - { - payload: { - asset_codes: assetCodes, - currency: toLower(nativeCurrency), - }, - scope: ['prices'], +export const fetchAssetPrices = (assetAddress: string | string[]) => ( + _: Dispatch, + getState: AppGetState +) => { + const { assetsSocket } = getState().explorer; + const { nativeCurrency } = getState().settings; + + const assetCodes = Array.isArray(assetAddress) + ? assetAddress + : [assetAddress]; + + const payload: SocketEmitArguments = [ + 'get', + { + payload: { + asset_codes: assetCodes, + currency: toLower(nativeCurrency), }, - ]; - assetsSocket?.emit(...payload); - }; + scope: ['prices'], + }, + ]; + assetsSocket?.emit(...payload); +}; /** * Unsubscribes from existing asset subscriptions. */ const explorerUnsubscribe = () => (_: Dispatch, getState: AppGetState) => { - const { addressSocket, addressSubscribed, assetsSocket } = - getState().explorer; + const { + addressSocket, + addressSubscribed, + assetsSocket, + } = getState().explorer; const { nativeCurrency } = getState().settings; const pairs = rainbowTokenList.CURATED_TOKENS; if (!isNil(addressSocket)) { @@ -338,65 +345,63 @@ const explorerUnsubscribe = () => (_: Dispatch, getState: AppGetState) => { /** * Clears the explorer's state and unsubscribes from listeners. */ -export const explorerClearState = - () => - (dispatch: ThunkDispatch) => { - dispatch(explorerUnsubscribe()); - dispatch({ type: EXPLORER_CLEAR_STATE }); - }; +export const explorerClearState = () => ( + dispatch: ThunkDispatch +) => { + dispatch(explorerUnsubscribe()); + dispatch({ type: EXPLORER_CLEAR_STATE }); +}; /** * Initializes the explorer, creating sockets and configuring listeners. */ -export const explorerInit = - () => - async ( - dispatch: ThunkDispatch, - getState: AppGetState - ) => { - const { network, accountAddress, nativeCurrency } = getState().settings; - const pairs = rainbowTokenList.CURATED_TOKENS; - const { addressSocket, assetsSocket } = getState().explorer; - - // if there is another socket unsubscribe first - if (addressSocket || assetsSocket) { - dispatch(explorerUnsubscribe()); - } +export const explorerInit = () => async ( + dispatch: ThunkDispatch, + getState: AppGetState +) => { + const { network, accountAddress, nativeCurrency } = getState().settings; + const pairs = rainbowTokenList.CURATED_TOKENS; + const { addressSocket, assetsSocket } = getState().explorer; - const provider = await getProviderForNetwork(network); - const providerUrl = provider?.connection?.url; - if (isHardHat(providerUrl) || network !== Network.mainnet) { - return; - } + // if there is another socket unsubscribe first + if (addressSocket || assetsSocket) { + dispatch(explorerUnsubscribe()); + } - const newAddressSocket = createSocket('address'); - const newAssetsSocket = createSocket('assets'); - dispatch({ - payload: { - addressSocket: newAddressSocket, - addressSubscribed: accountAddress, - assetsSocket: newAssetsSocket, - }, - type: EXPLORER_UPDATE_SOCKETS, - }); + const provider = await getProviderForNetwork(network); + const providerUrl = provider?.connection?.url; + if (isHardHat(providerUrl) || network !== Network.mainnet) { + return; + } + + const newAddressSocket = createSocket('address'); + const newAssetsSocket = createSocket('assets'); + dispatch({ + payload: { + addressSocket: newAddressSocket, + addressSubscribed: accountAddress, + assetsSocket: newAssetsSocket, + }, + type: EXPLORER_UPDATE_SOCKETS, + }); - dispatch(listenOnAddressMessages(newAddressSocket)); + dispatch(listenOnAddressMessages(newAddressSocket)); - newAddressSocket.on(messages.CONNECT, () => { - newAddressSocket.emit( - ...addressSubscription(accountAddress, nativeCurrency) - ); - }); + newAddressSocket.on(messages.CONNECT, () => { + newAddressSocket.emit( + ...addressSubscription(accountAddress, nativeCurrency) + ); + }); - dispatch(listenOnAssetMessages(newAssetsSocket)); + dispatch(listenOnAssetMessages(newAssetsSocket)); - newAssetsSocket.on(messages.CONNECT, () => { - dispatch(emitAssetRequest(keys(pairs))); + newAssetsSocket.on(messages.CONNECT, () => { + dispatch(emitAssetRequest(keys(pairs))); - // we want to get ETH info ASAP - dispatch(emitAssetRequest(ETH_ADDRESS)); - }); - }; + // we want to get ETH info ASAP + dispatch(emitAssetRequest(ETH_ADDRESS)); + }); +}; /** * Emits a portfolio request. The result is handled by a listener in @@ -405,14 +410,15 @@ export const explorerInit = * @param address The address. * @param currency The currency to use. */ -export const emitPortfolioRequest = - (address: string, currency?: string) => - (_: Dispatch, getState: AppGetState) => { - const nativeCurrency = currency || getState().settings.nativeCurrency; - const { addressSocket } = getState().explorer; - - addressSocket?.emit(...portfolioSubscription(address, nativeCurrency)); - }; +export const emitPortfolioRequest = (address: string, currency?: string) => ( + _: Dispatch, + getState: AppGetState +) => { + const nativeCurrency = currency || getState().settings.nativeCurrency; + const { addressSocket } = getState().explorer; + + addressSocket?.emit(...portfolioSubscription(address, nativeCurrency)); +}; /** * Subscribes to asset price information. The result is handled by a listener @@ -420,160 +426,163 @@ export const emitPortfolioRequest = * * @param assetAddress The asset address or addresses to request. */ -export const emitAssetRequest = - (assetAddress: string | string[]) => (_: Dispatch, getState: AppGetState) => { - const { nativeCurrency } = getState().settings; - const { assetsSocket } = getState().explorer; +export const emitAssetRequest = (assetAddress: string | string[]) => ( + _: Dispatch, + getState: AppGetState +) => { + const { nativeCurrency } = getState().settings; + const { assetsSocket } = getState().explorer; - const assetCodes = Array.isArray(assetAddress) - ? assetAddress - : [assetAddress]; + const assetCodes = Array.isArray(assetAddress) + ? assetAddress + : [assetAddress]; - const newAssetsCodes = assetCodes.filter( - code => !TokensListenedCache?.[nativeCurrency]?.[code] - ); + const newAssetsCodes = assetCodes.filter( + code => !TokensListenedCache?.[nativeCurrency]?.[code] + ); - newAssetsCodes.forEach(code => { - if (!TokensListenedCache?.[nativeCurrency]) { - TokensListenedCache[nativeCurrency] = {}; - } - assetsSocket && (TokensListenedCache[nativeCurrency][code] = true); - }); - - if (assetsSocket) { - if (newAssetsCodes.length > 0) { - assetsSocket.emit( - ...assetPricesSubscription(newAssetsCodes, nativeCurrency) - ); - assetsSocket.emit(...ethUSDSubscription); - return true; - } - } else { - setTimeout(() => emitAssetRequest(assetAddress), 100); + newAssetsCodes.forEach(code => { + if (!TokensListenedCache?.[nativeCurrency]) { + TokensListenedCache[nativeCurrency] = {}; + } + assetsSocket && (TokensListenedCache[nativeCurrency][code] = true); + }); + + if (assetsSocket) { + if (newAssetsCodes.length > 0) { + assetsSocket.emit( + ...assetPricesSubscription(newAssetsCodes, nativeCurrency) + ); + assetsSocket.emit(...ethUSDSubscription); + return true; } - return false; - }; + } else { + setTimeout(() => emitAssetRequest(assetAddress), 100); + } + return false; +}; /** * Emits a layer-2 transaction history request for the current address. The * result is handled by a listener in `listenOnAddressMessages`. */ -export const emitL2TransactionHistoryRequest = - () => (_: Dispatch, getState: AppGetState) => { - const { accountAddress, nativeCurrency } = getState().settings; - const { addressSocket } = getState().explorer; - addressSocket!.emit( - ...l2AddressTransactionHistoryRequest(accountAddress, nativeCurrency) - ); - }; +export const emitL2TransactionHistoryRequest = () => ( + _: Dispatch, + getState: AppGetState +) => { + const { accountAddress, nativeCurrency } = getState().settings; + const { addressSocket } = getState().explorer; + addressSocket!.emit( + ...l2AddressTransactionHistoryRequest(accountAddress, nativeCurrency) + ); +}; /** * Adds asset message listeners to a given socket. * * @param socket The socket to add listeners to. */ -const listenOnAssetMessages = - (socket: Socket) => (dispatch: ThunkDispatch) => { - socket.on( - messages.ASSETS.RECEIVED, - (message: AssetPricesReceivedMessage) => { - dispatch(assetPricesReceived(message)); - } - ); +const listenOnAssetMessages = (socket: Socket) => ( + dispatch: ThunkDispatch +) => { + socket.on(messages.ASSETS.RECEIVED, (message: AssetPricesReceivedMessage) => { + dispatch(assetPricesReceived(message)); + }); - socket.on(messages.ASSETS.CHANGED, (message: AssetPricesChangedMessage) => { - dispatch(assetPricesChanged(message)); - }); + socket.on(messages.ASSETS.CHANGED, (message: AssetPricesChangedMessage) => { + dispatch(assetPricesChanged(message)); + }); - socket.on( - messages.ASSET_CHARTS.RECEIVED, - (message: ChartsReceivedMessage) => { - // logger.log('charts received', message?.payload?.charts); - dispatch(assetChartsReceived(message)); - } - ); - }; + socket.on( + messages.ASSET_CHARTS.RECEIVED, + (message: ChartsReceivedMessage) => { + // logger.log('charts received', message?.payload?.charts); + dispatch(assetChartsReceived(message)); + } + ); +}; /** * Adds listeners for address information messages to a given socket. * * @param socket The socket to add listeners to. */ -const listenOnAddressMessages = - (socket: Socket) => (dispatch: ThunkDispatch) => { - socket.on( - messages.ADDRESS_PORTFOLIO.RECEIVED, - (message: PortfolioReceivedMessage) => { - dispatch(portfolioReceived(message)); - } - ); +const listenOnAddressMessages = (socket: Socket) => ( + dispatch: ThunkDispatch +) => { + socket.on( + messages.ADDRESS_PORTFOLIO.RECEIVED, + (message: PortfolioReceivedMessage) => { + dispatch(portfolioReceived(message)); + } + ); - socket.on( - messages.ADDRESS_TRANSACTIONS.RECEIVED, - (message: TransactionsReceivedMessage) => { - // logger.log('mainnet txns received', message?.payload?.transactions); + socket.on( + messages.ADDRESS_TRANSACTIONS.RECEIVED, + (message: TransactionsReceivedMessage) => { + // logger.log('mainnet txns received', message?.payload?.transactions); - if (getExperimetalFlag(L2_TXS)) { - dispatch(emitL2TransactionHistoryRequest()); - } - dispatch(transactionsReceived(message)); + if (getExperimetalFlag(L2_TXS)) { + dispatch(emitL2TransactionHistoryRequest()); } - ); + dispatch(transactionsReceived(message)); + } + ); - socket.on( - messages.ADDRESS_TRANSACTIONS.RECEIVED_ARBITRUM, - (message: TransactionsReceivedMessage) => { - // logger.log('arbitrum txns received', message?.payload?.transactions); - dispatch(transactionsReceived(message)); - } - ); + socket.on( + messages.ADDRESS_TRANSACTIONS.RECEIVED_ARBITRUM, + (message: TransactionsReceivedMessage) => { + // logger.log('arbitrum txns received', message?.payload?.transactions); + dispatch(transactionsReceived(message)); + } + ); - socket.on( - messages.ADDRESS_TRANSACTIONS.RECEIVED_OPTIMISM, - (message: TransactionsReceivedMessage) => { - // logger.log('optimism txns received', message?.payload?.transactions); - dispatch(transactionsReceived(message)); - } - ); + socket.on( + messages.ADDRESS_TRANSACTIONS.RECEIVED_OPTIMISM, + (message: TransactionsReceivedMessage) => { + // logger.log('optimism txns received', message?.payload?.transactions); + dispatch(transactionsReceived(message)); + } + ); - socket.on( - messages.ADDRESS_TRANSACTIONS.RECEIVED_POLYGON, - (message: TransactionsReceivedMessage) => { - // logger.log('polygon txns received', message?.payload?.transactions); - dispatch(transactionsReceived(message)); - } - ); + socket.on( + messages.ADDRESS_TRANSACTIONS.RECEIVED_POLYGON, + (message: TransactionsReceivedMessage) => { + // logger.log('polygon txns received', message?.payload?.transactions); + dispatch(transactionsReceived(message)); + } + ); - socket.on( - messages.ADDRESS_TRANSACTIONS.RECEIVED_BSC, - (message: TransactionsReceivedMessage) => { - // logger.log('bsc txns received', message?.payload?.transactions); - dispatch(transactionsReceived(message)); - } - ); - socket.on( - messages.ADDRESS_TRANSACTIONS.RECEIVED_ZORA, - (message: TransactionsReceivedMessage) => { - // logger.log('zora txns received', message?.payload?.transactions); - dispatch(transactionsReceived(message)); - } - ); - socket.on( - messages.ADDRESS_TRANSACTIONS.RECEIVED_BASE, - (message: TransactionsReceivedMessage) => { - // logger.log('base txns received', message?.payload?.transactions); - dispatch(transactionsReceived(message)); - } - ); + socket.on( + messages.ADDRESS_TRANSACTIONS.RECEIVED_BSC, + (message: TransactionsReceivedMessage) => { + // logger.log('bsc txns received', message?.payload?.transactions); + dispatch(transactionsReceived(message)); + } + ); + socket.on( + messages.ADDRESS_TRANSACTIONS.RECEIVED_ZORA, + (message: TransactionsReceivedMessage) => { + // logger.log('zora txns received', message?.payload?.transactions); + dispatch(transactionsReceived(message)); + } + ); + socket.on( + messages.ADDRESS_TRANSACTIONS.RECEIVED_BASE, + (message: TransactionsReceivedMessage) => { + // logger.log('base txns received', message?.payload?.transactions); + dispatch(transactionsReceived(message)); + } + ); - socket.on( - messages.ADDRESS_TRANSACTIONS.APPENDED, - (message: TransactionsReceivedMessage) => { - logger.log('txns appended', message?.payload?.transactions); - dispatch(transactionsReceived(message, true)); - } - ); - }; + socket.on( + messages.ADDRESS_TRANSACTIONS.APPENDED, + (message: TransactionsReceivedMessage) => { + logger.log('txns appended', message?.payload?.transactions); + dispatch(transactionsReceived(message, true)); + } + ); +}; // -- Reducer ----------------------------------------- // const INITIAL_STATE: ExplorerState = { diff --git a/src/redux/gas.ts b/src/redux/gas.ts index 193ba3fd834..7e0e45fb0ee 100644 --- a/src/redux/gas.ts +++ b/src/redux/gas.ts @@ -183,90 +183,91 @@ const getUpdatedGasFeeParams = ( * @param speed * @param newMaxPriorityFeePerGas */ -export const updateGasFeeForSpeed = - (speed: string, newMaxPriorityFeePerGas: string) => - async (dispatch: AppDispatch, getState: AppGetState) => { - const { gasFeeParamsBySpeed } = getState().gas; - const newGasFeeParams = { ...gasFeeParamsBySpeed }; - newGasFeeParams[speed].maxPriorityFeePerGas = parseGasFeeParam( - newMaxPriorityFeePerGas - ); +export const updateGasFeeForSpeed = ( + speed: string, + newMaxPriorityFeePerGas: string +) => async (dispatch: AppDispatch, getState: AppGetState) => { + const { gasFeeParamsBySpeed } = getState().gas; + const newGasFeeParams = { ...gasFeeParamsBySpeed }; + newGasFeeParams[speed].maxPriorityFeePerGas = parseGasFeeParam( + newMaxPriorityFeePerGas + ); - dispatch({ - payload: { - gasFeeParamsBySpeed: newGasFeeParams, - }, - type: GAS_PRICES_SUCCESS, - }); - }; + dispatch({ + payload: { + gasFeeParamsBySpeed: newGasFeeParams, + }, + type: GAS_PRICES_SUCCESS, + }); +}; -export const gasUpdateToCustomGasFee = - (gasParams: GasFeeParams) => - async (dispatch: AppDispatch, getState: AppGetState) => { - const { - txNetwork, - defaultGasLimit, - gasFeesBySpeed, - gasFeeParamsBySpeed, - gasLimit, - currentBlockParams, - blocksToConfirmation, - secondsPerNewBlock, - l1GasFeeOptimism, - } = getState().gas; +export const gasUpdateToCustomGasFee = (gasParams: GasFeeParams) => async ( + dispatch: AppDispatch, + getState: AppGetState +) => { + const { + txNetwork, + defaultGasLimit, + gasFeesBySpeed, + gasFeeParamsBySpeed, + gasLimit, + currentBlockParams, + blocksToConfirmation, + secondsPerNewBlock, + l1GasFeeOptimism, + } = getState().gas; - const { nativeCurrency } = getState().settings; - const _gasLimit = - gasLimit || getDefaultGasLimit(txNetwork, defaultGasLimit); - - let nativeTokenPriceUnit = ethereumUtils.getEthPriceUnit(); - - switch (txNetwork) { - case Network.polygon: - nativeTokenPriceUnit = ethereumUtils.getMaticPriceUnit(); - break; - case Network.bsc: - nativeTokenPriceUnit = ethereumUtils.getBnbPriceUnit(); - break; - default: - nativeTokenPriceUnit = ethereumUtils.getEthPriceUnit(); - break; - } + const { nativeCurrency } = getState().settings; + const _gasLimit = gasLimit || getDefaultGasLimit(txNetwork, defaultGasLimit); - const customGasFees = parseGasFees( - gasParams, - currentBlockParams?.baseFeePerGas, - _gasLimit, - nativeTokenPriceUnit, - nativeCurrency, - l1GasFeeOptimism - ); - const newGasFeesBySpeed = { ...gasFeesBySpeed }; - const newGasFeeParamsBySpeed = { ...gasFeeParamsBySpeed }; - - newGasFeesBySpeed[CUSTOM] = customGasFees; - newGasFeeParamsBySpeed[CUSTOM] = defaultGasParamsFormat( - CUSTOM, - gasParams.maxBaseFee.amount, - gasParams.maxPriorityFeePerGas.amount, - blocksToConfirmation, - secondsPerNewBlock - ); - const newSelectedGasFee = getSelectedGasFee( - newGasFeeParamsBySpeed, - newGasFeesBySpeed, - CUSTOM - ); - dispatch({ - payload: { - customGasFeeModifiedByUser: true, - gasFeeParamsBySpeed: newGasFeeParamsBySpeed, - gasFeesBySpeed: newGasFeesBySpeed, - selectedGasFee: newSelectedGasFee.selectedGasFee, - }, - type: GAS_PRICES_CUSTOM_UPDATE, - }); - }; + let nativeTokenPriceUnit = ethereumUtils.getEthPriceUnit(); + + switch (txNetwork) { + case Network.polygon: + nativeTokenPriceUnit = ethereumUtils.getMaticPriceUnit(); + break; + case Network.bsc: + nativeTokenPriceUnit = ethereumUtils.getBnbPriceUnit(); + break; + default: + nativeTokenPriceUnit = ethereumUtils.getEthPriceUnit(); + break; + } + + const customGasFees = parseGasFees( + gasParams, + currentBlockParams?.baseFeePerGas, + _gasLimit, + nativeTokenPriceUnit, + nativeCurrency, + l1GasFeeOptimism + ); + const newGasFeesBySpeed = { ...gasFeesBySpeed }; + const newGasFeeParamsBySpeed = { ...gasFeeParamsBySpeed }; + + newGasFeesBySpeed[CUSTOM] = customGasFees; + newGasFeeParamsBySpeed[CUSTOM] = defaultGasParamsFormat( + CUSTOM, + gasParams.maxBaseFee.amount, + gasParams.maxPriorityFeePerGas.amount, + blocksToConfirmation, + secondsPerNewBlock + ); + const newSelectedGasFee = getSelectedGasFee( + newGasFeeParamsBySpeed, + newGasFeesBySpeed, + CUSTOM + ); + dispatch({ + payload: { + customGasFeeModifiedByUser: true, + gasFeeParamsBySpeed: newGasFeeParamsBySpeed, + gasFeesBySpeed: newGasFeesBySpeed, + selectedGasFee: newSelectedGasFee.selectedGasFee, + }, + type: GAS_PRICES_CUSTOM_UPDATE, + }); +}; export const getPolygonGasPrices = async () => { try { @@ -439,301 +440,299 @@ export const getEIP1559GasParams = async (network: Network) => { }; }; -export const gasPricesStartPolling = - (network = Network.mainnet, flashbots = false) => - async (dispatch: AppDispatch, getState: AppGetState) => { - dispatch(gasPricesStopPolling()); - - // this should be chain agnostic - const getGasPrices = (network: Network) => - withRunExclusive( - () => - new Promise(async (fetchResolve, fetchReject) => { - try { +export const gasPricesStartPolling = ( + network = Network.mainnet, + flashbots = false +) => async (dispatch: AppDispatch, getState: AppGetState) => { + dispatch(gasPricesStopPolling()); + + // this should be chain agnostic + const getGasPrices = (network: Network) => + withRunExclusive( + () => + new Promise(async (fetchResolve, fetchReject) => { + try { + dispatch({ + payload: network, + type: GAS_UPDATE_TRANSACTION_NETWORK, + }); + const { + gasFeeParamsBySpeed: existingGasFees, + customGasFeeModifiedByUser, + defaultGasLimit, + gasLimit, + selectedGasFee, + txNetwork, + selectedGasFee: lastSelectedGasFee, + gasFeesBySpeed: lastGasFeesBySpeed, + currentBlockParams, + l1GasFeeOptimism, + } = getState().gas; + const { nativeCurrency } = getState().settings; + + const networkObj = getNetworkObj(network); + let dataIsReady = true; + + if (networkObj.gas.gasType === 'legacy') { + // OP chains have an additional fee we need to load + if (getNetworkObj(network).gas?.OptimismTxFee) { + dataIsReady = l1GasFeeOptimism !== null; + } + + const adjustedGasFees = await networkObj.gas.getGasPrices(); + + if (!adjustedGasFees) return; + + const gasFeeParamsBySpeed = parseL2GasPrices(adjustedGasFees); + if (!gasFeeParamsBySpeed) return; + + const _selectedGasFeeOption = selectedGasFee.option || NORMAL; + const _gasLimit = + gasLimit || getDefaultGasLimit(txNetwork, defaultGasLimit); + const { + selectedGasFee: updatedSelectedGasFee, + gasFeesBySpeed: updatedGasFeesBySpeed, + } = dataIsReady + ? getUpdatedGasFeeParams( + currentBlockParams?.baseFeePerGas, + gasFeeParamsBySpeed, + _gasLimit, + nativeCurrency, + _selectedGasFeeOption, + txNetwork, + l1GasFeeOptimism + ) + : { + gasFeesBySpeed: lastGasFeesBySpeed, + selectedGasFee: lastSelectedGasFee, + }; dispatch({ - payload: network, - type: GAS_UPDATE_TRANSACTION_NETWORK, + payload: { + gasFeeParamsBySpeed, + gasFeesBySpeed: updatedGasFeesBySpeed, + selectedGasFee: updatedSelectedGasFee, + }, + type: GAS_FEES_SUCCESS, }); - const { - gasFeeParamsBySpeed: existingGasFees, - customGasFeeModifiedByUser, - defaultGasLimit, - gasLimit, - selectedGasFee, - txNetwork, - selectedGasFee: lastSelectedGasFee, - gasFeesBySpeed: lastGasFeesBySpeed, - currentBlockParams, - l1GasFeeOptimism, - } = getState().gas; - const { nativeCurrency } = getState().settings; - - const networkObj = getNetworkObj(network); - let dataIsReady = true; - - if (networkObj.gas.gasType === 'legacy') { - // OP chains have an additional fee we need to load - if (getNetworkObj(network).gas?.OptimismTxFee) { - dataIsReady = l1GasFeeOptimism !== null; + } else { + try { + const { + gasFeeParamsBySpeed, + baseFeePerGas, + trend, + currentBaseFee, + blocksToConfirmation, + secondsPerNewBlock, + } = await getEIP1559GasParams(network); + + if (flashbots) { + [SLOW, NORMAL, FAST, URGENT].forEach(speed => { + // Override min tip to 5 if needed, when flashbots is enabled + // See https://docs.flashbots.net/flashbots-protect/rpc/quick-start#choosing-the-right-gas-price + if (gasFeeParamsBySpeed[speed]) { + if ( + Number( + gasFeeParamsBySpeed[speed].maxPriorityFeePerGas.gwei + ) < FLASHBOTS_MIN_TIP + ) { + gasFeeParamsBySpeed[speed] = { + ...gasFeeParamsBySpeed[speed], + maxPriorityFeePerGas: { + amount: `${FLASHBOTS_MIN_TIP}000000000`, + display: `${FLASHBOTS_MIN_TIP} gwei`, + gwei: `${FLASHBOTS_MIN_TIP}`, + }, + }; + } + } + }); } - const adjustedGasFees = await networkObj.gas.getGasPrices(); - - if (!adjustedGasFees) return; - - const gasFeeParamsBySpeed = parseL2GasPrices(adjustedGasFees); - if (!gasFeeParamsBySpeed) return; + // Set a really gas estimate to guarantee that we're gonna be over + // the basefee at the time we fork mainnet during our hardhat tests + let baseFee = baseFeePerGas; + if (network === Network.mainnet && IS_TESTING === 'true') { + const providerUrl = ( + web3Provider || + ({} as { + connection: { url: string }; + }) + )?.connection?.url; + if (isHardHat(providerUrl)) { + baseFee = parseGasFeeParam(gweiToWei(1000)); + } + } + if (customGasFeeModifiedByUser) { + // Preserve custom values while updating prices + gasFeeParamsBySpeed[CUSTOM] = { + ...existingGasFees[CUSTOM], + baseFeePerGas: baseFee, + }; + } else { + // set CUSTOM to URGENT if not defined + gasFeeParamsBySpeed[CUSTOM] = gasFeeParamsBySpeed[URGENT]; + } const _selectedGasFeeOption = selectedGasFee.option || NORMAL; const _gasLimit = gasLimit || getDefaultGasLimit(txNetwork, defaultGasLimit); + const { selectedGasFee: updatedSelectedGasFee, - gasFeesBySpeed: updatedGasFeesBySpeed, - } = dataIsReady - ? getUpdatedGasFeeParams( - currentBlockParams?.baseFeePerGas, - gasFeeParamsBySpeed, - _gasLimit, - nativeCurrency, - _selectedGasFeeOption, - txNetwork, - l1GasFeeOptimism - ) - : { - gasFeesBySpeed: lastGasFeesBySpeed, - selectedGasFee: lastSelectedGasFee, - }; + gasFeesBySpeed, + } = getUpdatedGasFeeParams( + currentBaseFee, + gasFeeParamsBySpeed, + _gasLimit, + nativeCurrency, + _selectedGasFeeOption, + txNetwork, + l1GasFeeOptimism + ); + dispatch({ payload: { - gasFeeParamsBySpeed, - gasFeesBySpeed: updatedGasFeesBySpeed, + blocksToConfirmation, + currentBlockParams: { + baseFeePerGas: currentBaseFee, + trend, + }, + gasFeeParamsBySpeed: gasFeeParamsBySpeed, + gasFeesBySpeed, selectedGasFee: updatedSelectedGasFee, + secondsPerNewBlock, }, type: GAS_FEES_SUCCESS, }); - } else { - try { - const { - gasFeeParamsBySpeed, - baseFeePerGas, - trend, - currentBaseFee, - blocksToConfirmation, - secondsPerNewBlock, - } = await getEIP1559GasParams(network); - - if (flashbots) { - [SLOW, NORMAL, FAST, URGENT].forEach(speed => { - // Override min tip to 5 if needed, when flashbots is enabled - // See https://docs.flashbots.net/flashbots-protect/rpc/quick-start#choosing-the-right-gas-price - if (gasFeeParamsBySpeed[speed]) { - if ( - Number( - gasFeeParamsBySpeed[speed].maxPriorityFeePerGas.gwei - ) < FLASHBOTS_MIN_TIP - ) { - gasFeeParamsBySpeed[speed] = { - ...gasFeeParamsBySpeed[speed], - maxPriorityFeePerGas: { - amount: `${FLASHBOTS_MIN_TIP}000000000`, - display: `${FLASHBOTS_MIN_TIP} gwei`, - gwei: `${FLASHBOTS_MIN_TIP}`, - }, - }; - } - } - }); - } - - // Set a really gas estimate to guarantee that we're gonna be over - // the basefee at the time we fork mainnet during our hardhat tests - let baseFee = baseFeePerGas; - if (network === Network.mainnet && IS_TESTING === 'true') { - const providerUrl = ( - web3Provider || - ({} as { - connection: { url: string }; - }) - )?.connection?.url; - if (isHardHat(providerUrl)) { - baseFee = parseGasFeeParam(gweiToWei(1000)); - } - } - - if (customGasFeeModifiedByUser) { - // Preserve custom values while updating prices - gasFeeParamsBySpeed[CUSTOM] = { - ...existingGasFees[CUSTOM], - baseFeePerGas: baseFee, - }; - } else { - // set CUSTOM to URGENT if not defined - gasFeeParamsBySpeed[CUSTOM] = gasFeeParamsBySpeed[URGENT]; - } - const _selectedGasFeeOption = selectedGasFee.option || NORMAL; - const _gasLimit = - gasLimit || getDefaultGasLimit(txNetwork, defaultGasLimit); - - const { - selectedGasFee: updatedSelectedGasFee, - gasFeesBySpeed, - } = getUpdatedGasFeeParams( - currentBaseFee, - gasFeeParamsBySpeed, - _gasLimit, - nativeCurrency, - _selectedGasFeeOption, - txNetwork, - l1GasFeeOptimism - ); - - dispatch({ - payload: { - blocksToConfirmation, - currentBlockParams: { - baseFeePerGas: currentBaseFee, - trend, - }, - gasFeeParamsBySpeed: gasFeeParamsBySpeed, - gasFeesBySpeed, - selectedGasFee: updatedSelectedGasFee, - secondsPerNewBlock, - }, - type: GAS_FEES_SUCCESS, - }); - } catch (e) { - logger.error( - new RainbowError(`Etherscan gas estimates error: ${e}`) - ); - logger.debug('falling back to eth gas station'); - } + } catch (e) { + logger.error( + new RainbowError(`Etherscan gas estimates error: ${e}`) + ); + logger.debug('falling back to eth gas station'); } - fetchResolve(true); - } catch (e) { - logger.error( - new RainbowError(`Gas Estimates Failed for ${network}: ${e}`) - ); - fetchReject(e); } - }) - ); - - const watchGasPrices = async ( - network: Network, - pollingInterval: number - ) => { - try { - await getGasPrices(network); - // eslint-disable-next-line no-empty - } catch (e) { - } finally { - gasPricesHandle && clearTimeout(gasPricesHandle); - gasPricesHandle = setTimeout(() => { - watchGasPrices(network, pollingInterval); - }, pollingInterval); - } - }; + fetchResolve(true); + } catch (e) { + logger.error( + new RainbowError(`Gas Estimates Failed for ${network}: ${e}`) + ); + fetchReject(e); + } + }) + ); - const pollingInterval = getGasPricePollingInterval(network); - watchGasPrices(network, pollingInterval); + const watchGasPrices = async (network: Network, pollingInterval: number) => { + try { + await getGasPrices(network); + // eslint-disable-next-line no-empty + } catch (e) { + } finally { + gasPricesHandle && clearTimeout(gasPricesHandle); + gasPricesHandle = setTimeout(() => { + watchGasPrices(network, pollingInterval); + }, pollingInterval); + } }; -export const gasUpdateGasFeeOption = - (newGasPriceOption: string) => - (dispatch: AppDispatch, getState: AppGetState) => - withRunExclusive(async () => { - const { - gasFeeParamsBySpeed, - gasFeesBySpeed, - selectedGasFee: oldSelectedFee, - } = getState().gas; - if (oldSelectedFee.option === newGasPriceOption) return; + const pollingInterval = getGasPricePollingInterval(network); + watchGasPrices(network, pollingInterval); +}; - const gasPriceOption = newGasPriceOption || NORMAL; - if (isEmpty(gasFeeParamsBySpeed)) return; - const selectedGasFee = getSelectedGasFee( - gasFeeParamsBySpeed, - gasFeesBySpeed, - gasPriceOption - ); - dispatch({ - payload: selectedGasFee, - type: GAS_UPDATE_GAS_PRICE_OPTION, - }); - analytics.track('Updated Gas Price', { gasPriceOption: gasPriceOption }); - }); +export const gasUpdateGasFeeOption = (newGasPriceOption: string) => ( + dispatch: AppDispatch, + getState: AppGetState +) => + withRunExclusive(async () => { + const { + gasFeeParamsBySpeed, + gasFeesBySpeed, + selectedGasFee: oldSelectedFee, + } = getState().gas; + if (oldSelectedFee.option === newGasPriceOption) return; -export const gasUpdateDefaultGasLimit = - (defaultGasLimit = ethUnits.basic_tx) => - (dispatch: AppDispatch) => { + const gasPriceOption = newGasPriceOption || NORMAL; + if (isEmpty(gasFeeParamsBySpeed)) return; + const selectedGasFee = getSelectedGasFee( + gasFeeParamsBySpeed, + gasFeesBySpeed, + gasPriceOption + ); dispatch({ - payload: defaultGasLimit, - type: GAS_UPDATE_DEFAULT_GAS_LIMIT, + payload: selectedGasFee, + type: GAS_UPDATE_GAS_PRICE_OPTION, }); - dispatch(gasUpdateTxFee(defaultGasLimit)); - }; + analytics.track('Updated Gas Price', { gasPriceOption: gasPriceOption }); + }); -export const gasUpdateTxFee = - ( - updatedGasLimit?: number, - overrideGasOption?: string, - l1GasFeeOptimism: BigNumber | null = null - ) => - (dispatch: AppDispatch, getState: AppGetState) => - withRunExclusive(async () => { - const { - defaultGasLimit, - gasLimit, - gasFeeParamsBySpeed, - selectedGasFee, - txNetwork, - currentBlockParams, - } = getState().gas; - - const { nativeCurrency } = getState().settings; - if ( - isEmpty(gasFeeParamsBySpeed) || - (getNetworkObj(txNetwork).gas?.OptimismTxFee && - l1GasFeeOptimism === null) - ) { - // if fee prices not ready, we need to store the gas limit for future calculations - // the rest is as the initial state value - if (updatedGasLimit) { - dispatch({ - payload: updatedGasLimit, - type: GAS_UPDATE_GAS_LIMIT, - }); - } - } else { - const _selectedGasFeeOption = - overrideGasOption || selectedGasFee.option || NORMAL; - const _gasLimit = - updatedGasLimit || - gasLimit || - getDefaultGasLimit(txNetwork, defaultGasLimit); - - const { selectedGasFee: updatedSelectedGasFee, gasFeesBySpeed } = - getUpdatedGasFeeParams( - currentBlockParams?.baseFeePerGas, - gasFeeParamsBySpeed, - _gasLimit, - nativeCurrency, - _selectedGasFeeOption, - txNetwork, - l1GasFeeOptimism - ); +export const gasUpdateDefaultGasLimit = ( + defaultGasLimit = ethUnits.basic_tx +) => (dispatch: AppDispatch) => { + dispatch({ + payload: defaultGasLimit, + type: GAS_UPDATE_DEFAULT_GAS_LIMIT, + }); + dispatch(gasUpdateTxFee(defaultGasLimit)); +}; + +export const gasUpdateTxFee = ( + updatedGasLimit?: number, + overrideGasOption?: string, + l1GasFeeOptimism: BigNumber | null = null +) => (dispatch: AppDispatch, getState: AppGetState) => + withRunExclusive(async () => { + const { + defaultGasLimit, + gasLimit, + gasFeeParamsBySpeed, + selectedGasFee, + txNetwork, + currentBlockParams, + } = getState().gas; + + const { nativeCurrency } = getState().settings; + if ( + isEmpty(gasFeeParamsBySpeed) || + (getNetworkObj(txNetwork).gas?.OptimismTxFee && l1GasFeeOptimism === null) + ) { + // if fee prices not ready, we need to store the gas limit for future calculations + // the rest is as the initial state value + if (updatedGasLimit) { dispatch({ - payload: { - gasFeesBySpeed, - gasLimit: _gasLimit, - l1GasFeeOptimism, - selectedGasFee: updatedSelectedGasFee, - }, - type: GAS_UPDATE_TX_FEE, + payload: updatedGasLimit, + type: GAS_UPDATE_GAS_LIMIT, }); } - }); + } else { + const _selectedGasFeeOption = + overrideGasOption || selectedGasFee.option || NORMAL; + const _gasLimit = + updatedGasLimit || + gasLimit || + getDefaultGasLimit(txNetwork, defaultGasLimit); + + const { + selectedGasFee: updatedSelectedGasFee, + gasFeesBySpeed, + } = getUpdatedGasFeeParams( + currentBlockParams?.baseFeePerGas, + gasFeeParamsBySpeed, + _gasLimit, + nativeCurrency, + _selectedGasFeeOption, + txNetwork, + l1GasFeeOptimism + ); + dispatch({ + payload: { + gasFeesBySpeed, + gasLimit: _gasLimit, + l1GasFeeOptimism, + selectedGasFee: updatedSelectedGasFee, + }, + type: GAS_UPDATE_TX_FEE, + }); + } + }); export const gasPricesStopPolling = () => (dispatch: AppDispatch) => { gasPricesHandle && clearTimeout(gasPricesHandle); diff --git a/src/redux/hiddenTokens.ts b/src/redux/hiddenTokens.ts index e5c69b5a1ab..25e0164e7d6 100644 --- a/src/redux/hiddenTokens.ts +++ b/src/redux/hiddenTokens.ts @@ -85,120 +85,118 @@ interface HiddenTokensUpdateAction { * Loads hidden token IDs and web-data settings from local storage and * updates state. */ -export const hiddenTokensLoadState = - () => - async ( - dispatch: Dispatch< - HiddenTokensLoadSuccessAction | HiddenTokensLoadFailureAction - >, - getState: AppGetState - ) => { - try { - const { accountAddress, network } = getState().settings; - - const hiddenTokens = await getHiddenTokens(accountAddress, network); - - dispatch({ - payload: { - hiddenTokens, - }, - type: HIDDEN_TOKENS_LOAD_SUCCESS, - }); - } catch (error) { - dispatch({ type: HIDDEN_TOKENS_LOAD_FAILURE }); - } - }; +export const hiddenTokensLoadState = () => async ( + dispatch: Dispatch< + HiddenTokensLoadSuccessAction | HiddenTokensLoadFailureAction + >, + getState: AppGetState +) => { + try { + const { accountAddress, network } = getState().settings; + + const hiddenTokens = await getHiddenTokens(accountAddress, network); + + dispatch({ + payload: { + hiddenTokens, + }, + type: HIDDEN_TOKENS_LOAD_SUCCESS, + }); + } catch (error) { + dispatch({ type: HIDDEN_TOKENS_LOAD_FAILURE }); + } +}; /** * Loads hidden token IDs and web-data settings from firebase and * updates state. */ -export const hiddenTokensUpdateStateFromWeb = - () => - async ( - dispatch: Dispatch< - HiddenTokensFetchSuccessAction | HiddenTokensFetchFailureAction - >, - getState: AppGetState - ) => { - try { - const isReadOnlyWallet = - getState().wallets.selected?.type === WalletTypes.readOnly; - const { accountAddress, network } = getState().settings; - - // if web data is enabled, fetch values from cloud - const pref = await getWebDataEnabled(accountAddress, network); - - if ((!isReadOnlyWallet && pref) || isReadOnlyWallet) { - const hiddenTokensFromCloud = (await getPreference( - 'hidden', - accountAddress - )) as any | undefined; - if ( - hiddenTokensFromCloud?.hidden?.ids && - hiddenTokensFromCloud?.hidden?.ids.length > 0 - ) { - dispatch({ - payload: { - hiddenTokens: hiddenTokensFromCloud?.hidden?.ids, - }, - type: HIDDEN_TOKENS_FETCH_SUCCESS, - }); - } +export const hiddenTokensUpdateStateFromWeb = () => async ( + dispatch: Dispatch< + HiddenTokensFetchSuccessAction | HiddenTokensFetchFailureAction + >, + getState: AppGetState +) => { + try { + const isReadOnlyWallet = + getState().wallets.selected?.type === WalletTypes.readOnly; + const { accountAddress, network } = getState().settings; + + // if web data is enabled, fetch values from cloud + const pref = await getWebDataEnabled(accountAddress, network); + + if ((!isReadOnlyWallet && pref) || isReadOnlyWallet) { + const hiddenTokensFromCloud = (await getPreference( + 'hidden', + accountAddress + )) as any | undefined; + if ( + hiddenTokensFromCloud?.hidden?.ids && + hiddenTokensFromCloud?.hidden?.ids.length > 0 + ) { + dispatch({ + payload: { + hiddenTokens: hiddenTokensFromCloud?.hidden?.ids, + }, + type: HIDDEN_TOKENS_FETCH_SUCCESS, + }); } - } catch (e) { - dispatch({ type: HIDDEN_TOKENS_FETCH_FAILURE }); } - }; + } catch (e) { + dispatch({ type: HIDDEN_TOKENS_FETCH_FAILURE }); + } +}; /** * Adds a token ID to the hidden in state and updates local storage. * * @param tokenId The new token ID. */ -export const addHiddenToken = - (tokenId: string) => - (dispatch: Dispatch, getState: AppGetState) => { - const account = getState().wallets.selected!; - - if (account.type === WalletTypes.readOnly) return; - - const { accountAddress, network } = getState().settings; - const { hiddenTokens } = getState().hiddenTokens; - const updatedHiddenTokens = concat(hiddenTokens, tokenId); - dispatch({ - payload: { - hiddenTokens: updatedHiddenTokens, - }, - type: HIDDEN_TOKENS_UPDATE, - }); - saveHiddenTokens(updatedHiddenTokens, accountAddress, network); - }; +export const addHiddenToken = (tokenId: string) => ( + dispatch: Dispatch, + getState: AppGetState +) => { + const account = getState().wallets.selected!; + + if (account.type === WalletTypes.readOnly) return; + + const { accountAddress, network } = getState().settings; + const { hiddenTokens } = getState().hiddenTokens; + const updatedHiddenTokens = concat(hiddenTokens, tokenId); + dispatch({ + payload: { + hiddenTokens: updatedHiddenTokens, + }, + type: HIDDEN_TOKENS_UPDATE, + }); + saveHiddenTokens(updatedHiddenTokens, accountAddress, network); +}; /** * Removes a token ID from the hidden in state and updates local storage. * * @param tokenId The token ID to remove. */ -export const removeHiddenToken = - (tokenId: string) => - (dispatch: Dispatch, getState: AppGetState) => { - const account = getState().wallets.selected!; +export const removeHiddenToken = (tokenId: string) => ( + dispatch: Dispatch, + getState: AppGetState +) => { + const account = getState().wallets.selected!; - if (account.type === WalletTypes.readOnly) return; + if (account.type === WalletTypes.readOnly) return; - const { accountAddress, network } = getState().settings; - const { hiddenTokens } = getState().hiddenTokens; + const { accountAddress, network } = getState().settings; + const { hiddenTokens } = getState().hiddenTokens; - const updatedHiddenTokens = without(hiddenTokens, tokenId); + const updatedHiddenTokens = without(hiddenTokens, tokenId); - dispatch({ - payload: { hiddenTokens: updatedHiddenTokens }, - type: HIDDEN_TOKENS_UPDATE, - }); + dispatch({ + payload: { hiddenTokens: updatedHiddenTokens }, + type: HIDDEN_TOKENS_UPDATE, + }); - saveHiddenTokens(updatedHiddenTokens, accountAddress, network); - }; + saveHiddenTokens(updatedHiddenTokens, accountAddress, network); +}; const INITIAL_STATE: HiddenTokensState = { hiddenTokens: [], diff --git a/src/redux/imageMetadata.ts b/src/redux/imageMetadata.ts index 2a3d21b2042..9234df32039 100644 --- a/src/redux/imageMetadata.ts +++ b/src/redux/imageMetadata.ts @@ -63,29 +63,34 @@ interface UpdateImageMetadataFunctionParameter { } // -- Actions ---------------------------------------- // -export const clearImageMetadataCache = - () => (dispatch: Dispatch) => - dispatch({ type: CLEAR }); +export const clearImageMetadataCache = () => ( + dispatch: Dispatch +) => dispatch({ type: CLEAR }); -export const imageMetadataCacheLoadState = - () => async (dispatch: Dispatch) => { - const metadataCache = await getImageMetadata(); - dispatch({ - payload: metadataCache, - type: LOAD, - }); - }; +export const imageMetadataCacheLoadState = () => async ( + dispatch: Dispatch +) => { + const metadataCache = await getImageMetadata(); + dispatch({ + payload: metadataCache, + type: LOAD, + }); +}; -export const updateImageMetadataCache = - ({ id, metadata }: UpdateImageMetadataFunctionParameter) => - (dispatch: Dispatch, getState: AppGetState) => { - const { imageMetadata } = getState().imageMetadata; - dispatch({ id, metadata, type: MERGE }); - saveImageMetadata({ - ...imageMetadata, - [id]: metadata, - }); - }; +export const updateImageMetadataCache = ({ + id, + metadata, +}: UpdateImageMetadataFunctionParameter) => ( + dispatch: Dispatch, + getState: AppGetState +) => { + const { imageMetadata } = getState().imageMetadata; + dispatch({ id, metadata, type: MERGE }); + saveImageMetadata({ + ...imageMetadata, + [id]: metadata, + }); +}; // -- Reducer ----------------------------------------- // const INITIAL_STATE: ImageMetadataState = { diff --git a/src/redux/keyboardHeight.ts b/src/redux/keyboardHeight.ts index b8583b0895e..092701f92b0 100644 --- a/src/redux/keyboardHeight.ts +++ b/src/redux/keyboardHeight.ts @@ -78,40 +78,39 @@ const INITIAL_STATE: KeyboardHeightState = { }, }; -export const keyboardHeightsLoadState = - () => async (dispatch: Dispatch) => { - const cachedKeyboardHeights = await loadKeyboardHeights(); +export const keyboardHeightsLoadState = () => async ( + dispatch: Dispatch +) => { + const cachedKeyboardHeights = await loadKeyboardHeights(); - dispatch({ - payload: { - ...INITIAL_STATE.keyboardHeight, - ...cachedKeyboardHeights, - }, - type: LOAD, - }); - }; + dispatch({ + payload: { + ...INITIAL_STATE.keyboardHeight, + ...cachedKeyboardHeights, + }, + type: LOAD, + }); +}; -export const setKeyboardHeight = - ({ +export const setKeyboardHeight = ({ + height, + keyboardType = KeyboardType.default, +}: SetKeyboardHeightFunctionParameter) => async ( + dispatch: Dispatch, + getState: AppGetState +) => { + await dispatch({ height, - keyboardType = KeyboardType.default, - }: SetKeyboardHeightFunctionParameter) => - async ( - dispatch: Dispatch, - getState: AppGetState - ) => { - await dispatch({ - height, - keyboardType, - type: SAVE, - }); + keyboardType, + type: SAVE, + }); - const prevState = getState().keyboardHeight.keyboardHeight; - saveKeyboardHeight({ - ...prevState, - [keyboardType]: height, - }); - }; + const prevState = getState().keyboardHeight.keyboardHeight; + saveKeyboardHeight({ + ...prevState, + [keyboardType]: height, + }); +}; // -- Reducer ----------------------------------------- // export default ( diff --git a/src/redux/nonceManager.ts b/src/redux/nonceManager.ts index f3dffb16714..84930984710 100644 --- a/src/redux/nonceManager.ts +++ b/src/redux/nonceManager.ts @@ -42,68 +42,71 @@ export const nonceManagerLoadState = () => async (dispatch: AppDispatch) => { } }; -export const incrementNonce = - (accountAddress: EthereumAddress, nonce: number, network = Network.mainnet) => - (dispatch: AppDispatch) => - dispatch(updateNonce(accountAddress, nonce, network)); +export const incrementNonce = ( + accountAddress: EthereumAddress, + nonce: number, + network = Network.mainnet +) => (dispatch: AppDispatch) => + dispatch(updateNonce(accountAddress, nonce, network)); -export const decrementNonce = - (accountAddress: EthereumAddress, nonce: number, network = Network.mainnet) => - (dispatch: AppDispatch) => - dispatch(updateNonce(accountAddress, nonce, network, false)); +export const decrementNonce = ( + accountAddress: EthereumAddress, + nonce: number, + network = Network.mainnet +) => (dispatch: AppDispatch) => + dispatch(updateNonce(accountAddress, nonce, network, false)); -export const updateNonce = - ( - accountAddress: EthereumAddress, - nonce: number, - network = Network.mainnet, - increment: boolean = true - ) => - (dispatch: AppDispatch, getState: AppGetState) => { - const { nonceManager: currentNonceData } = getState(); - const currentNonce = - currentNonceData[accountAddress.toLowerCase()]?.[network]?.nonce; - const counterShouldBeUpdated = - isNil(currentNonce) || - (increment ? currentNonce < nonce : currentNonce >= nonce); +export const updateNonce = ( + accountAddress: EthereumAddress, + nonce: number, + network = Network.mainnet, + increment: boolean = true +) => (dispatch: AppDispatch, getState: AppGetState) => { + const { nonceManager: currentNonceData } = getState(); + const currentNonce = + currentNonceData[accountAddress.toLowerCase()]?.[network]?.nonce; + const counterShouldBeUpdated = + isNil(currentNonce) || + (increment ? currentNonce < nonce : currentNonce >= nonce); - if (counterShouldBeUpdated) { - const newNonce = increment ? nonce : nonce - 1; - logger.log('Updating nonce: ', accountAddress, network, newNonce); + if (counterShouldBeUpdated) { + const newNonce = increment ? nonce : nonce - 1; + logger.log('Updating nonce: ', accountAddress, network, newNonce); - const lcAccountAddress = accountAddress.toLowerCase(); - const updatedNonceManager = { - ...currentNonceData, - [lcAccountAddress]: { - ...(currentNonceData[lcAccountAddress] || {}), - [network]: { nonce: newNonce }, - }, - }; - dispatch({ - payload: updatedNonceManager, - type: NONCE_MANAGER_UPDATE_NONCE, - }); - saveNonceManager(updatedNonceManager); - } - }; -export const resetNonces = - (accountAddress: EthereumAddress) => - async (dispatch: AppDispatch, getState: AppGetState) => { - const { nonceManager: currentNonceData } = getState(); - - const currentAccountAddress = accountAddress.toLowerCase(); - - const updatedNonceManager: NonceManager = { + const lcAccountAddress = accountAddress.toLowerCase(); + const updatedNonceManager = { ...currentNonceData, - [currentAccountAddress]: {}, + [lcAccountAddress]: { + ...(currentNonceData[lcAccountAddress] || {}), + [network]: { nonce: newNonce }, + }, }; - dispatch({ payload: updatedNonceManager, type: NONCE_MANAGER_UPDATE_NONCE, }); saveNonceManager(updatedNonceManager); + } +}; +export const resetNonces = (accountAddress: EthereumAddress) => async ( + dispatch: AppDispatch, + getState: AppGetState +) => { + const { nonceManager: currentNonceData } = getState(); + + const currentAccountAddress = accountAddress.toLowerCase(); + + const updatedNonceManager: NonceManager = { + ...currentNonceData, + [currentAccountAddress]: {}, }; + + dispatch({ + payload: updatedNonceManager, + type: NONCE_MANAGER_UPDATE_NONCE, + }); + saveNonceManager(updatedNonceManager); +}; // -- Reducer ----------------------------------------- // const INITIAL_STATE: NonceManager = {}; diff --git a/src/redux/requests.ts b/src/redux/requests.ts index 7aaae5d84ff..d9ee7f05113 100644 --- a/src/redux/requests.ts +++ b/src/redux/requests.ts @@ -137,23 +137,18 @@ interface RequestsClearStateAction { /** * Loads requests from local storage into state. */ -export const requestsLoadState = - () => - async ( - dispatch: Dispatch, - getState: AppGetState - ) => { - const { accountAddress, network } = getState().settings; - try { - const requests = await getLocalRequests(accountAddress, network); - const _requests = requests || {}; - dispatch({ - payload: _requests, - type: REQUESTS_UPDATE_REQUESTS_TO_APPROVE, - }); - // eslint-disable-next-line no-empty - } catch (error) {} - }; +export const requestsLoadState = () => async ( + dispatch: Dispatch, + getState: AppGetState +) => { + const { accountAddress, network } = getState().settings; + try { + const requests = await getLocalRequests(accountAddress, network); + const _requests = requests || {}; + dispatch({ payload: _requests, type: REQUESTS_UPDATE_REQUESTS_TO_APPROVE }); + // eslint-disable-next-line no-empty + } catch (error) {} +}; /** * Adds a new request to state and updates local storage. @@ -164,72 +159,70 @@ export const requestsLoadState = * @param payload The request payload. * @param peerMeta The WalletConnect peer metadata. */ -export const addRequestToApprove = - ( - clientId: string, - peerId: string, - requestId: number, - payload: any, - peerMeta: - | undefined - | null - | { - name?: string; - url?: string; - scheme?: string; - icons?: string[]; - } - ) => - ( - dispatch: Dispatch, - getState: AppGetState - ) => { - const { requests } = getState().requests; - const { walletConnectors } = getState().walletconnect; - const { accountAddress, network, nativeCurrency } = getState().settings; - const walletConnector = walletConnectors[peerId]; - // @ts-expect-error "_chainId" is private. - const chainId = walletConnector._chainId; - const dappNetwork = ethereumUtils.getNetworkFromChainId(Number(chainId)); - const displayDetails = getRequestDisplayDetails( - payload, - nativeCurrency, - dappNetwork - ); - const oneHourAgoTs = Date.now() - EXPIRATION_THRESHOLD_IN_MS; - // @ts-expect-error This fails to compile as `displayDetails` does not - // always return an object with `timestampInMs`. Still, the error thrown - // by an invalid access might be caught or expected elsewhere, so for now - // `ts-expect-error` is used. - if (displayDetails.timestampInMs < oneHourAgoTs) { - logger.log('request expired!'); - return; - } - const unsafeImageUrl = peerMeta?.icons?.[0]; - const imageUrl = maybeSignUri(unsafeImageUrl, { w: 200 }); - const dappName = peerMeta?.name || 'Unknown Dapp'; - const dappUrl = peerMeta?.url || 'Unknown Url'; - const dappScheme = peerMeta?.scheme || null; +export const addRequestToApprove = ( + clientId: string, + peerId: string, + requestId: number, + payload: any, + peerMeta: + | undefined + | null + | { + name?: string; + url?: string; + scheme?: string; + icons?: string[]; + } +) => ( + dispatch: Dispatch, + getState: AppGetState +) => { + const { requests } = getState().requests; + const { walletConnectors } = getState().walletconnect; + const { accountAddress, network, nativeCurrency } = getState().settings; + const walletConnector = walletConnectors[peerId]; + // @ts-expect-error "_chainId" is private. + const chainId = walletConnector._chainId; + const dappNetwork = ethereumUtils.getNetworkFromChainId(Number(chainId)); + const displayDetails = getRequestDisplayDetails( + payload, + nativeCurrency, + dappNetwork + ); + const oneHourAgoTs = Date.now() - EXPIRATION_THRESHOLD_IN_MS; + // @ts-expect-error This fails to compile as `displayDetails` does not + // always return an object with `timestampInMs`. Still, the error thrown + // by an invalid access might be caught or expected elsewhere, so for now + // `ts-expect-error` is used. + if (displayDetails.timestampInMs < oneHourAgoTs) { + logger.log('request expired!'); + return; + } + const unsafeImageUrl = peerMeta?.icons?.[0]; + const imageUrl = maybeSignUri(unsafeImageUrl, { w: 200 }); + const dappName = peerMeta?.name || 'Unknown Dapp'; + const dappUrl = peerMeta?.url || 'Unknown Url'; + const dappScheme = peerMeta?.scheme || null; - const request: RequestData = { - clientId, - dappName, - dappScheme, - dappUrl, - displayDetails, - imageUrl, - payload, - peerId, - requestId, - }; - const updatedRequests = { ...requests, [requestId]: request }; - dispatch({ - payload: updatedRequests, - type: REQUESTS_UPDATE_REQUESTS_TO_APPROVE, - }); - saveLocalRequests(updatedRequests, accountAddress, network); - return request; + const request: RequestData = { + clientId, + dappName, + dappScheme, + dappUrl, + displayDetails, + imageUrl, + payload, + peerId, + requestId, }; + const updatedRequests = { ...requests, [requestId]: request }; + dispatch({ + payload: updatedRequests, + type: REQUESTS_UPDATE_REQUESTS_TO_APPROVE, + }); + saveLocalRequests(updatedRequests, accountAddress, network); + return request; +}; /** * Filters requests that match a given client ID. @@ -237,40 +230,39 @@ export const addRequestToApprove = * @param topic The client ID to filter for. * @returns The matching requests. */ -export const requestsForTopic = - (topic: string | undefined) => - (dispatch: unknown, getState: AppGetState): RequestData[] => { - const { requests } = getState().requests; - return Object.values(requests).filter(({ clientId }) => clientId === topic); - }; +export const requestsForTopic = (topic: string | undefined) => ( + dispatch: unknown, + getState: AppGetState +): RequestData[] => { + const { requests } = getState().requests; + return Object.values(requests).filter(({ clientId }) => clientId === topic); +}; /** * Resets the state. */ -export const requestsResetState = - () => (dispatch: Dispatch) => - dispatch({ type: REQUESTS_CLEAR_STATE }); +export const requestsResetState = () => ( + dispatch: Dispatch +) => dispatch({ type: REQUESTS_CLEAR_STATE }); /** * Removes a request from state by its request ID. * * @param requestId The request ID to remove. */ -export const removeRequest = - (requestId: number) => - ( - dispatch: Dispatch, - getState: AppGetState - ) => { - const { accountAddress, network } = getState().settings; - const { requests } = getState().requests; - const updatedRequests = omitFlatten(requests, [requestId]); - removeLocalRequest(accountAddress, network, requestId); - dispatch({ - payload: updatedRequests, - type: REQUESTS_UPDATE_REQUESTS_TO_APPROVE, - }); - }; +export const removeRequest = (requestId: number) => ( + dispatch: Dispatch, + getState: AppGetState +) => { + const { accountAddress, network } = getState().settings; + const { requests } = getState().requests; + const updatedRequests = omitFlatten(requests, [requestId]); + removeLocalRequest(accountAddress, network, requestId); + dispatch({ + payload: updatedRequests, + type: REQUESTS_UPDATE_REQUESTS_TO_APPROVE, + }); +}; // -- Reducer ----------------------------------------- // diff --git a/src/redux/settings.ts b/src/redux/settings.ts index 4206243184e..ac97c76929a 100644 --- a/src/redux/settings.ts +++ b/src/redux/settings.ts @@ -123,197 +123,196 @@ interface SettingsStateUpdateLanguageSuccessAction { payload: SettingsState['language']; } -export const settingsLoadState = - () => - async ( - dispatch: ThunkDispatch< - AppState, - unknown, - | SettingsStateUpdateNativeCurrencyAndTestnetsSuccessAction - | SettingsStateUpdateAppIconSuccessAction - > - ) => { - try { - const nativeCurrency = await getNativeCurrency(); - const testnetsEnabled = await getTestnetsEnabled(); - const appIcon = (await getAppIcon()) as string; - dispatch({ - payload: appIcon, - type: SETTINGS_UPDATE_APP_ICON_SUCCESS, - }); +export const settingsLoadState = () => async ( + dispatch: ThunkDispatch< + AppState, + unknown, + | SettingsStateUpdateNativeCurrencyAndTestnetsSuccessAction + | SettingsStateUpdateAppIconSuccessAction + > +) => { + try { + const nativeCurrency = await getNativeCurrency(); + const testnetsEnabled = await getTestnetsEnabled(); + const appIcon = (await getAppIcon()) as string; + dispatch({ + payload: appIcon, + type: SETTINGS_UPDATE_APP_ICON_SUCCESS, + }); - const flashbotsEnabled = await getFlashbotsEnabled(); + const flashbotsEnabled = await getFlashbotsEnabled(); - analytics.identify({ - currency: nativeCurrency, - enabledFlashbots: flashbotsEnabled, - enabledTestnets: testnetsEnabled, - }); + analytics.identify({ + currency: nativeCurrency, + enabledFlashbots: flashbotsEnabled, + enabledTestnets: testnetsEnabled, + }); - dispatch({ - payload: { flashbotsEnabled, nativeCurrency, testnetsEnabled }, - type: SETTINGS_UPDATE_ACCOUNT_SETTINGS_SUCCESS, - }); - } catch (error) { - logger.log('Error loading native currency and testnets pref', error); - } - }; + dispatch({ + payload: { flashbotsEnabled, nativeCurrency, testnetsEnabled }, + type: SETTINGS_UPDATE_ACCOUNT_SETTINGS_SUCCESS, + }); + } catch (error) { + logger.log('Error loading native currency and testnets pref', error); + } +}; -export const settingsLoadNetwork = - () => async (dispatch: Dispatch) => { - try { - const network = await getNetwork(); - const chainId = ethereumUtils.getChainIdFromNetwork(network); - await web3SetHttpProvider(network); - dispatch({ - payload: { chainId, network }, - type: SETTINGS_UPDATE_NETWORK_SUCCESS, - }); - } catch (error) { - logger.log('Error loading network settings', error); - } - }; +export const settingsLoadNetwork = () => async ( + dispatch: Dispatch +) => { + try { + const network = await getNetwork(); + const chainId = ethereumUtils.getChainIdFromNetwork(network); + await web3SetHttpProvider(network); + dispatch({ + payload: { chainId, network }, + type: SETTINGS_UPDATE_NETWORK_SUCCESS, + }); + } catch (error) { + logger.log('Error loading network settings', error); + } +}; + +export const settingsLoadLanguage = () => async ( + dispatch: Dispatch +) => { + try { + const language = await getLanguage(); + updateLanguageLocale(language as Language); + dispatch({ + payload: language, + type: SETTINGS_UPDATE_LANGUAGE_SUCCESS, + }); + analytics.identify({ + language, + }); + } catch (error) { + logger.log('Error loading language settings', error); + } +}; -export const settingsLoadLanguage = - () => - async (dispatch: Dispatch) => { +export const settingsChangeTestnetsEnabled = ( + testnetsEnabled: boolean +) => async (dispatch: Dispatch) => { + dispatch({ + payload: testnetsEnabled, + type: SETTINGS_UPDATE_TESTNET_PREF_SUCCESS, + }); + saveTestnetsEnabled(testnetsEnabled); +}; + +export const settingsChangeAppIcon = (appIcon: string) => ( + dispatch: Dispatch +) => { + const callback = async () => { + logger.log('changing app icon to', appIcon); try { - const language = await getLanguage(); - updateLanguageLocale(language as Language); + await changeIcon(appIcon); + logger.log('icon changed to ', appIcon); + saveAppIcon(appIcon); dispatch({ - payload: language, - type: SETTINGS_UPDATE_LANGUAGE_SUCCESS, - }); - analytics.identify({ - language, + payload: appIcon, + type: SETTINGS_UPDATE_APP_ICON_SUCCESS, }); } catch (error) { - logger.log('Error loading language settings', error); + logger.log('Error changing app icon', error); } }; -export const settingsChangeTestnetsEnabled = - (testnetsEnabled: boolean) => - async (dispatch: Dispatch) => { - dispatch({ - payload: testnetsEnabled, - type: SETTINGS_UPDATE_TESTNET_PREF_SUCCESS, - }); - saveTestnetsEnabled(testnetsEnabled); - }; + if (android) { + Alert.alert( + lang.t('settings.icon_change.title'), + lang.t('settings.icon_change.warning'), + [ + { + onPress: () => {}, + text: lang.t('settings.icon_change.cancel'), + }, + { + onPress: callback, + text: lang.t('settings.icon_change.confirm'), + }, + ] + ); + } else { + callback(); + } +}; -export const settingsChangeAppIcon = - (appIcon: string) => - (dispatch: Dispatch) => { - const callback = async () => { - logger.log('changing app icon to', appIcon); - try { - await changeIcon(appIcon); - logger.log('icon changed to ', appIcon); - saveAppIcon(appIcon); - dispatch({ - payload: appIcon, - type: SETTINGS_UPDATE_APP_ICON_SUCCESS, - }); - } catch (error) { - logger.log('Error changing app icon', error); - } - }; +export const settingsChangeFlashbotsEnabled = ( + flashbotsEnabled: boolean +) => async (dispatch: Dispatch) => { + dispatch({ + payload: flashbotsEnabled, + type: SETTINGS_UPDATE_FLASHBOTS_PREF_SUCCESS, + }); + saveFlashbotsEnabled(flashbotsEnabled); +}; - if (android) { - Alert.alert( - lang.t('settings.icon_change.title'), - lang.t('settings.icon_change.warning'), - [ - { - onPress: () => {}, - text: lang.t('settings.icon_change.cancel'), - }, - { - onPress: callback, - text: lang.t('settings.icon_change.confirm'), - }, - ] - ); - } else { - callback(); - } - }; +export const settingsUpdateAccountAddress = (accountAddress: string) => async ( + dispatch: Dispatch +) => { + dispatch({ + payload: accountAddress, + type: SETTINGS_UPDATE_SETTINGS_ADDRESS, + }); +}; -export const settingsChangeFlashbotsEnabled = - (flashbotsEnabled: boolean) => - async (dispatch: Dispatch) => { +export const settingsUpdateNetwork = (network: Network) => async ( + dispatch: Dispatch +) => { + const chainId = ethereumUtils.getChainIdFromNetwork(network); + await web3SetHttpProvider(network); + try { dispatch({ - payload: flashbotsEnabled, - type: SETTINGS_UPDATE_FLASHBOTS_PREF_SUCCESS, + payload: { chainId, network }, + type: SETTINGS_UPDATE_NETWORK_SUCCESS, }); - saveFlashbotsEnabled(flashbotsEnabled); - }; + saveNetwork(network); + } catch (error) { + logger.log('Error updating network settings', error); + } +}; -export const settingsUpdateAccountAddress = - (accountAddress: string) => - async (dispatch: Dispatch) => { +export const settingsChangeLanguage = (language: Language) => async ( + dispatch: Dispatch +) => { + updateLanguageLocale(language); + try { dispatch({ - payload: accountAddress, - type: SETTINGS_UPDATE_SETTINGS_ADDRESS, + payload: language, + type: SETTINGS_UPDATE_LANGUAGE_SUCCESS, }); - }; - -export const settingsUpdateNetwork = - (network: Network) => - async (dispatch: Dispatch) => { - const chainId = ethereumUtils.getChainIdFromNetwork(network); - await web3SetHttpProvider(network); - try { - dispatch({ - payload: { chainId, network }, - type: SETTINGS_UPDATE_NETWORK_SUCCESS, - }); - saveNetwork(network); - } catch (error) { - logger.log('Error updating network settings', error); - } - }; - -export const settingsChangeLanguage = - (language: Language) => - async (dispatch: Dispatch) => { - updateLanguageLocale(language); - try { - dispatch({ - payload: language, - type: SETTINGS_UPDATE_LANGUAGE_SUCCESS, - }); - saveLanguage(language); - analytics.identify({ language }); - } catch (error) { - logger.log('Error changing language', error); - } - }; + saveLanguage(language); + analytics.identify({ language }); + } catch (error) { + logger.log('Error changing language', error); + } +}; -export const settingsChangeNativeCurrency = - (nativeCurrency: NativeCurrencyKey) => - async ( - dispatch: ThunkDispatch< - AppState, - unknown, - SettingsStateUpdateNativeCurrencySuccessAction - > - ) => { - dispatch(dataResetState()); - dispatch(explorerClearState()); - try { - dispatch({ - payload: nativeCurrency, - type: SETTINGS_UPDATE_NATIVE_CURRENCY_SUCCESS, - }); - dispatch(explorerInit()); - saveNativeCurrency(nativeCurrency); - analytics.identify({ currency: nativeCurrency }); - } catch (error) { - logger.log('Error changing native currency', error); - } - }; +export const settingsChangeNativeCurrency = ( + nativeCurrency: NativeCurrencyKey +) => async ( + dispatch: ThunkDispatch< + AppState, + unknown, + SettingsStateUpdateNativeCurrencySuccessAction + > +) => { + dispatch(dataResetState()); + dispatch(explorerClearState()); + try { + dispatch({ + payload: nativeCurrency, + type: SETTINGS_UPDATE_NATIVE_CURRENCY_SUCCESS, + }); + dispatch(explorerInit()); + saveNativeCurrency(nativeCurrency); + analytics.identify({ currency: nativeCurrency }); + } catch (error) { + logger.log('Error changing native currency', error); + } +}; // -- Reducer --------------------------------------------------------------- // export const INITIAL_STATE: SettingsState = { diff --git a/src/redux/showcaseTokens.ts b/src/redux/showcaseTokens.ts index abc3286cb4b..3156ef46a1a 100644 --- a/src/redux/showcaseTokens.ts +++ b/src/redux/showcaseTokens.ts @@ -111,121 +111,119 @@ interface ShowcaseTokensUpdateAction { * Loads showcased token IDs and web-data settings from local storage and * updates state. */ -export const showcaseTokensLoadState = - () => - async ( - dispatch: Dispatch< - ShowcaseTokensLoadSuccessAction | ShowcaseTokensLoadFailureAction - >, - getState: AppGetState - ) => { - try { - const { accountAddress, network } = getState().settings; +export const showcaseTokensLoadState = () => async ( + dispatch: Dispatch< + ShowcaseTokensLoadSuccessAction | ShowcaseTokensLoadFailureAction + >, + getState: AppGetState +) => { + try { + const { accountAddress, network } = getState().settings; - const showcaseTokens = await getShowcaseTokens(accountAddress, network); - const pref = await getWebDataEnabled(accountAddress, network); + const showcaseTokens = await getShowcaseTokens(accountAddress, network); + const pref = await getWebDataEnabled(accountAddress, network); - dispatch({ - payload: { - showcaseTokens, - webDataEnabled: !!pref, - }, - type: SHOWCASE_TOKENS_LOAD_SUCCESS, - }); - } catch (error) { - dispatch({ type: SHOWCASE_TOKENS_LOAD_FAILURE }); - } - }; + dispatch({ + payload: { + showcaseTokens, + webDataEnabled: !!pref, + }, + type: SHOWCASE_TOKENS_LOAD_SUCCESS, + }); + } catch (error) { + dispatch({ type: SHOWCASE_TOKENS_LOAD_FAILURE }); + } +}; /** * Loads showcased token IDs and web-data settings from firebase and * updates state. */ -export const showcaseTokensUpdateStateFromWeb = - () => - async ( - dispatch: Dispatch< - ShowcaseTokensFetchSuccessAction | ShowcaseTokensFetchFailureAction - >, - getState: AppGetState - ) => { - try { - const isReadOnlyWallet = - getState().wallets.selected?.type === WalletTypes.readOnly; - const { accountAddress, network } = getState().settings; +export const showcaseTokensUpdateStateFromWeb = () => async ( + dispatch: Dispatch< + ShowcaseTokensFetchSuccessAction | ShowcaseTokensFetchFailureAction + >, + getState: AppGetState +) => { + try { + const isReadOnlyWallet = + getState().wallets.selected?.type === WalletTypes.readOnly; + const { accountAddress, network } = getState().settings; - // if web data is enabled, fetch values from cloud - const pref = await getWebDataEnabled(accountAddress, network); + // if web data is enabled, fetch values from cloud + const pref = await getWebDataEnabled(accountAddress, network); - if ((!isReadOnlyWallet && pref) || isReadOnlyWallet) { - const showcaseTokensFromCloud = (await getPreference( - 'showcase', - accountAddress - )) as any | undefined; - if ( - showcaseTokensFromCloud?.showcase?.ids && - showcaseTokensFromCloud?.showcase?.ids.length > 0 - ) { - dispatch({ - payload: { - showcaseTokens: showcaseTokensFromCloud.showcase.ids, - webDataEnabled: !!pref, - }, - type: SHOWCASE_TOKENS_FETCH_SUCCESS, - }); - } + if ((!isReadOnlyWallet && pref) || isReadOnlyWallet) { + const showcaseTokensFromCloud = (await getPreference( + 'showcase', + accountAddress + )) as any | undefined; + if ( + showcaseTokensFromCloud?.showcase?.ids && + showcaseTokensFromCloud?.showcase?.ids.length > 0 + ) { + dispatch({ + payload: { + showcaseTokens: showcaseTokensFromCloud.showcase.ids, + webDataEnabled: !!pref, + }, + type: SHOWCASE_TOKENS_FETCH_SUCCESS, + }); } - } catch (error) { - dispatch({ type: SHOWCASE_TOKENS_FETCH_FAILURE }); } - }; + } catch (error) { + dispatch({ type: SHOWCASE_TOKENS_FETCH_FAILURE }); + } +}; /** * Adds a token ID to the showcase in state and updates local storage. * * @param tokenId The new token ID. */ -export const addShowcaseToken = - (tokenId: string) => - (dispatch: Dispatch, getState: AppGetState) => { - const account = getState().wallets.selected!; +export const addShowcaseToken = (tokenId: string) => ( + dispatch: Dispatch, + getState: AppGetState +) => { + const account = getState().wallets.selected!; - if (account.type === WalletTypes.readOnly) return; + if (account.type === WalletTypes.readOnly) return; - const { accountAddress, network } = getState().settings; - const { showcaseTokens = [] } = getState().showcaseTokens; - const updatedShowcaseTokens = showcaseTokens.concat(tokenId); - dispatch({ - payload: updatedShowcaseTokens, - type: SHOWCASE_TOKENS_UPDATE, - }); - saveShowcaseTokens(updatedShowcaseTokens, accountAddress, network); - }; + const { accountAddress, network } = getState().settings; + const { showcaseTokens = [] } = getState().showcaseTokens; + const updatedShowcaseTokens = showcaseTokens.concat(tokenId); + dispatch({ + payload: updatedShowcaseTokens, + type: SHOWCASE_TOKENS_UPDATE, + }); + saveShowcaseTokens(updatedShowcaseTokens, accountAddress, network); +}; /** * Removes a token ID from the showcase in state and updates local storage. * * @param tokenId The token ID to remove. */ -export const removeShowcaseToken = - (tokenId: string) => - (dispatch: Dispatch, getState: AppGetState) => { - const account = getState().wallets.selected!; +export const removeShowcaseToken = (tokenId: string) => ( + dispatch: Dispatch, + getState: AppGetState +) => { + const account = getState().wallets.selected!; - if (account.type === WalletTypes.readOnly) return; + if (account.type === WalletTypes.readOnly) return; - const { accountAddress, network } = getState().settings; - const { showcaseTokens } = getState().showcaseTokens; + const { accountAddress, network } = getState().settings; + const { showcaseTokens } = getState().showcaseTokens; - const updatedShowcaseTokens = without(showcaseTokens, tokenId); + const updatedShowcaseTokens = without(showcaseTokens, tokenId); - dispatch({ - payload: updatedShowcaseTokens, - type: SHOWCASE_TOKENS_UPDATE, - }); + dispatch({ + payload: updatedShowcaseTokens, + type: SHOWCASE_TOKENS_UPDATE, + }); - saveShowcaseTokens(updatedShowcaseTokens, accountAddress, network); - }; + saveShowcaseTokens(updatedShowcaseTokens, accountAddress, network); +}; /** * Updates whether or not web data should be enabled in state and @@ -235,15 +233,17 @@ export const removeShowcaseToken = * @param address The current user's address. * @param network The current network. */ -export const updateWebDataEnabled = - (enabled: boolean, address: string, network = networkTypes.mainnet) => - async (dispatch: Dispatch) => { - dispatch({ - payload: enabled, - type: UPDATE_WEB_DATA_ENABLED, - }); - await saveWebDataEnabled(enabled, address.toLowerCase(), network); - }; +export const updateWebDataEnabled = ( + enabled: boolean, + address: string, + network = networkTypes.mainnet +) => async (dispatch: Dispatch) => { + dispatch({ + payload: enabled, + type: UPDATE_WEB_DATA_ENABLED, + }); + await saveWebDataEnabled(enabled, address.toLowerCase(), network); +}; // -- Reducer ----------------------------------------- // diff --git a/src/redux/swap.ts b/src/redux/swap.ts index 9cea3464c70..3f0299c3c01 100644 --- a/src/redux/swap.ts +++ b/src/redux/swap.ts @@ -58,141 +58,147 @@ const SWAP_UPDATE_QUOTE = 'swap/SWAP_UPDATE_QUOTE'; const SWAP_CLEAR_STATE = 'swap/SWAP_CLEAR_STATE'; // -- Actions ---------------------------------------- // -export const updateSwapTypeDetails = - (type: string, typeSpecificParameters?: TypeSpecificParameters | null) => - (dispatch: AppDispatch) => { - dispatch({ - payload: { - type, - typeSpecificParameters, - }, - type: SWAP_UPDATE_TYPE_DETAILS, - }); - }; +export const updateSwapTypeDetails = ( + type: string, + typeSpecificParameters?: TypeSpecificParameters | null +) => (dispatch: AppDispatch) => { + dispatch({ + payload: { + type, + typeSpecificParameters, + }, + type: SWAP_UPDATE_TYPE_DETAILS, + }); +}; -export const updateSwapSlippage = - (slippage: number) => (dispatch: AppDispatch) => { - dispatch({ - payload: slippage, - type: SWAP_UPDATE_SLIPPAGE, - }); - }; +export const updateSwapSlippage = (slippage: number) => ( + dispatch: AppDispatch +) => { + dispatch({ + payload: slippage, + type: SWAP_UPDATE_SLIPPAGE, + }); +}; -export const updateSwapSource = - (newSource: Source) => (dispatch: AppDispatch) => { - dispatch({ - payload: newSource, - type: SWAP_UPDATE_SOURCE, - }); - }; +export const updateSwapSource = (newSource: Source) => ( + dispatch: AppDispatch +) => { + dispatch({ + payload: newSource, + type: SWAP_UPDATE_SOURCE, + }); +}; -export const updateSwapInputAmount = - (value: string | null, maxInputUpdate = false) => - (dispatch: AppDispatch) => { - dispatch({ - payload: { independentValue: value, maxInputUpdate }, - type: SWAP_UPDATE_INPUT_AMOUNT, - }); - }; +export const updateSwapInputAmount = ( + value: string | null, + maxInputUpdate = false +) => (dispatch: AppDispatch) => { + dispatch({ + payload: { independentValue: value, maxInputUpdate }, + type: SWAP_UPDATE_INPUT_AMOUNT, + }); +}; -export const updateSwapNativeAmount = - (value: string | null) => (dispatch: AppDispatch) => { - dispatch({ - payload: value, - type: SWAP_UPDATE_NATIVE_AMOUNT, - }); - }; +export const updateSwapNativeAmount = (value: string | null) => ( + dispatch: AppDispatch +) => { + dispatch({ + payload: value, + type: SWAP_UPDATE_NATIVE_AMOUNT, + }); +}; -export const updateSwapOutputAmount = - (value: string | null) => (dispatch: AppDispatch) => { - dispatch({ - payload: value, - type: SWAP_UPDATE_OUTPUT_AMOUNT, - }); - }; +export const updateSwapOutputAmount = (value: string | null) => ( + dispatch: AppDispatch +) => { + dispatch({ + payload: value, + type: SWAP_UPDATE_OUTPUT_AMOUNT, + }); +}; -export const updateSwapInputCurrency = - (newInputCurrency: SwappableAsset | null, ignoreTypeCheck = false) => - (dispatch: AppDispatch, getState: AppGetState) => { - const { independentField, outputCurrency, type } = getState().swap; +export const updateSwapInputCurrency = ( + newInputCurrency: SwappableAsset | null, + ignoreTypeCheck = false +) => (dispatch: AppDispatch, getState: AppGetState) => { + const { independentField, outputCurrency, type } = getState().swap; + if ( + type === ExchangeModalTypes.swap && + newInputCurrency?.uniqueId === outputCurrency?.uniqueId && + newInputCurrency + ) { + dispatch(flipSwapCurrencies(false)); + } else { + dispatch({ payload: newInputCurrency, type: SWAP_UPDATE_INPUT_CURRENCY }); if ( type === ExchangeModalTypes.swap && - newInputCurrency?.uniqueId === outputCurrency?.uniqueId && - newInputCurrency + newInputCurrency?.network !== outputCurrency?.network && + newInputCurrency && + !ignoreTypeCheck ) { - dispatch(flipSwapCurrencies(false)); - } else { - dispatch({ payload: newInputCurrency, type: SWAP_UPDATE_INPUT_CURRENCY }); - if ( - type === ExchangeModalTypes.swap && - newInputCurrency?.network !== outputCurrency?.network && - newInputCurrency && - !ignoreTypeCheck - ) { - dispatch(updateSwapOutputCurrency(null, true)); - } + dispatch(updateSwapOutputCurrency(null, true)); + } - if (newInputCurrency) { - dispatch(fetchAssetPrices(newInputCurrency.address)); - } - if (independentField === SwapModalField.input) { - dispatch(updateSwapInputAmount(null)); - } + if (newInputCurrency) { + dispatch(fetchAssetPrices(newInputCurrency.address)); + } + if (independentField === SwapModalField.input) { + dispatch(updateSwapInputAmount(null)); } - }; + } +}; -export const updateSwapOutputCurrency = - (newOutputCurrency: SwappableAsset | null, ignoreTypeCheck = false) => - (dispatch: AppDispatch, getState: AppGetState) => { - const { independentField, inputCurrency, type } = getState().swap; +export const updateSwapOutputCurrency = ( + newOutputCurrency: SwappableAsset | null, + ignoreTypeCheck = false +) => (dispatch: AppDispatch, getState: AppGetState) => { + const { independentField, inputCurrency, type } = getState().swap; + if ( + newOutputCurrency?.uniqueId === inputCurrency?.uniqueId && + newOutputCurrency + ) { + dispatch(flipSwapCurrencies(true)); + } else { if ( - newOutputCurrency?.uniqueId === inputCurrency?.uniqueId && - newOutputCurrency + type === ExchangeModalTypes.swap && + newOutputCurrency?.network !== inputCurrency?.network && + newOutputCurrency && + !ignoreTypeCheck ) { - dispatch(flipSwapCurrencies(true)); - } else { - if ( - type === ExchangeModalTypes.swap && - newOutputCurrency?.network !== inputCurrency?.network && - newOutputCurrency && - !ignoreTypeCheck - ) { - dispatch(updateSwapInputCurrency(null, true)); - } + dispatch(updateSwapInputCurrency(null, true)); + } - dispatch({ - payload: newOutputCurrency, - type: SWAP_UPDATE_OUTPUT_CURRENCY, - }); - if (newOutputCurrency) { - dispatch(fetchAssetPrices(newOutputCurrency.address)); - } - if ( - independentField === SwapModalField.output || - newOutputCurrency === null - ) { - dispatch(updateSwapOutputAmount(null)); - } + dispatch({ payload: newOutputCurrency, type: SWAP_UPDATE_OUTPUT_CURRENCY }); + if (newOutputCurrency) { + dispatch(fetchAssetPrices(newOutputCurrency.address)); } - }; + if ( + independentField === SwapModalField.output || + newOutputCurrency === null + ) { + dispatch(updateSwapOutputAmount(null)); + } + } +}; -export const flipSwapCurrencies = - (outputIndependentField: boolean, independentValue?: string | null) => - (dispatch: AppDispatch, getState: AppGetState) => { - const { inputCurrency, outputCurrency } = getState().swap; - dispatch({ - payload: { - flipCurrenciesUpdate: true, - independentField: outputIndependentField - ? SwapModalField.output - : SwapModalField.input, - independentValue, - newInputCurrency: outputCurrency, - newOutputCurrency: inputCurrency, - }, - type: SWAP_FLIP_CURRENCIES, - }); - }; +export const flipSwapCurrencies = ( + outputIndependentField: boolean, + independentValue?: string | null +) => (dispatch: AppDispatch, getState: AppGetState) => { + const { inputCurrency, outputCurrency } = getState().swap; + dispatch({ + payload: { + flipCurrenciesUpdate: true, + independentField: outputIndependentField + ? SwapModalField.output + : SwapModalField.input, + independentValue, + newInputCurrency: outputCurrency, + newOutputCurrency: inputCurrency, + }, + type: SWAP_FLIP_CURRENCIES, + }); +}; export const updateSwapQuote = (value: any) => (dispatch: AppDispatch) => { dispatch({ diff --git a/src/redux/transactionSignatures.ts b/src/redux/transactionSignatures.ts index a83c8969dc9..5efd5604c45 100644 --- a/src/redux/transactionSignatures.ts +++ b/src/redux/transactionSignatures.ts @@ -10,37 +10,39 @@ const TRANSACTION_SIGNATURES_LOAD_TRANSACTION_SIGNATURES_SUCCESS = 'transactionSignatures/DATA_LOAD_TRANSACTION_SIGNATURES_SUCCESS'; // -- Actions ---------------------------------------- // -export const transactionSignaturesLoadState = - () => async (dispatch: AppDispatch) => { +export const transactionSignaturesLoadState = () => async ( + dispatch: AppDispatch +) => { + try { + const signatures = await getTransactionSignatures(); + dispatch({ + payload: signatures, + type: TRANSACTION_SIGNATURES_LOAD_TRANSACTION_SIGNATURES_SUCCESS, + }); + // eslint-disable-next-line no-empty + } catch (error) {} +}; + +export const transactionSignaturesDataAddNewSignature = ( + parsedSignature: string, + bytes: string +) => async (dispatch: AppDispatch, getState: AppGetState) => { + const { signatures } = getState().transactionSignatures; + if (parsedSignature) { + const newTransactionSignatures = { + ...signatures, + [bytes]: parsedSignature, + }; try { - const signatures = await getTransactionSignatures(); dispatch({ - payload: signatures, - type: TRANSACTION_SIGNATURES_LOAD_TRANSACTION_SIGNATURES_SUCCESS, + payload: newTransactionSignatures, + type: TRANSACTION_SIGNATURES_ADD_NEW_TRANSACTION_SIGNATURE_SUCCESS, }); + saveTransactionSignatures(newTransactionSignatures); // eslint-disable-next-line no-empty - } catch (error) {} - }; - -export const transactionSignaturesDataAddNewSignature = - (parsedSignature: string, bytes: string) => - async (dispatch: AppDispatch, getState: AppGetState) => { - const { signatures } = getState().transactionSignatures; - if (parsedSignature) { - const newTransactionSignatures = { - ...signatures, - [bytes]: parsedSignature, - }; - try { - dispatch({ - payload: newTransactionSignatures, - type: TRANSACTION_SIGNATURES_ADD_NEW_TRANSACTION_SIGNATURE_SUCCESS, - }); - saveTransactionSignatures(newTransactionSignatures); - // eslint-disable-next-line no-empty - } catch (e) {} - } - }; + } catch (e) {} + } +}; // -- Reducer ----------------------------------------- // const INITIAL_STATE: { signatures: { [key: string]: string } } = { diff --git a/src/redux/walletconnect.ts b/src/redux/walletconnect.ts index b1a970f0444..26fcc41459f 100644 --- a/src/redux/walletconnect.ts +++ b/src/redux/walletconnect.ts @@ -234,12 +234,13 @@ const getNativeOptions = async () => { /** * Updates the state to mark as pending redirection. */ -export const walletConnectSetPendingRedirect = - () => (dispatch: Dispatch) => { - dispatch({ - type: WALLETCONNECT_SET_PENDING_REDIRECT, - }); - }; +export const walletConnectSetPendingRedirect = () => ( + dispatch: Dispatch +) => { + dispatch({ + type: WALLETCONNECT_SET_PENDING_REDIRECT, + }); +}; /** * Updaets the state to disable a pending redirect and either redirect or @@ -249,47 +250,48 @@ export const walletConnectSetPendingRedirect = * a scheme is not specified. * @param scheme The scheme to open, if specified. */ -export const walletConnectRemovePendingRedirect = - (type: WalletconnectResultType, scheme?: string | null) => - (dispatch: Dispatch) => { - dispatch({ - type: WALLETCONNECT_REMOVE_PENDING_REDIRECT, - }); - const lastActiveTime = new Date().getTime(); - if (scheme) { - Linking.openURL(`${scheme}://`); - } else if (type !== 'timedOut') { - if (type === 'sign' || type === 'transaction') { - showRedirectSheetThreshold += BIOMETRICS_ANIMATION_DELAY; - if (!IS_IOS) { - setTimeout(() => { - Minimizer.goBack(); - }, BIOMETRICS_ANIMATION_DELAY); - } - } else if (type === 'sign-canceled' || type === 'transaction-canceled') { - if (!IS_IOS) { - setTimeout(() => { - Minimizer.goBack(); - }, 300); - } - } else { - !IS_TEST && !IS_IOS && Minimizer.goBack(); +export const walletConnectRemovePendingRedirect = ( + type: WalletconnectResultType, + scheme?: string | null +) => (dispatch: Dispatch) => { + dispatch({ + type: WALLETCONNECT_REMOVE_PENDING_REDIRECT, + }); + const lastActiveTime = new Date().getTime(); + if (scheme) { + Linking.openURL(`${scheme}://`); + } else if (type !== 'timedOut') { + if (type === 'sign' || type === 'transaction') { + showRedirectSheetThreshold += BIOMETRICS_ANIMATION_DELAY; + if (!IS_IOS) { + setTimeout(() => { + Minimizer.goBack(); + }, BIOMETRICS_ANIMATION_DELAY); } - // If it's still active after showRedirectSheetThreshold - // We need to show the redirect sheet cause the redirect - // didn't work - setTimeout(() => { - const now = new Date().getTime(); - const delta = now - lastActiveTime; - if (AppState.currentState === 'active' && delta < 1000) { - return Navigation.handleAction(Routes.WALLET_CONNECT_REDIRECT_SHEET, { - type, - }); - } - return; - }, showRedirectSheetThreshold); + } else if (type === 'sign-canceled' || type === 'transaction-canceled') { + if (!IS_IOS) { + setTimeout(() => { + Minimizer.goBack(); + }, 300); + } + } else { + !IS_TEST && !IS_IOS && Minimizer.goBack(); } - }; + // If it's still active after showRedirectSheetThreshold + // We need to show the redirect sheet cause the redirect + // didn't work + setTimeout(() => { + const now = new Date().getTime(); + const delta = now - lastActiveTime; + if (AppState.currentState === 'active' && delta < 1000) { + return Navigation.handleAction(Routes.WALLET_CONNECT_REDIRECT_SHEET, { + type, + }); + } + return; + }, showRedirectSheetThreshold); + } +}; /** * Handles an incoming WalletConnect session request and updates state @@ -298,206 +300,208 @@ export const walletConnectRemovePendingRedirect = * @param uri The WalletConnect URI. * @param callback The callback function to use. */ -export const walletConnectOnSessionRequest = - (uri: string, connector?: string, callback?: WalletconnectRequestCallback) => - async ( - dispatch: ThunkDispatch, - getState: AppGetState - ) => { - // branch and linking are triggering this twice - // also branch trigger this when the app is coming back from background - // so this is a way to handle this case without persisting anything - const { walletConnectUris } = getState().walletconnect; - if (walletConnectUris.includes(uri)) return; - dispatch(saveWalletConnectUri(uri)); - - let timeout: ReturnType | null = null; - let walletConnector: WalletConnect | null = null; - const receivedTimestamp = Date.now(); +export const walletConnectOnSessionRequest = ( + uri: string, + connector?: string, + callback?: WalletconnectRequestCallback +) => async ( + dispatch: ThunkDispatch, + getState: AppGetState +) => { + // branch and linking are triggering this twice + // also branch trigger this when the app is coming back from background + // so this is a way to handle this case without persisting anything + const { walletConnectUris } = getState().walletconnect; + if (walletConnectUris.includes(uri)) return; + dispatch(saveWalletConnectUri(uri)); + + let timeout: ReturnType | null = null; + let walletConnector: WalletConnect | null = null; + const receivedTimestamp = Date.now(); + try { + const { clientMeta, push } = await getNativeOptions(); try { - const { clientMeta, push } = await getNativeOptions(); - try { - // Don't initiate a new session if we have already established one using this walletconnect URI - const allSessions = await getAllValidWalletConnectSessions(); - const wcUri = parseWalletConnectUri(uri); - - const alreadyConnected = Object.values(allSessions).some(session => { - return ( - session.handshakeTopic === wcUri.handshakeTopic && - session.key === wcUri.key - ); - }); + // Don't initiate a new session if we have already established one using this walletconnect URI + const allSessions = await getAllValidWalletConnectSessions(); + const wcUri = parseWalletConnectUri(uri); - if (alreadyConnected) { - return; - } + const alreadyConnected = Object.values(allSessions).some(session => { + return ( + session.handshakeTopic === wcUri.handshakeTopic && + session.key === wcUri.key + ); + }); - walletConnector = new WalletConnect({ clientMeta, uri }, push); - let meta: WalletconnectApprovalSheetRouteParams['meta'] | false = false; - let navigated = false; - let timedOut = false; - let routeParams: WalletconnectApprovalSheetRouteParams = { - callback: async ( - approved, - chainId, - accountAddress, - peerId, - dappScheme, - dappName, - dappUrl - ) => { - if (approved) { - dispatch(setPendingRequest(peerId, walletConnector!)); - dispatch( - walletConnectApproveSession( - peerId, - callback, - dappScheme, - chainId, - accountAddress - ) - ); - analytics.track('Approved new WalletConnect session', { - dappName, - dappUrl, - connector, - }); - } else if (!timedOut) { - await dispatch( - walletConnectRejectSession(peerId, walletConnector!) - ); - callback?.('reject', dappScheme); - analytics.track('Rejected new WalletConnect session', { - dappName, - dappUrl, - connector, - }); - } else { - callback?.('timedOut', dappScheme); - const url = new URL(uri); - // @ts-ignore - const bridge = qs.parse(url?.query)?.bridge; - analytics.track('New WalletConnect session time out', { - bridge, - dappName, - dappUrl, - connector, - }); - } - }, - receivedTimestamp, - }; + if (alreadyConnected) { + return; + } - walletConnector?.on('session_request', (error, payload) => { - clearTimeout(timeout!); - if (error) { - analytics.track('Error on wc session_request', { - // @ts-ignore - error, - payload, + walletConnector = new WalletConnect({ clientMeta, uri }, push); + let meta: WalletconnectApprovalSheetRouteParams['meta'] | false = false; + let navigated = false; + let timedOut = false; + let routeParams: WalletconnectApprovalSheetRouteParams = { + callback: async ( + approved, + chainId, + accountAddress, + peerId, + dappScheme, + dappName, + dappUrl + ) => { + if (approved) { + dispatch(setPendingRequest(peerId, walletConnector!)); + dispatch( + walletConnectApproveSession( + peerId, + callback, + dappScheme, + chainId, + accountAddress + ) + ); + analytics.track('Approved new WalletConnect session', { + dappName, + dappUrl, + connector, }); - logger.error(new RainbowError('WC: Error on wc session_request'), { - error, - payload, + } else if (!timedOut) { + await dispatch( + walletConnectRejectSession(peerId, walletConnector!) + ); + callback?.('reject', dappScheme); + analytics.track('Rejected new WalletConnect session', { + dappName, + dappUrl, + connector, + }); + } else { + callback?.('timedOut', dappScheme); + const url = new URL(uri); + // @ts-ignore + const bridge = qs.parse(url?.query)?.bridge; + analytics.track('New WalletConnect session time out', { + bridge, + dappName, + dappUrl, + connector, }); - return; } - const { peerId, peerMeta, chainId } = payload.params[0]; - - const imageUrl = peerMeta?.icons?.[0]; - const dappName = peerMeta?.name; - const dappUrl = peerMeta?.url; - const dappScheme = peerMeta?.scheme; + }, + receivedTimestamp, + }; - analytics.track('Showing Walletconnect session request', { - dappName, - dappUrl, - connector, + walletConnector?.on('session_request', (error, payload) => { + clearTimeout(timeout!); + if (error) { + analytics.track('Error on wc session_request', { + // @ts-ignore + error, + payload, }); + logger.error(new RainbowError('WC: Error on wc session_request'), { + error, + payload, + }); + return; + } + const { peerId, peerMeta, chainId } = payload.params[0]; - meta = { - chainIds: [chainId], - dappName, - dappScheme, - dappUrl, - imageUrl, - peerId, - }; - - // If we already showed the sheet - // We need navigate to the same route with the updated params - // which now includes the meta - if (navigated && !timedOut) { - routeParams = { ...routeParams, meta, timeout }; - Navigation.handleAction( - Routes.WALLET_CONNECT_APPROVAL_SHEET, - routeParams - ); - } + const imageUrl = peerMeta?.icons?.[0]; + const dappName = peerMeta?.name; + const dappUrl = peerMeta?.url; + const dappScheme = peerMeta?.scheme; + + analytics.track('Showing Walletconnect session request', { + dappName, + dappUrl, + connector, }); - let waitingFn: (callback: () => unknown, timeout: number) => unknown = - InteractionManager.runAfterInteractions; - if (IS_TEST) { - waitingFn = setTimeout; + meta = { + chainIds: [chainId], + dappName, + dappScheme, + dappUrl, + imageUrl, + peerId, + }; + + // If we already showed the sheet + // We need navigate to the same route with the updated params + // which now includes the meta + if (navigated && !timedOut) { + routeParams = { ...routeParams, meta, timeout }; + Navigation.handleAction( + Routes.WALLET_CONNECT_APPROVAL_SHEET, + routeParams + ); } + }); - waitingFn(async () => { - if (IS_TEST) { - // Wait until the app is idle so we can navigate - // This usually happens only when coming from a cold start - while (!getState().appState.walletReady) { - await delay(300); - } - } + let waitingFn: (callback: () => unknown, timeout: number) => unknown = + InteractionManager.runAfterInteractions; + if (IS_TEST) { + waitingFn = setTimeout; + } - // We need to add a timeout in case the bridge is down - // to explain the user what's happening - timeout = setTimeout(() => { - meta = android ? Navigation.getActiveRoute()?.params?.meta : meta; - if (meta) return; - timedOut = true; - routeParams = { ...routeParams, timedOut }; - Navigation.handleAction( - Routes.WALLET_CONNECT_APPROVAL_SHEET, - routeParams - ); - }, 20000); + waitingFn(async () => { + if (IS_TEST) { + // Wait until the app is idle so we can navigate + // This usually happens only when coming from a cold start + while (!getState().appState.walletReady) { + await delay(300); + } + } - // If we have the meta, send it + // We need to add a timeout in case the bridge is down + // to explain the user what's happening + timeout = setTimeout(() => { meta = android ? Navigation.getActiveRoute()?.params?.meta : meta; - if (meta) { - routeParams = { ...routeParams, meta }; - } - navigated = true; + if (meta) return; + timedOut = true; + routeParams = { ...routeParams, timedOut }; Navigation.handleAction( Routes.WALLET_CONNECT_APPROVAL_SHEET, routeParams ); - }, 2000); - } catch (error: any) { - clearTimeout(timeout!); - logger.error( - new RainbowError('WC: Exception during wc session_request'), - { error } + }, 20000); + + // If we have the meta, send it + meta = android ? Navigation.getActiveRoute()?.params?.meta : meta; + if (meta) { + routeParams = { ...routeParams, meta }; + } + navigated = true; + Navigation.handleAction( + Routes.WALLET_CONNECT_APPROVAL_SHEET, + routeParams ); - analytics.track('Exception on wc session_request', { - error, - }); - Alert.alert(lang.t('wallet.wallet_connect.error')); - } + }, 2000); } catch (error: any) { clearTimeout(timeout!); logger.error( - new RainbowError('WC: FCM exception during wc session_request'), + new RainbowError('WC: Exception during wc session_request'), { error } ); - analytics.track('FCM exception on wc session_request', { + analytics.track('Exception on wc session_request', { error, }); - Alert.alert(lang.t('wallet.wallet_connect.missing_fcm')); + Alert.alert(lang.t('wallet.wallet_connect.error')); } - }; + } catch (error: any) { + clearTimeout(timeout!); + logger.error( + new RainbowError('WC: FCM exception during wc session_request'), + { error } + ); + analytics.track('FCM exception on wc session_request', { + error, + }); + Alert.alert(lang.t('wallet.wallet_connect.missing_fcm')); + } +}; /** * Starts listening for requests on a given `WalletConnect` instance. @@ -505,241 +509,228 @@ export const walletConnectOnSessionRequest = * @param walletConnector The `WalletConnect` instance to listen for requests * on. */ -const listenOnNewMessages = - (walletConnector: WalletConnect) => - ( - dispatch: ThunkDispatch, - getState: AppGetState - ) => { - walletConnector.on('call_request', async (error, payload) => { - logger.debug( - 'WC: Request!', - { error, payload }, - logger.DebugContext.walletconnect - ); +const listenOnNewMessages = (walletConnector: WalletConnect) => ( + dispatch: ThunkDispatch, + getState: AppGetState +) => { + walletConnector.on('call_request', async (error, payload) => { + logger.debug( + 'WC: Request!', + { error, payload }, + logger.DebugContext.walletconnect + ); - if (error) { - analytics.track('Error on wc call_request', { - // @ts-ignore - error, - payload, + if (error) { + analytics.track('Error on wc call_request', { + // @ts-ignore + error, + payload, + }); + logger.error(new RainbowError('WC: Error on wc call_request'), { + message: error, + }); + return; + } + + const { clientId, peerId, peerMeta } = walletConnector; + const imageUrl = peerMeta?.icons?.[0]; + const dappName = peerMeta?.name; + const dappUrl = peerMeta?.url; + const requestId = payload.id; + if ( + payload.method === 'wallet_addEthereumChain' || + payload.method === `wallet_switchEthereumChain` + ) { + const { chainId } = payload.params[0]; + const currentNetwork = ethereumUtils.getNetworkFromChainId( + // @ts-expect-error "_chainId" is private. + Number(walletConnector._chainId) + ); + const supportedChains = RainbowNetworks.filter( + network => network.features.walletconnect + ).map(network => network.id.toString()); + const numericChainId = convertHexToString(chainId); + if (supportedChains.includes(numericChainId)) { + dispatch(walletConnectSetPendingRedirect()); + Navigation.handleAction(Routes.WALLET_CONNECT_APPROVAL_SHEET, { + callback: async (approved: boolean) => { + if (approved) { + walletConnector.approveRequest({ + id: requestId, + result: null, + }); + const { accountAddress } = getState().settings; + logger.debug( + 'WC: Updating session for chainID', + { numericChainId }, + logger.DebugContext.walletconnect + ); + await walletConnector.updateSession({ + accounts: [accountAddress], + // @ts-expect-error "numericChainId" is a string, not a number. + chainId: numericChainId, + }); + dispatch(setWalletConnector(walletConnector)); + saveWalletConnectSession( + walletConnector.peerId, + walletConnector.session + ); + analytics.track('Approved WalletConnect network switch', { + chainId, + dappName, + dappUrl, + }); + dispatch(walletConnectRemovePendingRedirect('connect')); + } else { + walletConnector.rejectRequest({ + error: { message: 'User rejected request' }, + id: requestId, + }); + analytics.track('Rejected new WalletConnect chain request', { + dappName, + dappUrl, + }); + } + }, + currentNetwork, + meta: { + chainIds: [Number(numericChainId)], + dappName, + dappUrl, + imageUrl, + }, + type: WalletConnectApprovalSheetType.switch_chain, }); - logger.error(new RainbowError('WC: Error on wc call_request'), { - message: error, + } else { + logger.info('WC: NOT SUPPORTED CHAIN'); + walletConnector.rejectRequest({ + error: { message: 'Chain currently not supported' }, + id: requestId, }); - return; } - const { clientId, peerId, peerMeta } = walletConnector; - const imageUrl = peerMeta?.icons?.[0]; - const dappName = peerMeta?.name; - const dappUrl = peerMeta?.url; - const requestId = payload.id; - if ( - payload.method === 'wallet_addEthereumChain' || - payload.method === `wallet_switchEthereumChain` - ) { - const { chainId } = payload.params[0]; - const currentNetwork = ethereumUtils.getNetworkFromChainId( - // @ts-expect-error "_chainId" is private. - Number(walletConnector._chainId) - ); - const supportedChains = RainbowNetworks.filter( - network => network.features.walletconnect - ).map(network => network.id.toString()); - const numericChainId = convertHexToString(chainId); - if (supportedChains.includes(numericChainId)) { - dispatch(walletConnectSetPendingRedirect()); - Navigation.handleAction(Routes.WALLET_CONNECT_APPROVAL_SHEET, { - callback: async (approved: boolean) => { - if (approved) { - walletConnector.approveRequest({ - id: requestId, - result: null, - }); - const { accountAddress } = getState().settings; - logger.debug( - 'WC: Updating session for chainID', - { numericChainId }, - logger.DebugContext.walletconnect - ); - await walletConnector.updateSession({ - accounts: [accountAddress], - // @ts-expect-error "numericChainId" is a string, not a number. - chainId: numericChainId, - }); - dispatch(setWalletConnector(walletConnector)); - saveWalletConnectSession( - walletConnector.peerId, - walletConnector.session - ); - analytics.track('Approved WalletConnect network switch', { - chainId, - dappName, - dappUrl, - }); - dispatch(walletConnectRemovePendingRedirect('connect')); - } else { - walletConnector.rejectRequest({ - error: { message: 'User rejected request' }, - id: requestId, - }); - analytics.track('Rejected new WalletConnect chain request', { - dappName, - dappUrl, - }); - } - }, - currentNetwork, - meta: { - chainIds: [Number(numericChainId)], - dappName, - dappUrl, - imageUrl, - }, - type: WalletConnectApprovalSheetType.switch_chain, - }); - } else { - logger.info('WC: NOT SUPPORTED CHAIN'); - walletConnector.rejectRequest({ - error: { message: 'Chain currently not supported' }, - id: requestId, - }); - } - - return; - } else if (!isSigningMethod(payload.method)) { - sendRpcCall(payload) - .then(result => { - walletConnector.approveRequest({ - id: payload.id, - result, - }); - }) - .catch(error => { - walletConnector.rejectRequest({ - error, - id: payload.id, - }); + return; + } else if (!isSigningMethod(payload.method)) { + sendRpcCall(payload) + .then(result => { + walletConnector.approveRequest({ + id: payload.id, + result, }); - return; - } else { - const { wallets } = getState().wallets; - // @ts-expect-error "_accounts" is private. - const address = walletConnector._accounts?.[0]; - const selectedWallet = findWalletWithAccount(wallets!, address); - const isReadOnlyWallet = selectedWallet!.type === WalletTypes.readOnly; - if (isReadOnlyWallet && !enableActionsOnReadOnlyWallet) { - watchingAlert(); + }) + .catch(error => { walletConnector.rejectRequest({ - error: { message: 'JSON RPC method not supported' }, + error, id: payload.id, }); - return; - } - const { requests: pendingRequests } = getState().requests; - const request = !pendingRequests[requestId] - ? dispatch( - addRequestToApprove( - clientId, - peerId, - requestId, - payload, - peerMeta - ) - ) - : null; - if (request) { - Navigation.handleAction(Routes.CONFIRM_REQUEST, { - openAutomatically: true, - transactionDetails: request, - }); - InteractionManager.runAfterInteractions(() => { - analytics.track('Showing Walletconnect signing request', { - dappName, - dappUrl, - }); - }); - } - } - }); - walletConnector.on('disconnect', error => { - if (error) { - logger.error(new RainbowError('WC: Error on wc disconnect'), { - message: error, }); - - // we used to throw, so for parity, return + return; + } else { + const { wallets } = getState().wallets; + // @ts-expect-error "_accounts" is private. + const address = walletConnector._accounts?.[0]; + const selectedWallet = findWalletWithAccount(wallets!, address); + const isReadOnlyWallet = selectedWallet!.type === WalletTypes.readOnly; + if (isReadOnlyWallet && !enableActionsOnReadOnlyWallet) { + watchingAlert(); + walletConnector.rejectRequest({ + error: { message: 'JSON RPC method not supported' }, + id: payload.id, + }); return; } + const { requests: pendingRequests } = getState().requests; + const request = !pendingRequests[requestId] + ? dispatch( + addRequestToApprove(clientId, peerId, requestId, payload, peerMeta) + ) + : null; + if (request) { + Navigation.handleAction(Routes.CONFIRM_REQUEST, { + openAutomatically: true, + transactionDetails: request, + }); + InteractionManager.runAfterInteractions(() => { + analytics.track('Showing Walletconnect signing request', { + dappName, + dappUrl, + }); + }); + } + } + }); + walletConnector.on('disconnect', error => { + if (error) { + logger.error(new RainbowError('WC: Error on wc disconnect'), { + message: error, + }); - dispatch( - walletConnectDisconnectAllByDappUrl( - walletConnector.peerMeta!.url, - false - ) - ); - }); - return walletConnector; - }; + // we used to throw, so for parity, return + return; + } + + dispatch( + walletConnectDisconnectAllByDappUrl(walletConnector.peerMeta!.url, false) + ); + }); + return walletConnector; +}; /** * Begins listening to WalletConnect events on existing connections. */ -export const walletConnectLoadState = - () => - async ( - dispatch: ThunkDispatch< - StoreAppState, - unknown, - WalletconnectUpdateConnectorsAction - >, - getState: AppGetState - ) => { - while (!getState().walletconnect.walletConnectors) { - await delay(50); - } - const { walletConnectors } = getState().walletconnect; - let newWalletConnectors = {}; - try { - const allSessions = await getAllValidWalletConnectSessions(); - const { clientMeta, push } = await getNativeOptions(); - - newWalletConnectors = mapValues(allSessions, session => { - const connector = walletConnectors[session.peerId]; - // @ts-expect-error "_transport" is private. - const connectorConnected = connector?._transport.connected; - if (!connectorConnected) { +export const walletConnectLoadState = () => async ( + dispatch: ThunkDispatch< + StoreAppState, + unknown, + WalletconnectUpdateConnectorsAction + >, + getState: AppGetState +) => { + while (!getState().walletconnect.walletConnectors) { + await delay(50); + } + const { walletConnectors } = getState().walletconnect; + let newWalletConnectors = {}; + try { + const allSessions = await getAllValidWalletConnectSessions(); + const { clientMeta, push } = await getNativeOptions(); + + newWalletConnectors = mapValues(allSessions, session => { + const connector = walletConnectors[session.peerId]; + // @ts-expect-error "_transport" is private. + const connectorConnected = connector?._transport.connected; + if (!connectorConnected) { + // @ts-expect-error "_eventManager" is private. + if (connector?._eventManager) { // @ts-expect-error "_eventManager" is private. - if (connector?._eventManager) { - // @ts-expect-error "_eventManager" is private. - connector._eventManager = null; - } - const walletConnector = new WalletConnect( - { clientMeta, session }, - push - ); - return dispatch(listenOnNewMessages(walletConnector)); + connector._eventManager = null; } - return connector; - }); - } catch (error) { - analytics.track('Error on walletConnectLoadState', { - // @ts-ignore - error, - }); - logger.error(new RainbowError('WC: Error on wc walletConnectLoadState'), { - error, - }); - newWalletConnectors = {}; - } - if (!isEmpty(newWalletConnectors)) { - dispatch({ - payload: newWalletConnectors, - type: WALLETCONNECT_UPDATE_CONNECTORS, - }); - } - }; + const walletConnector = new WalletConnect( + { clientMeta, session }, + push + ); + return dispatch(listenOnNewMessages(walletConnector)); + } + return connector; + }); + } catch (error) { + analytics.track('Error on walletConnectLoadState', { + // @ts-ignore + error, + }); + logger.error(new RainbowError('WC: Error on wc walletConnectLoadState'), { + error, + }); + newWalletConnectors = {}; + } + if (!isEmpty(newWalletConnectors)) { + dispatch({ + payload: newWalletConnectors, + type: WALLETCONNECT_UPDATE_CONNECTORS, + }); + } +}; /** * Updates the pending requests to include a new connector. @@ -747,22 +738,23 @@ export const walletConnectLoadState = * @param peerId The peer ID for the pending request. * @param walletConnector The `WalletConnect` instance for the pending request. */ -export const setPendingRequest = - (peerId: string, walletConnector: WalletConnect) => - ( - dispatch: Dispatch, - getState: AppGetState - ) => { - const { pendingRequests } = getState().walletconnect; - const updatedPendingRequests = { - ...pendingRequests, - [peerId]: walletConnector, - }; - dispatch({ - payload: updatedPendingRequests, - type: WALLETCONNECT_UPDATE_REQUESTS, - }); +export const setPendingRequest = ( + peerId: string, + walletConnector: WalletConnect +) => ( + dispatch: Dispatch, + getState: AppGetState +) => { + const { pendingRequests } = getState().walletconnect; + const updatedPendingRequests = { + ...pendingRequests, + [peerId]: walletConnector, }; + dispatch({ + payload: updatedPendingRequests, + type: WALLETCONNECT_UPDATE_REQUESTS, + }); +}; /** * Gets an existing pending request for a given peer ID. @@ -771,33 +763,33 @@ export const setPendingRequest = * @returns Within a dispatch, returns the pending request's `WalletConnector`, * or undefined. */ -export const getPendingRequest = - (peerId: string) => (_: Dispatch, getState: AppGetState) => { - const { pendingRequests } = getState().walletconnect; - return pendingRequests[peerId]; - }; +export const getPendingRequest = (peerId: string) => ( + _: Dispatch, + getState: AppGetState +) => { + const { pendingRequests } = getState().walletconnect; + return pendingRequests[peerId]; +}; /** * Removes a pending request from state given a peer ID. * @param peerId The peer ID for the pending request to remove. */ -export const removePendingRequest = - (peerId: string) => - ( - dispatch: Dispatch, - getState: AppGetState - ) => { - const { pendingRequests } = getState().walletconnect; - const updatedPendingRequests = pendingRequests; - if (updatedPendingRequests[peerId]) { - // eslint-disable-next-line @typescript-eslint/no-dynamic-delete - delete updatedPendingRequests[peerId]; - } - dispatch({ - payload: updatedPendingRequests, - type: WALLETCONNECT_UPDATE_REQUESTS, - }); - }; +export const removePendingRequest = (peerId: string) => ( + dispatch: Dispatch, + getState: AppGetState +) => { + const { pendingRequests } = getState().walletconnect; + const updatedPendingRequests = pendingRequests; + if (updatedPendingRequests[peerId]) { + // eslint-disable-next-line @typescript-eslint/no-dynamic-delete + delete updatedPendingRequests[peerId]; + } + dispatch({ + payload: updatedPendingRequests, + type: WALLETCONNECT_UPDATE_REQUESTS, + }); +}; /** * Updates the state's `walletConnectors` to include a new instance based on @@ -805,22 +797,20 @@ export const removePendingRequest = * * @param walletConnector The new `WalletConnect` instance. */ -export const setWalletConnector = - (walletConnector: WalletConnect) => - ( - dispatch: Dispatch, - getState: AppGetState - ) => { - const { walletConnectors } = getState().walletconnect; - const updatedWalletConnectors = { - ...walletConnectors, - [walletConnector.peerId]: walletConnector, - }; - dispatch({ - payload: updatedWalletConnectors, - type: WALLETCONNECT_UPDATE_CONNECTORS, - }); +export const setWalletConnector = (walletConnector: WalletConnect) => ( + dispatch: Dispatch, + getState: AppGetState +) => { + const { walletConnectors } = getState().walletconnect; + const updatedWalletConnectors = { + ...walletConnectors, + [walletConnector.peerId]: walletConnector, }; + dispatch({ + payload: updatedWalletConnectors, + type: WALLETCONNECT_UPDATE_CONNECTORS, + }); +}; /** * Gets a `WalletConnect` instance from `walletConnectors` in state based on a @@ -829,12 +819,14 @@ export const setWalletConnector = * @param peerId The peer ID for the `WalletConnect` instance. * @returns Within a dispatch, the `WalletConnect` instance. */ -export const getWalletConnector = - (peerId: string) => (_: Dispatch, getState: AppGetState) => { - const { walletConnectors } = getState().walletconnect; - const walletConnector = walletConnectors[peerId]; - return walletConnector; - }; +export const getWalletConnector = (peerId: string) => ( + _: Dispatch, + getState: AppGetState +) => { + const { walletConnectors } = getState().walletconnect; + const walletConnector = walletConnectors[peerId]; + return walletConnector; +}; /** * Removes a `WalletConnect` instance from the state's `walletConnectors` based @@ -842,23 +834,21 @@ export const getWalletConnector = * * @param peerId The peer ID of the `WalletConnect` instance to remove. */ -export const removeWalletConnector = - (peerId: string) => - ( - dispatch: Dispatch, - getState: AppGetState - ) => { - const { walletConnectors } = getState().walletconnect; - const updatedWalletConnectors = walletConnectors; - if (updatedWalletConnectors[peerId]) { - // eslint-disable-next-line @typescript-eslint/no-dynamic-delete - delete updatedWalletConnectors[peerId]; - } - dispatch({ - payload: updatedWalletConnectors, - type: WALLETCONNECT_UPDATE_CONNECTORS, - }); - }; +export const removeWalletConnector = (peerId: string) => ( + dispatch: Dispatch, + getState: AppGetState +) => { + const { walletConnectors } = getState().walletconnect; + const updatedWalletConnectors = walletConnectors; + if (updatedWalletConnectors[peerId]) { + // eslint-disable-next-line @typescript-eslint/no-dynamic-delete + delete updatedWalletConnectors[peerId]; + } + dispatch({ + payload: updatedWalletConnectors, + type: WALLETCONNECT_UPDATE_CONNECTORS, + }); +}; /** * Updates the account address and chain ID for all connectors that match @@ -868,29 +858,31 @@ export const removeWalletConnector = * @param accountAddress The account address to use. * @param chainId The chain ID to use. */ -export const walletConnectUpdateSessionConnectorByDappUrl = - (dappUrl: RequestData['dappUrl'], accountAddress: string, chainId: number) => - ( - dispatch: Dispatch, - getState: AppGetState - ) => { - const { walletConnectors } = getState().walletconnect; - const connectors = pickBy(walletConnectors, connector => { - return connector?.peerMeta?.url === dappUrl; - }); - const newSessionData = { - accounts: [accountAddress], - chainId, - }; - values(connectors).forEach(connector => { - connector.updateSession(newSessionData); - saveWalletConnectSession(connector.peerId, connector.session); - }); - dispatch({ - payload: clone(walletConnectors), - type: WALLETCONNECT_UPDATE_CONNECTORS, - }); +export const walletConnectUpdateSessionConnectorByDappUrl = ( + dappUrl: RequestData['dappUrl'], + accountAddress: string, + chainId: number +) => ( + dispatch: Dispatch, + getState: AppGetState +) => { + const { walletConnectors } = getState().walletconnect; + const connectors = pickBy(walletConnectors, connector => { + return connector?.peerMeta?.url === dappUrl; + }); + const newSessionData = { + accounts: [accountAddress], + chainId, }; + values(connectors).forEach(connector => { + connector.updateSession(newSessionData); + saveWalletConnectSession(connector.peerId, connector.session); + }); + dispatch({ + payload: clone(walletConnectors), + type: WALLETCONNECT_UPDATE_CONNECTORS, + }); +}; /** * Approves a WalletConnect session and updates state accordingly. @@ -901,33 +893,31 @@ export const walletConnectUpdateSessionConnectorByDappUrl = * @param chainId The chain ID to use in the approval. * @param accountAddress The account address to use in the approval. */ -export const walletConnectApproveSession = - ( - peerId: string, - callback: WalletconnectRequestCallback | undefined, - dappScheme: RequestData['dappScheme'], - chainId: number, - accountAddress: string - ) => - (dispatch: ThunkDispatch) => { - const walletConnector = dispatch(getPendingRequest(peerId)); - walletConnector.approveSession({ - accounts: [accountAddress], - chainId, - }); - - dispatch(removePendingRequest(peerId)); - saveWalletConnectSession(walletConnector.peerId, walletConnector.session); - - const listeningWalletConnector = dispatch( - listenOnNewMessages(walletConnector) - ); - - dispatch(setWalletConnector(listeningWalletConnector)); - if (callback) { - callback('connect', dappScheme); - } - }; +export const walletConnectApproveSession = ( + peerId: string, + callback: WalletconnectRequestCallback | undefined, + dappScheme: RequestData['dappScheme'], + chainId: number, + accountAddress: string +) => (dispatch: ThunkDispatch) => { + const walletConnector = dispatch(getPendingRequest(peerId)); + walletConnector.approveSession({ + accounts: [accountAddress], + chainId, + }); + + dispatch(removePendingRequest(peerId)); + saveWalletConnectSession(walletConnector.peerId, walletConnector.session); + + const listeningWalletConnector = dispatch( + listenOnNewMessages(walletConnector) + ); + + dispatch(setWalletConnector(listeningWalletConnector)); + if (callback) { + callback('connect', dappScheme); + } +}; /** * Rejects a WalletConnect session and updates state accordingly. @@ -935,12 +925,13 @@ export const walletConnectApproveSession = * @param peerId The peer ID for the request to reject. * @param walletConnector The `WalletConnect` instance to reject. */ -export const walletConnectRejectSession = - (peerId: string, walletConnector: WalletConnect) => - (dispatch: ThunkDispatch) => { - walletConnector.rejectSession(); - dispatch(removePendingRequest(peerId)); - }; +export const walletConnectRejectSession = ( + peerId: string, + walletConnector: WalletConnect +) => (dispatch: ThunkDispatch) => { + walletConnector.rejectSession(); + dispatch(removePendingRequest(peerId)); +}; /** * Removes all current WalletConnect sessions matching a given URL and @@ -950,44 +941,44 @@ export const walletConnectRejectSession = * @param killSession Whether or not to kill the corresponding WalletConnect * session. */ -export const walletConnectDisconnectAllByDappUrl = - (dappUrl: string, killSession = true) => - async ( - dispatch: Dispatch, - getState: AppGetState - ) => { - const { walletConnectors } = getState().walletconnect; - const matchingWalletConnectors = values( - pickBy( - walletConnectors, - connector => - connector?.peerMeta?.url === dappUrl || !connector?.peerMeta +export const walletConnectDisconnectAllByDappUrl = ( + dappUrl: string, + killSession = true +) => async ( + dispatch: Dispatch, + getState: AppGetState +) => { + const { walletConnectors } = getState().walletconnect; + const matchingWalletConnectors = values( + pickBy( + walletConnectors, + connector => connector?.peerMeta?.url === dappUrl || !connector?.peerMeta + ) + ); + try { + const peerIds = values( + mapValues( + matchingWalletConnectors, + (walletConnector: WalletConnect) => walletConnector.peerId ) ); - try { - const peerIds = values( - mapValues( - matchingWalletConnectors, - (walletConnector: WalletConnect) => walletConnector.peerId - ) - ); - await removeWalletConnectSessions(peerIds); + await removeWalletConnectSessions(peerIds); - if (killSession) { - matchingWalletConnectors.forEach(connector => connector?.killSession()); - } - - dispatch({ - payload: omitBy( - walletConnectors, - connector => connector?.peerMeta?.url === dappUrl - ), - type: WALLETCONNECT_UPDATE_CONNECTORS, - }); - } catch (error) { - Alert.alert(lang.t('wallet.wallet_connect.failed_to_disconnect')); + if (killSession) { + matchingWalletConnectors.forEach(connector => connector?.killSession()); } - }; + + dispatch({ + payload: omitBy( + walletConnectors, + connector => connector?.peerMeta?.url === dappUrl + ), + type: WALLETCONNECT_UPDATE_CONNECTORS, + }); + } catch (error) { + Alert.alert(lang.t('wallet.wallet_connect.failed_to_disconnect')); + } +}; /** * Responds to a `WalletConnect` request. @@ -996,57 +987,53 @@ export const walletConnectDisconnectAllByDappUrl = * @param requestId The request ID to respond to. * @param response The response to send. */ -export const walletConnectSendStatus = - ( - peerId: string, - requestId: number, - response: { result?: any; error?: any } - ) => - async (_: Dispatch, getState: AppGetState) => { - const walletConnector = getState().walletconnect.walletConnectors[peerId]; - if (walletConnector) { - const { result, error } = response; - try { - if (result) { - await walletConnector.approveRequest({ id: requestId, result }); - } else { - await walletConnector.rejectRequest({ - error, - id: requestId, - }); - } - } catch (error) { - Alert.alert( - lang.t('wallet.wallet_connect.failed_to_send_request_status') - ); +export const walletConnectSendStatus = ( + peerId: string, + requestId: number, + response: { result?: any; error?: any } +) => async (_: Dispatch, getState: AppGetState) => { + const walletConnector = getState().walletconnect.walletConnectors[peerId]; + if (walletConnector) { + const { result, error } = response; + try { + if (result) { + await walletConnector.approveRequest({ id: requestId, result }); + } else { + await walletConnector.rejectRequest({ + error, + id: requestId, + }); } - } else { + } catch (error) { Alert.alert( - lang.t( - 'wallet.wallet_connect.walletconnect_session_has_expired_while_trying_to_send' - ) + lang.t('wallet.wallet_connect.failed_to_send_request_status') ); } - }; + } else { + Alert.alert( + lang.t( + 'wallet.wallet_connect.walletconnect_session_has_expired_while_trying_to_send' + ) + ); + } +}; /** * Adds a new WalletConnect URI to state. * * @param uri The new URI. */ -export const saveWalletConnectUri = - (uri: string) => - async ( - dispatch: Dispatch, - getState: AppGetState - ) => { - const { walletConnectUris } = getState().walletconnect; - const newWalletConnectUris = [...walletConnectUris, uri]; - dispatch({ - payload: newWalletConnectUris, - type: WALLETCONNECT_ADD_URI, - }); - }; +export const saveWalletConnectUri = (uri: string) => async ( + dispatch: Dispatch, + getState: AppGetState +) => { + const { walletConnectUris } = getState().walletconnect; + const newWalletConnectUris = [...walletConnectUris, uri]; + dispatch({ + payload: newWalletConnectUris, + type: WALLETCONNECT_ADD_URI, + }); +}; // -- Reducer ----------------------------------------- // const INITIAL_STATE: WalletconnectState = { diff --git a/src/redux/wallets.ts b/src/redux/wallets.ts index ae75024d3a5..ab48c8dd7de 100644 --- a/src/redux/wallets.ts +++ b/src/redux/wallets.ts @@ -145,127 +145,125 @@ const WALLETS_SET_SELECTED = 'wallets/SET_SELECTED'; /** * Loads wallet information from storage and updates state accordingly. */ -export const walletsLoadState = - (profilesEnabled = false) => - async ( - dispatch: ThunkDispatch, - getState: AppGetState - ) => { - try { - const { accountAddress } = getState().settings; - let addressFromKeychain: string | null = accountAddress; - const allWalletsResult = await getAllWallets(); - const wallets = allWalletsResult?.wallets || {}; - if (isEmpty(wallets)) return; - const selected = await getSelectedWallet(); - // Prevent irrecoverable state (no selected wallet) - let selectedWallet = selected?.wallet; - // Check if the selected wallet is among all the wallets - if (selectedWallet && !wallets[selectedWallet.id]) { - // If not then we should clear it and default to the first one - const firstWalletKey = Object.keys(wallets)[0]; - selectedWallet = wallets[firstWalletKey]; - await setSelectedWallet(selectedWallet); - } +export const walletsLoadState = (profilesEnabled = false) => async ( + dispatch: ThunkDispatch, + getState: AppGetState +) => { + try { + const { accountAddress } = getState().settings; + let addressFromKeychain: string | null = accountAddress; + const allWalletsResult = await getAllWallets(); + const wallets = allWalletsResult?.wallets || {}; + if (isEmpty(wallets)) return; + const selected = await getSelectedWallet(); + // Prevent irrecoverable state (no selected wallet) + let selectedWallet = selected?.wallet; + // Check if the selected wallet is among all the wallets + if (selectedWallet && !wallets[selectedWallet.id]) { + // If not then we should clear it and default to the first one + const firstWalletKey = Object.keys(wallets)[0]; + selectedWallet = wallets[firstWalletKey]; + await setSelectedWallet(selectedWallet); + } - if (!selectedWallet) { - const address = await loadAddress(); - keys(wallets).some(key => { - const someWallet = wallets[key]; - const found = someWallet.addresses.some(account => { - return ( - toChecksumAddress(account.address) === toChecksumAddress(address!) - ); - }); - if (found) { - selectedWallet = someWallet; - logger.info('Found selected wallet based on loadAddress result'); - } - return found; + if (!selectedWallet) { + const address = await loadAddress(); + keys(wallets).some(key => { + const someWallet = wallets[key]; + const found = someWallet.addresses.some(account => { + return ( + toChecksumAddress(account.address) === toChecksumAddress(address!) + ); }); - } + if (found) { + selectedWallet = someWallet; + logger.info('Found selected wallet based on loadAddress result'); + } + return found; + }); + } - // Recover from broken state (account address not in selected wallet) - if (!addressFromKeychain) { - addressFromKeychain = await loadAddress(); - logger.info( - "addressFromKeychain wasn't set on settings so it is being loaded from loadAddress" - ); - } + // Recover from broken state (account address not in selected wallet) + if (!addressFromKeychain) { + addressFromKeychain = await loadAddress(); + logger.info( + "addressFromKeychain wasn't set on settings so it is being loaded from loadAddress" + ); + } - const selectedAddress = selectedWallet?.addresses.find(a => { - return a.visible && a.address === addressFromKeychain; - }); + const selectedAddress = selectedWallet?.addresses.find(a => { + return a.visible && a.address === addressFromKeychain; + }); - // Let's select the first visible account if we don't have a selected address - if (!selectedAddress) { - const allWallets = Object.values(allWalletsResult?.wallets || {}); - let account = null; - for (const wallet of allWallets) { - for (const rainbowAccount of wallet.addresses) { - if (rainbowAccount.visible) { - account = rainbowAccount; - break; - } + // Let's select the first visible account if we don't have a selected address + if (!selectedAddress) { + const allWallets = Object.values(allWalletsResult?.wallets || {}); + let account = null; + for (const wallet of allWallets) { + for (const rainbowAccount of wallet.addresses) { + if (rainbowAccount.visible) { + account = rainbowAccount; + break; } } - if (!account) return; - await dispatch(settingsUpdateAccountAddress(account.address)); - await saveAddress(account.address); - logger.info( - 'Selected the first visible address because there was not selected one' - ); } + if (!account) return; + await dispatch(settingsUpdateAccountAddress(account.address)); + await saveAddress(account.address); + logger.info( + 'Selected the first visible address because there was not selected one' + ); + } - const walletNames = await getWalletNames(); - dispatch({ - payload: { - selected: selectedWallet, - walletNames, - wallets, - }, - type: WALLETS_LOAD, - }); + const walletNames = await getWalletNames(); + dispatch({ + payload: { + selected: selectedWallet, + walletNames, + wallets, + }, + type: WALLETS_LOAD, + }); - dispatch(fetchWalletNames()); - profilesEnabled && dispatch(fetchWalletENSAvatars()); - return wallets; - } catch (error) { - logger.error(new RainbowError('Exception during walletsLoadState'), { - message: (error as Error)?.message, - }); - } - }; + dispatch(fetchWalletNames()); + profilesEnabled && dispatch(fetchWalletENSAvatars()); + return wallets; + } catch (error) { + logger.error(new RainbowError('Exception during walletsLoadState'), { + message: (error as Error)?.message, + }); + } +}; /** * Saves new wallets to storage and updates state accordingly. * * @param wallets The new wallets. */ -export const walletsUpdate = - (wallets: { [key: string]: RainbowWallet }) => - async (dispatch: Dispatch) => { - await saveAllWallets(wallets); - dispatch({ - payload: wallets, - type: WALLETS_UPDATE, - }); - }; +export const walletsUpdate = (wallets: { + [key: string]: RainbowWallet; +}) => async (dispatch: Dispatch) => { + await saveAllWallets(wallets); + dispatch({ + payload: wallets, + type: WALLETS_UPDATE, + }); +}; /** * Sets the selected wallet in storage and updates state accordingly. * * @param wallet The wallet to mark as selected. */ -export const walletsSetSelected = - (wallet: RainbowWallet) => - async (dispatch: Dispatch) => { - await setSelectedWallet(wallet); - dispatch({ - payload: wallet, - type: WALLETS_SET_SELECTED, - }); - }; +export const walletsSetSelected = (wallet: RainbowWallet) => async ( + dispatch: Dispatch +) => { + await setSelectedWallet(wallet); + dispatch({ + payload: wallet, + type: WALLETS_SET_SELECTED, + }); +}; /** * Marks all wallets with passed ids as backed-up @@ -277,50 +275,48 @@ export const walletsSetSelected = * @param backupFile The backup file, if present. * @param updateUserMetadata Whether to update user metadata. */ -export const setAllWalletsWithIdsAsBackedUp = - ( - walletIds: RainbowWallet['id'][], - method: RainbowWallet['backupType'], - backupFile: RainbowWallet['backupFile'] = null, - updateUserMetadata = true - ) => - async ( - dispatch: ThunkDispatch, - getState: AppGetState - ) => { - const { wallets, selected } = getState().wallets; - const newWallets = { ...wallets }; - - walletIds.forEach(walletId => { - newWallets[walletId] = { - ...newWallets[walletId], - backedUp: true, - // @ts-expect-error "Date" is not "string." - backupDate: Date.now(), - backupFile, - backupType: method, - }; - }); +export const setAllWalletsWithIdsAsBackedUp = ( + walletIds: RainbowWallet['id'][], + method: RainbowWallet['backupType'], + backupFile: RainbowWallet['backupFile'] = null, + updateUserMetadata = true +) => async ( + dispatch: ThunkDispatch, + getState: AppGetState +) => { + const { wallets, selected } = getState().wallets; + const newWallets = { ...wallets }; - await dispatch(walletsUpdate(newWallets)); - if (selected?.id && walletIds.includes(selected?.id)) { - await dispatch(walletsSetSelected(newWallets[selected.id])); - } + walletIds.forEach(walletId => { + newWallets[walletId] = { + ...newWallets[walletId], + backedUp: true, + // @ts-expect-error "Date" is not "string." + backupDate: Date.now(), + backupFile, + backupType: method, + }; + }); - if (method === WalletBackupTypes.cloud && updateUserMetadata) { - try { - await backupUserDataIntoCloud({ wallets: newWallets }); - } catch (e) { - logger.error( - new RainbowError('Saving multiple wallets UserData to cloud failed.'), - { - message: (e as Error)?.message, - } - ); - throw e; - } + await dispatch(walletsUpdate(newWallets)); + if (selected?.id && walletIds.includes(selected?.id)) { + await dispatch(walletsSetSelected(newWallets[selected.id])); + } + + if (method === WalletBackupTypes.cloud && updateUserMetadata) { + try { + await backupUserDataIntoCloud({ wallets: newWallets }); + } catch (e) { + logger.error( + new RainbowError('Saving multiple wallets UserData to cloud failed.'), + { + message: (e as Error)?.message, + } + ); + throw e; } - }; + } +}; /** * Marks a wallet as backed-up using a specified method and file in storage @@ -331,88 +327,82 @@ export const setAllWalletsWithIdsAsBackedUp = * @param backupFile The backup file, if present. * @param updateUserMetadata Whether to update user metadata. */ -export const setWalletBackedUp = - ( - walletId: RainbowWallet['id'], - method: RainbowWallet['backupType'], - backupFile: RainbowWallet['backupFile'] = null, - updateUserMetadata = true - ) => - async ( - dispatch: ThunkDispatch, - getState: AppGetState - ) => { - const { wallets, selected } = getState().wallets; - const newWallets = { ...wallets }; - newWallets[walletId] = { - ...newWallets[walletId], - backedUp: true, - // @ts-expect-error "Date" is not "string." - backupDate: Date.now(), - backupFile, - backupType: method, - }; +export const setWalletBackedUp = ( + walletId: RainbowWallet['id'], + method: RainbowWallet['backupType'], + backupFile: RainbowWallet['backupFile'] = null, + updateUserMetadata = true +) => async ( + dispatch: ThunkDispatch, + getState: AppGetState +) => { + const { wallets, selected } = getState().wallets; + const newWallets = { ...wallets }; + newWallets[walletId] = { + ...newWallets[walletId], + backedUp: true, + // @ts-expect-error "Date" is not "string." + backupDate: Date.now(), + backupFile, + backupType: method, + }; - await dispatch(walletsUpdate(newWallets)); - if (selected!.id === walletId) { - await dispatch(walletsSetSelected(newWallets[walletId])); - } + await dispatch(walletsUpdate(newWallets)); + if (selected!.id === walletId) { + await dispatch(walletsSetSelected(newWallets[walletId])); + } - if (method === WalletBackupTypes.cloud && updateUserMetadata) { - try { - await backupUserDataIntoCloud({ wallets: newWallets }); - } catch (e) { - logger.error( - new RainbowError('Saving wallet UserData to cloud failed.'), - { - message: (e as Error)?.message, - } - ); - throw e; - } + if (method === WalletBackupTypes.cloud && updateUserMetadata) { + try { + await backupUserDataIntoCloud({ wallets: newWallets }); + } catch (e) { + logger.error( + new RainbowError('Saving wallet UserData to cloud failed.'), + { + message: (e as Error)?.message, + } + ); + throw e; } - }; + } +}; /** * Grabs user data stored in the cloud and based on this data marks wallets * as backed up or not */ -export const updateWalletBackupStatusesBasedOnCloudUserData = - () => - async ( - dispatch: ThunkDispatch, - getState: AppGetState - ) => { - const { wallets, selected } = getState().wallets; - const newWallets = { ...wallets }; - - let currentUserData: - | { wallets: { [p: string]: RainbowWallet } } - | undefined; - try { - currentUserData = await fetchUserDataFromCloud(); - } catch (error) { - logger.error( - new RainbowError( - 'There was an error when trying to update wallet backup statuses' - ), - { error: (error as Error).message } - ); - return; - } - if (currentUserData === undefined) { - return; - } +export const updateWalletBackupStatusesBasedOnCloudUserData = () => async ( + dispatch: ThunkDispatch, + getState: AppGetState +) => { + const { wallets, selected } = getState().wallets; + const newWallets = { ...wallets }; + + let currentUserData: { wallets: { [p: string]: RainbowWallet } } | undefined; + try { + currentUserData = await fetchUserDataFromCloud(); + } catch (error) { + logger.error( + new RainbowError( + 'There was an error when trying to update wallet backup statuses' + ), + { error: (error as Error).message } + ); + return; + } + if (currentUserData === undefined) { + return; + } - // build hashmap of address to wallet based on backup metadata - const addressToWalletLookup = new Map(); - Object.values(currentUserData.wallets).forEach(wallet => { - wallet.addresses.forEach(account => { - addressToWalletLookup.set(account.address, wallet); - }); + // build hashmap of address to wallet based on backup metadata + const addressToWalletLookup = new Map(); + Object.values(currentUserData.wallets).forEach(wallet => { + wallet.addresses.forEach(account => { + addressToWalletLookup.set(account.address, wallet); }); + }); - /* + /* marking wallet as already backed up if all addresses are backed up properly and linked to the same wallet @@ -421,70 +411,68 @@ export const updateWalletBackupStatusesBasedOnCloudUserData = * we have an address in the backup metadata, but it's linked to multiple wallet ids (should never happen, but that's a sanity check) */ - Object.values(newWallets).forEach(wallet => { - const localWalletId = wallet.id; + Object.values(newWallets).forEach(wallet => { + const localWalletId = wallet.id; - let relatedCloudWalletId: string | null = null; - for (const account of wallet.addresses) { - const walletDataForCurrentAddress = addressToWalletLookup.get( - account.address - ); - if (!walletDataForCurrentAddress) { - return; - } - if (relatedCloudWalletId === null) { - relatedCloudWalletId = walletDataForCurrentAddress.id; - } else if (relatedCloudWalletId !== walletDataForCurrentAddress.id) { - logger.warn( - 'Wallet address is linked to multiple or different accounts in the cloud backup metadata. It could mean that there is an issue with the cloud backup metadata.' - ); - return; - } + let relatedCloudWalletId: string | null = null; + for (const account of wallet.addresses) { + const walletDataForCurrentAddress = addressToWalletLookup.get( + account.address + ); + if (!walletDataForCurrentAddress) { + return; } - if (relatedCloudWalletId === null) { + relatedCloudWalletId = walletDataForCurrentAddress.id; + } else if (relatedCloudWalletId !== walletDataForCurrentAddress.id) { + logger.warn( + 'Wallet address is linked to multiple or different accounts in the cloud backup metadata. It could mean that there is an issue with the cloud backup metadata.' + ); return; } + } - // update only if we checked the wallet is actually backed up - const cloudBackupData = currentUserData?.wallets[relatedCloudWalletId]; - if (cloudBackupData) { - newWallets[localWalletId] = { - ...newWallets[localWalletId], - backedUp: cloudBackupData.backedUp, - backupDate: cloudBackupData.backupDate, - backupFile: cloudBackupData.backupFile, - backupType: cloudBackupData.backupType, - }; - } - }); + if (relatedCloudWalletId === null) { + return; + } - await dispatch(walletsUpdate(newWallets)); - if (selected?.id) { - await dispatch(walletsSetSelected(newWallets[selected.id])); + // update only if we checked the wallet is actually backed up + const cloudBackupData = currentUserData?.wallets[relatedCloudWalletId]; + if (cloudBackupData) { + newWallets[localWalletId] = { + ...newWallets[localWalletId], + backedUp: cloudBackupData.backedUp, + backupDate: cloudBackupData.backupDate, + backupFile: cloudBackupData.backupFile, + backupType: cloudBackupData.backupType, + }; } - }; + }); + + await dispatch(walletsUpdate(newWallets)); + if (selected?.id) { + await dispatch(walletsSetSelected(newWallets[selected.id])); + } +}; /** * Clears backup status for all users' wallets */ -export const clearAllWalletsBackupStatus = - () => - async ( - dispatch: ThunkDispatch, - getState: AppGetState - ) => { - const { wallets } = getState().wallets; - const newWallets = { ...wallets }; - Object.keys(newWallets).forEach(key => { - newWallets[key].backedUp = undefined; - newWallets[key].backupDate = undefined; - newWallets[key].backupFile = undefined; - newWallets[key].backupType = undefined; - }); +export const clearAllWalletsBackupStatus = () => async ( + dispatch: ThunkDispatch, + getState: AppGetState +) => { + const { wallets } = getState().wallets; + const newWallets = { ...wallets }; + Object.keys(newWallets).forEach(key => { + newWallets[key].backedUp = undefined; + newWallets[key].backupDate = undefined; + newWallets[key].backupFile = undefined; + newWallets[key].backupType = undefined; + }); - await dispatch(walletsUpdate(newWallets)); - }; + await dispatch(walletsUpdate(newWallets)); +}; /** * Updates the selected address in state. @@ -501,56 +489,54 @@ export const addressSetSelected = (address: string) => () => * @param name The name for the new address. * @returns Within a dispatch, a new mapping from wallet IDs to wallet objects. */ -export const createAccountForWallet = - ( - id: RainbowWallet['id'], - color: RainbowWallet['color'], - name: RainbowWallet['name'] - ) => - async ( - dispatch: ThunkDispatch, - getState: AppGetState - ) => { - const { wallets } = getState().wallets; - const newWallets = { ...wallets }; - let index = 0; - newWallets[id].addresses.forEach( - account => (index = Math.max(index, account.index)) - ); - const newIndex = index + 1; - const account = (await generateAccount(id, newIndex))!; - const walletColorIndex = - color !== null ? color : addressHashedColorIndex(account!.address)!; - newWallets[id].addresses.push({ - address: account.address, - avatar: null, - color: walletColorIndex, - index: newIndex, - label: name, - visible: true, - }); +export const createAccountForWallet = ( + id: RainbowWallet['id'], + color: RainbowWallet['color'], + name: RainbowWallet['name'] +) => async ( + dispatch: ThunkDispatch, + getState: AppGetState +) => { + const { wallets } = getState().wallets; + const newWallets = { ...wallets }; + let index = 0; + newWallets[id].addresses.forEach( + account => (index = Math.max(index, account.index)) + ); + const newIndex = index + 1; + const account = (await generateAccount(id, newIndex))!; + const walletColorIndex = + color !== null ? color : addressHashedColorIndex(account!.address)!; + newWallets[id].addresses.push({ + address: account.address, + avatar: null, + color: walletColorIndex, + index: newIndex, + label: name, + visible: true, + }); - await dispatch(updateWebDataEnabled(true, account.address)); + await dispatch(updateWebDataEnabled(true, account.address)); - setPreference(PreferenceActionType.init, 'profile', account.address, { - accountColor: lightModeThemeColors.avatarBackgrounds[walletColorIndex], - accountSymbol: addressHashedEmoji(account.address), - }); + setPreference(PreferenceActionType.init, 'profile', account.address, { + accountColor: lightModeThemeColors.avatarBackgrounds[walletColorIndex], + accountSymbol: addressHashedEmoji(account.address), + }); - // Save all the wallets - saveAllWallets(newWallets); - // Set the address selected (KEYCHAIN) - await saveAddress(account.address); - // Set the wallet selected (KEYCHAIN) - await setSelectedWallet(newWallets[id]); + // Save all the wallets + saveAllWallets(newWallets); + // Set the address selected (KEYCHAIN) + await saveAddress(account.address); + // Set the wallet selected (KEYCHAIN) + await setSelectedWallet(newWallets[id]); - dispatch({ - payload: { selected: newWallets[id], wallets: newWallets }, - type: WALLETS_ADDED_ACCOUNT, - }); + dispatch({ + payload: { selected: newWallets[id], wallets: newWallets }, + type: WALLETS_ADDED_ACCOUNT, + }); - return newWallets; - }; + return newWallets; +}; /** * Fetches ENS avatars for the given `walletsState` and updates state @@ -644,177 +630,163 @@ export const getWalletENSAvatars = async ( * Fetches wallet ENS avatars using `getWalletENSAvatars` with the current * wallets in state. */ -export const fetchWalletENSAvatars = - () => - async ( - dispatch: ThunkDispatch, - getState: AppGetState - ) => - getWalletENSAvatars(getState().wallets, dispatch); +export const fetchWalletENSAvatars = () => async ( + dispatch: ThunkDispatch, + getState: AppGetState +) => getWalletENSAvatars(getState().wallets, dispatch); /** * Fetches wallet names and updates storage and state. */ -export const fetchWalletNames = - () => - async ( - dispatch: Dispatch, - getState: AppGetState - ) => { - const { wallets } = getState().wallets; - const updatedWalletNames: { [address: string]: string } = {}; - - // Fetch ENS names - await Promise.all( - Object.values(wallets ?? {}).flatMap(wallet => { - const visibleAccounts = wallet.addresses?.filter( - address => address.visible - ); - return visibleAccounts.map(async account => { - try { - const ens = await fetchReverseRecordWithRetry(account.address); - if (ens && ens !== account.address) { - updatedWalletNames[account.address] = ens; - } - // eslint-disable-next-line no-empty - } catch (error) {} - return account; - }); - }) - ); +export const fetchWalletNames = () => async ( + dispatch: Dispatch, + getState: AppGetState +) => { + const { wallets } = getState().wallets; + const updatedWalletNames: { [address: string]: string } = {}; + + // Fetch ENS names + await Promise.all( + Object.values(wallets ?? {}).flatMap(wallet => { + const visibleAccounts = wallet.addresses?.filter( + address => address.visible + ); + return visibleAccounts.map(async account => { + try { + const ens = await fetchReverseRecordWithRetry(account.address); + if (ens && ens !== account.address) { + updatedWalletNames[account.address] = ens; + } + // eslint-disable-next-line no-empty + } catch (error) {} + return account; + }); + }) + ); - dispatch({ - payload: updatedWalletNames, - type: WALLETS_UPDATE_NAMES, - }); - saveWalletNames(updatedWalletNames); - }; + dispatch({ + payload: updatedWalletNames, + type: WALLETS_UPDATE_NAMES, + }); + saveWalletNames(updatedWalletNames); +}; /** * Checks the validity of the keychain and updates storage and state * accordingly if the keychain is unhealthy. */ -export const checkKeychainIntegrity = - () => - async ( - dispatch: ThunkDispatch, - getState: AppGetState - ) => { - try { - let healthyKeychain = true; - logger.info('[KeychainIntegrityCheck]: starting checks'); +export const checkKeychainIntegrity = () => async ( + dispatch: ThunkDispatch, + getState: AppGetState +) => { + try { + let healthyKeychain = true; + logger.info('[KeychainIntegrityCheck]: starting checks'); + + const hasAddress = await hasKey(addressKey); + if (hasAddress) { + logger.info('[KeychainIntegrityCheck]: address is ok'); + } else { + healthyKeychain = false; + logger.info( + `[KeychainIntegrityCheck]: address is missing: ${hasAddress}` + ); + } - const hasAddress = await hasKey(addressKey); - if (hasAddress) { - logger.info('[KeychainIntegrityCheck]: address is ok'); - } else { - healthyKeychain = false; - logger.info( - `[KeychainIntegrityCheck]: address is missing: ${hasAddress}` - ); - } + const hasOldSeedPhraseMigratedFlag = await hasKey(oldSeedPhraseMigratedKey); + if (hasOldSeedPhraseMigratedFlag) { + logger.info('[KeychainIntegrityCheck]: migrated flag is OK'); + } else { + logger.info( + `[KeychainIntegrityCheck]: migrated flag is present: ${hasOldSeedPhraseMigratedFlag}` + ); + } - const hasOldSeedPhraseMigratedFlag = await hasKey( - oldSeedPhraseMigratedKey + const hasOldSeedphrase = await hasKey(seedPhraseKey); + if (hasOldSeedphrase) { + logger.info('[KeychainIntegrityCheck]: old seed is still present!'); + } else { + logger.info( + `[KeychainIntegrityCheck]: old seed is present: ${hasOldSeedphrase}` ); - if (hasOldSeedPhraseMigratedFlag) { - logger.info('[KeychainIntegrityCheck]: migrated flag is OK'); - } else { - logger.info( - `[KeychainIntegrityCheck]: migrated flag is present: ${hasOldSeedPhraseMigratedFlag}` - ); - } + } - const hasOldSeedphrase = await hasKey(seedPhraseKey); - if (hasOldSeedphrase) { - logger.info('[KeychainIntegrityCheck]: old seed is still present!'); - } else { - logger.info( - `[KeychainIntegrityCheck]: old seed is present: ${hasOldSeedphrase}` - ); - } + const { wallets, selected } = getState().wallets; + if (!wallets) { + logger.warn('[KeychainIntegrityCheck]: wallets are missing from redux'); + } - const { wallets, selected } = getState().wallets; - if (!wallets) { - logger.warn('[KeychainIntegrityCheck]: wallets are missing from redux'); - } + if (!selected) { + logger.warn( + '[KeychainIntegrityCheck]: selectedWallet is missing from redux' + ); + } - if (!selected) { - logger.warn( - '[KeychainIntegrityCheck]: selectedWallet is missing from redux' - ); - } + const nonReadOnlyWalletKeys = keys(wallets).filter( + key => wallets![key].type !== WalletTypes.readOnly + ); - const nonReadOnlyWalletKeys = keys(wallets).filter( - key => wallets![key].type !== WalletTypes.readOnly - ); + for (const key of nonReadOnlyWalletKeys) { + let healthyWallet = true; + const wallet = wallets![key]; + const seedKeyFound = await hasKey(`${key}_${seedPhraseKey}`); + if (!seedKeyFound) { + healthyWallet = false; + logger.warn('[KeychainIntegrityCheck]: seed key is missing'); + } else { + logger.info('[KeychainIntegrityCheck]: seed key is present'); + } - for (const key of nonReadOnlyWalletKeys) { - let healthyWallet = true; - const wallet = wallets![key]; - const seedKeyFound = await hasKey(`${key}_${seedPhraseKey}`); - if (!seedKeyFound) { + for (const account of wallet.addresses) { + const pkeyFound = await hasKey(`${account.address}_${privateKeyKey}`); + if (!pkeyFound) { healthyWallet = false; - logger.warn('[KeychainIntegrityCheck]: seed key is missing'); + logger.warn(`[KeychainIntegrityCheck]: pkey is missing`); } else { - logger.info('[KeychainIntegrityCheck]: seed key is present'); - } - - for (const account of wallet.addresses) { - const pkeyFound = await hasKey(`${account.address}_${privateKeyKey}`); - if (!pkeyFound) { - healthyWallet = false; - logger.warn(`[KeychainIntegrityCheck]: pkey is missing`); - } else { - logger.info(`[KeychainIntegrityCheck]: pkey is present`); - } + logger.info(`[KeychainIntegrityCheck]: pkey is present`); } + } - // Handle race condition: - // A wallet is NOT damaged if: - // - it's not imported - // - and hasn't been migrated yet - // - and the old seedphrase is still there - if ( - !wallet.imported && - !hasOldSeedPhraseMigratedFlag && - hasOldSeedphrase - ) { - healthyWallet = true; - } + // Handle race condition: + // A wallet is NOT damaged if: + // - it's not imported + // - and hasn't been migrated yet + // - and the old seedphrase is still there + if ( + !wallet.imported && + !hasOldSeedPhraseMigratedFlag && + hasOldSeedphrase + ) { + healthyWallet = true; + } - if (!healthyWallet) { + if (!healthyWallet) { + logger.warn('[KeychainIntegrityCheck]: declaring wallet unhealthy...'); + healthyKeychain = false; + wallet.damaged = true; + await dispatch(walletsUpdate(wallets!)); + // Update selected wallet if needed + if (wallet.id === selected!.id) { logger.warn( - '[KeychainIntegrityCheck]: declaring wallet unhealthy...' + '[KeychainIntegrityCheck]: declaring selected wallet unhealthy...' ); - healthyKeychain = false; - wallet.damaged = true; - await dispatch(walletsUpdate(wallets!)); - // Update selected wallet if needed - if (wallet.id === selected!.id) { - logger.warn( - '[KeychainIntegrityCheck]: declaring selected wallet unhealthy...' - ); - await dispatch(walletsSetSelected(wallets![wallet.id])); - } - logger.info('[KeychainIntegrityCheck]: done updating wallets'); + await dispatch(walletsSetSelected(wallets![wallet.id])); } + logger.info('[KeychainIntegrityCheck]: done updating wallets'); } - if (!healthyKeychain) { - captureMessage('Keychain Integrity is not OK'); - } - logger.info('[KeychainIntegrityCheck]: check completed'); - await saveKeychainIntegrityState('done'); - } catch (e) { - logger.error( - new RainbowError("[KeychainIntegrityCheck]: error thrown'"), - { - message: (e as Error)?.message, - } - ); - captureMessage('Error running keychain integrity checks'); } - }; + if (!healthyKeychain) { + captureMessage('Keychain Integrity is not OK'); + } + logger.info('[KeychainIntegrityCheck]: check completed'); + await saveKeychainIntegrityState('done'); + } catch (e) { + logger.error(new RainbowError("[KeychainIntegrityCheck]: error thrown'"), { + message: (e as Error)?.message, + }); + captureMessage('Error running keychain integrity checks'); + } +}; // -- Reducer ----------------------------------------- // const INITIAL_STATE: WalletsState = { diff --git a/src/references/rainbow-token-list/index.ts b/src/references/rainbow-token-list/index.ts index 00b99e450f4..60d29dc617c 100644 --- a/src/references/rainbow-token-list/index.ts +++ b/src/references/rainbow-token-list/index.ts @@ -209,12 +209,12 @@ class RainbowTokenList extends EventEmitter { `Token list update: new update loaded, generated on ${newTokenList?.timestamp}` ) : status === 304 - ? logger.debug( - `Token list update: no change since last update, skipping update.` - ) - : logger.debug( - `Token list update: Token list did not update. (Status: ${status}, CurrentListDate: ${this._tokenListData?.timestamp})` - ); + ? logger.debug( + `Token list update: no change since last update, skipping update.` + ) + : logger.debug( + `Token list update: Token list did not update. (Status: ${status}, CurrentListDate: ${this._tokenListData?.timestamp})` + ); if (newTokenList) { this._tokenListData = newTokenList; diff --git a/src/references/swap/bridges.ts b/src/references/swap/bridges.ts index bead5382c2c..fa9ab9a37d1 100644 --- a/src/references/swap/bridges.ts +++ b/src/references/swap/bridges.ts @@ -40,7 +40,8 @@ export const SocketBridges = { displayName: 'Across', }, 'optimism-bridge': { - icon: 'https://raw.githubusercontent.com/ethereum-optimism/brand-kit/main/assets/images/Profile-Logo.png', + icon: + 'https://raw.githubusercontent.com/ethereum-optimism/brand-kit/main/assets/images/Profile-Logo.png', serviceTime: 1200, displayName: 'Optimism', }, diff --git a/src/resources/assets/UserAssetsQuery.ts b/src/resources/assets/UserAssetsQuery.ts index 7f06413abdf..de3817a68d0 100644 --- a/src/resources/assets/UserAssetsQuery.ts +++ b/src/resources/assets/UserAssetsQuery.ts @@ -89,8 +89,10 @@ async function userAssetsQueryFunction({ network => network.enabled && network.networkType !== 'testnet' ).map(network => network.id); - const { erroredChainIds, results } = - await fetchAndParseUserAssetsForChainIds(address, currency, chainIds); + const { + erroredChainIds, + results, + } = await fetchAndParseUserAssetsForChainIds(address, currency, chainIds); let parsedSuccessResults = results; // grab cached data for chain IDs with errors diff --git a/src/resources/assets/assetSelectors.ts b/src/resources/assets/assetSelectors.ts index 0d2b1aeb871..55b86307ce9 100644 --- a/src/resources/assets/assetSelectors.ts +++ b/src/resources/assets/assetSelectors.ts @@ -27,8 +27,10 @@ const sortAssetsByNativeAmount = ( if (!isEmpty(assetsNativePrices)) { assetsNativePrices = parseAssetsNative(assetsNativePrices, nativeCurrency); } - const { hasValue = EMPTY_ARRAY, noValue = EMPTY_ARRAY } = - groupAssetsByMarketValue(assetsNativePrices); + const { + hasValue = EMPTY_ARRAY, + noValue = EMPTY_ARRAY, + } = groupAssetsByMarketValue(assetsNativePrices); const sortedAssetsNoShitcoins = hasValue.sort((a: any, b: any) => { const itemA = Number(a.native?.balance?.amount) ?? 0; diff --git a/src/resources/assets/hardhatAssets.ts b/src/resources/assets/hardhatAssets.ts index 56a9be3bf10..770235091e6 100644 --- a/src/resources/assets/hardhatAssets.ts +++ b/src/resources/assets/hardhatAssets.ts @@ -60,11 +60,12 @@ export const fetchHardhatBalances = async ( ({ asset }) => `${asset.asset_code}_${asset.network}` ); - const tokenAddresses = Object.values(chainAssetsMap).map( - ({ asset: { asset_code } }) => - asset_code === ETH_ADDRESS - ? ETHEREUM_ADDRESS_FOR_BALANCE_CONTRACT - : asset_code.toLowerCase() + const tokenAddresses = Object.values( + chainAssetsMap + ).map(({ asset: { asset_code } }) => + asset_code === ETH_ADDRESS + ? ETHEREUM_ADDRESS_FOR_BALANCE_CONTRACT + : asset_code.toLowerCase() ); const balances = await fetchHardhatBalancesWithBalanceChecker( tokenAddresses, diff --git a/src/resources/cards/cardCollectionQuery.ts b/src/resources/cards/cardCollectionQuery.ts index e2cfae8cf5b..efb6d10ac9c 100644 --- a/src/resources/cards/cardCollectionQuery.ts +++ b/src/resources/cards/cardCollectionQuery.ts @@ -32,7 +32,7 @@ export const TRIMMED_CARD_KEYS = [ 'primaryButton', ] as const; -export type TrimmedCard = Pick & { +export type TrimmedCard = Pick & { sys: Pick; imageCollection: { items: { diff --git a/src/resources/nfts/index.ts b/src/resources/nfts/index.ts index b457b1906d9..25e23ac8c96 100644 --- a/src/resources/nfts/index.ts +++ b/src/resources/nfts/index.ts @@ -115,15 +115,12 @@ export function useLegacyNFTs({ address }: { address: string }) { const nftsMap = useMemo( () => - nfts.reduce( - (acc, nft) => { - // index by both uniqueId and fullUniqueId bc why not - acc[nft.uniqueId] = nft; - acc[nft.fullUniqueId] = nft; - return acc; - }, - {} as { [key: string]: UniqueAsset } - ), + nfts.reduce((acc, nft) => { + // index by both uniqueId and fullUniqueId bc why not + acc[nft.uniqueId] = nft; + acc[nft.fullUniqueId] = nft; + return acc; + }, {} as { [key: string]: UniqueAsset }), [nfts] ); diff --git a/src/resources/nfts/utils.ts b/src/resources/nfts/utils.ts index 57f58930772..2cc4292e010 100644 --- a/src/resources/nfts/utils.ts +++ b/src/resources/nfts/utils.ts @@ -26,8 +26,7 @@ type ErrorResponse = { }[]; }; -type SuccessResponse = - paths['/collections/v6']['get']['responses']['200']['schema']; +type SuccessResponse = paths['/collections/v6']['get']['responses']['200']['schema']; export async function fetchReservoirNFTFloorPrice( nft: UniqueAsset diff --git a/src/resources/transactions/consolidatedTransactions.ts b/src/resources/transactions/consolidatedTransactions.ts index 231173e6972..25e6a15a7bf 100644 --- a/src/resources/transactions/consolidatedTransactions.ts +++ b/src/resources/transactions/consolidatedTransactions.ts @@ -48,7 +48,7 @@ type ConsolidatedTransactionsQueryKey = ReturnType< // Query Fetcher export async function fetchConsolidatedTransactions< - ConsolidatedTransactionsResult, + ConsolidatedTransactionsResult >( { address, currency, chainIds }: ConsolidatedTransactionsArgs, config: QueryConfig< diff --git a/src/resources/transactions/types.ts b/src/resources/transactions/types.ts index 977c25ebd5a..e8219a0027c 100644 --- a/src/resources/transactions/types.ts +++ b/src/resources/transactions/types.ts @@ -181,10 +181,8 @@ const transactionTypes = { ], } as const; -export type TransactionWithChangesType = - (typeof transactionTypes.withChanges)[number]; -export type TransactionWithoutChangesType = - (typeof transactionTypes.withoutChanges)[number]; +export type TransactionWithChangesType = typeof transactionTypes.withChanges[number]; +export type TransactionWithoutChangesType = typeof transactionTypes.withoutChanges[number]; export type TransactionType = | TransactionWithChangesType diff --git a/src/screens/AddCash/index.tsx b/src/screens/AddCash/index.tsx index d9e27e3e795..4cd88867639 100644 --- a/src/screens/AddCash/index.tsx +++ b/src/screens/AddCash/index.tsx @@ -51,11 +51,7 @@ export function AddCashSheet() { ? deviceHeight - insets.top : deviceHeight + statusBarHeight; - const { - isLoading, - data: providers, - error, - } = useQuery( + const { isLoading, data: providers, error } = useQuery( ['f2c', 'providers'], async () => { const [{ data, error }] = await wait(1000, [await getProviders()]); diff --git a/src/screens/ChangeWalletSheet.tsx b/src/screens/ChangeWalletSheet.tsx index 1b8378a56e2..5da48857731 100644 --- a/src/screens/ChangeWalletSheet.tsx +++ b/src/screens/ChangeWalletSheet.tsx @@ -98,9 +98,8 @@ const getWalletRowCount = (wallets: any) => { if (wallets) { Object.keys(wallets).forEach(key => { // Addresses - count += wallets[key].addresses.filter( - (account: any) => account.visible - ).length; + count += wallets[key].addresses.filter((account: any) => account.visible) + .length; }); } return count; @@ -130,8 +129,9 @@ export default function ChangeWalletSheet() { const [currentAddress, setCurrentAddress] = useState( currentAccountAddress || accountAddress ); - const [currentSelectedWallet, setCurrentSelectedWallet] = - useState(selectedWallet); + const [currentSelectedWallet, setCurrentSelectedWallet] = useState( + selectedWallet + ); const walletRowCount = useMemo(() => getWalletRowCount(wallets), [wallets]); @@ -261,8 +261,9 @@ export default function ChangeWalletSheet() { label: args.name, }; const updatedWalletAddresses = [...walletAddresses]; - updatedWalletAddresses[walletAddressIndex] = - updatedWalletAddress; + updatedWalletAddresses[ + walletAddressIndex + ] = updatedWalletAddress; const updatedWallet = { ...wallets[walletId], @@ -322,8 +323,9 @@ export default function ChangeWalletSheet() { const onPressNotifications = useCallback( (walletName: string, address: string) => { analytics.track('Tapped "Notification Settings"'); - const walletNotificationSettings = - getNotificationSettingsForWalletWithAddress(address); + const walletNotificationSettings = getNotificationSettingsForWalletWithAddress( + address + ); if (walletNotificationSettings) { navigate(Routes.SETTINGS_SHEET, { params: { diff --git a/src/screens/CurrencySelectModal.tsx b/src/screens/CurrencySelectModal.tsx index 7bae90ead78..f568925d9d8 100644 --- a/src/screens/CurrencySelectModal.tsx +++ b/src/screens/CurrencySelectModal.tsx @@ -168,12 +168,16 @@ export default function CurrencySelectModal() { const { inputCurrency, outputCurrency } = useSwapCurrencies(); - const { crosschainExactMatches, swapCurrencyList, swapCurrencyListLoading } = - useSwapCurrencyList(searchQueryForSearch, currentChainId, false); + const { + crosschainExactMatches, + swapCurrencyList, + swapCurrencyListLoading, + } = useSwapCurrencyList(searchQueryForSearch, currentChainId, false); - const { swappableUserAssets, unswappableUserAssets } = useSwappableUserAssets( - { outputCurrency } - ); + const { + swappableUserAssets, + unswappableUserAssets, + } = useSwappableUserAssets({ outputCurrency }); const checkForSameNetwork = useCallback( (newAsset: any, selectAsset: any, type: any) => { @@ -285,11 +289,9 @@ export default function CurrencySelectModal() { }, [crosschainExactMatches, swapCurrencyList]); const currencyList = useMemo(() => { - let list = ( - type === CurrencySelectionTypes.input - ? getWalletCurrencyList() - : activeSwapCurrencyList - ) as { + let list = (type === CurrencySelectionTypes.input + ? getWalletCurrencyList() + : activeSwapCurrencyList) as { data: EnrichedExchangeAsset[]; title: string; }[]; @@ -392,8 +394,9 @@ export default function CurrencySelectModal() { currentChainId && currentChainId !== ChainId.mainnet ) { - const currentL2Name = - ethereumUtils.getNetworkNameFromChainId(currentChainId); + const currentL2Name = ethereumUtils.getNetworkNameFromChainId( + currentChainId + ); const currentL2WalletAssets = assetsInWallet.filter( ({ network }) => network && network?.toLowerCase() === currentL2Name?.toLowerCase() diff --git a/src/screens/Diagnostics/DiagnosticsItemRow.tsx b/src/screens/Diagnostics/DiagnosticsItemRow.tsx index 9640bdaeccf..f8665fc2a95 100644 --- a/src/screens/Diagnostics/DiagnosticsItemRow.tsx +++ b/src/screens/Diagnostics/DiagnosticsItemRow.tsx @@ -13,8 +13,11 @@ import { DiagnosticsSecretInput } from '@/screens/Diagnostics/DiagnosticsSecretI export const DiagnosticsItemRow = ({ data }: any) => { const { colors } = useTheme(); - const { busy, handleSetSeedPhrase, handlePressImportButton } = - useImportingWallet(); + const { + busy, + handleSetSeedPhrase, + handlePressImportButton, + } = useImportingWallet(); const handlePressRestore = useCallback(async () => { if (busy) return; diff --git a/src/screens/Diagnostics/index.tsx b/src/screens/Diagnostics/index.tsx index 7a13785b902..82c5c5bf0fb 100644 --- a/src/screens/Diagnostics/index.tsx +++ b/src/screens/Diagnostics/index.tsx @@ -71,8 +71,9 @@ export const WalletDiagnosticsSheet = () => { if (userPin) { secret = await encryptor.decrypt(userPin, secret); } - const { address, type } = - await deriveAccountFromWalletInput(secret); + const { address, type } = await deriveAccountFromWalletInput( + secret + ); let createdAt = null; let label = null; Object.keys(walletsWithBalancesAndNames).some(k => { diff --git a/src/screens/ENSAdditionalRecordsSheet.tsx b/src/screens/ENSAdditionalRecordsSheet.tsx index 058874b020d..09dec072b69 100644 --- a/src/screens/ENSAdditionalRecordsSheet.tsx +++ b/src/screens/ENSAdditionalRecordsSheet.tsx @@ -23,8 +23,11 @@ export const getENSAdditionalRecordsSheetHeight = () => { export default function ENSAdditionalRecordsSheet() { const { params } = useRoute(); const [accentColor] = useRecoilState(accentColorAtom); - const { selectedFields, onAddField, onRemoveField } = - useENSRegistrationForm(); + const { + selectedFields, + onAddField, + onRemoveField, + } = useENSRegistrationForm(); const { height: deviceHeight } = useWindowDimensions(); const boxStyle = useMemo( diff --git a/src/screens/ENSConfirmRegisterSheet.tsx b/src/screens/ENSConfirmRegisterSheet.tsx index 8dc86d4e209..31cdf630890 100644 --- a/src/screens/ENSConfirmRegisterSheet.tsx +++ b/src/screens/ENSConfirmRegisterSheet.tsx @@ -151,8 +151,9 @@ export default function ENSConfirmRegisterSheet() { accountProfile.accountENS !== ensName && (!isEmpty(changedRecords) || mode === REGISTRATION_MODES.EDIT) ); - const { step, secondsSinceCommitConfirmed } = - useENSRegistrationStepHandler(false); + const { step, secondsSinceCommitConfirmed } = useENSRegistrationStepHandler( + false + ); const { action } = useENSRegistrationActionHandler({ sendReverseRecord, step, diff --git a/src/screens/ENSSearchSheet.tsx b/src/screens/ENSSearchSheet.tsx index a9546c4d77f..2ccaa048519 100644 --- a/src/screens/ENSSearchSheet.tsx +++ b/src/screens/ENSSearchSheet.tsx @@ -144,8 +144,8 @@ export default function ENSSearchSheet() { isAvailable ? colors.green : isRegistered - ? colors.yellowOrange - : colors.appleBlue + ? colors.yellowOrange + : colors.appleBlue } state={state} testID="ens-search-input" diff --git a/src/screens/ExchangeModal.tsx b/src/screens/ExchangeModal.tsx index 25d39b59564..5df45b6866a 100644 --- a/src/screens/ExchangeModal.tsx +++ b/src/screens/ExchangeModal.tsx @@ -118,7 +118,8 @@ export const DEFAULT_SLIPPAGE_BIPS = { }; export const getDefaultSlippageFromConfig = (network: Network) => { - const configSlippage = getRemoteConfig().default_slippage_bips as unknown as { + const configSlippage = (getRemoteConfig() + .default_slippage_bips as unknown) as { [network: string]: number; }; const slippage = @@ -148,8 +149,11 @@ export default function ExchangeModal({ }: ExchangeModalProps) { const { isHardwareWallet } = useWallets(); const dispatch = useDispatch(); - const { slippageInBips, maxInputUpdate, flipCurrenciesUpdate } = - useSwapSettings(); + const { + slippageInBips, + maxInputUpdate, + flipCurrenciesUpdate, + } = useSwapSettings(); const { params: { inputAsset: defaultInputAsset, outputAsset: defaultOutputAsset }, } = useRoute<{ @@ -186,8 +190,12 @@ export default function ExchangeModal({ txNetwork, isGasReady, } = useGas(); - const { accountAddress, flashbotsEnabled, nativeCurrency, network } = - useAccountSettings(); + const { + accountAddress, + flashbotsEnabled, + nativeCurrency, + network, + } = useAccountSettings(); const [isAuthorizing, setIsAuthorizing] = useState(false); const prevGasFeesParamsBySpeed = usePrevious(gasFeeParamsBySpeed); @@ -342,8 +350,8 @@ export default function ExchangeModal({ ); // For a limited period after the merge we need to block the use of flashbots. // This line should be removed after reenabling flashbots in remote config. - const swapSupportsFlashbots = - getNetworkObj(currentNetwork).features.flashbots; + const swapSupportsFlashbots = getNetworkObj(currentNetwork).features + .flashbots; const flashbots = swapSupportsFlashbots && flashbotsEnabled; const isDismissing = useRef(false); @@ -351,7 +359,7 @@ export default function ExchangeModal({ if (ios) { return; } - (dismissingScreenListener.current as unknown as () => void) = () => { + ((dismissingScreenListener.current as unknown) as () => void) = () => { Keyboard.dismiss(); isDismissing.current = true; }; @@ -364,9 +372,7 @@ export default function ExchangeModal({ ({ data: { closing } }) => { if (!closing && isDismissing.current) { isDismissing.current = false; - ( - lastFocusedInputHandle as unknown as MutableRefObject - )?.current?.focus(); + ((lastFocusedInputHandle as unknown) as MutableRefObject)?.current?.focus(); } } ); @@ -378,7 +384,7 @@ export default function ExchangeModal({ useEffect(() => { let slippage = DEFAULT_SLIPPAGE_BIPS?.[currentNetwork]; - const configSlippage = default_slippage_bips as unknown as { + const configSlippage = (default_slippage_bips as unknown) as { [network: string]: number; }; if (configSlippage?.[currentNetwork]) { @@ -398,14 +404,15 @@ export default function ExchangeModal({ const updateGasLimit = useCallback(async () => { try { const provider = await getProviderForNetwork(currentNetwork); - const swapParams: SwapActionParameters | CrosschainSwapActionParameters = - { - chainId, - inputAmount: inputAmount!, - outputAmount: outputAmount!, - provider, - tradeDetails: tradeDetails!, - }; + const swapParams: + | SwapActionParameters + | CrosschainSwapActionParameters = { + chainId, + inputAmount: inputAmount!, + outputAmount: outputAmount!, + provider, + tradeDetails: tradeDetails!, + }; const rapType = getSwapRapTypeByExchangeType(isCrosschainSwap); const gasLimit = await getSwapRapEstimationByType(rapType, swapParams); @@ -592,8 +599,12 @@ export default function ExchangeModal({ }; logger.log('[exchange - handle submit] rap'); const nonce = await getNextNonce(); - const { independentField, independentValue, slippageInBips, source } = - store.getState().swap; + const { + independentField, + independentValue, + slippageInBips, + source, + } = store.getState().swap; const swapParameters = { chainId, flashbots, @@ -641,7 +652,7 @@ export default function ExchangeModal({ isHardwareWallet, isHighPriceImpact: debouncedIsHighPriceImpact, legacyGasPrice: - (selectedGasFee?.gasFeeParams as unknown as LegacyGasFeeParams) + ((selectedGasFee?.gasFeeParams as unknown) as LegacyGasFeeParams) ?.gasPrice?.amount || '', liquiditySources: JSON.stringify(tradeDetails?.protocols || []), maxNetworkFee: @@ -725,7 +736,7 @@ export default function ExchangeModal({ isHardwareWallet, isHighPriceImpact: debouncedIsHighPriceImpact, legacyGasPrice: - (selectedGasFee?.gasFeeParams as unknown as LegacyGasFeeParams) + ((selectedGasFee?.gasFeeParams as unknown) as LegacyGasFeeParams) ?.gasPrice?.amount || '', liquiditySources: JSON.stringify(tradeDetails?.protocols || []), maxNetworkFee: @@ -872,8 +883,7 @@ export default function ExchangeModal({ isRefuelTx, restoreFocusOnSwapModal: () => { android && - (lastFocusedInputHandle.current = - lastFocusedInputHandleTemporary); + (lastFocusedInputHandle.current = lastFocusedInputHandleTemporary); setParams({ focused: true }); }, type: 'swap_details', @@ -918,8 +928,7 @@ export default function ExchangeModal({ ); const handleTapWhileDisabled = useCallback(() => { - const lastFocusedInput = - lastFocusedInputHandle?.current as unknown as TextInput; + const lastFocusedInput = (lastFocusedInputHandle?.current as unknown) as TextInput; lastFocusedInput?.blur(); navigate(Routes.EXPLAIN_SHEET, { inputToken: inputCurrency?.symbol, diff --git a/src/screens/ExplainSheet.js b/src/screens/ExplainSheet.js index 819c7d29da2..ad1f14a3b46 100644 --- a/src/screens/ExplainSheet.js +++ b/src/screens/ExplainSheet.js @@ -958,7 +958,8 @@ export const explainers = (params, colors) => ({ onPress={() => Linking.openURL( buildRainbowLearnUrl({ - url: 'https://learn.rainbow.me/a-beginners-guide-to-liquidity-providing', + url: + 'https://learn.rainbow.me/a-beginners-guide-to-liquidity-providing', query: { campaign: 'explain', }, @@ -993,7 +994,8 @@ export const explainers = (params, colors) => ({ onPress={() => Linking.openURL( buildRainbowLearnUrl({ - url: 'https://support.rainbow.me/en/articles/8324868-fee-on-transfer-tokens', + url: + 'https://support.rainbow.me/en/articles/8324868-fee-on-transfer-tokens', query: { campaign: 'explain', }, @@ -1074,8 +1076,8 @@ export const explainers = (params, colors) => ({ index > 0 ? -12 : params?.networks?.length % 2 === 0 - ? -2 - : -30, + ? -2 + : -30, }} style={{ borderColor: colors.transparent, @@ -1129,7 +1131,8 @@ export const explainers = (params, colors) => ({ onPress={() => Linking.openURL( buildRainbowLearnUrl({ - url: 'https://learn.rainbow.me/a-beginners-guide-to-layer-2-networks', + url: + 'https://learn.rainbow.me/a-beginners-guide-to-layer-2-networks', query: { campaign: 'explain', }, @@ -1170,7 +1173,8 @@ export const explainers = (params, colors) => ({ onPress={() => Linking.openURL( buildRainbowLearnUrl({ - url: 'https://learn.rainbow.me/protecting-transactions-with-flashbots', + url: + 'https://learn.rainbow.me/protecting-transactions-with-flashbots', query: { campaign: 'explain', }, @@ -1200,7 +1204,8 @@ export const explainers = (params, colors) => ({ onPress={() => Linking.openURL( buildRainbowLearnUrl({ - url: 'https://learn.rainbow.me/swap-with-confidence-with-rainbow', + url: + 'https://learn.rainbow.me/swap-with-confidence-with-rainbow', query: { campaign: 'explain', }, diff --git a/src/screens/ImportOrWatchWalletSheet.tsx b/src/screens/ImportOrWatchWalletSheet.tsx index 10d7b14a66b..145be323e5d 100644 --- a/src/screens/ImportOrWatchWalletSheet.tsx +++ b/src/screens/ImportOrWatchWalletSheet.tsx @@ -31,8 +31,9 @@ type RouteParams = { }; export const ImportOrWatchWalletSheet = () => { - const { params: { type = 'watch' } = {} } = - useRoute>(); + const { params: { type = 'watch' } = {} } = useRoute< + RouteProp + >(); const { busy, @@ -160,8 +161,8 @@ export const ImportOrWatchWalletSheet = () => { buttonDisabled ? 'labelSecondary' : seedPhrase - ? 'label' - : { custom: globalColors.purple60 } + ? 'label' + : { custom: globalColors.purple60 } } size="15pt" testID="import-sheet-button-label" diff --git a/src/screens/MintsSheet/MintsSheet.tsx b/src/screens/MintsSheet/MintsSheet.tsx index 83bbb5d524d..a88751b734a 100644 --- a/src/screens/MintsSheet/MintsSheet.tsx +++ b/src/screens/MintsSheet/MintsSheet.tsx @@ -32,8 +32,12 @@ import * as i18n from '@/languages'; const LoadingSpinner = IS_ANDROID ? Spinner : ActivityIndicator; export function MintsSheet() { - const { accountAddress, accountImage, accountColor, accountSymbol } = - useAccountProfile(); + const { + accountAddress, + accountImage, + accountColor, + accountSymbol, + } = useAccountProfile(); const { data: { mints }, isFetching, diff --git a/src/screens/NFTOffersSheet/index.tsx b/src/screens/NFTOffersSheet/index.tsx index 4375fc74ed1..fac04fa5a81 100644 --- a/src/screens/NFTOffersSheet/index.tsx +++ b/src/screens/NFTOffersSheet/index.tsx @@ -33,8 +33,12 @@ const PROFILE_AVATAR_SIZE = 36; export const NFTOffersSheet = () => { const separatorSecondary = useForegroundColor('separatorSecondary'); - const { accountColor, accountImage, accountSymbol, accountAddress } = - useAccountProfile(); + const { + accountColor, + accountImage, + accountSymbol, + accountAddress, + } = useAccountProfile(); const { isDarkMode } = useTheme(); const { width: deviceWidth, height: deviceHeight } = useDimensions(); diff --git a/src/screens/NotificationsPromoSheet/index.tsx b/src/screens/NotificationsPromoSheet/index.tsx index 554cc131922..4a35d45abf0 100644 --- a/src/screens/NotificationsPromoSheet/index.tsx +++ b/src/screens/NotificationsPromoSheet/index.tsx @@ -161,8 +161,10 @@ export function NotificationsPromoSheetInner({ export default function NotificationsPromoSheet() { const { justBecameActive } = useAppState(); - const [permissionsCheckResult, setPermissionsCheckResult] = - React.useState(); + const [ + permissionsCheckResult, + setPermissionsCheckResult, + ] = React.useState(); const checkPermissions = React.useCallback(async () => { const result = await perms.checkNotifications(); diff --git a/src/screens/PinAuthenticationScreen.js b/src/screens/PinAuthenticationScreen.js index 0fe91f2440b..f7716acb73d 100644 --- a/src/screens/PinAuthenticationScreen.js +++ b/src/screens/PinAuthenticationScreen.js @@ -227,8 +227,8 @@ const PinAuthenticationScreen = () => { {actionType === 'authentication' ? lang.t('wallet.pin_authentication.type_your_pin') : actionType === 'creation' - ? lang.t('wallet.pin_authentication.choose_your_pin') - : lang.t('wallet.pin_authentication.confirm_your_pin')} + ? lang.t('wallet.pin_authentication.choose_your_pin') + : lang.t('wallet.pin_authentication.confirm_your_pin')} diff --git a/src/screens/ProfileSheet.tsx b/src/screens/ProfileSheet.tsx index 706cffa1c29..16d22050548 100644 --- a/src/screens/ProfileSheet.tsx +++ b/src/screens/ProfileSheet.tsx @@ -51,14 +51,17 @@ export default function ProfileSheet() { const isPreview = name === Routes.PROFILE_PREVIEW_SHEET; // Prefetch first transaction timestamp unless already fetched for intro marquee - const { isSuccess: hasFirstTxTimestampFetched } = - useFirstTransactionTimestamp({ addressOrName: ensName }); + const { + isSuccess: hasFirstTxTimestampFetched, + } = useFirstTransactionTimestamp({ addressOrName: ensName }); // Prefetch asset list - const { isSuccess: hasListFetched, briefSectionsData } = - useExternalWalletSectionsData({ - address: profileAddress || undefined, - }); + const { + isSuccess: hasListFetched, + briefSectionsData, + } = useExternalWalletSectionsData({ + address: profileAddress || undefined, + }); const colorIndex = useMemo( () => (profileAddress ? addressHashedColorIndex(profileAddress) : 0), @@ -67,10 +70,9 @@ export default function ProfileSheet() { const dominantColor = usePersistentDominantColorFromImage(avatar?.imageUrl); - const wrapperStyle = useMemo( - () => ({ height: contentHeight }), - [contentHeight] - ); + const wrapperStyle = useMemo(() => ({ height: contentHeight }), [ + contentHeight, + ]); const accentColor = // Set accent color when ENS images have fetched & dominant diff --git a/src/screens/ReceiveModal.js b/src/screens/ReceiveModal.js index 916992d0928..79dde2744b2 100644 --- a/src/screens/ReceiveModal.js +++ b/src/screens/ReceiveModal.js @@ -78,10 +78,9 @@ export default function ReceiveModal() { setCopyCount(count => count + 1); }, []); - const checksummedAddress = useMemo( - () => toChecksumAddress(accountAddress), - [accountAddress] - ); + const checksummedAddress = useMemo(() => toChecksumAddress(accountAddress), [ + accountAddress, + ]); return ( diff --git a/src/screens/RestoreSheet.js b/src/screens/RestoreSheet.js index f4a89b80210..8386b7293af 100644 --- a/src/screens/RestoreSheet.js +++ b/src/screens/RestoreSheet.js @@ -8,8 +8,9 @@ import { IS_ANDROID } from '@/env'; import { useDimensions } from '@/hooks'; export function RestoreSheet() { - const { params: { userData, backupSelected, fromSettings } = {} } = - useRoute(); + const { + params: { userData, backupSelected, fromSettings } = {}, + } = useRoute(); const { height: deviceHeight } = useDimensions(); return ( diff --git a/src/screens/SelectENSSheet.tsx b/src/screens/SelectENSSheet.tsx index ec14f2b6797..a357ec319f2 100644 --- a/src/screens/SelectENSSheet.tsx +++ b/src/screens/SelectENSSheet.tsx @@ -38,8 +38,11 @@ const rowPadding = 19; const maxListHeight = deviceHeight - 220; export default function SelectENSSheet() { - const { isSuccess, nonPrimaryDomains, primaryDomain } = - useAccountENSDomains(); + const { + isSuccess, + nonPrimaryDomains, + primaryDomain, + } = useAccountENSDomains(); const secondary06 = useForegroundColor('secondary06 (Deprecated)'); diff --git a/src/screens/SendConfirmationSheet.tsx b/src/screens/SendConfirmationSheet.tsx index 668ac0c0687..1cf13ecb129 100644 --- a/src/screens/SendConfirmationSheet.tsx +++ b/src/screens/SendConfirmationSheet.tsx @@ -251,8 +251,10 @@ export const SendConfirmationSheet = () => { // eslint-disable-next-line @typescript-eslint/no-explicit-any } = useRoute(); - const [alreadySentTransactionsTotal, setAlreadySentTransactionsTotal] = - useState(0); + const [ + alreadySentTransactionsTotal, + setAlreadySentTransactionsTotal, + ] = useState(0); const [ alreadySentTransactionsCurrentNetwork, setAlreadySentTransactionsCurrentNetwork, diff --git a/src/screens/SendSheet.js b/src/screens/SendSheet.js index ba04a9ed1bd..56c93295ef8 100644 --- a/src/screens/SendSheet.js +++ b/src/screens/SendSheet.js @@ -183,8 +183,11 @@ export default function SendSheet(props) { const theme = useTheme(); const { colors, isDarkMode } = theme; - const { nativeCurrencyInputRef, setLastFocusedInputHandle, assetInputRef } = - useSendSheetInputRefs(); + const { + nativeCurrencyInputRef, + setLastFocusedInputHandle, + assetInputRef, + } = useSendSheetInputRefs(); const showEmptyState = !isValidAddress; const showAssetList = isValidAddress && isEmpty(selected); @@ -218,12 +221,13 @@ export default function SendSheet(props) { let _nativeAmount = ''; if (_assetAmount.length) { const priceUnit = selected?.price?.value ?? 0; - const { amount: convertedNativeAmount } = - convertAmountAndPriceToNativeDisplay( - _assetAmount, - priceUnit, - nativeCurrency - ); + const { + amount: convertedNativeAmount, + } = convertAmountAndPriceToNativeDisplay( + _assetAmount, + priceUnit, + nativeCurrency + ); _nativeAmount = formatInputDecimals( convertedNativeAmount, _assetAmount @@ -409,8 +413,9 @@ export default function SendSheet(props) { useEffect(() => { const resolveAddressIfNeeded = async () => { let realAddress = debouncedRecipient; - const isValid = - await checkIsValidAddressOrDomainFormat(debouncedRecipient); + const isValid = await checkIsValidAddressOrDomainFormat( + debouncedRecipient + ); if (isValid) { realAddress = await resolveNameOrAddress(debouncedRecipient); setToAddress(realAddress); diff --git a/src/screens/SettingsSheet/components/BackupSection.android.tsx b/src/screens/SettingsSheet/components/BackupSection.android.tsx index e8033595967..10c809d37ff 100644 --- a/src/screens/SettingsSheet/components/BackupSection.android.tsx +++ b/src/screens/SettingsSheet/components/BackupSection.android.tsx @@ -117,12 +117,12 @@ const BackupSection = () => { }) : lang.t('wallet.back_ups.and_1_more_wallet') : wallet.backedUp - ? wallet.backupType === WalletBackupTypes.cloud - ? lang.t('wallet.back_ups.backed_up') - : lang.t('wallet.back_ups.backed_up_manually') - : wallet.imported - ? lang.t('wallet.back_ups.imported') - : lang.t('back_up.needs_backup.not_backed_up') + ? wallet.backupType === WalletBackupTypes.cloud + ? lang.t('wallet.back_ups.backed_up') + : lang.t('wallet.back_ups.backed_up_manually') + : wallet.imported + ? lang.t('wallet.back_ups.imported') + : lang.t('back_up.needs_backup.not_backed_up') } warn={ numAccounts <= 1 && @@ -154,8 +154,8 @@ const BackupSection = () => { wallet.backupType === WalletBackupTypes.cloud ? 'complete' : wallet.backedUp || wallet.imported - ? 'incomplete' - : 'warning' + ? 'incomplete' + : 'warning' } /> } diff --git a/src/screens/SettingsSheet/components/BackupSection.tsx b/src/screens/SettingsSheet/components/BackupSection.tsx index b322057ebf1..51a34436112 100644 --- a/src/screens/SettingsSheet/components/BackupSection.tsx +++ b/src/screens/SettingsSheet/components/BackupSection.tsx @@ -104,12 +104,12 @@ const BackupSection = () => { }) : lang.t('wallet.back_ups.and_1_more_wallet') : wallet.backedUp - ? wallet.backupType === WalletBackupTypes.cloud - ? lang.t('wallet.back_ups.backed_up') - : lang.t('wallet.back_ups.backed_up_manually') - : wallet.imported - ? lang.t('wallet.back_ups.imported') - : lang.t('back_up.needs_backup.not_backed_up') + ? wallet.backupType === WalletBackupTypes.cloud + ? lang.t('wallet.back_ups.backed_up') + : lang.t('wallet.back_ups.backed_up_manually') + : wallet.imported + ? lang.t('wallet.back_ups.imported') + : lang.t('back_up.needs_backup.not_backed_up') } warn={ numAccounts <= 1 && !wallet.backedUp && !wallet.imported @@ -139,8 +139,8 @@ const BackupSection = () => { wallet.backupType === WalletBackupTypes.cloud ? 'complete' : wallet.backedUp || wallet.imported - ? 'incomplete' - : 'warning' + ? 'incomplete' + : 'warning' } /> } diff --git a/src/screens/SettingsSheet/components/DevSection.android.tsx b/src/screens/SettingsSheet/components/DevSection.android.tsx index a31cd4e71cd..23f85d2d103 100644 --- a/src/screens/SettingsSheet/components/DevSection.android.tsx +++ b/src/screens/SettingsSheet/components/DevSection.android.tsx @@ -65,10 +65,14 @@ const DevSection = () => { const { navigate } = useNavigation(); const { config, setConfig } = useContext(RainbowContext) as any; const { wallets } = useWallets(); - const { accountAddress, testnetsEnabled, settingsChangeTestnetsEnabled } = - useAccountSettings(); - const { walletNotificationSettings } = - useAllNotificationSettingsFromStorage(); + const { + accountAddress, + testnetsEnabled, + settingsChangeTestnetsEnabled, + } = useAccountSettings(); + const { + walletNotificationSettings, + } = useAllNotificationSettingsFromStorage(); const dispatch = useDispatch(); const resetAccountState = useResetAccountState(); const loadAccountData = useLoadAccountData(); @@ -522,8 +526,7 @@ const DevSection = () => { } onPress={async () => { - const publicKey = - await getPublicKeyOfTheSigningWalletAndCreateWalletIfNeeded(); + const publicKey = await getPublicKeyOfTheSigningWalletAndCreateWalletIfNeeded(); if (publicKey) { Clipboard.setString(publicKey); diff --git a/src/screens/SettingsSheet/components/DevSection.tsx b/src/screens/SettingsSheet/components/DevSection.tsx index 0cde442c605..2d5d0adf284 100644 --- a/src/screens/SettingsSheet/components/DevSection.tsx +++ b/src/screens/SettingsSheet/components/DevSection.tsx @@ -64,10 +64,14 @@ const DevSection = () => { const { navigate } = useNavigation(); const { config, setConfig } = useContext(RainbowContext) as any; const { wallets } = useWallets(); - const { accountAddress, testnetsEnabled, settingsChangeTestnetsEnabled } = - useAccountSettings(); - const { walletNotificationSettings } = - useAllNotificationSettingsFromStorage(); + const { + accountAddress, + testnetsEnabled, + settingsChangeTestnetsEnabled, + } = useAccountSettings(); + const { + walletNotificationSettings, + } = useAllNotificationSettingsFromStorage(); const dispatch = useDispatch(); const resetAccountState = useResetAccountState(); const loadAccountData = useLoadAccountData(); @@ -490,8 +494,7 @@ const DevSection = () => { } onPress={async () => { - const publicKey = - await getPublicKeyOfTheSigningWalletAndCreateWalletIfNeeded(); + const publicKey = await getPublicKeyOfTheSigningWalletAndCreateWalletIfNeeded(); if (publicKey) { Clipboard.setString(publicKey); diff --git a/src/screens/SettingsSheet/components/MenuItem.tsx b/src/screens/SettingsSheet/components/MenuItem.tsx index d84528b51aa..2180f809c6e 100644 --- a/src/screens/SettingsSheet/components/MenuItem.tsx +++ b/src/screens/SettingsSheet/components/MenuItem.tsx @@ -50,10 +50,10 @@ const TextIcon = ({ colorOverride ? { custom: colorOverride } : disabled - ? 'secondary60 (Deprecated)' - : isLink - ? 'action (Deprecated)' - : 'primary (Deprecated)' + ? 'secondary60 (Deprecated)' + : isLink + ? 'action (Deprecated)' + : 'primary (Deprecated)' } containsEmoji size="18px / 27px (Deprecated)" @@ -125,8 +125,8 @@ const Title = ({ text, weight = 'semibold', disabled, isLink }: TitleProps) => ( disabled ? 'secondary60 (Deprecated)' : isLink - ? 'action (Deprecated)' - : 'primary (Deprecated)' + ? 'action (Deprecated)' + : 'primary (Deprecated)' } containsEmoji size="18px / 27px (Deprecated)" diff --git a/src/screens/SettingsSheet/components/NotificationsSection.android.tsx b/src/screens/SettingsSheet/components/NotificationsSection.android.tsx index 153c2793993..f26c22da431 100644 --- a/src/screens/SettingsSheet/components/NotificationsSection.android.tsx +++ b/src/screens/SettingsSheet/components/NotificationsSection.android.tsx @@ -78,7 +78,7 @@ const WalletRowLabel = ({ notifications, groupOff }: WalletRowLabelProps) => { const allTopicsDisabled = groupOff || Object.values(notifications.topics).every(topic => !topic); const enabledTopics = Object.keys(notifications.topics).filter( - topic => notifications.topics[topic as unknown as number] + topic => notifications.topics[(topic as unknown) as number] ); if (allTopicsDisabled) { @@ -140,8 +140,9 @@ const WalletRow = ({ const navigateToWalletSettings = useCallback( (name: string, address: string) => { - const settingsForWallet = - getNotificationSettingsForWalletWithAddress(address); + const settingsForWallet = getNotificationSettingsForWalletWithAddress( + address + ); if (settingsForWallet) { navigate(Routes.WALLET_NOTIFICATIONS_SETTINGS, { @@ -233,8 +234,10 @@ const NotificationsSection = () => { updateGroupSettingsAndSubscriptions, watcherEnabled: storedWatcherEnabled, } = useWalletGroupNotificationSettings(); - const { globalNotificationSettings, walletNotificationSettings } = - useAllNotificationSettingsFromStorage(); + const { + globalNotificationSettings, + walletNotificationSettings, + } = useAllNotificationSettingsFromStorage(); const [topicState, setTopicState] = useState( globalNotificationSettings @@ -254,8 +257,10 @@ const NotificationsSection = () => { // We allow only one subscription in progress // this states controls which we are currently updating - const [topicSubscriptionInProgress, setTopicSubscriptionInProgress] = - useState(null); + const [ + topicSubscriptionInProgress, + setTopicSubscriptionInProgress, + ] = useState(null); const { ownedWallets, watchedWallets } = useMemo(() => { const ownedWallets: RainbowAccount[] = []; diff --git a/src/screens/SettingsSheet/components/NotificationsSection.tsx b/src/screens/SettingsSheet/components/NotificationsSection.tsx index f6f651b8a69..c4e79c903be 100644 --- a/src/screens/SettingsSheet/components/NotificationsSection.tsx +++ b/src/screens/SettingsSheet/components/NotificationsSection.tsx @@ -79,7 +79,7 @@ const WalletRowLabel = ({ notifications, groupOff }: WalletRowLabelProps) => { const allTopicsDisabled = groupOff || Object.values(notifications.topics).every(topic => !topic); const enabledTopics = Object.keys(notifications.topics).filter( - topic => notifications.topics[topic as unknown as number] + topic => notifications.topics[(topic as unknown) as number] ); if (allTopicsDisabled) { @@ -141,8 +141,9 @@ const WalletRow = ({ const navigateToWalletSettings = useCallback( (name: string, address: string) => { - const settingsForWallet = - getNotificationSettingsForWalletWithAddress(address); + const settingsForWallet = getNotificationSettingsForWalletWithAddress( + address + ); if (settingsForWallet) { navigate(Routes.WALLET_NOTIFICATIONS_SETTINGS, { @@ -234,8 +235,10 @@ const NotificationsSection = () => { updateGroupSettingsAndSubscriptions, watcherEnabled: storedWatcherEnabled, } = useWalletGroupNotificationSettings(); - const { globalNotificationSettings, walletNotificationSettings } = - useAllNotificationSettingsFromStorage(); + const { + globalNotificationSettings, + walletNotificationSettings, + } = useAllNotificationSettingsFromStorage(); const [topicState, setTopicState] = useState( globalNotificationSettings @@ -254,8 +257,10 @@ const NotificationsSection = () => { }); // We allow only one subscription in progress // this states controls which we are currently updating - const [topicSubscriptionInProgress, setTopicSubscriptionInProgress] = - useState(null); + const [ + topicSubscriptionInProgress, + setTopicSubscriptionInProgress, + ] = useState(null); const { ownedWallets, watchedWallets } = useMemo(() => { const ownedWallets: RainbowAccount[] = []; diff --git a/src/screens/SettingsSheet/components/PrivacySection.android.tsx b/src/screens/SettingsSheet/components/PrivacySection.android.tsx index b443e3cbcd0..dff7a9bc6ef 100644 --- a/src/screens/SettingsSheet/components/PrivacySection.android.tsx +++ b/src/screens/SettingsSheet/components/PrivacySection.android.tsx @@ -26,26 +26,23 @@ const PrivacySection = () => { publicShowCase => !publicShowCase, webDataEnabled ); - const [analyticsEnabled, toggleAnalytics] = useReducer( - analyticsEnabled => { - if (analyticsEnabled) { - device.set(['doNotTrack'], true); - logger.debug(`Analytics tracking disabled`); - analyticsV2.track(analyticsV2.event.analyticsTrackingDisabled); - logger.disable(); - analyticsV2.disable(); - return false; - } else { - device.set(['doNotTrack'], false); - logger.enable(); - analyticsV2.enable(); - logger.debug(`Analytics tracking enabled`); - analyticsV2.track(analyticsV2.event.analyticsTrackingEnabled); - return true; - } - }, - !device.get(['doNotTrack']) - ); + const [analyticsEnabled, toggleAnalytics] = useReducer(analyticsEnabled => { + if (analyticsEnabled) { + device.set(['doNotTrack'], true); + logger.debug(`Analytics tracking disabled`); + analyticsV2.track(analyticsV2.event.analyticsTrackingDisabled); + logger.disable(); + analyticsV2.disable(); + return false; + } else { + device.set(['doNotTrack'], false); + logger.enable(); + analyticsV2.enable(); + logger.debug(`Analytics tracking enabled`); + analyticsV2.track(analyticsV2.event.analyticsTrackingEnabled); + return true; + } + }, !device.get(['doNotTrack'])); const profilesEnabled = useExperimentalFlag(PROFILES); diff --git a/src/screens/SettingsSheet/components/PrivacySection.tsx b/src/screens/SettingsSheet/components/PrivacySection.tsx index af5c9a98737..b5ba51266a7 100644 --- a/src/screens/SettingsSheet/components/PrivacySection.tsx +++ b/src/screens/SettingsSheet/components/PrivacySection.tsx @@ -24,26 +24,23 @@ const PrivacySection = () => { publicShowCase => !publicShowCase, webDataEnabled ); - const [analyticsEnabled, toggleAnalytics] = useReducer( - analyticsEnabled => { - if (analyticsEnabled) { - device.set(['doNotTrack'], true); - logger.debug(`Analytics tracking disabled`); - analyticsV2.track(analyticsV2.event.analyticsTrackingDisabled); - logger.disable(); - analyticsV2.disable(); - return false; - } else { - device.set(['doNotTrack'], false); - logger.enable(); - analyticsV2.enable(); - logger.debug(`Analytics tracking enabled`); - analyticsV2.track(analyticsV2.event.analyticsTrackingEnabled); - return true; - } - }, - !device.get(['doNotTrack']) - ); + const [analyticsEnabled, toggleAnalytics] = useReducer(analyticsEnabled => { + if (analyticsEnabled) { + device.set(['doNotTrack'], true); + logger.debug(`Analytics tracking disabled`); + analyticsV2.track(analyticsV2.event.analyticsTrackingDisabled); + logger.disable(); + analyticsV2.disable(); + return false; + } else { + device.set(['doNotTrack'], false); + logger.enable(); + analyticsV2.enable(); + logger.debug(`Analytics tracking enabled`); + analyticsV2.track(analyticsV2.event.analyticsTrackingEnabled); + return true; + } + }, !device.get(['doNotTrack'])); const profilesEnabled = useExperimentalFlag(PROFILES); diff --git a/src/screens/SettingsSheet/components/SettingsSection.tsx b/src/screens/SettingsSheet/components/SettingsSection.tsx index d7db4c4cab0..a1c14770ae5 100644 --- a/src/screens/SettingsSheet/components/SettingsSection.tsx +++ b/src/screens/SettingsSheet/components/SettingsSection.tsx @@ -115,8 +115,12 @@ const SettingsSection = ({ onPressNotifications, }: SettingsSectionProps) => { const { wallets, isReadOnlyWallet } = useWallets(); - const { language, nativeCurrency, network, testnetsEnabled } = - useAccountSettings(); + const { + language, + nativeCurrency, + network, + testnetsEnabled, + } = useAccountSettings(); const isLanguageSelectionEnabled = useExperimentalFlag(LANGUAGE_SETTINGS); const isNotificationsEnabled = useExperimentalFlag(NOTIFICATIONS); @@ -246,8 +250,8 @@ const SettingsSection = ({ allBackedUp ? 'complete' : areBackedUp - ? 'incomplete' - : 'warning' + ? 'incomplete' + : 'warning' } /> } diff --git a/src/screens/SettingsSheet/components/WalletNotificationsSettings.android.tsx b/src/screens/SettingsSheet/components/WalletNotificationsSettings.android.tsx index cf67284bcf2..7ff53e7dbf3 100644 --- a/src/screens/SettingsSheet/components/WalletNotificationsSettings.android.tsx +++ b/src/screens/SettingsSheet/components/WalletNotificationsSettings.android.tsx @@ -97,8 +97,9 @@ type RouteParams = { const WalletNotificationsSettings = () => { const { colors } = useTheme(); const topicRowsData = useMemo(() => makeTopicRowsData(colors), [colors]); - const route = - useRoute>(); + const route = useRoute< + RouteProp + >(); const { isConnected } = useNetInfo(); const { wallets, walletNames } = useWallets(); const { address, notificationSettings } = route.params; @@ -109,8 +110,10 @@ const WalletNotificationsSettings = () => { address ).accountName; - const [notifications, setNotificationSettings] = - useState(notificationSettings); + const [ + notifications, + setNotificationSettings, + ] = useState(notificationSettings); const updateSettings = useCallback( (options: Partial) => { const newSettingsForWallet = updateSettingsForWalletWithAddress( @@ -172,8 +175,10 @@ const WalletNotificationsSettings = () => { // We allow only one subscription in progress // this states controls which we are currently updating - const [topicSubscriptionInProgress, setTopicSubscriptionInProgress] = - useState(null); + const [ + topicSubscriptionInProgress, + setTopicSubscriptionInProgress, + ] = useState(null); const toggleAllowNotifications = useCallback(() => { if (!isConnected) { diff --git a/src/screens/SettingsSheet/components/WalletNotificationsSettings.tsx b/src/screens/SettingsSheet/components/WalletNotificationsSettings.tsx index bc8761da14d..b86c3c234ea 100644 --- a/src/screens/SettingsSheet/components/WalletNotificationsSettings.tsx +++ b/src/screens/SettingsSheet/components/WalletNotificationsSettings.tsx @@ -91,13 +91,16 @@ type RouteParams = { const WalletNotificationsSettings = () => { const { colors } = useTheme(); const topicRowsData = useMemo(() => makeTopicRowsData(colors), [colors]); - const route = - useRoute>(); + const route = useRoute< + RouteProp + >(); const { isConnected } = useNetInfo(); const { address, notificationSettings } = route.params; - const [notifications, setNotificationSettings] = - useState(notificationSettings); + const [ + notifications, + setNotificationSettings, + ] = useState(notificationSettings); const updateSettings = useCallback( (options: Partial) => { const newSettingsForWallet = updateSettingsForWalletWithAddress( @@ -159,8 +162,10 @@ const WalletNotificationsSettings = () => { // We allow only one subscription in progress // this states controls which we are currently updating - const [topicSubscriptionInProgress, setTopicSubscriptionInProgress] = - useState(null); + const [ + topicSubscriptionInProgress, + setTopicSubscriptionInProgress, + ] = useState(null); const toggleAllowNotifications = useCallback(() => { if (!isConnected) { diff --git a/src/screens/ShowcaseSheet.js b/src/screens/ShowcaseSheet.js index 5187a8386f3..c2ed24496b0 100644 --- a/src/screens/ShowcaseSheet.js +++ b/src/screens/ShowcaseSheet.js @@ -44,8 +44,9 @@ const LoadingWrapper = styled.View({ }); export default function ShowcaseScreen() { - const { params: { address: addressOrDomain, setIsSearchModeEnabled } = {} } = - useRoute(); + const { + params: { address: addressOrDomain, setIsSearchModeEnabled } = {}, + } = useRoute(); const theme = useTheme(); diff --git a/src/screens/SignTransactionSheet.tsx b/src/screens/SignTransactionSheet.tsx index 569aa60a0e1..e920e303850 100644 --- a/src/screens/SignTransactionSheet.tsx +++ b/src/screens/SignTransactionSheet.tsx @@ -1695,8 +1695,8 @@ const SimulationCard = ({ simulationScanResult !== TransactionScanResultType.Ok ? simulationScanResult : simulationError - ? 'failed' - : 'insufficientBalance' + ? 'failed' + : 'insufficientBalance' } /> ) : ( @@ -1719,8 +1719,8 @@ const SimulationCard = ({ isLoading ? 'label' : simulationUnavailable - ? 'labelQuaternary' - : 'label' + ? 'labelQuaternary' + : 'label' } size="icon 15px" weight="bold" @@ -2210,8 +2210,8 @@ const DetailRow = ({ value === 'VERIFIED' ? 'verified' : value === 'UNVERIFIED' - ? 'unverified' - : 'unknown' + ? 'unverified' + : 'unknown' } value={value} /> diff --git a/src/screens/TransactionConfirmationScreen.js b/src/screens/TransactionConfirmationScreen.js index 3e614e5ffb6..78b6cbbb28a 100644 --- a/src/screens/TransactionConfirmationScreen.js +++ b/src/screens/TransactionConfirmationScreen.js @@ -211,8 +211,11 @@ export default function TransactionConfirmationScreen() { ({ walletconnect }) => walletconnect.walletConnectors ); - const { dataAddNewTransaction, removeRequest, walletConnectSendStatus } = - useTransactionConfirmation(); + const { + dataAddNewTransaction, + removeRequest, + walletConnectSendStatus, + } = useTransactionConfirmation(); const { callback, @@ -1127,8 +1130,8 @@ export default function TransactionConfirmationScreen() { (isMessageRequest ? MessageSheetHeight : (amount && amount !== '0.00') || !isBalanceEnough - ? TallSheetHeight - : ShortSheetHeight) * (android ? 1.5 : 1); + ? TallSheetHeight + : ShortSheetHeight) * (android ? 1.5 : 1); let marginTop = android ? deviceHeight - sheetHeight + 275 : null; diff --git a/src/screens/discover/components/DiscoverHome.js b/src/screens/discover/components/DiscoverHome.js index bb8239b0df2..6aee0a72619 100644 --- a/src/screens/discover/components/DiscoverHome.js +++ b/src/screens/discover/components/DiscoverHome.js @@ -34,8 +34,11 @@ import { import { useRoute } from '@react-navigation/native'; export default function DiscoverHome() { - const { profiles_enabled, mints_enabled, op_rewards_enabled } = - useRemoteConfig(); + const { + profiles_enabled, + mints_enabled, + op_rewards_enabled, + } = useRemoteConfig(); const { accountAddress, network } = useAccountSettings(); const { getCardsForPlacement } = useRemoteCardContext(); const { name } = useRoute(); @@ -62,10 +65,10 @@ export default function DiscoverHome() { key => wallets[key].type === walletTypes.bluetooth ).length > 0; - const cards = useMemo( - () => getCardsForPlacement(name), - [name, getCardsForPlacement] - ); + const cards = useMemo(() => getCardsForPlacement(name), [ + name, + getCardsForPlacement, + ]); return ( diff --git a/src/screens/discover/components/DiscoverSearchContainer.js b/src/screens/discover/components/DiscoverSearchContainer.js index 8b8dbb4346f..0405fa07912 100644 --- a/src/screens/discover/components/DiscoverSearchContainer.js +++ b/src/screens/discover/components/DiscoverSearchContainer.js @@ -60,8 +60,9 @@ export default forwardRef(function DiscoverSearchContainer( const [isFetchingEns, setIsFetchingEns] = useState(false); const delayedShowSearch = useDelayedValueWithLayoutAnimation(showSearch); - const { setIsSearchModeEnabled, isSearchModeEnabled } = - useContext(DiscoverSheetContext); + const { setIsSearchModeEnabled, isSearchModeEnabled } = useContext( + DiscoverSheetContext + ); const setIsInputFocused = useCallback( value => { diff --git a/src/screens/hardware-wallets/PairHardwareWalletAgainSheet.tsx b/src/screens/hardware-wallets/PairHardwareWalletAgainSheet.tsx index 20795d35021..57d03b96127 100644 --- a/src/screens/hardware-wallets/PairHardwareWalletAgainSheet.tsx +++ b/src/screens/hardware-wallets/PairHardwareWalletAgainSheet.tsx @@ -186,16 +186,16 @@ export const PairHardwareWalletAgainSheet = () => { hardwareTXError ? 'red' : isReady - ? 'green' - : 'surfaceSecondary' + ? 'green' + : 'surfaceSecondary' } shadow={ IS_IOS ? hardwareTXError ? '30px red' : isReady - ? '30px green' - : undefined + ? '30px green' + : undefined : undefined } borderRadius={INDICATOR_SIZE / 2} diff --git a/src/screens/hardware-wallets/PairHardwareWalletErrorSheet.tsx b/src/screens/hardware-wallets/PairHardwareWalletErrorSheet.tsx index 9a159630025..8a63c5e4417 100644 --- a/src/screens/hardware-wallets/PairHardwareWalletErrorSheet.tsx +++ b/src/screens/hardware-wallets/PairHardwareWalletErrorSheet.tsx @@ -27,8 +27,9 @@ type RouteParams = { }; export const PairHardwareWalletErrorSheet = () => { - const route = - useRoute>(); + const route = useRoute< + RouteProp + >(); const { width: deviceWidth } = useDimensions(); const { goBack, navigate } = useNavigation(); diff --git a/src/screens/hardware-wallets/PairHardwareWalletSigningSheet.tsx b/src/screens/hardware-wallets/PairHardwareWalletSigningSheet.tsx index 221816973dd..bed8b1488a4 100644 --- a/src/screens/hardware-wallets/PairHardwareWalletSigningSheet.tsx +++ b/src/screens/hardware-wallets/PairHardwareWalletSigningSheet.tsx @@ -93,13 +93,17 @@ type RouteParams = { }; export function PairHardwareWalletSigningSheet() { - const route = - useRoute>(); + const route = useRoute< + RouteProp + >(); const { navigate, goBack } = useNavigation(); const { isSmallPhone } = useDimensions(); const deviceId = useRecoilValue(LedgerImportDeviceIdAtom); - const { busy, handleSetSeedPhrase, handlePressImportButton } = - useImportingWallet({ showImportModal: true }); + const { + busy, + handleSetSeedPhrase, + handlePressImportButton, + } = useImportingWallet({ showImportModal: true }); const items: ItemDetails[] = [ { diff --git a/src/screens/mints/MintSheet.tsx b/src/screens/mints/MintSheet.tsx index 43461e84d89..b623bc387cf 100644 --- a/src/screens/mints/MintSheet.tsx +++ b/src/screens/mints/MintSheet.tsx @@ -731,8 +731,8 @@ const MintSheet = () => { {isZero(mintPriceAmount) ? i18n.t(i18n.l.minting.free) : showNativePrice - ? nativeMintPriceDisplay - : mintPriceDisplay} + ? nativeMintPriceDisplay + : mintPriceDisplay} diff --git a/src/screens/mints/PoapSheet.tsx b/src/screens/mints/PoapSheet.tsx index e4cea5c8c8a..6956ad526aa 100644 --- a/src/screens/mints/PoapSheet.tsx +++ b/src/screens/mints/PoapSheet.tsx @@ -344,10 +344,10 @@ const PoapSheet = () => { {claimStatus === 'claimed' ? i18n.t(i18n.l.poaps.minted) : claimStatus === 'claiming' - ? i18n.t(i18n.l.poaps.minting) - : claimStatus === 'none' - ? i18n.t(i18n.l.poaps.mint_poap) - : i18n.t(i18n.l.poaps.error)} + ? i18n.t(i18n.l.poaps.minting) + : claimStatus === 'none' + ? i18n.t(i18n.l.poaps.mint_poap) + : i18n.t(i18n.l.poaps.error)} diff --git a/src/screens/points/PointsScreen.tsx b/src/screens/points/PointsScreen.tsx index dc461d615e7..686ff83590b 100644 --- a/src/screens/points/PointsScreen.tsx +++ b/src/screens/points/PointsScreen.tsx @@ -36,8 +36,12 @@ export const POINTS_ROUTES = { const Swipe = createMaterialTopTabNavigator(); export default function PointsScreen() { - const { accountAddress, accountImage, accountColor, accountSymbol } = - useAccountProfile(); + const { + accountAddress, + accountImage, + accountColor, + accountSymbol, + } = useAccountProfile(); const { points_enabled, points_notifications_toggle } = useRemoteConfig(); const pointsEnabled = useExperimentalFlag(POINTS) || points_enabled || IS_TEST; @@ -48,8 +52,10 @@ export default function PointsScreen() { const { data } = usePoints({ walletAddress: accountAddress, }); - const { data: referralCode, refetch: resetReferralCode } = - usePointsReferralCode(); + const { + data: referralCode, + refetch: resetReferralCode, + } = usePointsReferralCode(); const isOnboarded = data?.points?.error?.type !== PointsErrorType.NonExistingUser; diff --git a/src/screens/points/components/AnimatedText.tsx b/src/screens/points/components/AnimatedText.tsx index ea34377b58e..cd9380e5ad5 100644 --- a/src/screens/points/components/AnimatedText.tsx +++ b/src/screens/points/components/AnimatedText.tsx @@ -63,8 +63,11 @@ export const AnimatedText = ({ weight = 'bold', }: AnimatedTextProps) => { const { colors } = useTheme(); - const { currentSequenceIndex, getNextAnimationIndex, incrementSequence } = - useAnimationContext(); + const { + currentSequenceIndex, + getNextAnimationIndex, + incrementSequence, + } = useAnimationContext(); const index = useRef(getNextAnimationIndex()).current; const displayedCharacters = useSharedValue( skipAnimation ? textContent.length : 0 @@ -86,8 +89,8 @@ export const AnimatedText = ({ textShadowColor: disableShadow ? 'transparent' : shadowOpacity && rainbowTextColors?.[i]?.shadow - ? colors.alpha(rainbowTextColors?.[i]?.shadow, shadowOpacity) - : rainbowTextColors?.[i]?.shadow, + ? colors.alpha(rainbowTextColors?.[i]?.shadow, shadowOpacity) + : rainbowTextColors?.[i]?.shadow, }), [ colors, @@ -108,10 +111,10 @@ export const AnimatedText = ({ textShadowColor: disableShadow ? 'transparent' : rainbowText - ? undefined - : shadowOpacity && color?.shadow - ? colors.alpha(color?.shadow, shadowOpacity) - : color?.shadow, + ? undefined + : shadowOpacity && color?.shadow + ? colors.alpha(color?.shadow, shadowOpacity) + : color?.shadow, }), [ color, diff --git a/src/screens/points/components/LeaderboardRow.tsx b/src/screens/points/components/LeaderboardRow.tsx index b436298fa28..c58d653736d 100644 --- a/src/screens/points/components/LeaderboardRow.tsx +++ b/src/screens/points/components/LeaderboardRow.tsx @@ -65,10 +65,9 @@ export const LeaderboardRow = ({ const contact = address ? contacts[address.toLowerCase()] : undefined; - const formattedAddress = useMemo( - () => formatAddress(address, 4, 5), - [address] - ); + const formattedAddress = useMemo(() => formatAddress(address, 4, 5), [ + address, + ]); const menuItems = useMemo(() => { return [ diff --git a/src/screens/points/components/NotificationToggleContextMenu.tsx b/src/screens/points/components/NotificationToggleContextMenu.tsx index c375a53e3a4..7b08e7f41b3 100644 --- a/src/screens/points/components/NotificationToggleContextMenu.tsx +++ b/src/screens/points/components/NotificationToggleContextMenu.tsx @@ -30,11 +30,14 @@ export const NotificationToggleContextMenu = () => { const separatorTertiary = useForegroundColor('separatorTertiary'); const { colorMode } = useColorMode(); const { isConnected } = useNetInfo(); - const { globalNotificationSettings } = - useAllNotificationSettingsFromStorage(); + const { + globalNotificationSettings, + } = useAllNotificationSettingsFromStorage(); - const [topicSubscriptionInProgress, setTopicSubscriptionInProgress] = - useState(false); + const [ + topicSubscriptionInProgress, + setTopicSubscriptionInProgress, + ] = useState(false); const toggleNotifications = useCallback(() => { if (!isConnected) { @@ -49,8 +52,9 @@ export const NotificationToggleContextMenu = () => { .then(() => { setAllGlobalNotificationSettingsToStorage({ ...globalNotificationSettings, - [GlobalNotificationTopic.POINTS]: - !globalNotificationSettings[GlobalNotificationTopic.POINTS], + [GlobalNotificationTopic.POINTS]: !globalNotificationSettings[ + GlobalNotificationTopic.POINTS + ], }); }) .catch(() => { diff --git a/src/screens/points/content/PointsContent.tsx b/src/screens/points/content/PointsContent.tsx index 70f7c7d89b1..453eeffa817 100644 --- a/src/screens/points/content/PointsContent.tsx +++ b/src/screens/points/content/PointsContent.tsx @@ -62,19 +62,14 @@ export default function PointsContent() { const { setClipboard } = useClipboard(); const { isReadOnlyWallet } = useWallets(); - const { - data: points, - isFetching, - dataUpdatedAt, - refetch, - } = usePoints({ + const { data: points, isFetching, dataUpdatedAt, refetch } = usePoints({ walletAddress: accountAddress, }); - const cards = useMemo( - () => getCardsForPlacement(name as string), - [getCardsForPlacement, name] - ); + const cards = useMemo(() => getCardsForPlacement(name as string), [ + getCardsForPlacement, + name, + ]); useFocusEffect( useCallback(() => { @@ -126,8 +121,9 @@ export default function PointsContent() { }, [dataUpdatedAt, refetch]); const nextDistributionSeconds = points?.points?.meta?.distribution?.next; - const totalPointsString = - points?.points?.user?.earnings?.total.toLocaleString('en-US'); + const totalPointsString = points?.points?.user?.earnings?.total.toLocaleString( + 'en-US' + ); const totalPointsMaskSize = 60 * Math.max(totalPointsString?.length ?? 0, 4); const totalUsers = points?.points?.leaderboard.stats.total_users; diff --git a/src/screens/points/content/console/calculate.tsx b/src/screens/points/content/console/calculate.tsx index aabaeaac043..21b2b277e43 100644 --- a/src/screens/points/content/console/calculate.tsx +++ b/src/screens/points/content/console/calculate.tsx @@ -37,8 +37,9 @@ export const Calculate = () => { const { accountENS, accountAddress } = useAccountProfile(); const [isCalculationComplete, setIsCalculationComplete] = useState(false); - const [shouldShowContinueButton, setShouldShowContinueButton] = - useState(false); + const [shouldShowContinueButton, setShouldShowContinueButton] = useState( + false + ); const accountName = (abbreviateEnsForDisplay(accountENS, 10) || formatAddress(accountAddress, 4, 5)) as string; diff --git a/src/screens/points/content/console/initialize.tsx b/src/screens/points/content/console/initialize.tsx index 874b79df2e7..126878e8f60 100644 --- a/src/screens/points/content/console/initialize.tsx +++ b/src/screens/points/content/console/initialize.tsx @@ -20,8 +20,12 @@ import { Bleed, Box, Stack } from '@/design-system'; export const Initialize = () => { const [showSignInButton, setShowSignInButton] = useState(false); - const { profile, setStep, setAnimationKey, signIn } = - usePointsProfileContext(); + const { + profile, + setStep, + setAnimationKey, + signIn, + } = usePointsProfileContext(); const { accountENS, accountAddress } = useAccountProfile(); const accountName = (abbreviateEnsForDisplay(accountENS, 10) || diff --git a/src/screens/points/content/console/share.tsx b/src/screens/points/content/console/share.tsx index 024f5580901..06ff01a47e5 100644 --- a/src/screens/points/content/console/share.tsx +++ b/src/screens/points/content/console/share.tsx @@ -19,8 +19,12 @@ import { metadataPOSTClient } from '@/graphql'; import { analyticsV2 } from '@/analytics'; export const Share = () => { - const { intent, setAnimationKey, setShareBonusPoints, setStep } = - usePointsProfileContext(); + const { + intent, + setAnimationKey, + setShareBonusPoints, + setStep, + } = usePointsProfileContext(); const { accountENS, accountAddress } = useAccountProfile(); const { width: deviceWidth } = useDimensions(); @@ -109,11 +113,12 @@ export const Share = () => { const beginNextPhase = setTimeout(async () => { if (intent) { Linking.openURL(intent); - const shareBonusPointsResponse = - await metadataPOSTClient.redeemCodeForPoints({ + const shareBonusPointsResponse = await metadataPOSTClient.redeemCodeForPoints( + { address: accountAddress, redemptionCode: 'TWITTERSHARED', - }); + } + ); if (shareBonusPointsResponse?.redeemCode?.earnings?.total) { setShareBonusPoints( shareBonusPointsResponse?.redeemCode?.earnings?.total diff --git a/src/screens/points/contexts/PointsProfileContext.tsx b/src/screens/points/contexts/PointsProfileContext.tsx index cd109e1f823..632af1baf05 100644 --- a/src/screens/points/contexts/PointsProfileContext.tsx +++ b/src/screens/points/contexts/PointsProfileContext.tsx @@ -119,26 +119,21 @@ export const PointsProfileProvider = ({ const [animationKey, setAnimationKey] = useState(0); const [shareBonusPoints, setShareBonusPoints] = useState(0); - const rainbowSwaps = - profile?.onboardPoints?.user?.onboarding?.categories?.find( - ({ type }) => type === PointsOnboardingCategoryType.RainbowSwaps - ); - const metamaskSwaps = - profile?.onboardPoints?.user?.onboarding?.categories?.find( - ({ type }) => type === PointsOnboardingCategoryType.MetamaskSwaps - ); - const rainbowBridges = - profile?.onboardPoints?.user?.onboarding?.categories?.find( - ({ type }) => type === PointsOnboardingCategoryType.RainbowBridges - ); - const nftCollections = - profile?.onboardPoints?.user?.onboarding?.categories?.find( - ({ type }) => type === PointsOnboardingCategoryType.NFTCollections - ); - const historicBalance = - profile?.onboardPoints?.user?.onboarding?.categories?.find( - ({ type }) => type === PointsOnboardingCategoryType.HistoricBalance - ); + const rainbowSwaps = profile?.onboardPoints?.user?.onboarding?.categories?.find( + ({ type }) => type === PointsOnboardingCategoryType.RainbowSwaps + ); + const metamaskSwaps = profile?.onboardPoints?.user?.onboarding?.categories?.find( + ({ type }) => type === PointsOnboardingCategoryType.MetamaskSwaps + ); + const rainbowBridges = profile?.onboardPoints?.user?.onboarding?.categories?.find( + ({ type }) => type === PointsOnboardingCategoryType.RainbowBridges + ); + const nftCollections = profile?.onboardPoints?.user?.onboarding?.categories?.find( + ({ type }) => type === PointsOnboardingCategoryType.NFTCollections + ); + const historicBalance = profile?.onboardPoints?.user?.onboarding?.categories?.find( + ({ type }) => type === PointsOnboardingCategoryType.HistoricBalance + ); const bonus = profile?.onboardPoints?.user?.onboarding?.categories?.find( ({ type }) => type === PointsOnboardingCategoryType.Bonus ); @@ -161,11 +156,12 @@ export const PointsProfileProvider = ({ ); try { - const challengeResponse = - await metadataPOSTClient.getPointsOnboardChallenge({ + const challengeResponse = await metadataPOSTClient.getPointsOnboardChallenge( + { address: accountAddress, referral: referralCode, - }); + } + ); const challenge = challengeResponse?.pointsOnboardChallenge; if (!challenge) { Alert.alert(i18n.t(i18n.l.points.console.generic_alert)); diff --git a/src/screens/rewards/RewardsSheet.tsx b/src/screens/rewards/RewardsSheet.tsx index 8f27ef8990a..ecae5ffc387 100644 --- a/src/screens/rewards/RewardsSheet.tsx +++ b/src/screens/rewards/RewardsSheet.tsx @@ -19,11 +19,7 @@ export const RewardsSheet: React.FC = () => { (state: AppState) => state.settings.accountAddress ); const [isLoading, setIsLoading] = useState(true); - const { - data, - isLoading: queryIsLoading, - isLoadingError, - } = useRewards({ + const { data, isLoading: queryIsLoading, isLoadingError } = useRewards({ address: accountAddress, }); diff --git a/src/screens/transaction-details/TransactionDetails.tsx b/src/screens/transaction-details/TransactionDetails.tsx index dec0c59938e..04eabcb1c3c 100644 --- a/src/screens/transaction-details/TransactionDetails.tsx +++ b/src/screens/transaction-details/TransactionDetails.tsx @@ -41,10 +41,10 @@ export const TransactionDetails = () => { const { height: deviceHeight } = useDimensions(); // Dynamic sheet height based on content height - useEffect( - () => setParams({ longFormHeight: sheetHeight }), - [setParams, sheetHeight] - ); + useEffect(() => setParams({ longFormHeight: sheetHeight }), [ + setParams, + sheetHeight, + ]); const onSheetContentLayout = (event: LayoutChangeEvent) => { const contentHeight = event.nativeEvent.layout.height; diff --git a/src/screens/transaction-details/components/TransactionDetailsAddressRow.tsx b/src/screens/transaction-details/components/TransactionDetailsAddressRow.tsx index 3f457b8b143..4ac68935326 100644 --- a/src/screens/transaction-details/components/TransactionDetailsAddressRow.tsx +++ b/src/screens/transaction-details/components/TransactionDetailsAddressRow.tsx @@ -217,10 +217,9 @@ export const TransactionDetailsAddressRow: React.FC = ({ easing: Easing.linear, }); - const accountEmoji = useMemo( - () => returnStringFirstEmoji(account?.label), - [account] - ); + const accountEmoji = useMemo(() => returnStringFirstEmoji(account?.label), [ + account, + ]); const accountName = useMemo( () => removeFirstEmojiFromString(account?.label), [] diff --git a/src/screens/transaction-details/components/TransactionDetailsStatusActionsAndTimestampSection.tsx b/src/screens/transaction-details/components/TransactionDetailsStatusActionsAndTimestampSection.tsx index 52c8b079ea9..77ab340146a 100644 --- a/src/screens/transaction-details/components/TransactionDetailsStatusActionsAndTimestampSection.tsx +++ b/src/screens/transaction-details/components/TransactionDetailsStatusActionsAndTimestampSection.tsx @@ -24,9 +24,10 @@ type Props = { hideIcon?: boolean; }; -export const TransactionDetailsStatusActionsAndTimestampSection: React.FC< - Props -> = ({ transaction, hideIcon }) => { +export const TransactionDetailsStatusActionsAndTimestampSection: React.FC = ({ + transaction, + hideIcon, +}) => { const { minedAt, status, pending, from } = transaction; const dispatch = useDispatch(); const { navigate, goBack } = useNavigation(); diff --git a/src/state/internal/createStore.ts b/src/state/internal/createStore.ts index 59c77627265..4e48af9b675 100644 --- a/src/state/internal/createStore.ts +++ b/src/state/internal/createStore.ts @@ -11,15 +11,17 @@ export type StoreWithPersist = Mutate< initializer: Initializer; }; -export function createStore(initializer: Initializer) { +export function createStore( + initializer: Initializer +) { const name = `rainbow.zustand`; return Object.assign( create( persist(initializer, { name, - getStorage: () => persistStorage, - }) + getStorage: () => (persistStorage), + }), ), - { initializer } + { initializer }, ); } diff --git a/src/styled-thing/hoist.ts b/src/styled-thing/hoist.ts index d202b8aa01c..62bb2ef67a1 100644 --- a/src/styled-thing/hoist.ts +++ b/src/styled-thing/hoist.ts @@ -74,7 +74,7 @@ function getStatics(component: OmniComponent) { // React v16.12 and above return '$$typeof' in component - ? TYPE_STATICS[component['$$typeof'] as unknown as string] + ? TYPE_STATICS[(component['$$typeof'] as unknown) as string] : REACT_STATICS; } @@ -91,22 +91,22 @@ type ExcludeList = { type NonReactStatics< S extends OmniComponent, - C extends ExcludeList = Record, + C extends ExcludeList = Record > = { [key in Exclude< keyof S, S extends React.MemoExoticComponent ? keyof typeof MEMO_STATICS | keyof C : S extends React.ForwardRefExoticComponent - ? keyof typeof FORWARD_REF_STATICS | keyof C - : keyof typeof REACT_STATICS | keyof typeof KNOWN_STATICS | keyof C + ? keyof typeof FORWARD_REF_STATICS | keyof C + : keyof typeof REACT_STATICS | keyof typeof KNOWN_STATICS | keyof C >]: S[key]; }; export default function hoistNonReactStatics< T extends OmniComponent, S extends OmniComponent, - C extends ExcludeList = Record, + C extends ExcludeList = Record >(targetComponent: T, sourceComponent: S, excludelist?: C) { if (typeof sourceComponent !== 'string') { // don't hoist over string (html) components @@ -128,7 +128,7 @@ export default function hoistNonReactStatics< const sourceStatics = getStatics(sourceComponent); for (const item of keys) { - const key = item as unknown as string; + const key = (item as unknown) as string; if ( !(key in KNOWN_STATICS) && !excludelist?.[key] && diff --git a/src/theme/ThemeContext.tsx b/src/theme/ThemeContext.tsx index 07165c14f20..859d04631b1 100644 --- a/src/theme/ThemeContext.tsx +++ b/src/theme/ThemeContext.tsx @@ -26,7 +26,7 @@ export const Themes = { SYSTEM: 'system', } as const; -export type ThemesType = (typeof Themes)[keyof typeof Themes]; +export type ThemesType = typeof Themes[keyof typeof Themes]; export interface ThemeContextProps { colors: Colors; diff --git a/src/utils/__mocks__/delay.ts b/src/utils/__mocks__/delay.ts index b21c26d67bd..b58fcec3502 100644 --- a/src/utils/__mocks__/delay.ts +++ b/src/utils/__mocks__/delay.ts @@ -1,8 +1,8 @@ /** * @desc Promise that will resolve after the ms interval */ -export const delay = jest - .fn() - .mockImplementation((ms: number): Promise => { +export const delay = jest.fn().mockImplementation( + (ms: number): Promise => { return new Promise(resolve => setTimeout(resolve, ms)); - }); + } +); diff --git a/src/utils/ens.ts b/src/utils/ens.ts index ebc4aa33fcc..3840d1e9728 100644 --- a/src/utils/ens.ts +++ b/src/utils/ens.ts @@ -111,7 +111,7 @@ export function validateENS( ): { valid: boolean; hint?: string; - code?: (typeof ERROR_CODES)[keyof typeof ERROR_CODES]; + code?: typeof ERROR_CODES[keyof typeof ERROR_CODES]; } { const splitDomain = domain.split('.'); diff --git a/src/utils/ethereumUtils.ts b/src/utils/ethereumUtils.ts index 9fe9ca9120f..836a532ec78 100644 --- a/src/utils/ethereumUtils.ts +++ b/src/utils/ethereumUtils.ts @@ -553,9 +553,9 @@ const calculateL1FeeOptimism = async ( newTx.data === '0x' ? ethUnits.basic_tx : ethUnits.basic_transfer ); } - const currentGasPrice = - // @ts-expect-error ts-migrate(2551) FIXME: Property 'selectedGasPrice' does not exist on type... Remove this comment to see the full error message - store.getState().gas.selectedGasPrice?.value?.amount; + // @ts-expect-error ts-migrate(2551) FIXME: Property 'selectedGasPrice' does not exist on type... Remove this comment to see the full error message + const currentGasPrice = store.getState().gas.selectedGasPrice?.value + ?.amount; if (currentGasPrice) newTx.gasPrice = toHex(currentGasPrice); // @ts-expect-error ts-migrate(100005) FIXME: Remove this comment to see the full error message const serializedTx = serialize(newTx); diff --git a/src/utils/haptics.ts b/src/utils/haptics.ts index 1cfd440957f..e56c3921aae 100644 --- a/src/utils/haptics.ts +++ b/src/utils/haptics.ts @@ -12,8 +12,7 @@ export const HapticFeedback = { selection: 'selection', } as const; -export type HapticFeedbackType = - (typeof HapticFeedback)[keyof typeof HapticFeedback]; +export type HapticFeedbackType = typeof HapticFeedback[keyof typeof HapticFeedback]; const hapticToTrigger = (haptic: HapticFeedbackType) => ({ [haptic]: () => ReactNativeHapticFeedback.trigger(haptic), diff --git a/src/utils/profileUtils.ts b/src/utils/profileUtils.ts index 9c0f460fd4d..f8029b45e9c 100644 --- a/src/utils/profileUtils.ts +++ b/src/utils/profileUtils.ts @@ -76,10 +76,9 @@ export function hashCode(text: string) { return hash; } -export function getNextEmojiWithColor(prevEmoji: string): { - emoji: string; - colorIndex: number; -} { +export function getNextEmojiWithColor( + prevEmoji: string +): { emoji: string; colorIndex: number } { const prevIndex = avatars.findIndex(({ emoji }) => emoji === prevEmoji); // if not matched, we get -1, what's fine return avatars[(prevIndex + 1) % avatars.length]; } diff --git a/src/utils/recompactAdapters.tsx b/src/utils/recompactAdapters.tsx index 8a023fe329e..df9b60bb5fa 100644 --- a/src/utils/recompactAdapters.tsx +++ b/src/utils/recompactAdapters.tsx @@ -20,9 +20,5 @@ export function compose(...funcs: any[]) { return funcs[0]; } - return funcs.reduce( - (a, b) => - (...args: any[]) => - a(b(...args)) - ); + return funcs.reduce((a, b) => (...args: any[]) => a(b(...args))); } diff --git a/src/walletConnect/index.tsx b/src/walletConnect/index.tsx index 4fb9ef0b2ff..3211f3bc4af 100644 --- a/src/walletConnect/index.tsx +++ b/src/walletConnect/index.tsx @@ -108,7 +108,7 @@ export function maybeGoBackAndClearHasPendingRedirect({ * MAY BE UNDEFINED if WC v2 hasn't been instantiated yet */ let syncWeb3WalletClient: - | Awaited> + | Awaited> | undefined; const walletConnectCore = new Core({ projectId: WC_PROJECT_ID }); @@ -132,7 +132,10 @@ export const web3WalletClient = Web3Wallet.init({ * return { address, message } and JSON.parse the value if it's from a typed * data request */ -export function parseRPCParams({ method, params }: RPCPayload): { +export function parseRPCParams({ + method, + params, +}: RPCPayload): { address?: string; message?: string; } { @@ -460,8 +463,11 @@ export async function onSessionProposal( const verifiedData = proposal.verifyContext.verified; const receivedTimestamp = Date.now(); - const { proposer, requiredNamespaces, optionalNamespaces } = - proposal.params; + const { + proposer, + requiredNamespaces, + optionalNamespaces, + } = proposal.params; const requiredChains = requiredNamespaces?.eip155?.chains || []; const optionalChains = optionalNamespaces?.eip155?.chains || []; @@ -1063,8 +1069,9 @@ export async function addAccountToSession( try { const client = await web3WalletClient; - const namespaces: Parameters[0]['namespaces'] = - {}; + const namespaces: Parameters< + typeof client.updateSession + >[0]['namespaces'] = {}; for (const [key, value] of Object.entries(session.requiredNamespaces)) { /** diff --git a/src/walletConnect/types.ts b/src/walletConnect/types.ts index ad8e6bad02a..053a6f18766 100644 --- a/src/walletConnect/types.ts +++ b/src/walletConnect/types.ts @@ -29,7 +29,7 @@ export type RPCPayload = | RPCMethod.SignTypedDataV4; params: [ string, // address - string, // stringify typed object + string // stringify typed object ]; } | { @@ -42,7 +42,7 @@ export type RPCPayload = gasPrice: string; gasLimit: string; value: string; - }, + } ]; } | { diff --git a/yarn.lock b/yarn.lock index 2458e6de6db..ddafa87bc79 100644 --- a/yarn.lock +++ b/yarn.lock @@ -14732,10 +14732,10 @@ prelude-ls@^1.2.1: resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== -prettier@3.2.5: - version "3.2.5" - resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.2.5.tgz#e52bc3090586e824964a8813b09aba6233b28368" - integrity sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A== +prettier@2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.2.1.tgz#795a1a78dd52f073da0cd42b21f9c91381923ff5" + integrity sha512-PqyhM2yCjg/oKkFPtTGUojv7gnZAoG80ttl45O6x2Ug/rMJw4wcc9k6aaf2hibP7BGVCCM33gZoGjyvt9mm16Q== prettier@^1.17.1: version "1.19.1" @@ -19165,9 +19165,9 @@ zod@^1.11.11: resolved "https://registry.yarnpkg.com/zod/-/zod-1.11.17.tgz#2aae9e91fc66128116ae9844e8f416a95f453f8e" integrity sha512-UzIwO92D0dSFwIRyyqAfRXICITLjF0IP8tRbEK/un7adirMssWZx8xF/1hZNE7t61knWZ+lhEuUvxlu2MO8qqA== -zustand@4.3.1: - version "4.3.1" - resolved "https://registry.yarnpkg.com/zustand/-/zustand-4.3.1.tgz#76c47ef713c43763953f7a9e518f89efd898e3bb" - integrity sha512-EVyo/eLlOTcJm/X5M00rwtbYFXwRVTaRteSvhtbTZUCQFJkNfIyHPiJ6Ke68MSWzcKHpPzvqNH4gC2ZS/sbNqw== +zustand@4.1.5: + version "4.1.5" + resolved "https://registry.yarnpkg.com/zustand/-/zustand-4.1.5.tgz#7402b511f5b23ccb0f9ba6d20ae01ec817e16eb6" + integrity sha512-PsdRT8Bvq22Yyh1tvpgdHNE7OAeFKqJXUxtJvj1Ixw2B9O2YZ1M34ImQ+xyZah4wZrR4lENMoDUutKPpyXCQ/Q== dependencies: use-sync-external-store "1.2.0" From 538f3ded01611862c24bc3833d45a4c734acd75c Mon Sep 17 00:00:00 2001 From: skylarbarrera Date: Mon, 5 Feb 2024 22:56:32 -0500 Subject: [PATCH 13/38] save --- .../FastComponents/FastCoinIcon.tsx | 6 +- src/components/coin-icon/TwoIconsIcon.tsx | 74 +++ .../coin-row/FastTransactionCoinRow.tsx | 464 ++++++++++++++---- .../coin-row/FastTransactionStatusBadge.tsx | 27 +- .../asset/ChartExpandedState.js | 5 - src/hooks/charts/useChartThrottledPoints.ts | 1 - src/hooks/useTransactionConfirmation.ts | 2 - src/redux/data.ts | 24 +- .../TransactionDetailsValueAndFeeSection.tsx | 87 +++- src/utils/abbreviations.ts | 6 +- src/walletConnect/__tests__/index.test | 2 - 11 files changed, 539 insertions(+), 159 deletions(-) create mode 100644 src/components/coin-icon/TwoIconsIcon.tsx diff --git a/src/components/asset-list/RecyclerAssetList2/FastComponents/FastCoinIcon.tsx b/src/components/asset-list/RecyclerAssetList2/FastComponents/FastCoinIcon.tsx index 20109384961..59a2b8a536d 100644 --- a/src/components/asset-list/RecyclerAssetList2/FastComponents/FastCoinIcon.tsx +++ b/src/components/asset-list/RecyclerAssetList2/FastComponents/FastCoinIcon.tsx @@ -57,12 +57,14 @@ export default React.memo(function FastCoinIcon({ network, symbol, theme, + ignoreBadge = false, }: { address: string; mainnetAddress?: string; network: Network; symbol: string; theme: ThemeContextProps; + ignoreBadge?: boolean; }) { const { colors } = theme; @@ -117,7 +119,9 @@ export default React.memo(function FastCoinIcon({ )} - {network && } + {!ignoreBadge && network && ( + + )} ); }); diff --git a/src/components/coin-icon/TwoIconsIcon.tsx b/src/components/coin-icon/TwoIconsIcon.tsx new file mode 100644 index 00000000000..7839ca413c2 --- /dev/null +++ b/src/components/coin-icon/TwoIconsIcon.tsx @@ -0,0 +1,74 @@ +import React from 'react'; +import { Box } from '@/design-system'; +import FastCoinIcon from '../asset-list/RecyclerAssetList2/FastComponents/FastCoinIcon'; +import { ParsedAddressAsset } from '@/entities'; +import MaskedView from '@react-native-masked-view/masked-view'; +import Svg, { ClipPath, Path } from 'react-native-svg'; +import { useTheme } from '@/theme'; + +const Mask = () => ( + + + + + +); +export function TwoCoinsIcon({ + size = 36, + under, + over, + badge = true, +}: { + size?: number; + under: ParsedAddressAsset; + over: ParsedAddressAsset; + badge?: boolean; +}) { + const theme = useTheme(); + const overSize = size * 0.75; + const underSize = size * 0.67; + + const network = over.network; + + return ( + + } + style={{ + zIndex: 1, + width: underSize * 0.924544, + height: underSize * 0.924544, + position: 'absolute', + top: 0, + left: 0, + }} + > + + + + + + {/* + {badge && chainId !== ChainId.mainnet && ( + + )} + */} + + ); +} diff --git a/src/components/coin-row/FastTransactionCoinRow.tsx b/src/components/coin-row/FastTransactionCoinRow.tsx index 90c7f143942..cdc97c1ae41 100644 --- a/src/components/coin-row/FastTransactionCoinRow.tsx +++ b/src/components/coin-row/FastTransactionCoinRow.tsx @@ -3,7 +3,7 @@ import { StyleSheet, View } from 'react-native'; import { ButtonPressAnimation } from '../animations'; import FastCoinIcon from '../asset-list/RecyclerAssetList2/FastComponents/FastCoinIcon'; import FastTransactionStatusBadge from './FastTransactionStatusBadge'; -import { Text, globalColors, useColorMode } from '@/design-system'; +import { Box, Inline, Text, globalColors, useColorMode } from '@/design-system'; import { RainbowTransaction, TransactionStatusTypes } from '@/entities'; import { ThemeContextProps } from '@/theme'; import { useNavigation } from '@/navigation'; @@ -12,22 +12,160 @@ import { ImgixImage } from '../images'; import { CardSize } from '../unique-token/CardSize'; import { ChainBadge } from '../coin-icon'; import { Network } from '@/networks/types'; -import { ethereumUtils } from '@/utils'; import { ETH_ADDRESS, ETH_SYMBOL } from '@/references'; +import { address } from '@/utils/abbreviations'; +import { Colors } from '@/styles'; +import { TransactionType } from '@/resources/transactions/types'; +import { + convertAmountAndPriceToNativeDisplay, + convertAmountToBalanceDisplay, +} from '@/helpers/utilities'; -const BottomRow = React.memo(function BottomRow({ - description, - nativeDisplay, - status, +export const getApprovalLabel = ({ + approvalAmount, + asset, type, +}: Pick) => { + if (!approvalAmount || !asset) return; + if (approvalAmount === 'UNLIMITED') return 'approvals.unlimited'; + if (type === 'revoke') return 'approvals.no_allowance'; + return `${approvalAmount} ${asset.symbol}`; +}; + +const approvalTypeValues = (transaction: RainbowTransaction) => { + const { asset, approvalAmount, hash, contract } = transaction; + + if (!asset || !approvalAmount) return; + return getApprovalLabel(transaction); + + // return [ + // contract?.name ? ( + // + // {contract.iconUrl && ( + // + // {'Con Icon'} + // + // )} + // {contract.name} + // + // ) : null, + // label && ( + // + // + // {label} + // + // + // ), + // ]; +}; + +const swapTypeValues = (changes: RainbowTransaction['changes']) => { + const tokenIn = changes?.filter(c => c?.direction === 'in')[0]; + const tokenOut = changes?.filter(c => c?.direction === 'out')[0]; + + if (!tokenIn?.asset.balance?.amount || !tokenOut?.asset.balance?.amount) + return; + + const valueOut = `-${convertAmountToBalanceDisplay( + tokenOut?.asset.balance?.amount, + { ...tokenOut?.asset } + )}`; + const valueIn = `+${convertAmountToBalanceDisplay( + tokenIn?.asset.balance?.amount, + { ...tokenIn?.asset } + )}`; + + return [valueOut, valueIn]; +}; + +const activityValues = (transaction: RainbowTransaction) => { + const { changes, direction, type } = transaction; + if (['swap', 'wrap', 'unwrap'].includes(type)) return swapTypeValues(changes); + if (['approve', 'revoke'].includes(type)) + return approvalTypeValues(transaction); + + const asset = changes?.filter( + c => c?.direction === direction && c?.asset.type !== 'nft' + )[0]?.asset; + const valueSymbol = direction === 'out' ? '-' : '+'; + + if (!asset) return; + + const { balance } = asset; + if (balance?.amount === '0') return; + + const assetValue = `${balance?.amount} ${asset.symbol}`; + + const nativeBalance = '0'; + const assetNativeValue = + +nativeBalance > 0 ? `${valueSymbol}${nativeBalance}` : 'no value'; + + return +nativeBalance > 0 + ? [assetValue, assetNativeValue] + : [assetNativeValue, `${valueSymbol}${assetValue}`]; +}; + +const activityTypeIcon: Record = { + airdrop: '􀐚', + approve: '􀁢', + contract_interaction: '􀉆', + receive: '􀄩', + send: '􀈠', + swap: '􀖅', + bid: '􀑍', + burn: '􀙬', + mint: '􀫸', + purchase: '􀍣', + sale: '􀋡', + wrap: '􀑉', + unwrap: '􀑉', + cancel: '􀁠', + repay: '􀄹', + bridge: '􀄹', + stake: '􀄷', + unstake: '􀄲', + withdraw: '􀄲', + deposit: '􀄷', + revoke: '􀁎', + speed_up: '􀓎', + claim: '􀄩', + borrow: '􀄩', + deployment: '􀄩', +}; + +export const ActivityTypeIcon = ({ + transaction: { status, type }, +}: { + transaction: Pick; +}) => { + // if (status === 'pending') return null; + if (status === 'failed') + return ( + + {'X'} + + ); + + const symbol = activityTypeIcon[type]; + if (!symbol) return null; + return ( + + {symbol} + + ); +}; + +const BottomRow = React.memo(function BottomRow({ + transaction, theme, }: { - description: string; - nativeDisplay: any; - status: keyof typeof TransactionStatusTypes; - type: keyof typeof TransactionTypes; + transaction: RainbowTransaction; theme: ThemeContextProps; }) { + const { status, type, native, to, asset } = transaction; const { colors } = theme; const isFailed = status === TransactionStatusTypes.failed; const isReceived = @@ -51,35 +189,251 @@ const BottomRow = React.memo(function BottomRow({ if (isOutgoingSwap) balanceTextColor = colors.dark; if (isSold) balanceTextColor = colors.green; - const balanceText = nativeDisplay - ? [isFailed || isSent ? '-' : null, nativeDisplay].filter(Boolean).join(' ') + const balanceText = native?.display + ? [isFailed || isSent ? '-' : null, native.display] + .filter(Boolean) + .join(' ') : ''; + let description = transaction.description; + let tag: string | undefined; + if (type === 'contract_interaction' && to) { + description = transaction.contract?.name || address(to, 6, 4); + tag = transaction.description; + } + + const nftChangesAmount = transaction.changes + ?.filter( + c => asset?.address === c?.asset.address && c?.asset.type === 'nft' + ) + .filter(Boolean).length; + if (nftChangesAmount) tag = nftChangesAmount.toString(); + + const [topValue, bottomValue] = activityValues(transaction) ?? []; return ( - - {description} - + + + {description} + + {tag && ( + + + {tag} + + + )} + - {balanceText} + {bottomValue} ); }); +export const ActivityIcon = ({ + transaction, + size = 36, + badge = true, + theme, +}: { + transaction: RainbowTransaction; + badge?: boolean; + size?: 36 | 20 | 14 | 16; + theme: ThemeContextProps; +}) => { + if (['wrap', 'undwrap', 'swap'].includes(transaction?.type)) { + const inAsset = transaction?.changes?.find(a => a?.direction === 'in') + ?.asset; + const outAsset = transaction?.changes?.find(a => a?.direction === 'out') + ?.asset; + + if (!!inAsset && !!outAsset) + return ( + + + + + ); + } + if (transaction?.contract?.iconUrl) { + return ( + + + + + {transaction.network !== Network.mainnet && ( + + )} + + ); + } + + if (transaction?.asset?.type === 'nft') { + return ( + + + + + {transaction.network !== Network.mainnet && ( + + )} + + ); + } + + return ( + + ); +}; + +const ActivityDescription = ({ + transaction, + colors, +}: { + transaction: RainbowTransaction; + colors: Colors; +}) => { + const { type, to, asset } = transaction; + let description = transaction.description; + let tag: string | undefined; + if (type === 'contract_interaction' && to) { + description = transaction.contract?.name || address(to, 6, 4); + tag = transaction.description; + } + + const nftChangesAmount = transaction.changes + ?.filter( + c => asset?.address === c?.asset.address && c?.asset.type === 'nft' + ) + .filter(Boolean).length; + if (nftChangesAmount) tag = nftChangesAmount.toString(); + + return ( + + + {description} + + {tag && ( + + {tag} + + )} + + ); +}; + export default React.memo(function TransactionCoinRow({ item, theme, @@ -99,6 +453,8 @@ export default React.memo(function TransactionCoinRow({ }); }, [item, navigation]); + const [topValue, bottomValue] = activityValues(item) ?? []; + return ( - {item.asset?.type === 'nft' ? ( - - - - - {item.network !== Network.mainnet && ( - - )} - - ) : ( - - )} + - + - {item.balance?.display ?? ''} + {topValue} - + diff --git a/src/components/coin-row/FastTransactionStatusBadge.tsx b/src/components/coin-row/FastTransactionStatusBadge.tsx index 489c7effd34..b80f51546b3 100644 --- a/src/components/coin-row/FastTransactionStatusBadge.tsx +++ b/src/components/coin-row/FastTransactionStatusBadge.tsx @@ -3,12 +3,17 @@ import { StyleProp, StyleSheet, View, ViewStyle } from 'react-native'; import Spinner from '../Spinner'; import { Icon } from '../icons'; import { Text } from '@/design-system'; -import { TransactionStatus, TransactionStatusTypes } from '@/entities'; +import { + RainbowTransaction, + TransactionStatus, + TransactionStatusTypes, +} from '@/entities'; import { position } from '@/styles'; import { ThemeContextProps } from '@/theme'; import * as lang from '@/languages'; import { TransactionType } from '@/resources/transactions/types'; import { transactionTypes } from '@/entities/transactions/transactionType'; +import { ActivityTypeIcon } from './FastTransactionCoinRow'; const StatusProps = { [TransactionStatusTypes.approved]: { @@ -162,43 +167,35 @@ const sx = StyleSheet.create({ }); export default React.memo(function FastTransactionStatusBadge({ - pending, - type, + transaction, style, - title, colors, }: { + transaction: RainbowTransaction; colors: ThemeContextProps['colors']; - pending: boolean; - type: TransactionType; - title: string; style?: StyleProp; }) { let statusColor = colors.alpha(colors.blueGreyDark, 0.7); - if (pending) { + if (transaction?.pending) { statusColor = colors.appleBlue; } - const showIcon = !!StatusProps[type]; - return ( - {pending && ( + {transaction?.pending && ( )} - {showIcon && ( - - )} + - {title} + {transaction?.title} ); diff --git a/src/components/expanded-state/asset/ChartExpandedState.js b/src/components/expanded-state/asset/ChartExpandedState.js index 3199f4aaa57..e294a75769a 100644 --- a/src/components/expanded-state/asset/ChartExpandedState.js +++ b/src/components/expanded-state/asset/ChartExpandedState.js @@ -209,11 +209,6 @@ export default function ChartExpandedState({ asset }) { : { ...asset }; }, [asset, genericAsset, hasBalance, nativeCurrency]); - if (assetWithPrice?.mainnet_address) { - assetWithPrice.l2Address = asset?.address; - assetWithPrice.address = assetWithPrice.mainnet_address; - } - const isL2 = useMemo(() => isL2Network(assetWithPrice.network), [ assetWithPrice.network, ]); diff --git a/src/hooks/charts/useChartThrottledPoints.ts b/src/hooks/charts/useChartThrottledPoints.ts index d24ab49a76c..1bb1c11bfbc 100644 --- a/src/hooks/charts/useChartThrottledPoints.ts +++ b/src/hooks/charts/useChartThrottledPoints.ts @@ -118,7 +118,6 @@ export default function useChartThrottledPoints({ } = usePriceChart({ address: asset.address, network: asset.network, - mainnetAddress: asset?.mainnet_address || asset?.mainnetAddress, }); const [throttledPoints, setThrottledPoints] = useState(() => traverseData({ nativePoints: [], points: [] }, chart) diff --git a/src/hooks/useTransactionConfirmation.ts b/src/hooks/useTransactionConfirmation.ts index e16420babe7..d9f9d19d4d5 100644 --- a/src/hooks/useTransactionConfirmation.ts +++ b/src/hooks/useTransactionConfirmation.ts @@ -1,10 +1,8 @@ -import { dataAddNewTransaction } from '../redux/data'; import { removeRequest } from '../redux/requests'; import { walletConnectSendStatus } from '../redux/walletconnect'; export default function useTransactionConfirmation() { return { - dataAddNewTransaction, removeRequest, walletConnectSendStatus, }; diff --git a/src/redux/data.ts b/src/redux/data.ts index 0b0d164eae6..2f52642068b 100644 --- a/src/redux/data.ts +++ b/src/redux/data.ts @@ -2,7 +2,7 @@ import { StaticJsonRpcProvider, TransactionResponse, } from '@ethersproject/providers'; -import { isEmpty, isNil, mapValues, partition } from 'lodash'; +import { isEmpty, isNil, mapValues } from 'lodash'; import { Dispatch } from 'redux'; import { ThunkDispatch } from 'redux-thunk'; import { @@ -94,7 +94,6 @@ export interface DataState { /** * Whether or not transactions are currently being loaded. */ - isLoadingTransactions: boolean; /** * Pending transactions for this account. @@ -151,13 +150,6 @@ interface DataUpdateEthUsdAction { payload: number | undefined; } -/** - * The action to set `isLoadingTransactions` to `true`. - */ -interface DataLoadTransactionsRequestAction { - type: typeof DATA_LOAD_TRANSACTIONS_REQUEST; -} - /** * The action used to update transactions and indicate that loading transactions * was successful. @@ -517,11 +509,7 @@ export const transactionsReceived = ( } if (appended && potentialNftTransaction) { - setTimeout(() => { - queryClient.invalidateQueries({ - queryKey: nftsQueryKey({ address: accountAddress }), - }); - }, 60000); + setTimeout(() => {}, 60000); } const txHashes = parsedTransactions.map(tx => ethereumUtils.getHash(tx)); @@ -1062,7 +1050,6 @@ export const watchPendingTransactions = ( const INITIAL_STATE: DataState = { ethUSDPrice: null, genericAssets: {}, - isLoadingTransactions: true, pendingTransactions: [], portfolios: {}, transactions: [], @@ -1082,21 +1069,14 @@ export default (state: DataState = INITIAL_STATE, action: DataAction) => { ...state, ethUSDPrice: action.payload, }; - case DATA_LOAD_TRANSACTIONS_REQUEST: - return { - ...state, - isLoadingTransactions: true, - }; case DATA_LOAD_TRANSACTIONS_SUCCESS: return { ...state, - isLoadingTransactions: false, transactions: action.payload, }; case DATA_LOAD_TRANSACTIONS_FAILURE: return { ...state, - isLoadingTransactions: false, }; case DATA_UPDATE_PENDING_TRANSACTIONS_SUCCESS: return { diff --git a/src/screens/transaction-details/components/TransactionDetailsValueAndFeeSection.tsx b/src/screens/transaction-details/components/TransactionDetailsValueAndFeeSection.tsx index 95368281c53..1b5f1c52c5b 100644 --- a/src/screens/transaction-details/components/TransactionDetailsValueAndFeeSection.tsx +++ b/src/screens/transaction-details/components/TransactionDetailsValueAndFeeSection.tsx @@ -5,23 +5,21 @@ import { RainbowTransaction, RainbowTransactionFee, } from '@/entities/transactions/transaction'; -import { CoinIcon } from '@/components/coin-icon'; -import { Box, Stack } from '@/design-system'; +import { Box, Stack, globalColors } from '@/design-system'; import { TransactionDetailsDivider } from '@/screens/transaction-details/components/TransactionDetailsDivider'; import * as i18n from '@/languages'; import { AssetTypes } from '@/entities'; -import { ethereumUtils } from '@/utils'; import { Network } from '@/networks/types'; -import { useUserAsset } from '@/resources/assets/useUserAsset'; -import { - convertAmountAndPriceToNativeDisplay, - convertAmountToBalanceDisplay, - convertAmountToNativeDisplay, -} from '@/helpers/utilities'; -s; +import { convertAmountAndPriceToNativeDisplay } from '@/helpers/utilities'; import { useAccountSettings } from '@/hooks'; import { useTheme } from '@/theme'; import FastCoinIcon from '@/components/asset-list/RecyclerAssetList2/FastComponents/FastCoinIcon'; +import { View } from 'react-native'; +import { ImgixImage } from '@/components/images'; +import { CardSize } from '@/components/unique-token/CardSize'; +import ChainBadge from '@/components/coin-icon/ChainBadge'; +import { ETH_ADDRESS } from '@rainbow-me/swaps'; +import { ETH_SYMBOL } from '@/references'; type Props = { transaction: RainbowTransaction; @@ -35,17 +33,12 @@ export const TransactionDetailsValueAndFeeSection: React.FC = ({ }) => { const theme = useTheme(); const { nativeCurrency } = useAccountSettings(); - const { network, symbol, type, fee } = transaction; + const { fee } = transaction; const assetData = transaction?.asset; const change = transaction?.changes?.[0]; - const coinAddress = assetData?.address; - const mainnetCoinAddress = assetData?.mainnet_address; - const coinSymbol = assetData?.symbol ?? symbol ?? undefined; - const coinType = - assetData?.type ?? network !== Network.mainnet ? network : AssetTypes.token; - - const value = change?.asset?.balance?.display || transaction.balance?.display; + const value = change?.value || transaction.balance?.display; + console.log(' VAL: ', change?.value); const nativeCurrencyValue = convertAmountAndPriceToNativeDisplay( change?.asset?.balance?.amount || '', change?.asset?.price?.value || '', @@ -61,13 +54,57 @@ export const TransactionDetailsValueAndFeeSection: React.FC = ({ {true && ( + assetData?.type === 'nft' ? ( + + + + + {transaction.network !== Network.mainnet && ( + + )} + + ) : ( + + ) } title={i18n.t(i18n.l.transaction_details.value)} value={value || ''} diff --git a/src/utils/abbreviations.ts b/src/utils/abbreviations.ts index 7145c772830..2cb9d829f1d 100644 --- a/src/utils/abbreviations.ts +++ b/src/utils/abbreviations.ts @@ -7,8 +7,8 @@ export function address( currentAddress: EthereumAddress, truncationLength = defaultNumCharsPerSection, firstSectionLength: number -): string | undefined { - if (!currentAddress) return; +): string { + if (!currentAddress) return ''; return [ currentAddress.substring(0, firstSectionLength || truncationLength), @@ -20,7 +20,7 @@ export function formatAddressForDisplay( text: string, truncationLength = 4, firstSectionLength = 10 -): string | undefined { +): string { return isValidDomainFormat(text) ? text : address(text, truncationLength, firstSectionLength); diff --git a/src/walletConnect/__tests__/index.test b/src/walletConnect/__tests__/index.test index fab06052951..63109a6cfa7 100644 --- a/src/walletConnect/__tests__/index.test +++ b/src/walletConnect/__tests__/index.test @@ -1,6 +1,5 @@ import { jest, test } from '@jest/globals'; import { isAddress } from '@ethersproject/address'; -import Minimizer from 'react-native-minimizer'; import { nanoid } from 'nanoid/non-secure'; import { Web3WalletTypes } from '@walletconnect/web3wallet'; @@ -164,7 +163,6 @@ test(`maybeGoBackAndClearHasPendingRedirect`, () => { jest.advanceTimersByTime(1); - expect(Minimizer.goBack).toHaveBeenCalled(); jest.useRealTimers(); }); From 30d5a0e717ec012ba3d8b116df6694ad2ff4f04b Mon Sep 17 00:00:00 2001 From: skylarbarrera Date: Tue, 6 Feb 2024 00:17:01 -0500 Subject: [PATCH 14/38] lint --- .prettierignore | 1 + .../coin-row/FastTransactionCoinRow.tsx | 45 +---- src/entities/f2c.ts | 1 - src/entities/transactions/transaction.ts | 19 +-- .../buildTransactionsSectionsSelector.tsx | 3 - src/helpers/transactions.ts | 36 +--- src/hooks/usePendingTransactions.ts | 18 +- src/hooks/useWalletsWithBalancesAndNames.ts | 2 +- src/notifications/NotificationsHandler.tsx | 25 +-- src/parsers/newTransaction.ts | 29 +--- src/raps/actions/crosschainSwap.ts | 3 +- src/raps/actions/swap.ts | 2 +- src/redux/data.ts | 154 +----------------- .../AddCash/components/ProviderCard.tsx | 1 - src/screens/SignTransactionSheet.tsx | 12 +- .../TransactionDetails.tsx | 2 +- .../DoubleLineTransactionDetailsRow.tsx | 2 +- ...etailsStatusActionsAndTimestampSection.tsx | 3 +- .../TransactionDetailsValueAndFeeSection.tsx | 1 - ...conColorAndGradientForTransactionStatus.ts | 9 +- src/state/internal/createStore.ts | 9 +- src/state/pendingTransactionsStore.ts | 2 +- src/utils/ethereumUtils.ts | 4 +- 23 files changed, 74 insertions(+), 309 deletions(-) diff --git a/.prettierignore b/.prettierignore index 841fb0f80b9..04a5a05c1b8 100644 --- a/.prettierignore +++ b/.prettierignore @@ -10,3 +10,4 @@ rainbow-scripts .vscode __generated__ coverage +src/state/internal diff --git a/src/components/coin-row/FastTransactionCoinRow.tsx b/src/components/coin-row/FastTransactionCoinRow.tsx index cdc97c1ae41..28355a53728 100644 --- a/src/components/coin-row/FastTransactionCoinRow.tsx +++ b/src/components/coin-row/FastTransactionCoinRow.tsx @@ -16,10 +16,7 @@ import { ETH_ADDRESS, ETH_SYMBOL } from '@/references'; import { address } from '@/utils/abbreviations'; import { Colors } from '@/styles'; import { TransactionType } from '@/resources/transactions/types'; -import { - convertAmountAndPriceToNativeDisplay, - convertAmountToBalanceDisplay, -} from '@/helpers/utilities'; +import { convertAmountToBalanceDisplay } from '@/helpers/utilities'; export const getApprovalLabel = ({ approvalAmount, @@ -165,35 +162,7 @@ const BottomRow = React.memo(function BottomRow({ transaction: RainbowTransaction; theme: ThemeContextProps; }) { - const { status, type, native, to, asset } = transaction; - const { colors } = theme; - const isFailed = status === TransactionStatusTypes.failed; - const isReceived = - status === TransactionStatusTypes.received || - status === TransactionStatusTypes.purchased; - const isSent = status === TransactionStatusTypes.sent; - const isSold = status === TransactionStatusTypes.sold; - - const isOutgoingSwap = status === TransactionStatusTypes.swapped; - const isIncomingSwap = - status === TransactionStatusTypes.received && - type === TransactionTypes.trade; - - let coinNameColor = colors.dark; - if (isOutgoingSwap) coinNameColor = colors.blueGreyDark50; - - let balanceTextColor = colors.blueGreyDark50; - if (isReceived) balanceTextColor = colors.green; - if (isSent) balanceTextColor = colors.dark; - if (isIncomingSwap) balanceTextColor = colors.swapPurple; - if (isOutgoingSwap) balanceTextColor = colors.dark; - if (isSold) balanceTextColor = colors.green; - - const balanceText = native?.display - ? [isFailed || isSent ? '-' : null, native.display] - .filter(Boolean) - .join(' ') - : ''; + const { type, to, asset } = transaction; let description = transaction.description; let tag: string | undefined; @@ -215,7 +184,7 @@ const BottomRow = React.memo(function BottomRow({ @@ -228,15 +197,15 @@ const BottomRow = React.memo(function BottomRow({ borderRadius: 5, width: 20, height: 20, - borderColor: colors.dark, + borderColor: theme.colors.dark, alignItems: 'center', }} > {tag} @@ -249,7 +218,7 @@ const BottomRow = React.memo(function BottomRow({ align="right" color={bottomValue?.includes('+') ? 'green' : 'labelSecondary'} size="16px / 22px (Deprecated)" - weight={isReceived ? 'medium' : undefined} + weight={'medium'} > {bottomValue} diff --git a/src/entities/f2c.ts b/src/entities/f2c.ts index 1aff8768a97..2b69b525c01 100644 --- a/src/entities/f2c.ts +++ b/src/entities/f2c.ts @@ -1,5 +1,4 @@ export enum FiatProviderName { - Ratio = 'ratio', Ramp = 'ramp', Coinbase = 'coinbase', Moonpay = 'moonpay', diff --git a/src/entities/transactions/transaction.ts b/src/entities/transactions/transaction.ts index 5084fb05b9a..677c00cb099 100644 --- a/src/entities/transactions/transaction.ts +++ b/src/entities/transactions/transaction.ts @@ -18,7 +18,13 @@ export type TransactionDirection = 'in' | 'out' | 'self'; export interface RainbowTransaction { address?: string; - asset?: ParsedAsset | null; + asset?: + | (ParsedAsset & { + asset_contract?: { + address?: string; + }; + }) + | null; balance?: { amount: string; display: string; @@ -79,16 +85,6 @@ export interface RainbowTransaction { type: TransactionType; value?: BigNumberish; // for pending tx fee?: RainbowTransactionFee; - fiatProvider?: { - name: FiatProviderName.Ratio; - orderId: string; - userId: string; - /** - * Required for all providers, used to associate requests with transaction - * data once we receive it. - */ - analyticsSessionId: string; - }; // etc { name: FiatProviderName.Ramp, orderId: string } } export type MinedTransaction = RainbowTransaction & { @@ -101,6 +97,7 @@ export type MinedTransaction = RainbowTransaction & { }; export type NewTransaction = Omit & { + amount?: string; gasLimit?: BigNumberish; changes?: Array< | { diff --git a/src/helpers/buildTransactionsSectionsSelector.tsx b/src/helpers/buildTransactionsSectionsSelector.tsx index e656db21e52..474837866f3 100644 --- a/src/helpers/buildTransactionsSectionsSelector.tsx +++ b/src/helpers/buildTransactionsSectionsSelector.tsx @@ -79,9 +79,6 @@ export const buildTransactionsSections = ({ contacts: { [address: string]: Contact }; requests: RequestData[]; theme: ThemeContextProps; - isFocused: boolean; - initialized: boolean; - navigate: (...args: any[]) => void; transactions: RainbowTransaction[]; }) => { if (!transactions) { diff --git a/src/helpers/transactions.ts b/src/helpers/transactions.ts index b8057fd0314..3fb8fe52528 100644 --- a/src/helpers/transactions.ts +++ b/src/helpers/transactions.ts @@ -1,8 +1,4 @@ -import { - TransactionStatus, - TransactionType, - TransactionTypes, -} from '@/entities'; +import { TransactionStatus } from '@/entities'; export const calculateTimestampOfToday = () => { const d = new Date(); @@ -36,33 +32,3 @@ export const todayTimestamp = calculateTimestampOfToday(); export const yesterdayTimestamp = calculateTimestampOfYesterday(); export const thisMonthTimestamp = calculateTimestampOfThisMonth(); export const thisYearTimestamp = calculateTimestampOfThisYear(); - -/** - * Returns the `TransactionStatus` that represents completion for a given - * transaction type. - * - * @param type The transaction type. - * @returns The confirmed status. - */ -export const getConfirmedState = ( - type?: TransactionType -): TransactionStatus => { - switch (type) { - case TransactionTypes.authorize: - return TransactionStatus.approved; - case TransactionTypes.deposit: - return TransactionStatus.deposited; - case TransactionTypes.withdraw: - return TransactionStatus.withdrew; - case TransactionTypes.receive: - return TransactionStatus.received; - case TransactionTypes.purchase: - return TransactionStatus.purchased; - case TransactionTypes.sell: - return TransactionStatus.sold; - case TransactionTypes.mint: - return TransactionStatus.minted; - default: - return TransactionStatus.sent; - } -}; diff --git a/src/hooks/usePendingTransactions.ts b/src/hooks/usePendingTransactions.ts index b734f57ba0e..e034347fcd9 100644 --- a/src/hooks/usePendingTransactions.ts +++ b/src/hooks/usePendingTransactions.ts @@ -1,13 +1,19 @@ -import { useCallback } from 'react'; -import { useSelector } from 'react-redux'; -import { AppState } from '@/redux/store'; +import { useCallback, useMemo } from 'react'; import { ethereumUtils, isLowerCaseMatch } from '@/utils'; +import { usePendingTransactionsStore } from '@/state/pendingTransactionsStore'; + +import useAccountSettings from './useAccountSettings'; export default function usePendingTransactions() { - const pendingTransactions = useSelector( - ({ data }: AppState) => data.pendingTransactions - ); + const { accountAddress } = useAccountSettings(); + const { + pendingTransactions: storePendingTransactions, + } = usePendingTransactionsStore(); + const pendingTransactions = useMemo( + () => storePendingTransactions[accountAddress] || [], + [accountAddress, storePendingTransactions] + ); const getPendingTransactionByHash = useCallback( (transactionHash: string) => pendingTransactions.find(pendingTransaction => diff --git a/src/hooks/useWalletsWithBalancesAndNames.ts b/src/hooks/useWalletsWithBalancesAndNames.ts index d44a9793942..ebfc60cf60d 100644 --- a/src/hooks/useWalletsWithBalancesAndNames.ts +++ b/src/hooks/useWalletsWithBalancesAndNames.ts @@ -12,7 +12,7 @@ export default function useWalletsWithBalancesAndNames() { mapValues(wallets, wallet => { const updatedAccounts = (wallet.addresses ?? []).map(account => ({ ...account, - balance: walletBalances[account.address], + balance: walletBalances?.[account.address], ens: walletNames[account.address], })); return { ...wallet, addresses: updatedAccounts }; diff --git a/src/notifications/NotificationsHandler.tsx b/src/notifications/NotificationsHandler.tsx index 25621f65243..3a9145b9b0a 100644 --- a/src/notifications/NotificationsHandler.tsx +++ b/src/notifications/NotificationsHandler.tsx @@ -38,9 +38,8 @@ import { getProviderForNetwork } from '@/handlers/web3'; import { ethereumUtils, isLowerCaseMatch } from '@/utils'; import { NewTransactionOrAddCashTransaction } from '@/entities/transactions/transaction'; import { TransactionDirection, TransactionStatus } from '@/entities'; -import { getTitle, getTransactionLabel, parseNewTransaction } from '@/parsers'; +import { parseNewTransaction } from '@/parsers'; import { isZero } from '@/helpers/utilities'; -import { getConfirmedState } from '@/helpers/transactions'; import { mapNotificationTransactionType } from '@/notifications/mapTransactionsType'; import walletTypes from '@/helpers/walletTypes'; import { @@ -229,7 +228,7 @@ export const NotificationsHandler = ({ walletReady }: Props) => { gasPrice: rpcTransaction.gasPrice, data: rpcTransaction.data, }; - return; + const parsedTransaction = await parseNewTransaction( newTransactionDetails, nativeCurrency @@ -249,7 +248,8 @@ export const NotificationsHandler = ({ walletReady }: Props) => { resultTransaction.status = TransactionStatus.failed; } else { // cancelled or replaced - resultTransaction.status = TransactionStatus.cancelled; + resultTransaction.type = 'cancel'; + resultTransaction.status = TransactionStatus.failed; } } const status = receipt?.status || 0; @@ -269,26 +269,9 @@ export const NotificationsHandler = ({ walletReady }: Props) => { ) { direction = TransactionDirection.in; } - - const newStatus = getTransactionLabel({ - direction, - pending: false, - protocol: parsedTransaction?.protocol, - status: - parsedTransaction.status === TransactionStatus.cancelling - ? TransactionStatus.cancelled - : getConfirmedState(parsedTransaction.type), - type: parsedTransaction?.type, - }); - resultTransaction.status = newStatus; } else { resultTransaction.status = TransactionStatus.failed; } - resultTransaction.title = getTitle({ - protocol: parsedTransaction.protocol, - status: resultTransaction.status, - type: parsedTransaction.type, - }); resultTransaction.pending = false; resultTransaction.minedAt = minedAt; diff --git a/src/parsers/newTransaction.ts b/src/parsers/newTransaction.ts index f7af679e8f9..72e92b044e1 100644 --- a/src/parsers/newTransaction.ts +++ b/src/parsers/newTransaction.ts @@ -1,10 +1,7 @@ -import { getDescription, getTitle } from './transactions'; import { NativeCurrencyKey, NewTransactionOrAddCashTransaction, RainbowTransaction, - TransactionStatus, - TransactionType, } from '@/entities'; import { isL2Network } from '@/handlers/web3'; import { ETH_ADDRESS } from '@/references'; @@ -28,7 +25,6 @@ export const parseNewTransaction = async ( const { amount, asset, - dappName, data, from, flashbots, @@ -41,17 +37,16 @@ export const parseNewTransaction = async ( network, nft, nonce, - hash: txHash, + hash, protocol, sourceAmount, - status: txStatus, + status, to, transferId, - type: txType, + type, txTo, value, swap, - fiatProvider, } = txDetails; if (amount && asset) { @@ -72,21 +67,6 @@ export const parseNewTransaction = async ( assetPrice, nativeCurrency ); - const hash = txHash ? `${txHash}-0` : null; - - const status = txStatus ?? TransactionStatus.sending; - const type = txType ?? TransactionType.send; - - const title = getTitle({ - protocol: protocol ?? null, - status, - type, - }); - - const nftName = - type === TransactionType.authorize ? nft?.collection.name : nft?.name; - - const description = 'yo it me'; return { address: asset?.address ?? ETH_ADDRESS, @@ -112,13 +92,12 @@ export const parseNewTransaction = async ( sourceAmount, status, symbol: asset?.symbol ?? null, - title, + title: 'oops', to, transferId, txTo: txTo || to, type, value, swap, - fiatProvider, }; }; diff --git a/src/raps/actions/crosschainSwap.ts b/src/raps/actions/crosschainSwap.ts index a00e8882f2b..a9e91a2ac2b 100644 --- a/src/raps/actions/crosschainSwap.ts +++ b/src/raps/actions/crosschainSwap.ts @@ -145,6 +145,7 @@ const crosschainSwap = async ( logger.log(`[${actionName}] response`, swap); const isBridge = inputCurrency.symbol === outputCurrency.symbol; + if (!swap?.hash) return; const newTransaction: NewTransaction = { data: swap?.data, @@ -164,7 +165,7 @@ const crosschainSwap = async ( value: tradeDetails.buyAmount.toString(), }, ], - hash: swap?.hash, + hash: swap.hash, network: inputCurrency.network, nonce: swap?.nonce, status: 'pending', diff --git a/src/raps/actions/swap.ts b/src/raps/actions/swap.ts index fd5fadb5b54..4bf464284c8 100644 --- a/src/raps/actions/swap.ts +++ b/src/raps/actions/swap.ts @@ -208,7 +208,7 @@ const swap = async ( logger.log(`[${actionName}] response`, swap); - if (!swap) throw Error; + if (!swap || !swap?.hash) throw Error; const newTransaction: NewTransaction = { data: swap?.data, diff --git a/src/redux/data.ts b/src/redux/data.ts index 2f52642068b..b68654ceedb 100644 --- a/src/redux/data.ts +++ b/src/redux/data.ts @@ -39,9 +39,7 @@ import { ethereumUtils, isLowerCaseMatch } from '@/utils'; import logger from '@/utils/logger'; import { fetchWalletENSDataAfterRegistration, - getPendingTransactionData, getTransactionFlashbotStatus, - getTransactionReceiptStatus, getTransactionSocketStatus, } from '@/handlers/transactions'; import { SwapType } from '@rainbow-me/swaps'; @@ -91,6 +89,7 @@ export interface DataState { [assetAddress: string]: ParsedAddressAsset; }; + isLoadingTransactions: boolean; /** * Whether or not transactions are currently being loaded. */ @@ -150,6 +149,13 @@ interface DataUpdateEthUsdAction { payload: number | undefined; } +/** + * The action to set `isLoadingTransactions` to `true`. + */ +interface DataLoadTransactionsRequestAction { + type: typeof DATA_LOAD_TRANSACTIONS_REQUEST; +} + /** * The action used to update transactions and indicate that loading transactions * was successful. @@ -445,7 +451,6 @@ export const transactionsReceived = ( >, getState: AppGetState ) => { - return; loggr.debug('transactionsReceived', { message: { ...message, @@ -481,20 +486,6 @@ export const transactionsReceived = ( loggr.debug('transactionsReceived: attempting to parse transactions'); - const { - parsedTransactions, - potentialNftTransaction, - } = await parseTransactions( - transactionData, - accountAddress, - nativeCurrency, - transactions, - pendingTransactions, - undefined, - currentNetwork, - appended - ); - const isCurrentAccountAddress = accountAddress === getState().settings.accountAddress; if (!isCurrentAccountAddress) { @@ -507,46 +498,6 @@ export const transactionsReceived = ( ); return; } - - if (appended && potentialNftTransaction) { - setTimeout(() => {}, 60000); - } - - const txHashes = parsedTransactions.map(tx => ethereumUtils.getHash(tx)); - const updatedPendingTransactions = pendingTransactions.filter( - tx => !txHashes.includes(ethereumUtils.getHash(tx)) - ); - - dispatch({ - payload: updatedPendingTransactions, - type: DATA_UPDATE_PENDING_TRANSACTIONS_SUCCESS, - }); - dispatch({ - payload: parsedTransactions, - type: DATA_LOAD_TRANSACTIONS_SUCCESS, - }); - saveLocalTransactions(parsedTransactions, accountAddress, network); - saveLocalPendingTransactions( - updatedPendingTransactions, - accountAddress, - network - ); - - if (appended && parsedTransactions.length) { - if ( - selected && - !selected.backedUp && - !selected.imported && - selected.type !== WalletTypes.readOnly && - selected.type !== WalletTypes.bluetooth - ) { - setTimeout(() => { - triggerOnSwipeLayout(() => - Navigation.handleAction(Routes.BACKUP_SHEET, { single: true }) - ); - }, BACKUP_SHEET_DELAY_MS); - } - } }; const callbacksOnAssetReceived: { @@ -693,7 +644,6 @@ export const dataAddNewTransaction = ( >, getState: AppGetState ) => { - return; loggr.debug('dataAddNewTransaction', {}, loggr.DebugContext.f2c); const { pendingTransactions } = getState().data; @@ -828,92 +778,6 @@ export const dataWatchPendingTransactions = ( if (isEmpty(pending)) { return true; } - let txStatusesDidChange = false; - const updatedPendingTransactions = await Promise.all( - pending.map(async tx => { - const updatedPendingTransaction: RainbowTransaction = { ...tx }; - const txHash = ethereumUtils.getHash(tx) || ''; - let pendingTransactionData: { - title: string; - minedAt: number | null; - pending: boolean; - status: TransactionStatus; - } | null = { - status: TransactionStatus.sending, - title: tx?.title || TransactionStatus.sending, - minedAt: null, - pending: true, - }; - return; - try { - logger.log('Checking pending tx with hash', txHash); - const p = - (await getProviderForNetwork(updatedPendingTransaction.network)) || - provider; - const txObj: TransactionResponse | undefined = await p.getTransaction( - txHash - ); - // if the nonce of last confirmed tx is higher than this pending tx then it got dropped - const nonceAlreadyIncluded = currentNonce > (tx?.nonce ?? txObj.nonce); - if ( - (txObj && txObj?.blockNumber && txObj?.blockHash) || - nonceAlreadyIncluded - ) { - // When speeding up a non "normal tx" we need to resubscribe - // because zerion "append" event isn't reliable - logger.log('TX CONFIRMED!', txObj); - if (!nonceAlreadyIncluded) { - appEvents.emit('transactionConfirmed', { - ...txObj, - internalType: tx.type, - }); - } - if (tx?.ensRegistration) { - fetchWalletENSDataAfterRegistration(); - } - - if (updatedPendingTransaction?.swap?.type === SwapType.crossChain) { - pendingTransactionData = await getTransactionSocketStatus( - updatedPendingTransaction - ); - if (!pendingTransactionData.pending) { - appEvents.emit('transactionConfirmed', { - ...txObj, - internalType: tx.type, - }); - txStatusesDidChange = true; - } - } else { - pendingTransactionData = getPendingTransactionData( - updatedPendingTransaction, - transactionStatus - ); - txStatusesDidChange = true; - } - } else if (tx.flashbots) { - pendingTransactionData = await getTransactionFlashbotStatus( - updatedPendingTransaction, - txHash - ); - if (pendingTransactionData && !pendingTransactionData.pending) { - txStatusesDidChange = true; - // decrement the nonce since it was dropped - // @ts-ignore-next-line - dispatch(decrementNonce(tx.from!, tx.nonce!, Network.mainnet)); - } - } - if (pendingTransactionData) { - updatedPendingTransaction.title = pendingTransactionData.title; - updatedPendingTransaction.status = pendingTransactionData.status; - updatedPendingTransaction.pending = pendingTransactionData.pending; - updatedPendingTransaction.minedAt = pendingTransactionData.minedAt; - } - } catch (error) { - logger.log('Error watching pending txn', error); - } - return updatedPendingTransaction; - }) - ); return false; }; @@ -1024,7 +888,6 @@ export const watchPendingTransactions = ( dispatch: ThunkDispatch, getState: AppGetState ) => { - return; pendingTransactionsHandle && clearTimeout(pendingTransactionsHandle); if (remainingTries === 0) return; @@ -1052,6 +915,7 @@ const INITIAL_STATE: DataState = { genericAssets: {}, pendingTransactions: [], portfolios: {}, + isLoadingTransactions: false, transactions: [], }; diff --git a/src/screens/AddCash/components/ProviderCard.tsx b/src/screens/AddCash/components/ProviderCard.tsx index 5a22d5cdcf5..440484949ed 100644 --- a/src/screens/AddCash/components/ProviderCard.tsx +++ b/src/screens/AddCash/components/ProviderCard.tsx @@ -31,7 +31,6 @@ type PaymentMethodConfig = { const providerLogos = { [FiatProviderName.Ramp]: RampLogo, - [FiatProviderName.Ratio]: RatioLogo, [FiatProviderName.Coinbase]: CoinbaseLogo, [FiatProviderName.Moonpay]: MoonpayLogo, }; diff --git a/src/screens/SignTransactionSheet.tsx b/src/screens/SignTransactionSheet.tsx index e920e303850..9e6bf4dba08 100644 --- a/src/screens/SignTransactionSheet.tsx +++ b/src/screens/SignTransactionSheet.tsx @@ -973,8 +973,9 @@ export const SignTransactionSheet = () => { let txSavedInCurrentWallet = false; const displayDetails = transactionDetails.displayDetails; + let txDetails: NewTransaction | null = null; if (sendInsteadOfSign && sendResult?.hash) { - const txDetails: NewTransaction = { + txDetails = { asset: nativeAsset || displayDetails?.request?.asset, contract: { name: displayDetails.dappName, @@ -1036,13 +1037,14 @@ export const SignTransactionSheet = () => { closeScreen(false); // When the tx is sent from a different wallet, // we need to switch to that wallet before saving the tx - if (!txSavedInCurrentWallet) { + + if (!txSavedInCurrentWallet && !isNil(txDetails)) { InteractionManager.runAfterInteractions(async () => { - await switchToWalletWithAddress(txDetails.from!); + await switchToWalletWithAddress(txDetails?.from as string); addNewTransaction({ - transaction: txDetails, + transaction: txDetails as NewTransaction, network: currentNetwork || Network.mainnet, - address: txDetails?.from!, + address: txDetails?.from as string, }); }); } diff --git a/src/screens/transaction-details/TransactionDetails.tsx b/src/screens/transaction-details/TransactionDetails.tsx index 04eabcb1c3c..5f0b9139226 100644 --- a/src/screens/transaction-details/TransactionDetails.tsx +++ b/src/screens/transaction-details/TransactionDetails.tsx @@ -34,7 +34,7 @@ export const TransactionDetails = () => { hash: tx.hash || '', network: tx.network || Network.mainnet, }); - const transaction = data; + const transaction = data!; const [sheetHeight, setSheetHeight] = useState(0); const [statusIconHidden, setStatusIconHidden] = useState(false); const { presentedToast, presentToastFor } = useTransactionDetailsToasts(); diff --git a/src/screens/transaction-details/components/DoubleLineTransactionDetailsRow.tsx b/src/screens/transaction-details/components/DoubleLineTransactionDetailsRow.tsx index bd7f83e66dc..1ac5d1094a4 100644 --- a/src/screens/transaction-details/components/DoubleLineTransactionDetailsRow.tsx +++ b/src/screens/transaction-details/components/DoubleLineTransactionDetailsRow.tsx @@ -5,7 +5,7 @@ type Props = { leftComponent: React.ReactNode; secondaryValue?: string; title: string; - value: string; + value: string | number; }; export const DoubleLineTransactionDetailsRow: React.FC = ({ diff --git a/src/screens/transaction-details/components/TransactionDetailsStatusActionsAndTimestampSection.tsx b/src/screens/transaction-details/components/TransactionDetailsStatusActionsAndTimestampSection.tsx index 77ab340146a..8cf3c1f6ecc 100644 --- a/src/screens/transaction-details/components/TransactionDetailsStatusActionsAndTimestampSection.tsx +++ b/src/screens/transaction-details/components/TransactionDetailsStatusActionsAndTimestampSection.tsx @@ -38,8 +38,7 @@ export const TransactionDetailsStatusActionsAndTimestampSection: React.FC const { colors } = useTheme(); const { icon, color, gradient } = getIconColorAndGradientForTransactionStatus( colors, - status, - pending + status ); const isOutgoing = from?.toLowerCase() === accountAddress?.toLowerCase(); diff --git a/src/screens/transaction-details/components/TransactionDetailsValueAndFeeSection.tsx b/src/screens/transaction-details/components/TransactionDetailsValueAndFeeSection.tsx index 1b5f1c52c5b..e9a5cb5545f 100644 --- a/src/screens/transaction-details/components/TransactionDetailsValueAndFeeSection.tsx +++ b/src/screens/transaction-details/components/TransactionDetailsValueAndFeeSection.tsx @@ -8,7 +8,6 @@ import { import { Box, Stack, globalColors } from '@/design-system'; import { TransactionDetailsDivider } from '@/screens/transaction-details/components/TransactionDetailsDivider'; import * as i18n from '@/languages'; -import { AssetTypes } from '@/entities'; import { Network } from '@/networks/types'; import { convertAmountAndPriceToNativeDisplay } from '@/helpers/utilities'; import { useAccountSettings } from '@/hooks'; diff --git a/src/screens/transaction-details/helpers/getIconColorAndGradientForTransactionStatus.ts b/src/screens/transaction-details/helpers/getIconColorAndGradientForTransactionStatus.ts index ff15e3aa84e..8e514e77c82 100644 --- a/src/screens/transaction-details/helpers/getIconColorAndGradientForTransactionStatus.ts +++ b/src/screens/transaction-details/helpers/getIconColorAndGradientForTransactionStatus.ts @@ -1,23 +1,22 @@ -import { TransactionStatus } from '@/entities'; +import { TransactionStatus } from '@/resources/transactions/types'; import { ThemeContextProps } from '@/theme'; export function getIconColorAndGradientForTransactionStatus( colors: ThemeContextProps['colors'], - status?: TransactionStatus, - pending?: boolean + status?: TransactionStatus ): { icon: string; color: 'red' | 'blue' | 'labelSecondary'; gradient: string[]; } { - if (pending) { + if (status === 'pending') { return { icon: '􀖇', color: 'labelSecondary', gradient: colors.gradients.transparentToLightGrey, }; } - if (status === TransactionStatus.failed) { + if (status === 'failed') { return { icon: '􀆄', color: 'red', diff --git a/src/state/internal/createStore.ts b/src/state/internal/createStore.ts index 4e48af9b675..373ea35ae99 100644 --- a/src/state/internal/createStore.ts +++ b/src/state/internal/createStore.ts @@ -1,8 +1,9 @@ -import { persist } from 'zustand/middleware'; +import { PersistOptions, persist } from 'zustand/middleware'; import create, { Mutate, StoreApi } from 'zustand/vanilla'; import { persistStorage } from './persistStorage'; + type Initializer = Parameters>[0]; export type StoreWithPersist = Mutate< StoreApi, @@ -12,12 +13,14 @@ export type StoreWithPersist = Mutate< }; export function createStore( - initializer: Initializer + initializer: Initializer, + { persist: persistOptions }: { persist?: PersistOptions } = {}, ) { - const name = `rainbow.zustand`; + const name = `rainbow.zustand.${persistOptions?.name}`; return Object.assign( create( persist(initializer, { + ...persistOptions, name, getStorage: () => (persistStorage), }), diff --git a/src/state/pendingTransactionsStore.ts b/src/state/pendingTransactionsStore.ts index 1d968d4ba8d..227c4e8eb21 100644 --- a/src/state/pendingTransactionsStore.ts +++ b/src/state/pendingTransactionsStore.ts @@ -1,6 +1,6 @@ import { RainbowTransaction, NewTransaction } from '@/entities/transactions'; import { createStore } from './internal/createStore'; -import { create } from 'zustand'; +import create from 'zustand'; import { parseNewTransaction } from '@/parsers/transactions'; import { Network } from '@/networks/types'; diff --git a/src/utils/ethereumUtils.ts b/src/utils/ethereumUtils.ts index 836a532ec78..2353470a5ce 100644 --- a/src/utils/ethereumUtils.ts +++ b/src/utils/ethereumUtils.ts @@ -25,6 +25,7 @@ import { GasFee, LegacySelectedGasFee, NativeCurrencyKey, + NewTransaction, ParsedAddressAsset, RainbowToken, RainbowTransaction, @@ -238,7 +239,8 @@ const getBalanceAmount = ( return amount; }; -const getHash = (txn: RainbowTransaction) => txn.hash?.split('-').shift(); +const getHash = (txn: RainbowTransaction | NewTransaction) => + txn.hash?.split('-').shift(); const formatGenericAsset = ( asset: ParsedAddressAsset, From 89a6898b5a07b90012fbd4773eb87f53329e79cc Mon Sep 17 00:00:00 2001 From: skylarbarrera Date: Wed, 7 Feb 2024 12:49:03 -0500 Subject: [PATCH 15/38] save --- src/components/coin-icon/TwoIconsIcon.tsx | 96 ++++----- .../coin-row/FastTransactionCoinRow.tsx | 182 ++++++++++-------- .../coin-row/FastTransactionStatusBadge.tsx | 20 +- src/entities/transactions/transaction.ts | 5 +- .../buildTransactionsSectionsSelector.tsx | 23 ++- src/hooks/useAccountTransactions.ts | 1 + src/languages/en_US.json | 150 ++++++++++++--- src/notifications/NotificationsHandler.tsx | 4 +- src/parsers/newTransaction.ts | 1 - src/parsers/transactions.ts | 3 +- src/raps/actions/crosschainSwap.ts | 1 - src/raps/actions/ens.ts | 1 - src/raps/actions/swap.ts | 1 - src/screens/ProfileScreen.js | 4 +- .../SettingsSheet/components/DevSection.tsx | 18 +- src/screens/SignTransactionSheet.tsx | 1 - .../TransactionDetailsValueAndFeeSection.tsx | 1 - src/state/pendingTransactionsStore.ts | 1 + 18 files changed, 319 insertions(+), 194 deletions(-) diff --git a/src/components/coin-icon/TwoIconsIcon.tsx b/src/components/coin-icon/TwoIconsIcon.tsx index 7839ca413c2..b8d60e0f112 100644 --- a/src/components/coin-icon/TwoIconsIcon.tsx +++ b/src/components/coin-icon/TwoIconsIcon.tsx @@ -1,20 +1,12 @@ import React from 'react'; import { Box } from '@/design-system'; -import FastCoinIcon from '../asset-list/RecyclerAssetList2/FastComponents/FastCoinIcon'; import { ParsedAddressAsset } from '@/entities'; -import MaskedView from '@react-native-masked-view/masked-view'; -import Svg, { ClipPath, Path } from 'react-native-svg'; import { useTheme } from '@/theme'; +import { ImgixImage } from '@/components/images'; +import ChainBadge from './ChainBadge'; -const Mask = () => ( - - - - - -); export function TwoCoinsIcon({ - size = 36, + size = 45, under, over, badge = true, @@ -25,50 +17,60 @@ export function TwoCoinsIcon({ badge?: boolean; }) { const theme = useTheme(); - const overSize = size * 0.75; - const underSize = size * 0.67; - - const network = over.network; + const overSize = size * 0.85; + const underSize = size * 0.75; return ( - } + - - - - + + + + + + + {badge && ( + + )} - {/* - {badge && chainId !== ChainId.mainnet && ( - - )} - */} ); } diff --git a/src/components/coin-row/FastTransactionCoinRow.tsx b/src/components/coin-row/FastTransactionCoinRow.tsx index 28355a53728..377a9ffa9f7 100644 --- a/src/components/coin-row/FastTransactionCoinRow.tsx +++ b/src/components/coin-row/FastTransactionCoinRow.tsx @@ -3,8 +3,15 @@ import { StyleSheet, View } from 'react-native'; import { ButtonPressAnimation } from '../animations'; import FastCoinIcon from '../asset-list/RecyclerAssetList2/FastComponents/FastCoinIcon'; import FastTransactionStatusBadge from './FastTransactionStatusBadge'; -import { Box, Inline, Text, globalColors, useColorMode } from '@/design-system'; -import { RainbowTransaction, TransactionStatusTypes } from '@/entities'; +import { + Bleed, + Box, + Inline, + Text, + globalColors, + useColorMode, +} from '@/design-system'; +import { NativeCurrencyKey, RainbowTransaction } from '@/entities'; import { ThemeContextProps } from '@/theme'; import { useNavigation } from '@/navigation'; import Routes from '@rainbow-me/routes'; @@ -16,7 +23,13 @@ import { ETH_ADDRESS, ETH_SYMBOL } from '@/references'; import { address } from '@/utils/abbreviations'; import { Colors } from '@/styles'; import { TransactionType } from '@/resources/transactions/types'; -import { convertAmountToBalanceDisplay } from '@/helpers/utilities'; +import { + convertAmountAndPriceToNativeDisplay, + convertAmountToBalanceDisplay, + greaterThan, +} from '@/helpers/utilities'; +import { TwoCoinsIcon } from '../coin-icon/TwoIconsIcon'; +import Spinner from '../Spinner'; export const getApprovalLabel = ({ approvalAmount, @@ -78,7 +91,10 @@ const swapTypeValues = (changes: RainbowTransaction['changes']) => { return [valueOut, valueIn]; }; -const activityValues = (transaction: RainbowTransaction) => { +const activityValues = ( + transaction: RainbowTransaction, + nativeCurrency: NativeCurrencyKey +) => { const { changes, direction, type } = transaction; if (['swap', 'wrap', 'unwrap'].includes(type)) return swapTypeValues(changes); if (['approve', 'revoke'].includes(type)) @@ -94,13 +110,21 @@ const activityValues = (transaction: RainbowTransaction) => { const { balance } = asset; if (balance?.amount === '0') return; - const assetValue = `${balance?.amount} ${asset.symbol}`; + const assetValue = convertAmountToBalanceDisplay( + balance?.amount || '0', + asset + ); - const nativeBalance = '0'; - const assetNativeValue = - +nativeBalance > 0 ? `${valueSymbol}${nativeBalance}` : 'no value'; + const nativeBalance = convertAmountAndPriceToNativeDisplay( + balance?.amount || '0', + asset?.price?.value || '0', + nativeCurrency + ); + const assetNativeValue = greaterThan(nativeBalance.amount, '0') + ? nativeBalance?.display + : 'no value'; - return +nativeBalance > 0 + return greaterThan(nativeBalance.amount, '0') ? [assetValue, assetNativeValue] : [assetNativeValue, `${valueSymbol}${assetValue}`]; }; @@ -135,21 +159,33 @@ const activityTypeIcon: Record = { export const ActivityTypeIcon = ({ transaction: { status, type }, + color, }: { transaction: Pick; + color: string; }) => { // if (status === 'pending') return null; + if (status === 'pending') { + return ( + + ); + } + if (status === 'failed') return ( - - {'X'} + + {'􀀲'} ); const symbol = activityTypeIcon[type]; if (!symbol) return null; return ( - + {symbol} ); @@ -157,9 +193,11 @@ export const ActivityTypeIcon = ({ const BottomRow = React.memo(function BottomRow({ transaction, + nativeCurrency, theme, }: { transaction: RainbowTransaction; + nativeCurrency: NativeCurrencyKey; theme: ThemeContextProps; }) { const { type, to, asset } = transaction; @@ -178,38 +216,42 @@ const BottomRow = React.memo(function BottomRow({ .filter(Boolean).length; if (nftChangesAmount) tag = nftChangesAmount.toString(); - const [topValue, bottomValue] = activityValues(transaction) ?? []; + const [topValue, bottomValue] = + activityValues(transaction, nativeCurrency) ?? []; return ( - + {description} {tag && ( - - + - {tag} - - + + {tag} + + + )} @@ -218,7 +260,8 @@ const BottomRow = React.memo(function BottomRow({ align="right" color={bottomValue?.includes('+') ? 'green' : 'labelSecondary'} size="16px / 22px (Deprecated)" - weight={'medium'} + weight={'regular'} + numberOfLines={1} > {bottomValue} @@ -229,40 +272,23 @@ const BottomRow = React.memo(function BottomRow({ export const ActivityIcon = ({ transaction, - size = 36, + size = 40, badge = true, theme, }: { transaction: RainbowTransaction; badge?: boolean; - size?: 36 | 20 | 14 | 16; + size?: 40 | 20 | 14 | 16; theme: ThemeContextProps; }) => { - if (['wrap', 'undwrap', 'swap'].includes(transaction?.type)) { + if (['wrap', 'unwrap', 'swap'].includes(transaction?.type)) { const inAsset = transaction?.changes?.find(a => a?.direction === 'in') ?.asset; const outAsset = transaction?.changes?.find(a => a?.direction === 'out') ?.asset; if (!!inAsset && !!outAsset) - return ( - - - - - ); + return ; } if (transaction?.contract?.iconUrl) { return ( @@ -272,8 +298,6 @@ export const ActivityIcon = ({ shadowOffset: { width: 0, height: 2 }, shadowOpacity: 0.02, shadowRadius: 3, - paddingTop: 9, - paddingBottom: 10, overflow: 'visible', }} > @@ -290,8 +314,8 @@ export const ActivityIcon = ({ {transaction.network !== Network.mainnet && ( - + )} ); @@ -314,8 +338,6 @@ export const ActivityIcon = ({ shadowOffset: { width: 0, height: 2 }, shadowOpacity: 0.02, shadowRadius: 3, - paddingTop: 9, - paddingBottom: 10, overflow: 'visible', }} > @@ -332,8 +354,8 @@ export const ActivityIcon = ({ {transaction.network !== Network.mainnet && ( - + )} ); @@ -385,7 +407,7 @@ const ActivityDescription = ({ {description} @@ -393,7 +415,7 @@ const ActivityDescription = ({ {tag && ( {tag} @@ -405,40 +427,44 @@ const ActivityDescription = ({ export default React.memo(function TransactionCoinRow({ item, + nativeCurrency, theme, }: { item: RainbowTransaction; + nativeCurrency: NativeCurrencyKey; theme: ThemeContextProps; }) { - const { colorMode } = useColorMode(); const { colors } = theme; const navigation = useNavigation(); const onPress = useCallback(() => { - console.log('changes: ', item?.changes?.[0]?.asset); - console.log('asset: ', item?.asset); navigation.navigate(Routes.TRANSACTION_DETAILS, { transaction: item, }); }, [item, navigation]); - const [topValue, bottomValue] = activityValues(item) ?? []; + const [topValue, bottomValue] = activityValues(item, nativeCurrency) ?? []; return ( - + - + + @@ -446,7 +472,11 @@ export default React.memo(function TransactionCoinRow({ - + @@ -473,6 +503,7 @@ const sx = StyleSheet.create({ }, description: { flex: 1, + maxWidth: '50%', }, icon: { justifyContent: 'center', @@ -489,5 +520,6 @@ const sx = StyleSheet.create({ justifyContent: 'space-between', paddingHorizontal: 19, overflow: 'visible', + height: 59, }, }); diff --git a/src/components/coin-row/FastTransactionStatusBadge.tsx b/src/components/coin-row/FastTransactionStatusBadge.tsx index b80f51546b3..272148e49df 100644 --- a/src/components/coin-row/FastTransactionStatusBadge.tsx +++ b/src/components/coin-row/FastTransactionStatusBadge.tsx @@ -2,7 +2,7 @@ import React from 'react'; import { StyleProp, StyleSheet, View, ViewStyle } from 'react-native'; import Spinner from '../Spinner'; import { Icon } from '../icons'; -import { Text } from '@/design-system'; +import { Text, useForegroundColor } from '@/design-system'; import { RainbowTransaction, TransactionStatus, @@ -175,27 +175,23 @@ export default React.memo(function FastTransactionStatusBadge({ colors: ThemeContextProps['colors']; style?: StyleProp; }) { - let statusColor = colors.alpha(colors.blueGreyDark, 0.7); - if (transaction?.pending) { + let statusColor = useForegroundColor('labelTertiary'); + if (transaction?.status === 'pending') { statusColor = colors.appleBlue; + } else if (transaction?.status === 'failed') { + statusColor = colors.red; } return ( - {transaction?.pending && ( - - )} - + - {transaction?.title} + {/* @ts-ignore */} + {lang.t(lang.l.transactions.type[transaction?.title])} ); diff --git a/src/entities/transactions/transaction.ts b/src/entities/transactions/transaction.ts index 677c00cb099..4544e6766f3 100644 --- a/src/entities/transactions/transaction.ts +++ b/src/entities/transactions/transaction.ts @@ -62,14 +62,13 @@ export interface RainbowTransaction { network: Network; nft?: UniqueAsset; nonce?: number | null; - pending?: boolean; protocol?: ProtocolType | null; flashbots?: boolean; approvalAmount?: 'UNLIMITED' | (string & object); ensCommitRegistrationName?: string; ensRegistration?: boolean; sourceAmount?: string; // for purchases - status?: TransactionStatus; + status: TransactionStatus; swap?: { type: SwapType; toChainId: ChainId; @@ -149,5 +148,5 @@ export interface NewTransactionOrAddCashTransaction export type MinimalTransactionDetails = Pick< RainbowTransaction, - 'minedAt' | 'hash' | 'type' | 'network' | 'from' | 'pending' | 'to' | 'status' + 'minedAt' | 'hash' | 'type' | 'network' | 'from' | 'to' | 'status' >; diff --git a/src/helpers/buildTransactionsSectionsSelector.tsx b/src/helpers/buildTransactionsSectionsSelector.tsx index 474837866f3..d46007fb1ef 100644 --- a/src/helpers/buildTransactionsSectionsSelector.tsx +++ b/src/helpers/buildTransactionsSectionsSelector.tsx @@ -9,11 +9,16 @@ import { todayTimestamp, yesterdayTimestamp, } from './transactions'; -import { RainbowTransaction, TransactionStatusTypes } from '@/entities'; +import { + NativeCurrencyKey, + RainbowTransaction, + TransactionStatusTypes, +} from '@/entities'; import * as i18n from '@/languages'; import { RequestData } from '@/redux/requests'; import { ThemeContextProps } from '@/theme'; import { Contact } from '@/redux/contacts'; +import { TransactionStatus } from '@/resources/transactions/types'; type RainbowTransactionWithContact = RainbowTransaction & { contact: Contact | null; @@ -25,13 +30,13 @@ type RainbowTransactionWithContactAndMainnetAddress = RainbowTransactionWithCont }; // bad news const groupTransactionByDate = ({ - pending, + status, minedAt, }: { - pending: boolean; + status: TransactionStatus; minedAt: string; }) => { - if (pending) { + if (status === 'pending') { return i18n.t(i18n.l.transactions.pending_title); } @@ -73,6 +78,7 @@ export const buildTransactionsSections = ({ requests, theme, transactions, + nativeCurrency, }: { accountAddress: string; mainnetAddresses: { [uniqueId: string]: string }; @@ -80,6 +86,7 @@ export const buildTransactionsSections = ({ requests: RequestData[]; theme: ThemeContextProps; transactions: RainbowTransaction[]; + nativeCurrency: NativeCurrencyKey; }) => { if (!transactions) { return { sections: [] }; @@ -136,7 +143,13 @@ export const buildTransactionsSections = ({ item, }: { item: RainbowTransactionWithContactAndMainnetAddress; - }) => , + }) => ( + + ), title: section, }; }); diff --git a/src/hooks/useAccountTransactions.ts b/src/hooks/useAccountTransactions.ts index 2405565cbf9..2d284bc2318 100644 --- a/src/hooks/useAccountTransactions.ts +++ b/src/hooks/useAccountTransactions.ts @@ -93,6 +93,7 @@ export default function useAccountTransactions() { requests, theme, transactions: slicedTransaction, + nativeCurrency, }; const { sections } = buildTransactionsSections(accountState); diff --git a/src/languages/en_US.json b/src/languages/en_US.json index a9711a7ffbc..15bda9c06d9 100644 --- a/src/languages/en_US.json +++ b/src/languages/en_US.json @@ -1828,34 +1828,128 @@ "pending_title": "Pending", "dropped_title": "Dropped", "type": { - "approved": "Approved", - "approving": "Approving", - "bridging": "Bridging", - "bridged": "Bridged", - "cancelled": "Cancelled", - "cancelling": "Cancelling", - "contract interaction": "Contract interaction", - "deposited": "Deposited", - "depositing": "Depositing", - "dropped": "Dropped", - "failed": "Failed", - "purchased": "Purchased", - "purchasing": "Purchasing", - "minting": "Minting", - "minted": "Minted", - "received": "Received", - "receiving": "Receiving", - "self": "Self", - "sending": "Sending", - "sent": "Sent", - "speeding up": "Speeding up", - "selling": "Selling", - "sold": "Sold", - "swapped": "Swapped", - "swapping": "Swapping", - "unknown": "Unknown", - "withdrawing": "Withdrawing", - "withdrew": "Withdrew" + "savings": "Savings", + "cancelled": "Transaction Cancelled", + "burn": { + "pending": "Burning", + "confirmed": "Burned", + "failed": "Burn Failed" + }, + "cancel": { + "pending": "Canceling", + "confirmed": "Cancelled", + "failed": "Cancel Failed" + }, + "send": { + "pending": "Sending", + "confirmed": "Sent", + "failed": "Send Failed" + }, + "receive": { + "pending": "", + "confirmed": "Received", + "failed": "" + }, + "withdraw": { + "pending": "Withdrawing", + "confirmed": "Withdrew", + "failed": "Withdraw Failed" + }, + "deposit": { + "pending": "Depositing", + "confirmed": "Deposited", + "failed": "Deposit Failed" + }, + "mint": { + "pending": "Minting", + "confirmed": "Minted", + "failed": "Mint Failed" + }, + "approve": { + "pending": "Approving", + "confirmed": "Approved", + "failed": "Approve Failed" + }, + "contract_interaction": { + "pending": "Interaction Pending", + "confirmed": "Interacted", + "failed": "Interaction Failed" + }, + "swap": { + "pending": "Swapping", + "confirmed": "Swapped", + "failed": "Swap Failed" + }, + "borrow": { + "pending": "Borrowing", + "confirmed": "Borrowed", + "failed": "Borrow Failed" + }, + "claim": { + "pending": "Claiming", + "confirmed": "Claimed", + "failed": "Claim Failed" + }, + "deployment": { + "pending": "Deploying", + "confirmed": "Deployed", + "failed": "Deploy Failed" + }, + "repay": { + "pending": "Repaying", + "confirmed": "Repayed", + "failed": "Repay Failed" + }, + "stake": { + "pending": "Staking", + "confirmed": "Staked", + "failed": "Stake Failed" + }, + "unstake": { + "pending": "Unstaking", + "confirmed": "Unstaked", + "failed": "Unstake Failed" + }, + "purchase": { + "pending": "Purchasing", + "confirmed": "Purchased", + "failed": "Purchase Failed" + }, + "revoke": { + "pending": "Revoking", + "confirmed": "Revoked", + "failed": "Revoke Failed" + }, + "sale": { + "pending": "Selling", + "confirmed": "Sold", + "failed": "Sale Failed" + }, + "bridge": { + "pending": "Bridging", + "confirmed": "Bridged", + "failed": "Bridge Failed" + }, + "airdrop": { + "pending": "", + "confirmed": "Airdropped", + "failed": "" + }, + "wrap": { + "pending": "Wrapping", + "confirmed": "Wrapped", + "failed": "Wrap Failed" + }, + "unwrap": { + "pending": "Unwrapping", + "confirmed": "Unwrapped", + "failed": "Unwrap Failed" + }, + "bid": { + "pending": "Bidding", + "confirmed": "Bid", + "failed": "Bid Failed" + } }, "savings": "Savings", "signed": "Signed", diff --git a/src/notifications/NotificationsHandler.tsx b/src/notifications/NotificationsHandler.tsx index 3a9145b9b0a..1b20906b79c 100644 --- a/src/notifications/NotificationsHandler.tsx +++ b/src/notifications/NotificationsHandler.tsx @@ -206,7 +206,6 @@ export const NotificationsHandler = ({ walletReady }: Props) => { ); const provider = await getProviderForNetwork(network); const rpcTransaction = await provider.getTransaction(data.hash); - const transactionConfirmed = rpcTransaction?.blockNumber && rpcTransaction?.blockHash; if (!transactionConfirmed) { @@ -227,6 +226,7 @@ export const NotificationsHandler = ({ walletReady }: Props) => { maxPriorityFeePerGas: rpcTransaction.maxPriorityFeePerGas, gasPrice: rpcTransaction.gasPrice, data: rpcTransaction.data, + status: rpcTransaction.blockNumber ? 'confirmed' : 'pending', }; const parsedTransaction = await parseNewTransaction( @@ -272,7 +272,7 @@ export const NotificationsHandler = ({ walletReady }: Props) => { } else { resultTransaction.status = TransactionStatus.failed; } - resultTransaction.pending = false; + resultTransaction.status = 'confirmed'; resultTransaction.minedAt = minedAt; if (resultTransaction) { diff --git a/src/parsers/newTransaction.ts b/src/parsers/newTransaction.ts index 72e92b044e1..6a66292cf78 100644 --- a/src/parsers/newTransaction.ts +++ b/src/parsers/newTransaction.ts @@ -87,7 +87,6 @@ export const parseNewTransaction = async ( network, nft, nonce, - pending: true, protocol, sourceAmount, status, diff --git a/src/parsers/transactions.ts b/src/parsers/transactions.ts index 20e75c69848..bcf385f549c 100644 --- a/src/parsers/transactions.ts +++ b/src/parsers/transactions.ts @@ -169,9 +169,8 @@ export const parseNewTransaction = (tx: NewTransaction): RainbowTransaction => { return { ...tx, status: 'pending', - pending: true, data: tx.data, - title: `transactions.${tx.type}.${tx.status}`, + title: `${tx.type}.${tx.status}`, description: asset?.name || methodName, from: tx.from, changes: tx.changes, diff --git a/src/raps/actions/crosschainSwap.ts b/src/raps/actions/crosschainSwap.ts index a9e91a2ac2b..b98340edc81 100644 --- a/src/raps/actions/crosschainSwap.ts +++ b/src/raps/actions/crosschainSwap.ts @@ -169,7 +169,6 @@ const crosschainSwap = async ( network: inputCurrency.network, nonce: swap?.nonce, status: 'pending', - pending: true, type: 'swap', flashbots: parameters.flashbots, swap: { diff --git a/src/raps/actions/ens.ts b/src/raps/actions/ens.ts index fa66c1307d8..597b3a7bc77 100644 --- a/src/raps/actions/ens.ts +++ b/src/raps/actions/ens.ts @@ -578,7 +578,6 @@ const ensAction = async ( value: toHex(tx.value), network: NetworkTypes.mainnet, status: 'pending', - pending: true, }; logger.log(`[${actionName}] adding new txn`, newTransaction); diff --git a/src/raps/actions/swap.ts b/src/raps/actions/swap.ts index 4bf464284c8..3cfa0f761bb 100644 --- a/src/raps/actions/swap.ts +++ b/src/raps/actions/swap.ts @@ -232,7 +232,6 @@ const swap = async ( network: inputCurrency.network, nonce: swap.nonce, status: 'pending', - pending: true, type: 'swap', flashbots: parameters.flashbots, ...gasParams, diff --git a/src/screens/ProfileScreen.js b/src/screens/ProfileScreen.js index 082bca58905..01e1dddfa06 100644 --- a/src/screens/ProfileScreen.js +++ b/src/screens/ProfileScreen.js @@ -16,6 +16,7 @@ import { position } from '@/styles'; import { Navbar } from '@/components/navbar/Navbar'; import ImageAvatar from '@/components/contacts/ImageAvatar'; import { ContactAvatar } from '@/components/contacts'; +import { usePendingTransactionWatcher } from '@/hooks/usePendingTransactionWatcher'; const ACTIVITY_LIST_INITIALIZATION_DELAY = 5000; @@ -40,8 +41,9 @@ export default function ProfileScreen() { transactionsCount, } = accountTransactions; const { pendingRequestCount } = useRequests(); - const { network } = useAccountSettings(); + const { network, accountAddress } = useAccountSettings(); const { accountSymbol, accountColor, accountImage } = useAccountProfile(); + usePendingTransactionWatcher({ address: accountAddress }); const isEmpty = !transactionsCount && !pendingRequestCount; diff --git a/src/screens/SettingsSheet/components/DevSection.tsx b/src/screens/SettingsSheet/components/DevSection.tsx index 2d5d0adf284..6417b53fa4e 100644 --- a/src/screens/SettingsSheet/components/DevSection.tsx +++ b/src/screens/SettingsSheet/components/DevSection.tsx @@ -59,6 +59,10 @@ import { saveLocalPendingTransactions } from '@/handlers/localstorage/accountLoc import { getFCMToken } from '@/notifications/tokens'; import { resetNonces } from '@/redux/nonceManager'; import { removeGlobalNotificationSettings } from '@/notifications/settings/settings'; +import { + pendingTransactionsStore, + usePendingTransactionsStore, +} from '@/state/pendingTransactionsStore'; const DevSection = () => { const { navigate } = useNavigation(); @@ -76,6 +80,7 @@ const DevSection = () => { const resetAccountState = useResetAccountState(); const loadAccountData = useLoadAccountData(); const initializeAccountData = useInitializeAccountData(); + const { clearPendingTransactions } = usePendingTransactionsStore(); const [loadingStates, setLoadingStates] = useState({ clearLocalStorage: false, clearAsyncStorage: false, @@ -215,19 +220,6 @@ const DevSection = () => { return Promise.resolve(); }, [walletNotificationSettings]); - const clearPendingTransactions = async () => { - // clear local storage - saveLocalPendingTransactions([], accountAddress, Network.mainnet); - // clear redux - dispatch({ - payload: [], - type: DATA_UPDATE_PENDING_TRANSACTIONS_SUCCESS, - }); - - // reset nonces - resetNonces(accountAddress); - }; - const clearLocalStorage = async () => { setLoadingStates(prev => ({ ...prev, clearLocalStorage: true })); diff --git a/src/screens/SignTransactionSheet.tsx b/src/screens/SignTransactionSheet.tsx index bc9caee4027..ad9065180de 100644 --- a/src/screens/SignTransactionSheet.tsx +++ b/src/screens/SignTransactionSheet.tsx @@ -990,7 +990,6 @@ export const SignTransactionSheet = () => { nonce: sendResult.nonce, to: displayDetails?.request?.to, value: sendResult.value.toString(), - pending: true, type: 'contract_interaction', ...gasParams, }; diff --git a/src/screens/transaction-details/components/TransactionDetailsValueAndFeeSection.tsx b/src/screens/transaction-details/components/TransactionDetailsValueAndFeeSection.tsx index e9a5cb5545f..4e44654afad 100644 --- a/src/screens/transaction-details/components/TransactionDetailsValueAndFeeSection.tsx +++ b/src/screens/transaction-details/components/TransactionDetailsValueAndFeeSection.tsx @@ -37,7 +37,6 @@ export const TransactionDetailsValueAndFeeSection: React.FC = ({ const change = transaction?.changes?.[0]; const value = change?.value || transaction.balance?.display; - console.log(' VAL: ', change?.value); const nativeCurrencyValue = convertAmountAndPriceToNativeDisplay( change?.asset?.balance?.amount || '', change?.asset?.price?.value || '', diff --git a/src/state/pendingTransactionsStore.ts b/src/state/pendingTransactionsStore.ts index 227c4e8eb21..d8a70814ccd 100644 --- a/src/state/pendingTransactionsStore.ts +++ b/src/state/pendingTransactionsStore.ts @@ -13,6 +13,7 @@ export const addNewTransaction = ({ network: Network; transaction: NewTransaction; }) => { + console.log('adding new transaction'); const parsedTransaction = parseNewTransaction(transaction); pendingTransactionsStore .getState() From e4a27f716efd404ce2707fbd92b39af99786ed4f Mon Sep 17 00:00:00 2001 From: skylarbarrera Date: Thu, 8 Feb 2024 12:24:33 -0500 Subject: [PATCH 16/38] ui tweaks --- src/components/coin-icon/TwoIconsIcon.tsx | 2 +- src/components/coin-row/FastTransactionCoinRow.tsx | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/components/coin-icon/TwoIconsIcon.tsx b/src/components/coin-icon/TwoIconsIcon.tsx index b8d60e0f112..280d8d8ac04 100644 --- a/src/components/coin-icon/TwoIconsIcon.tsx +++ b/src/components/coin-icon/TwoIconsIcon.tsx @@ -66,7 +66,7 @@ export function TwoCoinsIcon({ {badge && ( )} diff --git a/src/components/coin-row/FastTransactionCoinRow.tsx b/src/components/coin-row/FastTransactionCoinRow.tsx index 377a9ffa9f7..aaf1bdcb4cf 100644 --- a/src/components/coin-row/FastTransactionCoinRow.tsx +++ b/src/components/coin-row/FastTransactionCoinRow.tsx @@ -209,6 +209,16 @@ const BottomRow = React.memo(function BottomRow({ tag = transaction.description; } + if (['wrap', 'unwrap', 'swap'].includes(transaction?.type)) { + const inAsset = transaction?.changes?.find(a => a?.direction === 'in') + ?.asset; + const outAsset = transaction?.changes?.find(a => a?.direction === 'out') + ?.asset; + + if (!!inAsset && !!outAsset) + description = `${inAsset?.symbol} 􀄫 ${outAsset?.symbol}`; + } + const nftChangesAmount = transaction.changes ?.filter( c => asset?.address === c?.asset.address && c?.asset.type === 'nft' From 0bc2f3b6ee1f0029964f466a88b1e7245da4190a Mon Sep 17 00:00:00 2001 From: skylarbarrera Date: Thu, 8 Feb 2024 15:25:54 -0500 Subject: [PATCH 17/38] clean up state and add nonces --- src/hooks/useAccountTransactions.ts | 2 +- src/hooks/usePendingTransactions.ts | 2 +- src/hooks/useWatchPendingTxs.ts | 2 +- src/raps/actions/crosschainSwap.ts | 2 +- src/raps/actions/ens.ts | 2 +- src/raps/actions/swap.ts | 2 +- src/raps/actions/unlock.ts | 2 +- src/screens/NFTSingleOfferSheet/index.tsx | 2 +- src/screens/SendSheet.js | 2 +- .../SettingsSheet/components/DevSection.tsx | 2 +- src/screens/SignTransactionSheet.tsx | 2 +- src/screens/mints/MintSheet.tsx | 2 +- src/state/nonces/index.test.ts | 181 ++++++++++++++++++ src/state/nonces/index.ts | 59 ++++++ src/state/pendingTransactionState.ts | 66 ------- .../index.ts} | 2 +- 16 files changed, 253 insertions(+), 79 deletions(-) create mode 100644 src/state/nonces/index.test.ts create mode 100644 src/state/nonces/index.ts delete mode 100644 src/state/pendingTransactionState.ts rename src/state/{pendingTransactionsStore.ts => pendingTransactions/index.ts} (98%) diff --git a/src/hooks/useAccountTransactions.ts b/src/hooks/useAccountTransactions.ts index c84ba955d3d..a9e9c0e43dc 100644 --- a/src/hooks/useAccountTransactions.ts +++ b/src/hooks/useAccountTransactions.ts @@ -9,7 +9,7 @@ import { getCachedProviderForNetwork, isHardHat } from '@/handlers/web3'; import { useUserAssets } from '@/resources/assets/UserAssetsQuery'; import { useConsolidatedTransactions } from '@/resources/transactions/consolidatedTransactions'; import { RainbowTransaction } from '@/entities'; -import { usePendingTransactionsStore } from '@/state/pendingTransactionsStore'; +import { usePendingTransactionsStore } from '@/state/pendingTransactions'; export const NOE_PAGE = 30; diff --git a/src/hooks/usePendingTransactions.ts b/src/hooks/usePendingTransactions.ts index 3a34228a36b..43151480cc8 100644 --- a/src/hooks/usePendingTransactions.ts +++ b/src/hooks/usePendingTransactions.ts @@ -1,6 +1,6 @@ import { useCallback, useMemo } from 'react'; import { ethereumUtils, isLowerCaseMatch } from '@/utils'; -import { usePendingTransactionsStore } from '@/state/pendingTransactionsStore'; +import { usePendingTransactionsStore } from '@/state/pendingTransactions'; import useAccountSettings from './useAccountSettings'; diff --git a/src/hooks/useWatchPendingTxs.ts b/src/hooks/useWatchPendingTxs.ts index e396abd4a07..167bd4f40cb 100644 --- a/src/hooks/useWatchPendingTxs.ts +++ b/src/hooks/useWatchPendingTxs.ts @@ -10,7 +10,7 @@ import { consolidatedTransactionsQueryKey } from '@/resources/transactions/conso import { RainbowNetworks } from '@/networks'; import { queryClient } from '@/react-query/queryClient'; import { getTransactionFlashbotStatus } from '@/handlers/transactions'; -import { usePendingTransactionsStore } from '@/state/pendingTransactionsStore'; +import { usePendingTransactionsStore } from '@/state/pendingTransactions'; export const useWatchPendingTransactions = ({ address }: { address: string }) => { //const { swapRefreshAssets } = useSwapRefreshAssets(); diff --git a/src/raps/actions/crosschainSwap.ts b/src/raps/actions/crosschainSwap.ts index 2474115d460..b0581fe221d 100644 --- a/src/raps/actions/crosschainSwap.ts +++ b/src/raps/actions/crosschainSwap.ts @@ -14,7 +14,7 @@ import { estimateCrosschainSwapGasLimit } from '@/handlers/swap'; import { swapMetadataStorage } from './swap'; import { REFERRER } from '@/references'; import { overrideWithFastSpeedIfNeeded } from '../utils'; -import { addNewTransaction } from '@/state/pendingTransactionsStore'; +import { addNewTransaction } from '@/state/pendingTransactions'; const actionName = 'crosschainSwap'; diff --git a/src/raps/actions/ens.ts b/src/raps/actions/ens.ts index f313d141beb..3bafe473dfc 100644 --- a/src/raps/actions/ens.ts +++ b/src/raps/actions/ens.ts @@ -17,7 +17,7 @@ import store from '@/redux/store'; import { ethereumUtils } from '@/utils'; import logger from '@/utils/logger'; import { parseGasParamAmounts } from '@/parsers'; -import { addNewTransaction } from '@/state/pendingTransactionsStore'; +import { addNewTransaction } from '@/state/pendingTransactions'; import { Network } from '@/networks/types'; const executeCommit = async ( diff --git a/src/raps/actions/swap.ts b/src/raps/actions/swap.ts index 89116da584c..e41f6155e65 100644 --- a/src/raps/actions/swap.ts +++ b/src/raps/actions/swap.ts @@ -15,7 +15,7 @@ import { MMKV } from 'react-native-mmkv'; import { STORAGE_IDS } from '@/model/mmkv'; import { REFERRER } from '@/references'; import { overrideWithFastSpeedIfNeeded } from '../utils'; -import { addNewTransaction } from '@/state/pendingTransactionsStore'; +import { addNewTransaction } from '@/state/pendingTransactions'; export const swapMetadataStorage = new MMKV({ id: STORAGE_IDS.SWAPS_METADATA_STORAGE, diff --git a/src/raps/actions/unlock.ts b/src/raps/actions/unlock.ts index b593697c98f..a642e480c20 100644 --- a/src/raps/actions/unlock.ts +++ b/src/raps/actions/unlock.ts @@ -17,7 +17,7 @@ import { AllowancesCache, ethereumUtils } from '@/utils'; import { overrideWithFastSpeedIfNeeded } from '../utils'; import logger from '@/utils/logger'; import { ParsedAsset } from '@/resources/assets/types'; -import { addNewTransaction } from '@/state/pendingTransactionsStore'; +import { addNewTransaction } from '@/state/pendingTransactions'; export const estimateApprove = async ( owner: string, diff --git a/src/screens/NFTSingleOfferSheet/index.tsx b/src/screens/NFTSingleOfferSheet/index.tsx index 9f3c5ccdfdc..97a63e85292 100644 --- a/src/screens/NFTSingleOfferSheet/index.tsx +++ b/src/screens/NFTSingleOfferSheet/index.tsx @@ -48,7 +48,7 @@ import { CardSize } from '@/components/unique-token/CardSize'; import { queryClient } from '@/react-query'; import { nftOffersQueryKey } from '@/resources/reservoir/nftOffersQuery'; import { getRainbowFeeAddress } from '@/resources/reservoir/utils'; -import { addNewTransaction } from '@/state/pendingTransactionsStore'; +import { addNewTransaction } from '@/state/pendingTransactions'; import { getUniqueId } from '@/utils/ethereumUtils'; const NFT_IMAGE_HEIGHT = 160; diff --git a/src/screens/SendSheet.js b/src/screens/SendSheet.js index 32e4c111dc2..de875abd394 100644 --- a/src/screens/SendSheet.js +++ b/src/screens/SendSheet.js @@ -64,7 +64,7 @@ import { NoResultsType } from '@/components/list/NoResults'; import { setHardwareTXError } from '@/navigation/HardwareWalletTxNavigator'; import { Wallet } from '@ethersproject/wallet'; import { getNetworkObj } from '@/networks'; -import { addNewTransaction } from '@/state/pendingTransactionsStore'; +import { addNewTransaction } from '@/state/pendingTransactions'; const sheetHeight = deviceUtils.dimensions.height - (IS_ANDROID ? 30 : 10); const statusBarHeight = IS_IOS ? safeAreaInsetValues.top : StatusBar.currentHeight; diff --git a/src/screens/SettingsSheet/components/DevSection.tsx b/src/screens/SettingsSheet/components/DevSection.tsx index e4827cd36e9..0a30c71b3d3 100644 --- a/src/screens/SettingsSheet/components/DevSection.tsx +++ b/src/screens/SettingsSheet/components/DevSection.tsx @@ -53,7 +53,7 @@ import { saveLocalPendingTransactions } from '@/handlers/localstorage/accountLoc import { getFCMToken } from '@/notifications/tokens'; import { resetNonces } from '@/redux/nonceManager'; import { removeGlobalNotificationSettings } from '@/notifications/settings/settings'; -import { pendingTransactionsStore, usePendingTransactionsStore } from '@/state/pendingTransactionsStore'; +import { pendingTransactionsStore, usePendingTransactionsStore } from '@/state/pendingTransactions'; const DevSection = () => { const { navigate } = useNavigation(); diff --git a/src/screens/SignTransactionSheet.tsx b/src/screens/SignTransactionSheet.tsx index 725fb3b6b50..d760228e703 100644 --- a/src/screens/SignTransactionSheet.tsx +++ b/src/screens/SignTransactionSheet.tsx @@ -94,7 +94,7 @@ import { isAddress } from '@ethersproject/address'; import { methodRegistryLookupAndParse } from '@/utils/methodRegistry'; import { sanitizeTypedData } from '@/utils/signingUtils'; import { hexToNumber, isHex } from 'viem'; -import { addNewTransaction } from '@/state/pendingTransactionsStore'; +import { addNewTransaction } from '@/state/pendingTransactions'; import { account } from '@/storage'; const COLLAPSED_CARD_HEIGHT = 56; diff --git a/src/screens/mints/MintSheet.tsx b/src/screens/mints/MintSheet.tsx index 55fe44bda82..cc56fe0bf0a 100644 --- a/src/screens/mints/MintSheet.tsx +++ b/src/screens/mints/MintSheet.tsx @@ -53,7 +53,7 @@ import { QuantityButton } from './components/QuantityButton'; import { estimateGas, getProviderForNetwork } from '@/handlers/web3'; import { getRainbowFeeAddress } from '@/resources/reservoir/utils'; import { IS_ANDROID, IS_IOS } from '@/env'; -import { addNewTransaction } from '@/state/pendingTransactionsStore'; +import { addNewTransaction } from '@/state/pendingTransactions'; import { getUniqueId } from '@/utils/ethereumUtils'; const NFT_IMAGE_HEIGHT = 250; diff --git a/src/state/nonces/index.test.ts b/src/state/nonces/index.test.ts new file mode 100644 index 00000000000..3973fe5033c --- /dev/null +++ b/src/state/nonces/index.test.ts @@ -0,0 +1,181 @@ +const TEST_ADDRESS_1 = '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266'; +const TEST_ADDRESS_2 = '0x70997970c51812dc3a010c7d01b50e0d17dc79c8'; +const TEST_ADDRESS_3 = '0x3c44cdddb6a900fa2b585dd299e03d12fa4293bc'; + +import { nonceStore } from '.'; +import { Network } from '@/networks/types'; + +test('should be able to set nonce for one wallet in one network', async () => { + const { nonces, setNonce } = nonceStore.getState(); + expect(nonces).toStrictEqual({}); + setNonce({ + address: TEST_ADDRESS_1, + currentNonce: 1, + latestConfirmedNonce: 1, + network: Network.mainnet, + }); + const newNonces = nonceStore.getState().nonces; + expect(newNonces).toStrictEqual({ + [TEST_ADDRESS_1]: { + [Network.mainnet]: { + currentNonce: 1, + latestConfirmedNonce: 1, + }, + }, + }); +}); + +test('should be able to set nonce for same wallet in a different network', async () => { + const { setNonce } = nonceStore.getState(); + setNonce({ + address: TEST_ADDRESS_1, + currentNonce: 4, + latestConfirmedNonce: 4, + network: Network.optimism, + }); + const newNonces = nonceStore.getState().nonces; + expect(newNonces).toStrictEqual({ + [TEST_ADDRESS_1]: { + [Network.mainnet]: { + currentNonce: 1, + latestConfirmedNonce: 1, + }, + [Network.optimism]: { + currentNonce: 4, + latestConfirmedNonce: 4, + }, + }, + }); +}); + +test('should be able to set nonce for other wallet in one network', async () => { + const { setNonce } = nonceStore.getState(); + setNonce({ + address: TEST_ADDRESS_2, + currentNonce: 2, + latestConfirmedNonce: 2, + network: Network.mainnet, + }); + const newNonces = nonceStore.getState().nonces; + expect(newNonces).toStrictEqual({ + [TEST_ADDRESS_1]: { + [Network.mainnet]: { + currentNonce: 1, + latestConfirmedNonce: 1, + }, + [Network.optimism]: { + currentNonce: 4, + latestConfirmedNonce: 4, + }, + }, + [TEST_ADDRESS_2]: { + [Network.mainnet]: { + currentNonce: 2, + latestConfirmedNonce: 2, + }, + }, + }); +}); + +test('should be able to set nonce for other wallet in other network', async () => { + const { setNonce } = nonceStore.getState(); + setNonce({ + address: TEST_ADDRESS_3, + currentNonce: 3, + latestConfirmedNonce: 3, + network: Network.arbitrum, + }); + const newNonces = nonceStore.getState().nonces; + expect(newNonces).toStrictEqual({ + [TEST_ADDRESS_1]: { + [Network.mainnet]: { + currentNonce: 1, + latestConfirmedNonce: 1, + }, + [Network.optimism]: { + currentNonce: 4, + latestConfirmedNonce: 4, + }, + }, + [TEST_ADDRESS_2]: { + [Network.mainnet]: { + currentNonce: 2, + latestConfirmedNonce: 2, + }, + }, + [TEST_ADDRESS_3]: { + [Network.arbitrum]: { + currentNonce: 3, + latestConfirmedNonce: 3, + }, + }, + }); +}); + +test('should be able to set nonce nonce information correctly', async () => { + const { setNonce, getNonce } = nonceStore.getState(); + setNonce({ + address: TEST_ADDRESS_3, + currentNonce: 3, + latestConfirmedNonce: 3, + network: Network.arbitrum, + }); + const nonces11 = getNonce({ + address: TEST_ADDRESS_1, + network: Network.mainnet, + }); + const nonces12 = getNonce({ + address: TEST_ADDRESS_1, + network: Network.optimism, + }); + const nonces2 = getNonce({ + address: TEST_ADDRESS_2, + network: Network.mainnet, + }); + const nonces3 = getNonce({ + address: TEST_ADDRESS_3, + network: Network.arbitrum, + }); + expect(nonces11?.currentNonce).toEqual(1); + expect(nonces11?.latestConfirmedNonce).toEqual(1); + expect(nonces12?.currentNonce).toEqual(4); + expect(nonces12?.latestConfirmedNonce).toEqual(4); + expect(nonces2?.currentNonce).toEqual(2); + expect(nonces2?.latestConfirmedNonce).toEqual(2); + expect(nonces3?.currentNonce).toEqual(3); + expect(nonces3?.latestConfirmedNonce).toEqual(3); +}); + +test('should be able to update nonce', async () => { + const { setNonce, getNonce } = nonceStore.getState(); + setNonce({ + address: TEST_ADDRESS_1, + currentNonce: 30, + latestConfirmedNonce: 30, + network: Network.mainnet, + }); + const updatedNonce = getNonce({ + address: TEST_ADDRESS_1, + network: Network.mainnet, + }); + const oldNonce = getNonce({ + address: TEST_ADDRESS_1, + network: Network.optimism, + }); + expect(updatedNonce?.currentNonce).toStrictEqual(30); + expect(updatedNonce?.latestConfirmedNonce).toStrictEqual(30); + expect(oldNonce?.currentNonce).toStrictEqual(4); + expect(oldNonce?.latestConfirmedNonce).toStrictEqual(4); + setNonce({ + address: TEST_ADDRESS_1, + currentNonce: 31, + latestConfirmedNonce: 30, + network: Network.mainnet, + }); + const updatedNonceSecondTime = getNonce({ + address: TEST_ADDRESS_1, + network: Network.mainnet, + }); + expect(updatedNonceSecondTime?.currentNonce).toStrictEqual(31); + expect(updatedNonceSecondTime?.latestConfirmedNonce).toStrictEqual(30); +}); diff --git a/src/state/nonces/index.ts b/src/state/nonces/index.ts new file mode 100644 index 00000000000..0ffdfff784c --- /dev/null +++ b/src/state/nonces/index.ts @@ -0,0 +1,59 @@ +import create from 'zustand'; +import { createStore } from '../internal/createStore'; +import { Network } from '@/networks/types'; + +type NonceData = { + currentNonce?: number; + latestConfirmedNonce?: number; +}; + +type GetNonceArgs = { + address: string; + network: Network; +}; + +type UpdateNonceArgs = NonceData & GetNonceArgs; + +export interface CurrentNonceState { + nonces: Record>; + setNonce: ({ address, currentNonce, latestConfirmedNonce, network }: UpdateNonceArgs) => void; + getNonce: ({ address, network }: GetNonceArgs) => NonceData | null; + clearNonces: () => void; +} + +export const nonceStore = createStore( + (set, get) => ({ + nonces: {}, + setNonce: ({ address, currentNonce, latestConfirmedNonce, network }) => { + const { nonces: oldNonces } = get(); + const addressAndChainIdNonces = oldNonces?.[address]?.[network] || {}; + set({ + nonces: { + ...oldNonces, + [address]: { + ...oldNonces[address], + [network]: { + currentNonce: currentNonce ?? addressAndChainIdNonces?.currentNonce, + latestConfirmedNonce: latestConfirmedNonce ?? addressAndChainIdNonces?.latestConfirmedNonce, + }, + }, + }, + }); + }, + getNonce: ({ address, network }) => { + const { nonces } = get(); + return nonces[address]?.[network] ?? null; + }, + clearNonces: () => { + set({ nonces: {} }); + }, + }), + { + persist: { + name: 'nonces', + version: 0, + }, + } +); + +export const useNonceStore = create(nonceStore); diff --git a/src/state/pendingTransactionState.ts b/src/state/pendingTransactionState.ts deleted file mode 100644 index 816a608df80..00000000000 --- a/src/state/pendingTransactionState.ts +++ /dev/null @@ -1,66 +0,0 @@ -import { RainbowTransaction } from '@/entities/transactions'; -import { createStore } from './internal/createStore'; -import create from 'zustand'; - -export interface PendingTransactionsState { - pendingTransactions: Record; - addPendingTransaction: ({ address, pendingTransaction }: { address: string; pendingTransaction: RainbowTransaction }) => void; - updatePendingTransaction: ({ address, pendingTransaction }: { address: string; pendingTransaction: RainbowTransaction }) => void; - setPendingTransactions: ({ address, pendingTransactions }: { address: string; pendingTransactions: RainbowTransaction[] }) => void; - clearPendingTransactions: () => void; -} - -export const pendingTransactionsStore = createStore( - (set, get) => ({ - pendingTransactions: {}, - addPendingTransaction: ({ address, pendingTransaction }) => { - const { pendingTransactions: currentPendingTransactions } = get(); - const addressPendingTransactions = currentPendingTransactions[address] || []; - set({ - pendingTransactions: { - ...currentPendingTransactions, - [address]: [...addressPendingTransactions, pendingTransaction], - }, - }); - }, - updatePendingTransaction: ({ address, pendingTransaction }) => { - const { pendingTransactions: currentPendingTransactions } = get(); - const addressPendingTransactions = currentPendingTransactions[address] || []; - - set({ - pendingTransactions: { - ...currentPendingTransactions, - [address]: [ - ...addressPendingTransactions.filter(tx => { - if (tx.network === pendingTransaction.network) { - return tx.nonce !== pendingTransaction.nonce; - } - return true; - }), - pendingTransaction, - ], - }, - }); - }, - setPendingTransactions: ({ address, pendingTransactions }) => { - const { pendingTransactions: currentPendingTransactions } = get(); - set({ - pendingTransactions: { - ...currentPendingTransactions, - [address]: [...pendingTransactions], - }, - }); - }, - clearPendingTransactions: () => { - set({ pendingTransactions: {} }); - }, - }), - { - persist: { - name: 'pendingTransactions', - version: 1, - }, - } -); - -export const usePendingTransactionsStore = create(pendingTransactionsStore); diff --git a/src/state/pendingTransactionsStore.ts b/src/state/pendingTransactions/index.ts similarity index 98% rename from src/state/pendingTransactionsStore.ts rename to src/state/pendingTransactions/index.ts index 0f3fb77b3b6..441ce1e783b 100644 --- a/src/state/pendingTransactionsStore.ts +++ b/src/state/pendingTransactions/index.ts @@ -1,5 +1,5 @@ import { RainbowTransaction, NewTransaction } from '@/entities/transactions'; -import { createStore } from './internal/createStore'; +import { createStore } from '../internal/createStore'; import create from 'zustand'; import { parseNewTransaction } from '@/parsers/transactions'; import { Network } from '@/networks/types'; From 734f9c64a9deccf341f9e481e39a28339ccf2c17 Mon Sep 17 00:00:00 2001 From: skylarbarrera Date: Thu, 8 Feb 2024 23:46:17 -0500 Subject: [PATCH 18/38] ben ui review --- src/components/coin-icon/TwoIconsIcon.tsx | 2 +- .../coin-row/FastTransactionCoinRow.tsx | 49 ++++-- .../coin-row/FastTransactionStatusBadge.tsx | 155 +----------------- src/languages/en_US.json | 5 + 4 files changed, 47 insertions(+), 164 deletions(-) diff --git a/src/components/coin-icon/TwoIconsIcon.tsx b/src/components/coin-icon/TwoIconsIcon.tsx index 773f5dece90..d886e8305a4 100644 --- a/src/components/coin-icon/TwoIconsIcon.tsx +++ b/src/components/coin-icon/TwoIconsIcon.tsx @@ -21,7 +21,7 @@ export function TwoCoinsIcon({ const underSize = size * 0.75; return ( - + ) => { if (!approvalAmount || !asset) return; - if (approvalAmount === 'UNLIMITED') return 'approvals.unlimited'; - if (type === 'revoke') return 'approvals.no_allowance'; + if (approvalAmount === 'UNLIMITED') return lang.t(lang.l.transactions.approvals.unlimited); + if (type === 'revoke') return lang.t(lang.l.transactions.approvals.no_allowance); return `${approvalAmount} ${asset.symbol}`; }; @@ -31,7 +32,8 @@ const approvalTypeValues = (transaction: RainbowTransaction) => { const { asset, approvalAmount, hash, contract } = transaction; if (!asset || !approvalAmount) return; - return getApprovalLabel(transaction); + transaction.protocol; + return [transaction.protocol || '', getApprovalLabel(transaction)]; // return [ // contract?.name ? ( @@ -63,7 +65,7 @@ const swapTypeValues = (changes: RainbowTransaction['changes']) => { if (!tokenIn?.asset.balance?.amount || !tokenOut?.asset.balance?.amount) return; - const valueOut = `-${convertAmountToBalanceDisplay(tokenOut?.asset.balance?.amount, { ...tokenOut?.asset })}`; + const valueOut = `${convertAmountToBalanceDisplay(tokenOut?.asset.balance?.amount, { ...tokenOut?.asset })}`; const valueIn = `+${convertAmountToBalanceDisplay(tokenIn?.asset.balance?.amount, { ...tokenIn?.asset })}`; return [valueOut, valueIn]; @@ -75,7 +77,14 @@ const activityValues = (transaction: RainbowTransaction, nativeCurrency: NativeC if (['approve', 'revoke'].includes(type)) return approvalTypeValues(transaction); const asset = changes?.filter(c => c?.direction === direction && c?.asset.type !== 'nft')[0]?.asset; - const valueSymbol = direction === 'out' ? '-' : '+'; + let valueSymbol = direction === 'out' ? '-' : '+'; + + if (type === 'send') { + valueSymbol = '-'; + } + if (type === 'receive') { + valueSymbol = '+'; + } if (!asset) return; @@ -85,17 +94,29 @@ const activityValues = (transaction: RainbowTransaction, nativeCurrency: NativeC const assetValue = convertAmountToBalanceDisplay(balance?.amount || '0', asset); const nativeBalance = convertAmountAndPriceToNativeDisplay(balance?.amount || '0', asset?.price?.value || '0', nativeCurrency); - const assetNativeValue = greaterThan(nativeBalance.amount, '0') ? nativeBalance?.display : 'no value'; + const assetNativeValue = greaterThan(nativeBalance.amount, '0') + ? `${valueSymbol}${nativeBalance?.display}` + : lang.t(lang.l.transactions.no_value); - return greaterThan(nativeBalance.amount, '0') ? [assetValue, assetNativeValue] : [assetNativeValue, `${valueSymbol}${assetValue}`]; + return greaterThan(nativeBalance.amount, '0') ? [`${assetValue}`, assetNativeValue] : [assetNativeValue, `${valueSymbol}${assetValue}`]; +}; +const getIconTopMargin = (type: TransactionType) => { + switch (type) { + case 'swap': + return 1; + case 'mint': + return -1; + + default: + return 0; + } }; - const activityTypeIcon: Record = { airdrop: '􀐚', approve: '􀁢', contract_interaction: '􀉆', receive: '􀄩', - send: '􀈠', + send: '􀈟', swap: '􀖅', bid: '􀑍', burn: '􀙬', @@ -132,7 +153,7 @@ export const ActivityTypeIcon = ({ if (status === 'failed') return ( - + {'􀀲'} ); @@ -140,9 +161,11 @@ export const ActivityTypeIcon = ({ const symbol = activityTypeIcon[type]; if (!symbol) return null; return ( - - {symbol} - + + + {symbol} + + ); }; diff --git a/src/components/coin-row/FastTransactionStatusBadge.tsx b/src/components/coin-row/FastTransactionStatusBadge.tsx index 5f833626905..56616000cba 100644 --- a/src/components/coin-row/FastTransactionStatusBadge.tsx +++ b/src/components/coin-row/FastTransactionStatusBadge.tsx @@ -1,161 +1,14 @@ import React from 'react'; import { StyleProp, StyleSheet, View, ViewStyle } from 'react-native'; -import Spinner from '../Spinner'; -import { Icon } from '../icons'; import { Text, useForegroundColor } from '@/design-system'; -import { RainbowTransaction, TransactionStatus, TransactionStatusTypes } from '@/entities'; -import { position } from '@/styles'; +import { RainbowTransaction } from '@/entities'; import { ThemeContextProps } from '@/theme'; import * as lang from '@/languages'; -import { TransactionType } from '@/resources/transactions/types'; -import { transactionTypes } from '@/entities/transactions/transactionType'; import { ActivityTypeIcon } from './FastTransactionCoinRow'; -const StatusProps = { - [TransactionStatusTypes.approved]: { - marginRight: 4, - marginTop: ios ? 1 : 0, - name: 'dot', - }, - [TransactionStatusTypes.cancelled]: { - marginRight: 4, - marginTop: ios ? 1 : 0, - }, - [TransactionStatusTypes.cancelling]: { - marginRight: 4, - marginTop: ios ? 1 : 0, - }, - [TransactionStatusTypes.deposited]: { - name: 'sunflower', - style: { - fontSize: 11, - left: -1.3, - marginRight: 1, - marginTop: ios ? -3 : -5, - }, - }, - [TransactionStatusTypes.depositing]: { - marginRight: 4, - marginTop: ios ? 1 : 0, - }, - [TransactionStatusTypes.approving]: { - marginRight: 4, - marginTop: ios ? 1 : 0, - }, - [TransactionStatusTypes.swapping]: { - marginRight: 4, - marginTop: ios ? 1 : 0, - }, - [TransactionStatusTypes.selling]: { - marginRight: 4, - marginTop: ios ? 1 : 0, - }, - [TransactionStatusTypes.speeding_up]: { - marginRight: 4, - marginTop: ios ? 1 : 0, - }, - [TransactionStatusTypes.failed]: { - marginRight: 4, - marginTop: ios ? -1 : -2, - name: 'closeCircled', - style: position.maxSizeAsObject(12), - }, - [TransactionStatusTypes.purchased]: { - marginRight: 2, - marginTop: ios ? 0 : -1, - name: 'arrow', - }, - [TransactionStatusTypes.purchasing]: { - marginRight: 4, - marginTop: ios ? 0 : -1, - }, - [TransactionStatusTypes.received]: { - marginRight: 2, - marginTop: ios ? 0 : -1, - name: 'arrow', - }, - [TransactionStatusTypes.self]: { - marginRight: 4, - marginTop: ios ? 0 : -1, - name: 'dot', - }, - [TransactionStatusTypes.sending]: { - marginRight: 4, - marginTop: ios ? 0 : -1, - }, - [TransactionStatusTypes.sent]: { - marginRight: 3, - marginTop: ios ? 0 : -1, - name: 'sendSmall', - }, - [TransactionStatusTypes.swapped]: { - marginRight: 3, - marginTop: ios ? -1 : -2, - name: 'swap', - small: true, - style: position.maxSizeAsObject(12), - }, - [TransactionStatusTypes.contract_interaction]: { - name: 'robot', - style: { - fontSize: 11, - left: -1.3, - marginRight: 1, - marginTop: ios ? -3 : -5, - }, - }, - [TransactionStatusTypes.bridged]: { - name: 'bridge', - style: { - left: -0.9, - marginTop: -2.5, - marginBottom: -4, - marginRight: 0, - }, - }, - [TransactionStatusTypes.bridging]: { - marginRight: 4, - marginTop: ios ? 1 : 0, - }, - [TransactionStatusTypes.withdrawing]: { - marginRight: 4, - }, - [TransactionStatusTypes.withdrew]: { - name: 'sunflower', - style: { - fontSize: 11, - left: -1.3, - marginRight: 1, - marginTop: ios ? -3 : -5, - }, - }, - [TransactionStatusTypes.sold]: { - name: 'sunflower', - style: { - fontSize: 11, - left: -1.3, - marginRight: 1, - marginTop: ios ? -3 : -5, - }, - }, - [TransactionStatusTypes.minted]: { - name: 'sunflower', - style: { - fontSize: 11, - left: -1.3, - marginRight: 1, - marginTop: ios ? -3 : -5, - }, - }, - [TransactionStatusTypes.minting]: { - marginRight: 4, - marginTop: ios ? 1 : 0, - }, -}; - const sx = StyleSheet.create({ icon: { - ...position.maxSizeAsObject(10), + marginRight: 2, }, row: { flexDirection: 'row', @@ -180,7 +33,9 @@ export default React.memo(function FastTransactionStatusBadge({ return ( - + + + {/* @ts-ignore */} {lang.t(lang.l.transactions.type[transaction?.title])} diff --git a/src/languages/en_US.json b/src/languages/en_US.json index 55ed259dda6..bc063f24a56 100644 --- a/src/languages/en_US.json +++ b/src/languages/en_US.json @@ -1951,6 +1951,11 @@ "failed": "Bid Failed" } }, + "approvals": { + "no_allowance": "No Allowance", + "unlimited": "Unlimited" + }, + "no_value": "No value", "savings": "Savings", "signed": "Signed", "contract_interaction": "Contract Interaction", From 4a6b4b7913641951cee71096e3e9b739c95a9a0d Mon Sep 17 00:00:00 2001 From: skylarbarrera Date: Fri, 9 Feb 2024 16:18:27 -0500 Subject: [PATCH 19/38] pipe up once shit --- src/entities/transactions/transaction.ts | 1 + src/hooks/useWatchPendingTxs.ts | 22 +++++++-------- src/state/pendingTransactions/index.ts | 35 +++++++++++++++--------- 3 files changed, 33 insertions(+), 25 deletions(-) diff --git a/src/entities/transactions/transaction.ts b/src/entities/transactions/transaction.ts index 9e3d84be0b2..3c7e8623071 100644 --- a/src/entities/transactions/transaction.ts +++ b/src/entities/transactions/transaction.ts @@ -113,6 +113,7 @@ export type NewTransaction = Omit & { isBridge: boolean; }; meta?: SwapMetadata; + nonce: number; }; export interface RainbowTransactionFee { diff --git a/src/hooks/useWatchPendingTxs.ts b/src/hooks/useWatchPendingTxs.ts index 167bd4f40cb..4fe06a9b9fb 100644 --- a/src/hooks/useWatchPendingTxs.ts +++ b/src/hooks/useWatchPendingTxs.ts @@ -11,11 +11,13 @@ import { RainbowNetworks } from '@/networks'; import { queryClient } from '@/react-query/queryClient'; import { getTransactionFlashbotStatus } from '@/handlers/transactions'; import { usePendingTransactionsStore } from '@/state/pendingTransactions'; +import { useNonceStore } from '@/state/nonces'; export const useWatchPendingTransactions = ({ address }: { address: string }) => { //const { swapRefreshAssets } = useSwapRefreshAssets(); const { pendingTransactions: storePendingTransactions, setPendingTransactions } = usePendingTransactionsStore(); + const { setNonce } = useNonceStore(); const pendingTransactions = useMemo(() => storePendingTransactions[address] || [], [address, storePendingTransactions]); @@ -138,20 +140,16 @@ export const useWatchPendingTransactions = ({ address }: { address: string }) => const providerTransactionCount = await provider.getTransactionCount(address, 'latest'); const currentProviderNonce = providerTransactionCount - 1; const currentNonceForChainId = highestNoncePerChainId.get(network) - 1; + + setNonce({ + address, + network: network, + currentNonce: currentProviderNonce > currentNonceForChainId ? currentProviderNonce : currentNonceForChainId, + latestConfirmedNonce: currentProviderNonce, + }); }); - // need to set nonce - // setNonce({ - // address, - // chainId, - // currentNonce: - // currentProviderNonce > currentNonceForChainId - // ? currentProviderNonce - // : currentNonceForChainId, - // latestConfirmedNonce: currentProviderNonce, - // }); - // }); }, - [address] + [address, setNonce] ); const watchPendingTransactions = useCallback(async () => { diff --git a/src/state/pendingTransactions/index.ts b/src/state/pendingTransactions/index.ts index 441ce1e783b..68bbfa254a5 100644 --- a/src/state/pendingTransactions/index.ts +++ b/src/state/pendingTransactions/index.ts @@ -3,20 +3,8 @@ import { createStore } from '../internal/createStore'; import create from 'zustand'; import { parseNewTransaction } from '@/parsers/transactions'; import { Network } from '@/networks/types'; +import { nonceStore } from '../nonces'; -export const addNewTransaction = ({ - address, - network, - transaction, -}: { - address: string; - network: Network; - transaction: NewTransaction; -}) => { - console.log('adding new transaction'); - const parsedTransaction = parseNewTransaction(transaction); - pendingTransactionsStore.getState().addPendingTransaction({ address, pendingTransaction: parsedTransaction }); -}; export interface PendingTransactionsState { pendingTransactions: Record; addPendingTransaction: ({ address, pendingTransaction }: { address: string; pendingTransaction: RainbowTransaction }) => void; @@ -80,3 +68,24 @@ export const pendingTransactionsStore = createStore( ); export const usePendingTransactionsStore = create(pendingTransactionsStore); + +export const addNewTransaction = ({ + address, + network, + transaction, +}: { + address: string; + network: Network; + transaction: NewTransaction; +}) => { + console.log('adding new transaction'); + const { addPendingTransaction } = pendingTransactionsStore.getState(); + const { setNonce } = nonceStore.getState(); + const parsedTransaction = parseNewTransaction(transaction); + addPendingTransaction({ address, pendingTransaction: parsedTransaction }); + setNonce({ + address, + network, + currentNonce: transaction.nonce, + }); +}; From 6842d518570539498c7d421fd84dcd68c85d618f Mon Sep 17 00:00:00 2001 From: skylarbarrera Date: Fri, 9 Feb 2024 16:32:09 -0500 Subject: [PATCH 20/38] clean --- src/languages/en_US.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/languages/en_US.json b/src/languages/en_US.json index bc063f24a56..8e79a8a0e42 100644 --- a/src/languages/en_US.json +++ b/src/languages/en_US.json @@ -1952,7 +1952,7 @@ } }, "approvals": { - "no_allowance": "No Allowance", + "no_allowance": "No Allowance", "unlimited": "Unlimited" }, "no_value": "No value", From 518a9b057476dac272f051ea6cb4743ceaabed65 Mon Sep 17 00:00:00 2001 From: skylarbarrera Date: Fri, 9 Feb 2024 16:32:32 -0500 Subject: [PATCH 21/38] clean --- src/screens/NFTSingleOfferSheet/index.tsx | 8 +++++++- src/screens/mints/MintSheet.tsx | 4 +++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/screens/NFTSingleOfferSheet/index.tsx b/src/screens/NFTSingleOfferSheet/index.tsx index 97a63e85292..243ae335de6 100644 --- a/src/screens/NFTSingleOfferSheet/index.tsx +++ b/src/screens/NFTSingleOfferSheet/index.tsx @@ -50,6 +50,7 @@ import { nftOffersQueryKey } from '@/resources/reservoir/nftOffersQuery'; import { getRainbowFeeAddress } from '@/resources/reservoir/utils'; import { addNewTransaction } from '@/state/pendingTransactions'; import { getUniqueId } from '@/utils/ethereumUtils'; +import { getNextNonce } from '@/state/nonces'; const NFT_IMAGE_HEIGHT = 160; const TWO_HOURS_MS = 2 * 60 * 60 * 1000; @@ -265,6 +266,8 @@ export function NFTSingleOfferSheet() { chain: networkObj, transport: http(networkObj.rpc), }); + const nonce = await getNextNonce({ address: accountAddress, network }); + getClient()?.actions.acceptOffer({ items: [ { @@ -323,6 +326,7 @@ export function NFTSingleOfferSheet() { from: item.data?.from, hash: item.txHashes[0], network: offer.network as Network, + nonce, asset: { ...offer.paymentToken, network: offer.network as Network, @@ -347,12 +351,14 @@ export function NFTSingleOfferSheet() { type: 'sale', }; } else if (step.id === 'nft-approval') { + // may need to check if we need another nonce increment here. i think so tx = { status: 'pending', to: item.data?.to, from: item.data?.from, hash: item.txHashes[0], network: offer.network as Network, + nonce, asset, type: 'approve', }; @@ -389,7 +395,7 @@ export function NFTSingleOfferSheet() { }, }); navigate(Routes.PROFILE_SCREEN); - }, [accountAddress, dispatch, feeParam, navigate, network, nft, offer, rainbowFeeDecimal]); + }, [accountAddress, feeParam, navigate, network, nft, offer, rainbowFeeDecimal]); return ( diff --git a/src/screens/mints/MintSheet.tsx b/src/screens/mints/MintSheet.tsx index cc56fe0bf0a..d7f313d968f 100644 --- a/src/screens/mints/MintSheet.tsx +++ b/src/screens/mints/MintSheet.tsx @@ -55,6 +55,7 @@ import { getRainbowFeeAddress } from '@/resources/reservoir/utils'; import { IS_ANDROID, IS_IOS } from '@/env'; import { addNewTransaction } from '@/state/pendingTransactions'; import { getUniqueId } from '@/utils/ethereumUtils'; +import { getNextNonce } from '@/state/nonces'; const NFT_IMAGE_HEIGHT = 250; // inset * 2 -> 28 *2 @@ -360,6 +361,7 @@ const MintSheet = () => { }); const feeAddress = getRainbowFeeAddress(currentNetwork); + const nonce = await getNextNonce({ address: accountAddress, network: currentNetwork }); try { await getClient()?.actions.buyToken({ items: [ @@ -408,7 +410,7 @@ const MintSheet = () => { from: item.data?.from, hash: item.txHashes[0], network: currentNetwork, - + nonce, changes: [ { direction: 'out', From b8c6cc0711bfc4cac461fb72e0e90b0f3ac7496e Mon Sep 17 00:00:00 2001 From: skylarbarrera Date: Sun, 11 Feb 2024 17:18:01 -0500 Subject: [PATCH 22/38] rename and fix case --- .../coin-icon/{TwoIconsIcon.tsx => TwoCoinsIcon.tsx} | 0 src/components/coin-row/FastTransactionCoinRow.tsx | 4 ++-- 2 files changed, 2 insertions(+), 2 deletions(-) rename src/components/coin-icon/{TwoIconsIcon.tsx => TwoCoinsIcon.tsx} (100%) diff --git a/src/components/coin-icon/TwoIconsIcon.tsx b/src/components/coin-icon/TwoCoinsIcon.tsx similarity index 100% rename from src/components/coin-icon/TwoIconsIcon.tsx rename to src/components/coin-icon/TwoCoinsIcon.tsx diff --git a/src/components/coin-row/FastTransactionCoinRow.tsx b/src/components/coin-row/FastTransactionCoinRow.tsx index 5a77c66ee77..1c958c7b6ca 100644 --- a/src/components/coin-row/FastTransactionCoinRow.tsx +++ b/src/components/coin-row/FastTransactionCoinRow.tsx @@ -17,7 +17,7 @@ import { address } from '@/utils/abbreviations'; import { Colors } from '@/styles'; import { TransactionType } from '@/resources/transactions/types'; import { convertAmountAndPriceToNativeDisplay, convertAmountToBalanceDisplay, greaterThan } from '@/helpers/utilities'; -import { TwoCoinsIcon } from '../coin-icon/TwoIconsIcon'; +import { TwoCoinsIcon } from '../coin-icon/TwoCoinsIcon'; import Spinner from '../Spinner'; import * as lang from '@/languages'; @@ -257,7 +257,7 @@ export const ActivityIcon = ({ const inAsset = transaction?.changes?.find(a => a?.direction === 'in')?.asset; const outAsset = transaction?.changes?.find(a => a?.direction === 'out')?.asset; - if (!!inAsset && !!outAsset) return ; + if (!!inAsset?.icon_url && !!outAsset?.icon_url) return ; } if (transaction?.contract?.iconUrl) { return ( From 144eed246249fe0bb18d0e5cb35670b7beda639d Mon Sep 17 00:00:00 2001 From: skylarbarrera Date: Sun, 11 Feb 2024 18:38:13 -0500 Subject: [PATCH 23/38] fix tag color and position --- src/components/coin-row/FastTransactionCoinRow.tsx | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/components/coin-row/FastTransactionCoinRow.tsx b/src/components/coin-row/FastTransactionCoinRow.tsx index 1c958c7b6ca..fef13902e34 100644 --- a/src/components/coin-row/FastTransactionCoinRow.tsx +++ b/src/components/coin-row/FastTransactionCoinRow.tsx @@ -3,7 +3,7 @@ import { StyleSheet, View } from 'react-native'; import { ButtonPressAnimation } from '../animations'; import FastCoinIcon from '../asset-list/RecyclerAssetList2/FastComponents/FastCoinIcon'; import FastTransactionStatusBadge from './FastTransactionStatusBadge'; -import { Bleed, Box, Inline, Text, globalColors } from '@/design-system'; +import { Bleed, Box, Inline, Text, globalColors, useForegroundColor } from '@/design-system'; import { NativeCurrencyKey, RainbowTransaction } from '@/entities'; import { ThemeContextProps } from '@/theme'; import { useNavigation } from '@/navigation'; @@ -179,6 +179,7 @@ const BottomRow = React.memo(function BottomRow({ theme: ThemeContextProps; }) { const { type, to, asset } = transaction; + const separatorSecondary = useForegroundColor('separatorSecondary'); let description = transaction.description; let tag: string | undefined; @@ -208,12 +209,12 @@ const BottomRow = React.memo(function BottomRow({ {description} {tag && ( - + Date: Sun, 11 Feb 2024 19:34:47 -0500 Subject: [PATCH 24/38] clean up --- .prettierignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.prettierignore b/.prettierignore index 04a5a05c1b8..376e3c2a79b 100644 --- a/.prettierignore +++ b/.prettierignore @@ -10,4 +10,4 @@ rainbow-scripts .vscode __generated__ coverage -src/state/internal + From 6cfff413730dc4ed2e7c6c82a87ec49f16a85d06 Mon Sep 17 00:00:00 2001 From: skylarbarrera Date: Sun, 11 Feb 2024 19:34:55 -0500 Subject: [PATCH 25/38] clean up --- src/components/activity-list/ActivityList.js | 6 ++-- src/components/coin-icon/TwoCoinsIcon.tsx | 6 +--- .../coin-row/FastTransactionCoinRow.tsx | 1 + src/handlers/transactions.ts | 2 +- .../buildTransactionsSectionsSelector.tsx | 21 +++++-------- src/hooks/charts/useChartThrottledPoints.ts | 1 + src/hooks/useAccountTransactions.ts | 31 +++---------------- src/languages/en_US.json | 1 + src/parsers/newTransaction.ts | 2 +- .../transactions/consolidatedTransactions.ts | 2 +- .../SettingsSheet/components/DevSection.tsx | 8 ++--- .../TransactionDetails.tsx | 10 ++---- .../TransactionDetailsValueAndFeeSection.tsx | 2 +- src/state/pendingTransactions/index.ts | 2 -- 14 files changed, 28 insertions(+), 67 deletions(-) diff --git a/src/components/activity-list/ActivityList.js b/src/components/activity-list/ActivityList.js index 5acb04fe546..f3d83c30129 100644 --- a/src/components/activity-list/ActivityList.js +++ b/src/components/activity-list/ActivityList.js @@ -1,4 +1,4 @@ -import lang from 'i18n-js'; +import * as lang from '@/languages'; import React, { useCallback, useEffect, useMemo, useState } from 'react'; import { SectionList, StyleSheet, View } from 'react-native'; import sectionListGetItemLayout from 'react-native-section-list-get-item-layout'; @@ -95,7 +95,7 @@ const ActivityList = ({ let currentPendingTransactionsCount = 0; const pendingTxSection = sections[requests?.length ? 1 : 0]; - if (pendingTxSection && pendingTxSection.title === 'Pending') { + if (pendingTxSection && pendingTxSection.title === lang.t(lang.l.transactions.pending_title)) { currentPendingTransactionsCount = pendingTxSection.data.length; } return currentPendingTransactionsCount; @@ -139,7 +139,7 @@ const ActivityList = ({ } } else { return ( - + {header} ); diff --git a/src/components/coin-icon/TwoCoinsIcon.tsx b/src/components/coin-icon/TwoCoinsIcon.tsx index d886e8305a4..7a46c126afd 100644 --- a/src/components/coin-icon/TwoCoinsIcon.tsx +++ b/src/components/coin-icon/TwoCoinsIcon.tsx @@ -46,11 +46,7 @@ export function TwoCoinsIcon({ size={underSize} /> - + diff --git a/src/handlers/transactions.ts b/src/handlers/transactions.ts index b984161475c..99998d2a8aa 100644 --- a/src/handlers/transactions.ts +++ b/src/handlers/transactions.ts @@ -98,7 +98,7 @@ export const getTransactionFlashbotStatus = async ( if (flashbotsStatus === 'FAILED' || flashbotsStatus === 'CANCELLED') { const status = 'failed'; const minedAt = Math.floor(Date.now() / 1000); - const title = `transactions.${transaction.type}.failed`; + const title = `${transaction.type}.failed`; return { flashbotsStatus, status, minedAt, title }; } } catch (e) { diff --git a/src/helpers/buildTransactionsSectionsSelector.tsx b/src/helpers/buildTransactionsSectionsSelector.tsx index f7424dadadd..872ff9e5ec7 100644 --- a/src/helpers/buildTransactionsSectionsSelector.tsx +++ b/src/helpers/buildTransactionsSectionsSelector.tsx @@ -14,10 +14,6 @@ type RainbowTransactionWithContact = RainbowTransaction & { contact: Contact | null; }; -type RainbowTransactionWithContactAndMainnetAddress = RainbowTransactionWithContact & { - mainnetAddress: string; - accountAddress: string; -}; // bad news const groupTransactionByDate = ({ status, minedAt }: { status: TransactionStatus; minedAt: string }) => { if (status === 'pending') { @@ -59,7 +55,6 @@ const addContactInfo = export const buildTransactionsSections = ({ accountAddress, - mainnetAddresses, contacts, requests, theme, @@ -67,7 +62,6 @@ export const buildTransactionsSections = ({ nativeCurrency, }: { accountAddress: string; - mainnetAddresses: { [uniqueId: string]: string }; contacts: { [address: string]: Contact }; requests: RequestData[]; theme: ThemeContextProps; @@ -80,8 +74,8 @@ export const buildTransactionsSections = ({ let sectionedTransactions: { title: string; - data: RainbowTransactionWithContactAndMainnetAddress[]; - renderItem: ({ item }: { item: RainbowTransactionWithContactAndMainnetAddress }) => JSX.Element; + data: RainbowTransactionWithContact[]; + renderItem: ({ item }: { item: RainbowTransactionWithContact }) => JSX.Element; }[] = []; const transactionsWithContacts = transactions?.map(addContactInfo(contacts)); @@ -93,17 +87,16 @@ export const buildTransactionsSections = ({ const filter = test.filter(key => key !== 'Dropped'); const sectioned: { title: string; - data: RainbowTransactionWithContactAndMainnetAddress[]; - renderItem: ({ item }: { item: RainbowTransactionWithContactAndMainnetAddress }) => JSX.Element; + data: RainbowTransactionWithContact[]; + renderItem: ({ item }: { item: RainbowTransactionWithContact }) => JSX.Element; }[] = filter.map((section: string) => { - const sectionData: RainbowTransactionWithContactAndMainnetAddress[] = transactionsByDate[section].map(txn => { + const sectionData: RainbowTransactionWithContact[] = transactionsByDate[section].map(txn => { const typeTxn = txn as RainbowTransactionWithContact; const res = { ...typeTxn, to: typeTxn.to || '', from: typeTxn.from || '', accountAddress, - mainnetAddress: mainnetAddresses[`${typeTxn.address}_${typeTxn.network}`], }; return res; @@ -111,7 +104,7 @@ export const buildTransactionsSections = ({ return { data: sectionData, - renderItem: ({ item }: { item: RainbowTransactionWithContactAndMainnetAddress }) => ( + renderItem: ({ item }: { item: RainbowTransactionWithContact }) => ( ), title: section, @@ -133,7 +126,7 @@ export const buildTransactionsSections = ({ { data: requests, renderItem: ({ item }: any) => , - title: 'Requests', + title: i18n.t(i18n.l.walletconnect.requests), }, ]; } diff --git a/src/hooks/charts/useChartThrottledPoints.ts b/src/hooks/charts/useChartThrottledPoints.ts index 226a4f8d49c..a88dc3b111c 100644 --- a/src/hooks/charts/useChartThrottledPoints.ts +++ b/src/hooks/charts/useChartThrottledPoints.ts @@ -99,6 +99,7 @@ export default function useChartThrottledPoints({ } = usePriceChart({ address: asset.address, network: asset.network, + mainnetAddress: asset?.mainnet_address || asset?.mainnetAddress, }); const [throttledPoints, setThrottledPoints] = useState(() => traverseData({ nativePoints: [], points: [] }, chart)); diff --git a/src/hooks/useAccountTransactions.ts b/src/hooks/useAccountTransactions.ts index a9e9c0e43dc..77b666d57eb 100644 --- a/src/hooks/useAccountTransactions.ts +++ b/src/hooks/useAccountTransactions.ts @@ -28,14 +28,14 @@ export default function useAccountTransactions() { const pendingTransactions = useMemo(() => { const txs = storePendingTransactions[accountAddress] || []; - console.log('PENDING: ', txs); return txs; }, [accountAddress, storePendingTransactions]); - const { data, fetchNextPage } = useConsolidatedTransactions({ + const { data, fetchNextPage, hasNextPage } = useConsolidatedTransactions({ address: accountAddress, currency: nativeCurrency, }); + const pages = data?.pages; const transactions: RainbowTransaction[] = useMemo(() => pages?.flatMap(p => p.transactions) || [], [pages]); @@ -44,23 +44,6 @@ export default function useAccountTransactions() { const slicedTransaction = useMemo(() => allTransactions, [allTransactions]); - const mainnetAddresses = useMemo( - () => - userAssets - ? slicedTransaction.reduce((acc: { [key: string]: string }, txn: RainbowTransaction) => { - if (txn?.network && txn?.address) { - const asset = userAssets[`${txn.address}_${txn.network}`]?.mainnet_address; - if (asset) { - acc[`${txn.address}_${txn.network}`] = asset; - } - } - - return acc; - }, {}) - : {}, - [userAssets, slicedTransaction] - ); - const { contacts } = useContacts(); const { requests } = useRequests(); const theme = useTheme(); @@ -69,7 +52,6 @@ export default function useAccountTransactions() { const accountState = { accountAddress, contacts, - mainnetAddresses, navigate, requests, theme, @@ -80,15 +62,12 @@ export default function useAccountTransactions() { const { sections } = buildTransactionsSections(accountState); const remainingItemsLabel = useMemo(() => { - const remainingLength = allTransactions.length - slicedTransaction.length; - if (remainingLength === 0) { + console.log({ hasNextPage }); + if (!hasNextPage) { return null; } - if (remainingLength <= NOE_PAGE) { - return `Show last ${remainingLength} transactions.`; - } return `Show ${NOE_PAGE} more transactions...`; - }, [slicedTransaction.length, allTransactions.length]); + }, [hasNextPage]); return { isLoadingTransactions: !!allTransactions, diff --git a/src/languages/en_US.json b/src/languages/en_US.json index 8e79a8a0e42..ccfd8e7e11b 100644 --- a/src/languages/en_US.json +++ b/src/languages/en_US.json @@ -2459,6 +2459,7 @@ } }, "walletconnect": { + "requests": "Requests", "wants_to_connect": "wants to connect to your wallet", "wants_to_connect_to_network": "wants to connect to the %{network} network", "available_networks": "Available Networks", diff --git a/src/parsers/newTransaction.ts b/src/parsers/newTransaction.ts index 11c5fdf3b9b..14f7e6a8a50 100644 --- a/src/parsers/newTransaction.ts +++ b/src/parsers/newTransaction.ts @@ -79,7 +79,7 @@ export const parseNewTransaction = async ( sourceAmount, status, symbol: asset?.symbol ?? null, - title: 'oops', + title: `${type}.${status}`, to, transferId, txTo: txTo || to, diff --git a/src/resources/transactions/consolidatedTransactions.ts b/src/resources/transactions/consolidatedTransactions.ts index 3b8c0382e22..32bb45672f0 100644 --- a/src/resources/transactions/consolidatedTransactions.ts +++ b/src/resources/transactions/consolidatedTransactions.ts @@ -24,7 +24,7 @@ export type ConsolidatedTransactionsArgs = { // Query Key export const consolidatedTransactionsQueryKey = ({ address, currency, chainIds }: ConsolidatedTransactionsArgs) => - createQueryKey('consolidatedTransactionss', { address, currency, chainIds }, { persisterVersion: 1 }); + createQueryKey('consolidatedTransactions', { address, currency, chainIds }, { persisterVersion: 1 }); type ConsolidatedTransactionsQueryKey = ReturnType; diff --git a/src/screens/SettingsSheet/components/DevSection.tsx b/src/screens/SettingsSheet/components/DevSection.tsx index d919fc5eb46..c76cf5bc850 100644 --- a/src/screens/SettingsSheet/components/DevSection.tsx +++ b/src/screens/SettingsSheet/components/DevSection.tsx @@ -52,6 +52,7 @@ import { isAuthenticated } from '@/utils/authentication'; import { getFCMToken } from '@/notifications/tokens'; import { removeGlobalNotificationSettings } from '@/notifications/settings/settings'; import { nonceStore } from '@/state/nonces'; +import { pendingTransactionsStore } from '@/state/pendingTransactions'; const DevSection = () => { const { navigate } = useNavigation(); @@ -180,13 +181,10 @@ const DevSection = () => { }, [walletNotificationSettings]); const clearPendingTransactions = async () => { - // clear pending txs - - // TODO clear pending transactions - - // reset nonces + const { clearPendingTransactions: clearPendingTxs } = pendingTransactionsStore.getState(); const { clearNonces } = nonceStore.getState(); + clearPendingTxs(); clearNonces(); }; diff --git a/src/screens/transaction-details/TransactionDetails.tsx b/src/screens/transaction-details/TransactionDetails.tsx index c8c1474658e..bd92727e4bc 100644 --- a/src/screens/transaction-details/TransactionDetails.tsx +++ b/src/screens/transaction-details/TransactionDetails.tsx @@ -8,15 +8,12 @@ import { BackgroundProvider, Box } from '@/design-system'; import { TransactionDetailsValueAndFeeSection } from '@/screens/transaction-details/components/TransactionDetailsValueAndFeeSection'; import { TransactionDetailsHashAndActionsSection } from '@/screens/transaction-details/components/TransactionDetailsHashAndActionsSection'; import { TransactionDetailsFromToSection } from '@/screens/transaction-details/components/TransactionDetailsFromToSection'; -import { StackNavigationProp } from '@react-navigation/stack'; import { Toast, ToastPositionContainer } from '@/components/toasts'; import * as i18n from '@/languages'; import { TransactionDetailsStatusActionsAndTimestampSection } from '@/screens/transaction-details/components/TransactionDetailsStatusActionsAndTimestampSection'; import { useTransactionDetailsToasts } from '@/screens/transaction-details/hooks/useTransactionDetailsToasts'; import { LayoutChangeEvent } from 'react-native'; import { useDimensions } from '@/hooks'; -import { useTransaction } from '@/resources/transactions/transaction'; -import { Network } from '@/networks/types'; type RouteParams = { TransactionDetails: { @@ -30,11 +27,8 @@ export const TransactionDetails = () => { const route = useRoute>(); const { setParams } = navigation; const { transaction: tx } = route.params; - const { data } = useTransaction({ - hash: tx.hash || '', - network: tx.network || Network.mainnet, - }); - const transaction = data!; + + const transaction = tx; const [sheetHeight, setSheetHeight] = useState(0); const [statusIconHidden, setStatusIconHidden] = useState(false); const { presentedToast, presentToastFor } = useTransactionDetailsToasts(); diff --git a/src/screens/transaction-details/components/TransactionDetailsValueAndFeeSection.tsx b/src/screens/transaction-details/components/TransactionDetailsValueAndFeeSection.tsx index 66b2d44117d..8b57d7e45cc 100644 --- a/src/screens/transaction-details/components/TransactionDetailsValueAndFeeSection.tsx +++ b/src/screens/transaction-details/components/TransactionDetailsValueAndFeeSection.tsx @@ -44,7 +44,7 @@ export const TransactionDetailsValueAndFeeSection: React.FC = ({ transact - {true && ( + {value && ( ( (set, get) => ({ pendingTransactions: {}, addPendingTransaction: ({ address, pendingTransaction }) => { - console.log('adding pending transaction'); const { pendingTransactions: currentPendingTransactions } = get(); const addressPendingTransactions = currentPendingTransactions[address] || []; set({ @@ -78,7 +77,6 @@ export const addNewTransaction = ({ network: Network; transaction: NewTransaction; }) => { - console.log('adding new transaction'); const { addPendingTransaction } = pendingTransactionsStore.getState(); const { setNonce } = nonceStore.getState(); const parsedTransaction = parseNewTransaction(transaction); From 079e7f3046061d21f8febd1193507f9c72475130 Mon Sep 17 00:00:00 2001 From: skylarbarrera Date: Sun, 11 Feb 2024 19:37:52 -0500 Subject: [PATCH 26/38] rm logs --- src/hooks/useWatchPendingTxs.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/hooks/useWatchPendingTxs.ts b/src/hooks/useWatchPendingTxs.ts index 4fe06a9b9fb..415e74a2879 100644 --- a/src/hooks/useWatchPendingTxs.ts +++ b/src/hooks/useWatchPendingTxs.ts @@ -154,7 +154,6 @@ export const useWatchPendingTransactions = ({ address }: { address: string }) => const watchPendingTransactions = useCallback(async () => { if (!pendingTransactions?.length) return; - console.log('watching pending txs'); const updatedPendingTransactions = await Promise.all( pendingTransactions.map((tx: RainbowTransaction) => processPendingTransaction(tx)) ); @@ -177,7 +176,6 @@ export const useWatchPendingTransactions = ({ address }: { address: string }) => ); if (minedTransactions.length) { - console.log('we mined a transaction'); const chainIds = RainbowNetworks.filter(network => network.enabled && network.networkType !== 'testnet').map(network => network.id); await queryClient.refetchQueries({ queryKey: consolidatedTransactionsQueryKey({ From 9edcfda484ddae0a709e2ef74fdc626bbe271c75 Mon Sep 17 00:00:00 2001 From: skylarbarrera Date: Mon, 12 Feb 2024 12:32:59 -0500 Subject: [PATCH 27/38] save --- .../components/TransactionMasthead.tsx | 248 ++++++++++++++++++ 1 file changed, 248 insertions(+) create mode 100644 src/screens/transaction-details/components/TransactionMasthead.tsx diff --git a/src/screens/transaction-details/components/TransactionMasthead.tsx b/src/screens/transaction-details/components/TransactionMasthead.tsx new file mode 100644 index 00000000000..c5d43059708 --- /dev/null +++ b/src/screens/transaction-details/components/TransactionMasthead.tsx @@ -0,0 +1,248 @@ +import React, { useEffect, useState } from 'react'; +import { NativeCurrencyKey, RainbowTransaction } from '@/entities'; + +import { Bleed, Box, Columns, Cover, Row, Rows, Separator, Stack, Text } from '@/design-system'; + +import styled from '@/styled-thing'; +import { position } from '@/styles'; +import { ThemeContextProps, useTheme } from '@/theme'; +import { usePersistentDominantColorFromImage } from '@/hooks/usePersistentDominantColorFromImage'; +import { ImgixImage } from '@/components/images'; +import RowWithMargins from '@/components/layout/RowWithMargins'; +import { IS_ANDROID } from '@/env'; +import { convertAmountAndPriceToNativeDisplay, convertAmountToBalanceDisplay } from '@/helpers/utilities'; +import { fetchENSAvatar } from '@/hooks/useENSAvatar'; +import { fetchReverseRecord } from '@/handlers/ens'; + +import { address } from '@/utils/abbreviations'; +import { ContactAvatar } from '@/components/contacts'; +import { profileUtils } from '@/utils'; +import { profile } from 'console'; +import { useENSResolver } from '@/hooks'; + +const TransactionMastheadHeight = android ? 153 : 135; + +const Container = styled(Box).attrs({ + direction: 'column', +})({ + borderRadius: 30, + flex: 1, + paddingHorizontal: 20, + height: TransactionMastheadHeight, + overflow: 'hidden', + zIndex: 0, + ...(android ? { paddingTop: 4 } : {}), + justifyContent: 'center', + alitnItems: 'center', +}); + +const Gradient = styled(Box).attrs(({ theme: { colors }, color }: { theme: ThemeContextProps; color: string }) => ({ + backgroundColor: colors.alpha(color, 0.08), +}))({ + ...position.coverAsObject, +}); + +function CurrencyTile({ + contactAddress, + title, + subtitle, + image, + fallback, +}: { + contactAddress?: string; + title: string; + subtitle: string; + image: string; + fallback?: string; +}) { + const { colors } = useTheme(); + const colorForAsset = + usePersistentDominantColorFromImage(image) || + colors.avatarColor[profileUtils.addressHashedColorIndex(contactAddress as string) as number] || + colors.appleBlue; + const avatarColor = colors.avatarBackgrounds[profileUtils.addressHashedColorIndex(contactAddress as string) || 1]; + const colorToUse = title.includes('...') ? avatarColor : colorForAsset; + return ( + + + + + + {!title.includes('...') ? ( + + ) : ( + + )} + + + + + + + {title} + + + + + + {subtitle} + + + + + + + + + ); +} + +const DoubleChevron = () => ( + + + + 􀯻 + + + + 􀯻 + + + + +); + +export default function TransactionMasthead({ + transaction, + nativeCurrency, +}: { + transaction: RainbowTransaction; + nativeCurrency: NativeCurrencyKey; +}) { + const [leftTitle, setLeftTitle] = useState(address(transaction?.from || '', 6, 4)); + const [leftSubtitle, setLeftSubtitle] = useState(''); + const [rightTitle, setRightTitle] = useState(address(transaction?.to || '', 6, 4)); + const [rightSubtitle, setRightSubtitle] = useState(''); + const [rightImage, setRightImage] = useState(transaction?.asset?.icon_url || ''); + const [leftImage, setLeftImage] = useState(transaction?.asset?.icon_url || ''); + + useEffect(() => { + const fetchAndSetData = async () => { + try { + if (['wrap', 'unwrap', 'swap'].includes(transaction?.type)) { + const inAsset = transaction?.changes?.find(a => a?.direction === 'in')?.asset; + const outAsset = transaction?.changes?.find(a => a?.direction === 'out')?.asset; + + if (inAsset && outAsset) { + setLeftImage(outAsset?.icon_url || ''); + setRightImage(inAsset?.icon_url || ''); + const inAssetValueDisplay = convertAmountToBalanceDisplay(inAsset?.balance?.amount || '0', inAsset); + const outAssetValueDisplay = convertAmountToBalanceDisplay(outAsset?.balance?.amount || '0', outAsset); + const inAssetNativeDisplay = convertAmountAndPriceToNativeDisplay( + inAsset?.balance?.amount || '0', + inAsset?.price?.value || '0', + nativeCurrency + )?.display; + const outAssetNativeDisplay = convertAmountAndPriceToNativeDisplay( + outAsset?.balance?.amount || '0', + outAsset?.price?.value || '0', + nativeCurrency + ).display; + + setLeftTitle(outAssetValueDisplay); + setLeftSubtitle(outAssetNativeDisplay); + setRightTitle(inAssetValueDisplay); + setRightSubtitle(inAssetNativeDisplay); + return; + } + } + + const fromEns = await fetchReverseRecord(transaction?.from || ''); + const toEns = await fetchReverseRecord(transaction?.to || ''); + + if (fromEns) { + setLeftSubtitle(leftTitle); + setLeftTitle(fromEns); + const fromAvatar = await fetchENSAvatar(fromEns); + if (fromAvatar?.imageUrl) { + setLeftImage(fromAvatar.imageUrl); + } + } + if (transaction.type === 'contract_interaction' || transaction.type === 'approve') { + if (transaction?.contract?.iconUrl) { + setRightImage(transaction?.contract?.iconUrl); + } + if (transaction?.contract?.name) { + setRightTitle(transaction?.contract?.name); + } + } + + if (toEns && transaction.type !== 'contract_interaction') { + setRightSubtitle(rightTitle); + setRightTitle(toEns); + const toAvatar = await fetchENSAvatar(toEns); + if (toAvatar?.imageUrl) { + setRightImage(toAvatar.imageUrl); + } + } + + if (transaction.type === 'mint') { + const tempTitle = rightTitle; + const tempSubtitle = rightSubtitle; + setRightTitle(leftTitle); + setRightSubtitle(leftSubtitle); + setLeftTitle(tempTitle); + setLeftSubtitle(tempSubtitle); + } + } catch (error) { + console.error('Failed to fetch transaction details:', error); + // Handle errors or set fallback values as needed + } + }; + + fetchAndSetData(); + }, []); + + return ( + + + + + + + + + + + + + + + + + ); +} From 909aa95304b7a84d65b4671baf7eb7292db9c685 Mon Sep 17 00:00:00 2001 From: skylarbarrera Date: Mon, 12 Feb 2024 12:35:36 -0500 Subject: [PATCH 28/38] fix display --- .../components/TransactionDetailsValueAndFeeSection.tsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/screens/transaction-details/components/TransactionDetailsValueAndFeeSection.tsx b/src/screens/transaction-details/components/TransactionDetailsValueAndFeeSection.tsx index 8b57d7e45cc..19ef38406d3 100644 --- a/src/screens/transaction-details/components/TransactionDetailsValueAndFeeSection.tsx +++ b/src/screens/transaction-details/components/TransactionDetailsValueAndFeeSection.tsx @@ -6,7 +6,7 @@ import { Box, Stack, globalColors } from '@/design-system'; import { TransactionDetailsDivider } from '@/screens/transaction-details/components/TransactionDetailsDivider'; import * as i18n from '@/languages'; import { Network } from '@/networks/types'; -import { convertAmountAndPriceToNativeDisplay } from '@/helpers/utilities'; +import { convertAmountAndPriceToNativeDisplay, convertRawAmountToBalance } from '@/helpers/utilities'; import { useAccountSettings } from '@/hooks'; import { useTheme } from '@/theme'; import FastCoinIcon from '@/components/asset-list/RecyclerAssetList2/FastComponents/FastCoinIcon'; @@ -32,6 +32,7 @@ export const TransactionDetailsValueAndFeeSection: React.FC = ({ transact const change = transaction?.changes?.[0]; const value = change?.value || transaction.balance?.display; + const valueDisplay = convertRawAmountToBalance(value || '', assetData!).display || ''; const nativeCurrencyValue = convertAmountAndPriceToNativeDisplay( change?.asset?.balance?.amount || '', change?.asset?.price?.value || '', @@ -92,7 +93,7 @@ export const TransactionDetailsValueAndFeeSection: React.FC = ({ transact ) } title={i18n.t(i18n.l.transaction_details.value)} - value={value || ''} + value={valueDisplay || ''} secondaryValue={nativeCurrencyValue} /> )} From 21a68056d7eb98e592b58c3f39b945a8bd7d64f6 Mon Sep 17 00:00:00 2001 From: skylarbarrera Date: Mon, 12 Feb 2024 12:38:00 -0500 Subject: [PATCH 29/38] cleaning --- .../components/TransactionDetailsValueAndFeeSection.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/screens/transaction-details/components/TransactionDetailsValueAndFeeSection.tsx b/src/screens/transaction-details/components/TransactionDetailsValueAndFeeSection.tsx index 19ef38406d3..375273d81d9 100644 --- a/src/screens/transaction-details/components/TransactionDetailsValueAndFeeSection.tsx +++ b/src/screens/transaction-details/components/TransactionDetailsValueAndFeeSection.tsx @@ -94,7 +94,7 @@ export const TransactionDetailsValueAndFeeSection: React.FC = ({ transact } title={i18n.t(i18n.l.transaction_details.value)} value={valueDisplay || ''} - secondaryValue={nativeCurrencyValue} + secondaryValue={change?.asset?.price?.value ? nativeCurrencyValue : ''} /> )} {fee && ( From 8944edb5ca0b3def28e4280dc17a476b6e6f5b32 Mon Sep 17 00:00:00 2001 From: skylarbarrera Date: Mon, 12 Feb 2024 14:03:25 -0500 Subject: [PATCH 30/38] use new tx parsing for notifs --- src/notifications/NotificationsHandler.tsx | 89 ++++------------------ 1 file changed, 14 insertions(+), 75 deletions(-) diff --git a/src/notifications/NotificationsHandler.tsx b/src/notifications/NotificationsHandler.tsx index 902b4f0d8de..be993a76ec9 100644 --- a/src/notifications/NotificationsHandler.tsx +++ b/src/notifications/NotificationsHandler.tsx @@ -22,13 +22,7 @@ import { Navigation } from '@/navigation'; import Routes from '@rainbow-me/routes'; import { AppState as ApplicationState, AppStateStatus, NativeEventSubscription } from 'react-native'; import notifee, { Event as NotifeeEvent, EventType } from '@notifee/react-native'; -import { getProviderForNetwork } from '@/handlers/web3'; import { ethereumUtils, isLowerCaseMatch } from '@/utils'; -import { NewTransactionOrAddCashTransaction } from '@/entities/transactions/transaction'; -import { TransactionDirection, TransactionStatus } from '@/entities'; -import { parseNewTransaction } from '@/parsers'; -import { isZero } from '@/helpers/utilities'; -import { mapNotificationTransactionType } from '@/notifications/mapTransactionsType'; import walletTypes from '@/helpers/walletTypes'; import { NotificationSubscriptionChangesListener, @@ -43,6 +37,7 @@ import { initializeNotificationSettingsForAllAddressesAndCleanupSettingsForRemovedWallets, } from '@/notifications/settings/initialization'; import { logger } from '@/logger'; +import { transactionFetchQuery } from '@/resources/transactions/transaction'; type Callback = () => void; @@ -160,78 +155,22 @@ export const NotificationsHandler = ({ walletReady }: Props) => { return; } Navigation.handleAction(Routes.PROFILE_SCREEN, {}); - const zerionTransaction = store.getState().data.transactions.find(tx => isLowerCaseMatch(ethereumUtils.getHash(tx) ?? '', data.hash)); - if (zerionTransaction) { - Navigation.handleAction(Routes.TRANSACTION_DETAILS, { - transaction: zerionTransaction, - }); - } else { - const network = ethereumUtils.getNetworkFromChainId(parseInt(data.chain, 10)); - const provider = await getProviderForNetwork(network); - const rpcTransaction = await provider.getTransaction(data.hash); - const transactionConfirmed = rpcTransaction?.blockNumber && rpcTransaction?.blockHash; - if (!transactionConfirmed) { - return; - } - - const newTransactionDetails: NewTransactionOrAddCashTransaction = { - type: mapNotificationTransactionType(data.transaction_type), - network, - hash: rpcTransaction.hash, - amount: rpcTransaction.value.toString(), - nonce: rpcTransaction.nonce, - from: rpcTransaction.from, - to: rpcTransaction.to ?? null, - asset: null, - gasLimit: rpcTransaction.gasLimit, - maxFeePerGas: rpcTransaction.maxFeePerGas, - maxPriorityFeePerGas: rpcTransaction.maxPriorityFeePerGas, - gasPrice: rpcTransaction.gasPrice, - data: rpcTransaction.data, - status: rpcTransaction.blockNumber ? 'confirmed' : 'pending', - }; - const parsedTransaction = await parseNewTransaction(newTransactionDetails, nativeCurrency); - const resultTransaction = { ...parsedTransaction }; - const minedAt = Math.floor(Date.now() / 1000); - let receipt; - - try { - if (rpcTransaction) { - receipt = await rpcTransaction.wait(); - } - } catch (e: any) { - // https://docs.ethers.io/v5/api/providers/types/#providers-TransactionResponse - if (e.transaction) { - // if a transaction field exists, it was confirmed but failed - resultTransaction.status = TransactionStatus.failed; - } else { - // cancelled or replaced - resultTransaction.type = 'cancel'; - resultTransaction.status = TransactionStatus.failed; - } - } - const status = receipt?.status || 0; - if (!isZero(status)) { - let direction = TransactionDirection.out; - if (parsedTransaction?.from && parsedTransaction?.to && isLowerCaseMatch(parsedTransaction.from, parsedTransaction.to)) { - direction = TransactionDirection.self; - } - if (parsedTransaction?.from && parsedTransaction?.to && isLowerCaseMatch(walletAddress, parsedTransaction.to)) { - direction = TransactionDirection.in; - } - } else { - resultTransaction.status = TransactionStatus.failed; - } - resultTransaction.status = 'confirmed'; - resultTransaction.minedAt = minedAt; + const network = ethereumUtils.getNetworkFromChainId(parseInt(data.chain, 10)); + const transaction = await transactionFetchQuery({ + hash: data.hash, + network: network, + address: walletAddress, + currency: nativeCurrency, + }); - if (resultTransaction) { - Navigation.handleAction(Routes.TRANSACTION_DETAILS, { - transaction: resultTransaction, - }); - } + if (!transaction) { + return; } + + Navigation.handleAction(Routes.TRANSACTION_DETAILS, { + transaction, + }); } else if (type === NotificationTypes.walletConnect) { logger.info(`NotificationsHandler: handling wallet connect notification`, { notification }); } else if (type === NotificationTypes.marketing) { From 3ada07f313d07a53b5628f60c110a4f875a029ec Mon Sep 17 00:00:00 2001 From: skylarbarrera Date: Tue, 19 Mar 2024 13:12:28 -0400 Subject: [PATCH 31/38] oops --- src/state/nonces/index.test.ts | 181 --------------------------------- 1 file changed, 181 deletions(-) delete mode 100644 src/state/nonces/index.test.ts diff --git a/src/state/nonces/index.test.ts b/src/state/nonces/index.test.ts deleted file mode 100644 index 3973fe5033c..00000000000 --- a/src/state/nonces/index.test.ts +++ /dev/null @@ -1,181 +0,0 @@ -const TEST_ADDRESS_1 = '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266'; -const TEST_ADDRESS_2 = '0x70997970c51812dc3a010c7d01b50e0d17dc79c8'; -const TEST_ADDRESS_3 = '0x3c44cdddb6a900fa2b585dd299e03d12fa4293bc'; - -import { nonceStore } from '.'; -import { Network } from '@/networks/types'; - -test('should be able to set nonce for one wallet in one network', async () => { - const { nonces, setNonce } = nonceStore.getState(); - expect(nonces).toStrictEqual({}); - setNonce({ - address: TEST_ADDRESS_1, - currentNonce: 1, - latestConfirmedNonce: 1, - network: Network.mainnet, - }); - const newNonces = nonceStore.getState().nonces; - expect(newNonces).toStrictEqual({ - [TEST_ADDRESS_1]: { - [Network.mainnet]: { - currentNonce: 1, - latestConfirmedNonce: 1, - }, - }, - }); -}); - -test('should be able to set nonce for same wallet in a different network', async () => { - const { setNonce } = nonceStore.getState(); - setNonce({ - address: TEST_ADDRESS_1, - currentNonce: 4, - latestConfirmedNonce: 4, - network: Network.optimism, - }); - const newNonces = nonceStore.getState().nonces; - expect(newNonces).toStrictEqual({ - [TEST_ADDRESS_1]: { - [Network.mainnet]: { - currentNonce: 1, - latestConfirmedNonce: 1, - }, - [Network.optimism]: { - currentNonce: 4, - latestConfirmedNonce: 4, - }, - }, - }); -}); - -test('should be able to set nonce for other wallet in one network', async () => { - const { setNonce } = nonceStore.getState(); - setNonce({ - address: TEST_ADDRESS_2, - currentNonce: 2, - latestConfirmedNonce: 2, - network: Network.mainnet, - }); - const newNonces = nonceStore.getState().nonces; - expect(newNonces).toStrictEqual({ - [TEST_ADDRESS_1]: { - [Network.mainnet]: { - currentNonce: 1, - latestConfirmedNonce: 1, - }, - [Network.optimism]: { - currentNonce: 4, - latestConfirmedNonce: 4, - }, - }, - [TEST_ADDRESS_2]: { - [Network.mainnet]: { - currentNonce: 2, - latestConfirmedNonce: 2, - }, - }, - }); -}); - -test('should be able to set nonce for other wallet in other network', async () => { - const { setNonce } = nonceStore.getState(); - setNonce({ - address: TEST_ADDRESS_3, - currentNonce: 3, - latestConfirmedNonce: 3, - network: Network.arbitrum, - }); - const newNonces = nonceStore.getState().nonces; - expect(newNonces).toStrictEqual({ - [TEST_ADDRESS_1]: { - [Network.mainnet]: { - currentNonce: 1, - latestConfirmedNonce: 1, - }, - [Network.optimism]: { - currentNonce: 4, - latestConfirmedNonce: 4, - }, - }, - [TEST_ADDRESS_2]: { - [Network.mainnet]: { - currentNonce: 2, - latestConfirmedNonce: 2, - }, - }, - [TEST_ADDRESS_3]: { - [Network.arbitrum]: { - currentNonce: 3, - latestConfirmedNonce: 3, - }, - }, - }); -}); - -test('should be able to set nonce nonce information correctly', async () => { - const { setNonce, getNonce } = nonceStore.getState(); - setNonce({ - address: TEST_ADDRESS_3, - currentNonce: 3, - latestConfirmedNonce: 3, - network: Network.arbitrum, - }); - const nonces11 = getNonce({ - address: TEST_ADDRESS_1, - network: Network.mainnet, - }); - const nonces12 = getNonce({ - address: TEST_ADDRESS_1, - network: Network.optimism, - }); - const nonces2 = getNonce({ - address: TEST_ADDRESS_2, - network: Network.mainnet, - }); - const nonces3 = getNonce({ - address: TEST_ADDRESS_3, - network: Network.arbitrum, - }); - expect(nonces11?.currentNonce).toEqual(1); - expect(nonces11?.latestConfirmedNonce).toEqual(1); - expect(nonces12?.currentNonce).toEqual(4); - expect(nonces12?.latestConfirmedNonce).toEqual(4); - expect(nonces2?.currentNonce).toEqual(2); - expect(nonces2?.latestConfirmedNonce).toEqual(2); - expect(nonces3?.currentNonce).toEqual(3); - expect(nonces3?.latestConfirmedNonce).toEqual(3); -}); - -test('should be able to update nonce', async () => { - const { setNonce, getNonce } = nonceStore.getState(); - setNonce({ - address: TEST_ADDRESS_1, - currentNonce: 30, - latestConfirmedNonce: 30, - network: Network.mainnet, - }); - const updatedNonce = getNonce({ - address: TEST_ADDRESS_1, - network: Network.mainnet, - }); - const oldNonce = getNonce({ - address: TEST_ADDRESS_1, - network: Network.optimism, - }); - expect(updatedNonce?.currentNonce).toStrictEqual(30); - expect(updatedNonce?.latestConfirmedNonce).toStrictEqual(30); - expect(oldNonce?.currentNonce).toStrictEqual(4); - expect(oldNonce?.latestConfirmedNonce).toStrictEqual(4); - setNonce({ - address: TEST_ADDRESS_1, - currentNonce: 31, - latestConfirmedNonce: 30, - network: Network.mainnet, - }); - const updatedNonceSecondTime = getNonce({ - address: TEST_ADDRESS_1, - network: Network.mainnet, - }); - expect(updatedNonceSecondTime?.currentNonce).toStrictEqual(31); - expect(updatedNonceSecondTime?.latestConfirmedNonce).toStrictEqual(30); -}); From ea212b639eff1f53d29f8aedb7313b76c6b5a834 Mon Sep 17 00:00:00 2001 From: skylarbarrera Date: Tue, 19 Mar 2024 13:13:34 -0400 Subject: [PATCH 32/38] oop --- src/components/activity-list/ActivityList.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/activity-list/ActivityList.js b/src/components/activity-list/ActivityList.js index f3d83c30129..4367a80af1a 100644 --- a/src/components/activity-list/ActivityList.js +++ b/src/components/activity-list/ActivityList.js @@ -115,7 +115,7 @@ const ActivityList = ({ } else { return ( true && } + ListFooterComponent={() => remainingItemsLabel && } ref={handleListRef} ListHeaderComponent={header} alwaysBounceVertical={false} From 5475c30299d2e988dc9b4db38e46d23263b3663d Mon Sep 17 00:00:00 2001 From: skylarbarrera Date: Fri, 22 Mar 2024 14:06:39 -0400 Subject: [PATCH 33/38] change label --- ...nsactionDetailsStatusActionsAndTimestampSection.tsx | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/screens/transaction-details/components/TransactionDetailsStatusActionsAndTimestampSection.tsx b/src/screens/transaction-details/components/TransactionDetailsStatusActionsAndTimestampSection.tsx index 1c8785bbaf9..7aaf0ce0307 100644 --- a/src/screens/transaction-details/components/TransactionDetailsStatusActionsAndTimestampSection.tsx +++ b/src/screens/transaction-details/components/TransactionDetailsStatusActionsAndTimestampSection.tsx @@ -24,7 +24,7 @@ type Props = { }; export const TransactionDetailsStatusActionsAndTimestampSection: React.FC = ({ transaction, hideIcon }) => { - const { minedAt, status, from } = transaction; + const { minedAt, status, type, from } = transaction; const dispatch = useDispatch(); const { navigate, goBack } = useNavigation(); const accountAddress = useSelector((state: AppState) => state.settings.accountAddress); @@ -112,7 +112,7 @@ export const TransactionDetailsStatusActionsAndTimestampSection: React.FC - {status && !hideIcon && ( + {type && !hideIcon && ( )} + - {status && ( + {type && ( - {capitalize(status)} + {/* @ts-ignore */} + {i18n.t(i18n.l.transactions.type[transaction?.title])} )} {date && ( From 555082b231237383c84f3c1b13cb671940100a84 Mon Sep 17 00:00:00 2001 From: skylarbarrera Date: Fri, 22 Mar 2024 14:08:41 -0400 Subject: [PATCH 34/38] use masthead --- .../TransactionDetailsFromToSection.tsx | 62 ++----------------- 1 file changed, 4 insertions(+), 58 deletions(-) diff --git a/src/screens/transaction-details/components/TransactionDetailsFromToSection.tsx b/src/screens/transaction-details/components/TransactionDetailsFromToSection.tsx index 822d8b4042d..bf76c97a9ef 100644 --- a/src/screens/transaction-details/components/TransactionDetailsFromToSection.tsx +++ b/src/screens/transaction-details/components/TransactionDetailsFromToSection.tsx @@ -1,11 +1,8 @@ -import React, { useMemo } from 'react'; -import { Box, Stack } from '@/design-system'; -import * as i18n from '@/languages'; -import { TransactionDetailsAddressRow } from '@/screens/transaction-details/components/TransactionDetailsAddressRow'; -import { useContacts, useUserAccounts } from '@/hooks'; -import { isLowerCaseMatch } from '@/utils'; +import React from 'react'; +import { Box } from '@/design-system'; import { TransactionDetailsDivider } from '@/screens/transaction-details/components/TransactionDetailsDivider'; import { RainbowTransaction } from '@/entities'; +import TransactionMasthead from './TransactionMasthead'; type Props = { transaction: RainbowTransaction; @@ -13,62 +10,11 @@ type Props = { }; export const TransactionDetailsFromToSection: React.FC = ({ transaction, presentToast }) => { - const from = transaction.from ?? undefined; - const to = transaction.to ?? undefined; - const { contacts } = useContacts(); - const fromContact = from ? contacts[from] : undefined; - const toContact = to ? contacts[to] : undefined; - - const { userAccounts, watchedAccounts } = useUserAccounts(); - - const fromAccount = useMemo(() => { - if (!from) { - return undefined; - } else { - return ( - userAccounts.find(account => isLowerCaseMatch(account.address, from)) ?? - watchedAccounts.find(account => isLowerCaseMatch(account.address, from)) - ); - } - }, [from]); - const toAccount = useMemo(() => { - if (!to) { - return undefined; - } else { - return ( - userAccounts.find(account => isLowerCaseMatch(account.address, to)) ?? - watchedAccounts.find(account => isLowerCaseMatch(account.address, to)) - ); - } - }, [to]); - - if (!from && !to) { - return null; - } return ( <> - - {from && ( - - )} - {to && ( - - )} - + ); From ca23ee341c9170a03f9ba30e14e60da3a5b45f86 Mon Sep 17 00:00:00 2001 From: skylarbarrera Date: Fri, 22 Mar 2024 14:09:58 -0400 Subject: [PATCH 35/38] fix NaN --- .../TransactionDetailsValueAndFeeSection.tsx | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/screens/transaction-details/components/TransactionDetailsValueAndFeeSection.tsx b/src/screens/transaction-details/components/TransactionDetailsValueAndFeeSection.tsx index 33098b35ee5..7f60bfe1c26 100644 --- a/src/screens/transaction-details/components/TransactionDetailsValueAndFeeSection.tsx +++ b/src/screens/transaction-details/components/TransactionDetailsValueAndFeeSection.tsx @@ -32,12 +32,10 @@ export const TransactionDetailsValueAndFeeSection: React.FC = ({ transact const change = transaction?.changes?.[0]; const value = change?.value || transaction.balance?.display; - const valueDisplay = convertRawAmountToBalance(value || '', assetData!).display || ''; - const nativeCurrencyValue = convertAmountAndPriceToNativeDisplay( - change?.asset?.balance?.amount || '', - change?.asset?.price?.value || '', - nativeCurrency - ).display; + const valueDisplay = value ? convertRawAmountToBalance(value || '', assetData!).display : ''; + const nativeCurrencyValue = change?.asset?.price?.value + ? convertAmountAndPriceToNativeDisplay(change?.asset?.balance?.amount || '', change?.asset?.price?.value || '', nativeCurrency).display + : ''; const feeValue = fee?.value.display ?? ''; const feeNativeCurrencyValue = fee?.native?.display ?? ''; From b9d0e82f9a0406e004313a8cf09fb823ed9b685f Mon Sep 17 00:00:00 2001 From: skylarbarrera Date: Mon, 25 Mar 2024 12:09:24 -0400 Subject: [PATCH 36/38] clean up for v1 --- .../components/TransactionMasthead.tsx | 399 ++++++++++++------ 1 file changed, 279 insertions(+), 120 deletions(-) diff --git a/src/screens/transaction-details/components/TransactionMasthead.tsx b/src/screens/transaction-details/components/TransactionMasthead.tsx index c5d43059708..c3a6be575d5 100644 --- a/src/screens/transaction-details/components/TransactionMasthead.tsx +++ b/src/screens/transaction-details/components/TransactionMasthead.tsx @@ -1,24 +1,33 @@ -import React, { useEffect, useState } from 'react'; -import { NativeCurrencyKey, RainbowTransaction } from '@/entities'; +// @refresh reset -import { Bleed, Box, Columns, Cover, Row, Rows, Separator, Stack, Text } from '@/design-system'; +import React, { useEffect, useMemo, useState } from 'react'; +import { NativeCurrencyKey, ParsedAddressAsset, RainbowTransaction } from '@/entities'; + +import { Bleed, Box, Columns, Cover, Row, Rows, Separator, Stack, Text, TextProps } from '@/design-system'; import styled from '@/styled-thing'; import { position } from '@/styles'; import { ThemeContextProps, useTheme } from '@/theme'; import { usePersistentDominantColorFromImage } from '@/hooks/usePersistentDominantColorFromImage'; -import { ImgixImage } from '@/components/images'; import RowWithMargins from '@/components/layout/RowWithMargins'; import { IS_ANDROID } from '@/env'; import { convertAmountAndPriceToNativeDisplay, convertAmountToBalanceDisplay } from '@/helpers/utilities'; import { fetchENSAvatar } from '@/hooks/useENSAvatar'; import { fetchReverseRecord } from '@/handlers/ens'; -import { address } from '@/utils/abbreviations'; +import { address, formatAddressForDisplay } from '@/utils/abbreviations'; import { ContactAvatar } from '@/components/contacts'; -import { profileUtils } from '@/utils'; -import { profile } from 'console'; -import { useENSResolver } from '@/hooks'; +import { isLowerCaseMatch } from '@/utils'; +import { useSelector } from 'react-redux'; +import { AppState } from '@/redux/store'; +import { useContacts, useUserAccounts } from '@/hooks'; +import { useTiming } from 'react-native-redash'; +import Animated, { Easing, SharedValue, interpolate, useAnimatedStyle } from 'react-native-reanimated'; +import { removeFirstEmojiFromString, returnStringFirstEmoji } from '@/helpers/emojiHandler'; +import { addressHashedColorIndex, addressHashedEmoji } from '@/utils/profileUtils'; +import ImageAvatar from '@/components/contacts/ImageAvatar'; +import RainbowCoinIcon from '@/components/coin-icon/RainbowCoinIcon'; +import { Network } from '@/networks/types'; const TransactionMastheadHeight = android ? 153 : 135; @@ -46,47 +55,170 @@ function CurrencyTile({ contactAddress, title, subtitle, + address = '', + asset, + showAsset, image, fallback, + onAddressCopied, }: { + asset?: ParsedAddressAsset; + showAsset?: boolean; contactAddress?: string; - title: string; - subtitle: string; - image: string; + title?: string; + subtitle?: string; + image?: string; fallback?: string; + address?: string; + onAddressCopied: () => void; }) { - const { colors } = useTheme(); - const colorForAsset = - usePersistentDominantColorFromImage(image) || - colors.avatarColor[profileUtils.addressHashedColorIndex(contactAddress as string) as number] || - colors.appleBlue; - const avatarColor = colors.avatarBackgrounds[profileUtils.addressHashedColorIndex(contactAddress as string) || 1]; - const colorToUse = title.includes('...') ? avatarColor : colorForAsset; + const accountAddress = useSelector((state: AppState) => state.settings.accountAddress); + const theme = useTheme(); + + // @ts-ignore + const { contacts } = useContacts(); + + const { userAccounts, watchedAccounts } = useUserAccounts(); + const addressContact = address ? contacts[address] : undefined; + const addressAccount = useMemo(() => { + if (!address) { + return undefined; + } else { + return ( + userAccounts.find(account => isLowerCaseMatch(account.address, address)) ?? + watchedAccounts.find(account => isLowerCaseMatch(account.address, address)) + ); + } + }, [address]); + + const formattedAddress = formatAddressForDisplay(address, 4, 6); + const [fetchedEnsName, setFetchedEnsName] = useState(); + const [fetchedEnsImage, setFetchedEnsImage] = useState(); + const [imageLoaded, setImageLoaded] = useState(!!addressAccount?.image); + + const accountEmoji = useMemo(() => returnStringFirstEmoji(addressAccount?.label), [addressAccount]); + const accountName = useMemo(() => removeFirstEmojiFromString(addressAccount?.label), []); + const avatarColor = + addressAccount?.color ?? addressContact?.color ?? theme.colors.avatarBackgrounds[addressHashedColorIndex(address) || 1]; + console.log({ avatarColor }); + const emoji = accountEmoji || addressHashedEmoji(address); + + const name = accountName || fetchedEnsName || addressContact?.nickname || addressContact?.ens || formattedAddress; + + //i18n - search for 'You' + console.log({ accountAddress, address }); + if (accountAddress?.toLowerCase() === address?.toLowerCase() && !showAsset) { + title = 'You'; + } + + const shouldShowAddress = (!name.includes('...') || name === 'You') && !showAsset; + const imageUrl = fetchedEnsImage ?? addressAccount?.image; + const ensAvatarSharedValue = useTiming(!!image || (!!imageUrl && imageLoaded), { + duration: image || addressAccount?.image ? 0 : 420, + }); + + useEffect(() => { + if (!addressContact?.nickname && !accountName) { + fetchReverseRecord(address).then(name => { + if (name) { + setFetchedEnsName(name); + } + }); + } + }, []); + + useEffect(() => { + if (!addressAccount?.image && (fetchedEnsName || addressContact?.ens)) { + const ens = fetchedEnsName ?? addressContact?.ens; + if (ens) { + fetchENSAvatar(ens, { cacheFirst: true }).then(avatar => { + if (avatar?.imageUrl) { + setFetchedEnsImage(avatar.imageUrl); + } + }); + } + } + }, [fetchedEnsName]); + + console.log({ urlTOuse: showAsset ? asset?.icon_url : fetchedEnsImage }); + const colorForAsset = usePersistentDominantColorFromImage(showAsset ? asset?.icon_url : imageUrl) || avatarColor; + + const colorToUse = colorForAsset; + + console.log({ colorForAsset, colorToUse, avatarColor }); + + const emojiAvatarAnimatedStyle = useAnimatedStyle(() => ({ + opacity: interpolate(ensAvatarSharedValue.value, [0, 1], [1, 0]), + })); + const ensAvatarAnimatedStyle = useAnimatedStyle(() => ({ + opacity: ensAvatarSharedValue.value, + })); + + const onImageLoad = () => { + setImageLoaded(true); + }; + return ( - {!title.includes('...') ? ( - - ) : ( - - )} + + {showAsset ? ( + + ) : ( + <> + + {/*add coin icon*/} + + + + + + + + + )} + - - {title} - + + + - - {subtitle} - + @@ -97,6 +229,39 @@ function CurrencyTile({ ); } +type AnimatedTextProps = Omit & { + text: string; + loadedText: string | undefined; +}; +const AnimatedText = ({ text, loadedText, size, weight, color, align, ...props }: AnimatedTextProps) => { + const loadedTextValue = useTiming(!!loadedText, { + duration: 420, + easing: Easing.linear, + }); + const textStyle = useAnimatedStyle(() => ({ + opacity: interpolate(loadedTextValue.value, [0, 0.5, 1], [1, 0, 0]), + })); + const loadedTextStyle = useAnimatedStyle(() => ({ + opacity: interpolate(loadedTextValue.value, [0, 0.5, 1], [0, 0, 1]), + })); + + return ( + + + + {text} + + + + + + {loadedText} + + + + + ); +}; const DoubleChevron = () => ( @@ -112,97 +277,85 @@ const DoubleChevron = () => ( ); -export default function TransactionMasthead({ - transaction, - nativeCurrency, -}: { - transaction: RainbowTransaction; - nativeCurrency: NativeCurrencyKey; -}) { - const [leftTitle, setLeftTitle] = useState(address(transaction?.from || '', 6, 4)); - const [leftSubtitle, setLeftSubtitle] = useState(''); - const [rightTitle, setRightTitle] = useState(address(transaction?.to || '', 6, 4)); - const [rightSubtitle, setRightSubtitle] = useState(''); - const [rightImage, setRightImage] = useState(transaction?.asset?.icon_url || ''); - const [leftImage, setLeftImage] = useState(transaction?.asset?.icon_url || ''); +export default function TransactionMasthead({ transaction }: { transaction: RainbowTransaction }) { + const nativeCurrency = useSelector((state: AppState) => state.settings.nativeCurrency); - useEffect(() => { - const fetchAndSetData = async () => { - try { - if (['wrap', 'unwrap', 'swap'].includes(transaction?.type)) { - const inAsset = transaction?.changes?.find(a => a?.direction === 'in')?.asset; - const outAsset = transaction?.changes?.find(a => a?.direction === 'out')?.asset; - - if (inAsset && outAsset) { - setLeftImage(outAsset?.icon_url || ''); - setRightImage(inAsset?.icon_url || ''); - const inAssetValueDisplay = convertAmountToBalanceDisplay(inAsset?.balance?.amount || '0', inAsset); - const outAssetValueDisplay = convertAmountToBalanceDisplay(outAsset?.balance?.amount || '0', outAsset); - const inAssetNativeDisplay = convertAmountAndPriceToNativeDisplay( - inAsset?.balance?.amount || '0', - inAsset?.price?.value || '0', - nativeCurrency - )?.display; - const outAssetNativeDisplay = convertAmountAndPriceToNativeDisplay( - outAsset?.balance?.amount || '0', - outAsset?.price?.value || '0', - nativeCurrency - ).display; - - setLeftTitle(outAssetValueDisplay); - setLeftSubtitle(outAssetNativeDisplay); - setRightTitle(inAssetValueDisplay); - setRightSubtitle(inAssetNativeDisplay); - return; - } - } + const inputAsset = useMemo(() => { + const inAsset = transaction?.changes?.find(a => a?.direction === 'in')?.asset; + if (!inAsset) return undefined; - const fromEns = await fetchReverseRecord(transaction?.from || ''); - const toEns = await fetchReverseRecord(transaction?.to || ''); + console.log('price : ', inAsset?.price?.value); - if (fromEns) { - setLeftSubtitle(leftTitle); - setLeftTitle(fromEns); - const fromAvatar = await fetchENSAvatar(fromEns); - if (fromAvatar?.imageUrl) { - setLeftImage(fromAvatar.imageUrl); - } - } - if (transaction.type === 'contract_interaction' || transaction.type === 'approve') { - if (transaction?.contract?.iconUrl) { - setRightImage(transaction?.contract?.iconUrl); - } - if (transaction?.contract?.name) { - setRightTitle(transaction?.contract?.name); - } - } + return { + inAssetValueDisplay: convertAmountToBalanceDisplay(inAsset?.balance?.amount || '0', inAsset), + inAssetNativeDisplay: inAsset?.price?.value + ? convertAmountAndPriceToNativeDisplay(inAsset?.balance?.amount || '0', inAsset?.price?.value || '0', nativeCurrency)?.display + : '-', + ...inAsset, + }; + }, []); - if (toEns && transaction.type !== 'contract_interaction') { - setRightSubtitle(rightTitle); - setRightTitle(toEns); - const toAvatar = await fetchENSAvatar(toEns); - if (toAvatar?.imageUrl) { - setRightImage(toAvatar.imageUrl); - } - } + const outputAsset = useMemo(() => { + const outAsset = transaction?.changes?.find(a => a?.direction === 'out')?.asset; + if (!outAsset) return undefined; - if (transaction.type === 'mint') { - const tempTitle = rightTitle; - const tempSubtitle = rightSubtitle; - setRightTitle(leftTitle); - setRightSubtitle(leftSubtitle); - setLeftTitle(tempTitle); - setLeftSubtitle(tempSubtitle); - } - } catch (error) { - console.error('Failed to fetch transaction details:', error); - // Handle errors or set fallback values as needed - } + return { + image: outAsset?.icon_url || '', + inAssetValueDisplay: convertAmountToBalanceDisplay(outAsset?.balance?.amount || '0', outAsset), + inAssetNativeDisplay: outAsset?.price?.value + ? convertAmountAndPriceToNativeDisplay(outAsset?.balance?.amount || '0', outAsset?.price?.value || '0', nativeCurrency)?.display + : '-', + ...outAsset, }; - - fetchAndSetData(); }, []); + const contractImage = transaction?.contract?.iconUrl; + const contractName = transaction?.contract?.name; + console.log({ contractName, contractImage }); + + // if its a mint then we want to show the mint contract first + const toAddress = (transaction.type === 'mint' ? transaction?.from : transaction?.to) || undefined; + const fromAddress = (transaction.type === 'mint' ? transaction?.to : transaction?.from) || undefined; + + const getRightMasteadData = (): { title?: string; subtitle?: string; image?: string } => { + if (transaction.type === 'swap') { + return { + title: inputAsset?.inAssetValueDisplay, + subtitle: inputAsset?.inAssetNativeDisplay, + }; + } + if (transaction.type === 'contract_interaction' || transaction.type === 'approve') { + return { + title: contractName, + subtitle: transaction?.from || '', + image: contractImage, + }; + } + + return { + title: undefined, + subtitle: undefined, + image: undefined, + }; + }; + + const getLeftMasteadData = (): { title?: string; subtitle?: string; image?: string } => { + if (transaction.type === 'swap') { + return { + title: outputAsset?.inAssetValueDisplay, + subtitle: outputAsset?.inAssetNativeDisplay, + }; + } + return { + title: undefined, + subtitle: undefined, + image: undefined, + }; + }; + + const leftMasteadData = getLeftMasteadData(); + const rightMasteadData = getRightMasteadData(); + return ( @@ -210,19 +363,25 @@ export default function TransactionMasthead({ {}} /> {}} /> From b438351e03c520c975d4905bc5128d4f061f93dd Mon Sep 17 00:00:00 2001 From: skylarbarrera Date: Mon, 25 Mar 2024 12:12:18 -0400 Subject: [PATCH 37/38] i18n + logs --- src/languages/en_US.json | 1 + .../components/TransactionMasthead.tsx | 14 +++----------- 2 files changed, 4 insertions(+), 11 deletions(-) diff --git a/src/languages/en_US.json b/src/languages/en_US.json index 089b960970d..b910e9937a5 100644 --- a/src/languages/en_US.json +++ b/src/languages/en_US.json @@ -1992,6 +1992,7 @@ "to": "To", "value": "Value", "hash": "Tx Hash", + "you": "You", "network_fee": "Network Fee", "hash_copied": "\uDBC0\uDC63 Transaction hash copied", "address_copied": "\uDBC0\uDC63 Address copied", diff --git a/src/screens/transaction-details/components/TransactionMasthead.tsx b/src/screens/transaction-details/components/TransactionMasthead.tsx index c3a6be575d5..5d815e11dbf 100644 --- a/src/screens/transaction-details/components/TransactionMasthead.tsx +++ b/src/screens/transaction-details/components/TransactionMasthead.tsx @@ -28,6 +28,7 @@ import { addressHashedColorIndex, addressHashedEmoji } from '@/utils/profileUtil import ImageAvatar from '@/components/contacts/ImageAvatar'; import RainbowCoinIcon from '@/components/coin-icon/RainbowCoinIcon'; import { Network } from '@/networks/types'; +import * as lang from '@/languages'; const TransactionMastheadHeight = android ? 153 : 135; @@ -100,18 +101,15 @@ function CurrencyTile({ const accountName = useMemo(() => removeFirstEmojiFromString(addressAccount?.label), []); const avatarColor = addressAccount?.color ?? addressContact?.color ?? theme.colors.avatarBackgrounds[addressHashedColorIndex(address) || 1]; - console.log({ avatarColor }); const emoji = accountEmoji || addressHashedEmoji(address); const name = accountName || fetchedEnsName || addressContact?.nickname || addressContact?.ens || formattedAddress; - //i18n - search for 'You' - console.log({ accountAddress, address }); if (accountAddress?.toLowerCase() === address?.toLowerCase() && !showAsset) { - title = 'You'; + title = lang.t(lang.l.transaction_details.you); } - const shouldShowAddress = (!name.includes('...') || name === 'You') && !showAsset; + const shouldShowAddress = (!name.includes('...') || name === lang.t(lang.l.transaction_details.you)) && !showAsset; const imageUrl = fetchedEnsImage ?? addressAccount?.image; const ensAvatarSharedValue = useTiming(!!image || (!!imageUrl && imageLoaded), { duration: image || addressAccount?.image ? 0 : 420, @@ -140,13 +138,10 @@ function CurrencyTile({ } }, [fetchedEnsName]); - console.log({ urlTOuse: showAsset ? asset?.icon_url : fetchedEnsImage }); const colorForAsset = usePersistentDominantColorFromImage(showAsset ? asset?.icon_url : imageUrl) || avatarColor; const colorToUse = colorForAsset; - console.log({ colorForAsset, colorToUse, avatarColor }); - const emojiAvatarAnimatedStyle = useAnimatedStyle(() => ({ opacity: interpolate(ensAvatarSharedValue.value, [0, 1], [1, 0]), })); @@ -284,8 +279,6 @@ export default function TransactionMasthead({ transaction }: { transaction: Rain const inAsset = transaction?.changes?.find(a => a?.direction === 'in')?.asset; if (!inAsset) return undefined; - console.log('price : ', inAsset?.price?.value); - return { inAssetValueDisplay: convertAmountToBalanceDisplay(inAsset?.balance?.amount || '0', inAsset), inAssetNativeDisplay: inAsset?.price?.value @@ -311,7 +304,6 @@ export default function TransactionMasthead({ transaction }: { transaction: Rain const contractImage = transaction?.contract?.iconUrl; const contractName = transaction?.contract?.name; - console.log({ contractName, contractImage }); // if its a mint then we want to show the mint contract first const toAddress = (transaction.type === 'mint' ? transaction?.from : transaction?.to) || undefined; From b56233ce311b43c6777b2fa025e6918f38677f46 Mon Sep 17 00:00:00 2001 From: skylarbarrera Date: Mon, 25 Mar 2024 12:27:24 -0400 Subject: [PATCH 38/38] lint --- src/state/internal/createStore.ts | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/src/state/internal/createStore.ts b/src/state/internal/createStore.ts index 373ea35ae99..3c49c5eb18a 100644 --- a/src/state/internal/createStore.ts +++ b/src/state/internal/createStore.ts @@ -3,18 +3,14 @@ import create, { Mutate, StoreApi } from 'zustand/vanilla'; import { persistStorage } from './persistStorage'; - type Initializer = Parameters>[0]; -export type StoreWithPersist = Mutate< - StoreApi, - [['zustand/persist', unknown]] -> & { +export type StoreWithPersist = Mutate, [['zustand/persist', unknown]]> & { initializer: Initializer; }; export function createStore( initializer: Initializer, - { persist: persistOptions }: { persist?: PersistOptions } = {}, + { persist: persistOptions }: { persist?: PersistOptions } = {} ) { const name = `rainbow.zustand.${persistOptions?.name}`; return Object.assign( @@ -22,9 +18,9 @@ export function createStore( persist(initializer, { ...persistOptions, name, - getStorage: () => (persistStorage), - }), + getStorage: () => persistStorage, + }) ), - { initializer }, + { initializer } ); }