diff --git a/src/logic/collectibles/sources/Gnosis.ts b/src/logic/collectibles/sources/Gnosis.ts index 3cc05a2fce..c916a653c8 100644 --- a/src/logic/collectibles/sources/Gnosis.ts +++ b/src/logic/collectibles/sources/Gnosis.ts @@ -1,6 +1,6 @@ import { RateLimit } from 'async-sema' -import { Collectibles, NFTAsset, NFTAssets, NFTTokens } from 'src/logic/collectibles/sources/collectibles' +import { Collectibles, NFTAsset, NFTAssets, NFTTokens } from 'src/logic/collectibles/sources/collectibles.d' import NFTIcon from 'src/routes/safe/components/Balances/assets/nft_icon.png' import { fetchErc20AndErc721AssetsList, fetchSafeCollectibles } from 'src/logic/tokens/api' import { TokenResult } from 'src/logic/tokens/api/fetchErc20AndErc721AssetsList' diff --git a/src/logic/collectibles/sources/OpenSea.ts b/src/logic/collectibles/sources/OpenSea.ts index 1e08fcf2db..97661b7605 100644 --- a/src/logic/collectibles/sources/OpenSea.ts +++ b/src/logic/collectibles/sources/OpenSea.ts @@ -2,7 +2,7 @@ import { RateLimit } from 'async-sema' import { getNetworkId } from 'src/config' import { ETHEREUM_NETWORK } from 'src/config/networks/network.d' -import { Collectibles, NFTAssets, NFTTokens, OpenSeaAssets } from 'src/logic/collectibles/sources/collectibles' +import { Collectibles, NFTAssets, NFTTokens, OpenSeaAssets } from 'src/logic/collectibles/sources/collectibles.d' import NFTIcon from 'src/routes/safe/components/Balances/assets/nft_icon.png' import { OPENSEA_API_KEY } from 'src/utils/constants' diff --git a/src/logic/collectibles/store/selectors/index.ts b/src/logic/collectibles/store/selectors/index.ts index 8b04793b8e..3a922048b1 100644 --- a/src/logic/collectibles/store/selectors/index.ts +++ b/src/logic/collectibles/store/selectors/index.ts @@ -1,5 +1,5 @@ import { createSelector } from 'reselect' -import { NFTAsset, NFTAssets, NFTTokens } from 'src/logic/collectibles/sources/collectibles' +import { NFTAsset, NFTAssets, NFTTokens } from 'src/logic/collectibles/sources/collectibles.d' import { AppReduxState } from 'src/store' import { NFT_ASSETS_REDUCER_ID, NFT_TOKENS_REDUCER_ID } from 'src/logic/collectibles/store/reducer/collectibles' diff --git a/src/logic/contracts/generateBatchRequests.ts b/src/logic/contracts/generateBatchRequests.ts index 2d48979bd8..0ed3c09c48 100644 --- a/src/logic/contracts/generateBatchRequests.ts +++ b/src/logic/contracts/generateBatchRequests.ts @@ -1,4 +1,6 @@ import { web3ReadOnly as web3 } from 'src/logic/wallets/getWeb3' +import { BatchRequest } from 'web3-core' +import { AbiItem } from 'web3-utils' /** * Generates a batch request for grouping RPC calls @@ -10,23 +12,33 @@ import { web3ReadOnly as web3 } from 'src/logic/wallets/getWeb3' * @param {array<{ args: [any], method: string, type: 'eth'|undefined } | string>} args.methods - methods to be called * @returns {Promise<[*]>} */ -const generateBatchRequests = ({ abi, address, batch, context, methods }: any): any => { - const contractInstance: any = new web3.eth.Contract(abi, address) +type MethodsArgsType = Array + + interface Props { + abi: AbiItem[] + address: string + batch?: BatchRequest + context?: unknown + methods: Array + } + +const generateBatchRequests = ({ abi, address, batch, context, methods }: Props): Promise => { + const contractInstance = new web3.eth.Contract(abi, address) const localBatch = new web3.BatchRequest() const values = methods.map((methodObject) => { - let method, type, args = [] + let method, type, args: MethodsArgsType = [] if (typeof methodObject === 'string') { method = methodObject } else { - ;({ method, type, args = [] } = methodObject) + ({ method, type, args } = methodObject) } return new Promise((resolve) => { const resolver = (error, result) => { if (error) { - resolve(null) + resolve() } else { resolve(result) } @@ -43,7 +55,8 @@ const generateBatchRequests = ({ abi, address, batch, context, methods }: any): // If batch was provided add to external batch batch ? batch.add(request) : localBatch.add(request) } catch (e) { - resolve(null) + console.error('There was an error trying to batch request from web3.', e) + resolve() } }) }) @@ -54,9 +67,8 @@ const generateBatchRequests = ({ abi, address, batch, context, methods }: any): // in the outside function where the batch object is created. !batch && localBatch.execute() - const returnValues = context ? [context, ...values] : values - - return Promise.all(returnValues) + // @ts-ignore + return Promise.all([context, ...values]) } export default generateBatchRequests diff --git a/src/logic/safe/store/actions/__tests__/transactionHelpers.test.ts b/src/logic/safe/store/actions/__tests__/transactionHelpers.test.ts index f9927c8bff..6fb7a15d7d 100644 --- a/src/logic/safe/store/actions/__tests__/transactionHelpers.test.ts +++ b/src/logic/safe/store/actions/__tests__/transactionHelpers.test.ts @@ -750,7 +750,36 @@ describe('calculateTransactionType', () => { describe('buildTx', () => { it('Returns a valid transaction', async () => { // given - const cancelTx1 = makeTransaction() + const cancelTx1 = { + baseGas: 0, + blockNumber: 0, + confirmations: [], + confirmationsRequired: 2, + data: null, + dataDecoded: undefined, + ethGasPrice: '0', + executionDate: null, + executor: '', + fee: '', + gasPrice: '', + gasToken: '', + gasUsed: 0, + isExecuted: false, + isSuccessful: true, + modified: '', + nonce: 0, + operation: 0, + origin: null, + refundReceiver: '', + safe: '', + safeTxGas: 0, + safeTxHash: '', + signatures: '', + submissionDate: null, + to: '', + transactionHash: null, + value: '', + } const transaction = getMockedTxServiceModel({ to: safeAddress2, value: '0' }) const userAddress = 'address1' const cancellationTxs = List([cancelTx1]) @@ -764,7 +793,7 @@ describe('buildTx', () => { }) const knownTokens = Map & Readonly>() knownTokens.set('0x00Df91984582e6e96288307E9c2f20b38C8FeCE9', token) - const outgoingTxs = List([cancelTx1]) + const outgoingTxs = [cancelTx1] const safeInstance = makeSafe({ name: 'LOADED SAFE', address: safeAddress }) const expectedTx = makeTransaction({ baseGas: 0, @@ -814,7 +843,7 @@ describe('buildTx', () => { outgoingTxs, safe: safeInstance, tx: transaction, - txCode: null, + txCode: undefined, }) // then diff --git a/src/logic/safe/store/actions/fetchSafe.ts b/src/logic/safe/store/actions/fetchSafe.ts index e688ce222b..6813ea5f0d 100644 --- a/src/logic/safe/store/actions/fetchSafe.ts +++ b/src/logic/safe/store/actions/fetchSafe.ts @@ -1,5 +1,7 @@ import GnosisSafeSol from '@gnosis.pm/safe-contracts/build/contracts/GnosisSafe.json' import { List, Set, Map } from 'immutable' +import { Action, Dispatch } from 'redux' +import { AbiItem } from 'web3-utils' import generateBatchRequests from 'src/logic/contracts/generateBatchRequests' import { getLocalSafe, getSafeName } from 'src/logic/safe/utils' @@ -10,10 +12,8 @@ import addSafeOwner from 'src/logic/safe/store/actions/addSafeOwner' import removeSafeOwner from 'src/logic/safe/store/actions/removeSafeOwner' import updateSafe from 'src/logic/safe/store/actions/updateSafe' import { makeOwner } from 'src/logic/safe/store/models/owner' - import { checksumAddress } from 'src/utils/checksumAddress' import { ModulePair, SafeOwner, SafeRecordProps } from 'src/logic/safe/store/models/safe' -import { Action, Dispatch } from 'redux' import { SENTINEL_ADDRESS } from 'src/logic/contracts/safeContracts' import { AppReduxState } from 'src/store' import { latestMasterContractVersionSelector } from '../selectors' @@ -40,8 +40,8 @@ const buildOwnersFrom = (safeOwners: string[], localSafe?: SafeRecordProps): Lis return List(ownersList) } -const buildModulesLinkedList = (modules: string[] | undefined, nextModule: string): Array | null => { - if (modules?.length) { +const buildModulesLinkedList = (modules?: string[], nextModule?: string): Array | null => { + if (modules?.length && nextModule) { return modules.map((moduleAddress, index, modules) => { const prevModule = modules[index + 1] return [moduleAddress, prevModule !== undefined ? prevModule : nextModule] @@ -58,9 +58,9 @@ export const buildSafe = async ( const safeAddress = checksumAddress(safeAdd) const safeParams = ['getThreshold', 'nonce', 'VERSION', 'getOwners'] - const [[thresholdStr, nonceStr, currentVersion, remoteOwners], localSafe, ethBalance] = await Promise.all([ - generateBatchRequests({ - abi: GnosisSafeSol.abi, + const [[, thresholdStr, nonceStr, currentVersion, remoteOwners = []], localSafe, ethBalance] = await Promise.all([ + generateBatchRequests<[undefined, string | undefined, string | undefined, string | undefined, string[]]>({ + abi: GnosisSafeSol.abi as AbiItem[], address: safeAddress, methods: safeParams, }), @@ -81,7 +81,7 @@ export const buildSafe = async ( owners, ethBalance, nonce, - currentVersion, + currentVersion: currentVersion ?? '', needsUpdate, featuresEnabled, balances: Map(), @@ -104,9 +104,23 @@ export const checkAndUpdateSafe = (safeAdd: string) => async (dispatch: Dispatch // TODO: 100 is an arbitrary large number, to avoid the need for pagination. But pagination must be properly handled { method: 'getModulesPaginated', args: [SENTINEL_ADDRESS, 100] }, ] - const [[remoteThreshold, remoteNonce, remoteOwners, modules], localSafe] = await Promise.all([ - generateBatchRequests({ - abi: GnosisSafeSol.abi, + const [[, remoteThreshold, remoteNonce, remoteOwners, modules], localSafe] = await Promise.all([ + generateBatchRequests< + [ + undefined, + string | undefined, + string | undefined, + string[], + ( + | { + array: string[] + next: string + } + | undefined + ), + ] + >({ + abi: GnosisSafeSol.abi as AbiItem[], address: safeAddress, methods: safeParams, }), diff --git a/src/logic/safe/store/actions/transactions/fetchTransactions/loadIncomingTransactions.ts b/src/logic/safe/store/actions/transactions/fetchTransactions/loadIncomingTransactions.ts index 4accf5dd83..d52130a90e 100644 --- a/src/logic/safe/store/actions/transactions/fetchTransactions/loadIncomingTransactions.ts +++ b/src/logic/safe/store/actions/transactions/fetchTransactions/loadIncomingTransactions.ts @@ -1,5 +1,8 @@ import bn from 'bignumber.js' import { List, Map } from 'immutable' +import { Transaction, TransactionReceipt } from 'web3-core' +import { AbiItem } from 'web3-utils' + import { getNetworkInfo } from 'src/config' import generateBatchRequests from 'src/logic/contracts/generateBatchRequests' import { ALTERNATIVE_TOKEN_ABI } from 'src/logic/tokens/utils/alternativeAbi' @@ -53,8 +56,16 @@ const batchIncomingTxsTokenDataRequest = (txs: IncomingTxServiceModel[]) => { { method: 'getTransactionReceipt', args: [tx.transactionHash], type: 'eth' }, ] - return generateBatchRequests({ - abi: ALTERNATIVE_TOKEN_ABI, + return generateBatchRequests< + [ + IncomingTxServiceModel, + string | undefined, + string | undefined, + Transaction | undefined, + TransactionReceipt | undefined, + ] + >({ + abi: ALTERNATIVE_TOKEN_ABI as AbiItem[], address: tx.tokenAddress, batch, context: tx, @@ -65,11 +76,11 @@ const batchIncomingTxsTokenDataRequest = (txs: IncomingTxServiceModel[]) => { batch.execute() return Promise.all(whenTxsValues).then((txsValues) => - txsValues.map(([tx, symbol, decimals, { gasPrice }, { gasUsed }]) => [ + txsValues.map(([tx, symbol, decimals, ethTx, ethTxReceipt]) => [ tx, - symbol === null ? nativeCoin.symbol : symbol, - decimals === null ? nativeCoin.decimals : decimals, - new bn(gasPrice).times(gasUsed), + symbol ? symbol : nativeCoin.symbol, + decimals ? decimals : nativeCoin.decimals, + new bn(ethTx?.gasPrice ?? 0).times(ethTxReceipt?.gasUsed ?? 0), ]), ) } diff --git a/src/logic/safe/store/actions/transactions/fetchTransactions/loadOutgoingTransactions.ts b/src/logic/safe/store/actions/transactions/fetchTransactions/loadOutgoingTransactions.ts index 89d53d9599..4dca08fb9e 100644 --- a/src/logic/safe/store/actions/transactions/fetchTransactions/loadOutgoingTransactions.ts +++ b/src/logic/safe/store/actions/transactions/fetchTransactions/loadOutgoingTransactions.ts @@ -1,7 +1,7 @@ import { fromJS, List, Map } from 'immutable' import generateBatchRequests from 'src/logic/contracts/generateBatchRequests' -import { TOKEN_REDUCER_ID } from 'src/logic/tokens/store/reducer/tokens' +import { TOKEN_REDUCER_ID, TokenState } from 'src/logic/tokens/store/reducer/tokens' import { web3ReadOnly } from 'src/logic/wallets/getWeb3' import { PROVIDER_REDUCER_ID } from 'src/logic/wallets/store/reducer/provider' import { buildTx, isCancelTransaction } from 'src/logic/safe/store/actions/transactions/utils/transactionHelpers' @@ -59,8 +59,8 @@ export type SafeTransactionsType = { } export type OutgoingTxs = { - cancellationTxs: any - outgoingTxs: any + cancellationTxs: Record + outgoingTxs: TxServiceModel[] } export type BatchProcessTxsProps = OutgoingTxs & { @@ -97,12 +97,14 @@ const extractCancelAndOutgoingTxs = (safeAddress: string, outgoingTxs: TxService ) } +type BatchRequestReturnValues = [TxServiceModel, string | undefined] + /** * Requests Contract's code for all the Contracts the Safe has interacted with * @param transactions * @returns {Promise<[Promise<*[]>, Promise<*[]>, Promise<*[]>, Promise<*[]>, Promise<*[]>, Promise<*[]>, Promise<*[]>, Promise<*[]>, Promise<*[]>, Promise<*[]>]>} */ -const batchRequestContractCode = (transactions: any[]): Promise => { +const batchRequestContractCode = (transactions: TxServiceModel[]): Promise => { if (!transactions || !Array.isArray(transactions)) { throw new Error('`transactions` must be provided in order to lookup information') } @@ -110,7 +112,7 @@ const batchRequestContractCode = (transactions: any[]): Promise => { const batch = new web3ReadOnly.BatchRequest() const whenTxsValues = transactions.map((tx) => { - return generateBatchRequests({ + return generateBatchRequests({ abi: [], address: tx.to, batch, @@ -141,7 +143,7 @@ const batchProcessOutgoingTransactions = async ({ safe, }: BatchProcessTxsProps): Promise<{ cancel: Record - outgoing: Array + outgoing: Transaction[] }> => { // cancellation transactions const cancelTxsValues = Object.values(cancellationTxs) @@ -193,9 +195,9 @@ export const loadOutgoingTransactions = async (safeAddress: string): Promise { ) } -export const isOutgoingTransaction = (tx: TxServiceModel, safeAddress: string): boolean => { +export const isOutgoingTransaction = (tx: TxServiceModel, safeAddress?: string): boolean => { return !sameAddress(tx.to, safeAddress) && !isEmptyData(tx.data) } export const isCustomTransaction = async ( tx: TxServiceModel, - txCode: string | null, - safeAddress: string, - knownTokens: Map, + txCode?: string, + safeAddress?: string, + knownTokens?: TokenState, ): Promise => { const isOutgoing = isOutgoingTransaction(tx, safeAddress) const isErc20 = await isSendERC20Transaction(tx, txCode, knownTokens) @@ -162,7 +162,7 @@ export const getConfirmations = (tx: TxServiceModel): List => { export const isTransactionCancelled = ( tx: TxServiceModel, outgoingTxs: Array, - cancellationTxs: { number: TxServiceModel }, + cancellationTxs: Record, ): boolean => { return ( // not executed @@ -231,7 +231,7 @@ export const calculateTransactionType = (tx: Transaction): TransactionTypeValues export type BuildTx = BatchProcessTxsProps & { tx: TxServiceModel - txCode: string | null + txCode?: string } export const buildTx = async ({ diff --git a/src/logic/safe/utils/safeVersion.ts b/src/logic/safe/utils/safeVersion.ts index 2c4b91d36a..bdfa608020 100644 --- a/src/logic/safe/utils/safeVersion.ts +++ b/src/logic/safe/utils/safeVersion.ts @@ -40,10 +40,10 @@ const checkFeatureEnabledByVersion = (featureConfig: FeatureConfigByVersion, ver return featureConfig.validVersion ? semverSatisfies(version, featureConfig.validVersion) : true } -export const enabledFeatures = (version: string): FEATURES[] => { +export const enabledFeatures = (version?: string): FEATURES[] => { const disabledFeatures = getNetworkConfigDisabledFeatures() return FEATURES_BY_VERSION.reduce((acc: FEATURES[], feature: Feature) => { - if (!disabledFeatures.includes(feature.name) && checkFeatureEnabledByVersion(feature, version)) { + if (!disabledFeatures.includes(feature.name) && version && checkFeatureEnabledByVersion(feature, version)) { acc.push(feature.name) } return acc diff --git a/src/logic/tokens/store/actions/fetchTokens.ts b/src/logic/tokens/store/actions/fetchTokens.ts index fdb7ea76ab..20e170afb3 100644 --- a/src/logic/tokens/store/actions/fetchTokens.ts +++ b/src/logic/tokens/store/actions/fetchTokens.ts @@ -4,6 +4,7 @@ import ERC20Detailed from '@openzeppelin/contracts/build/contracts/ERC20Detailed import ERC721 from '@openzeppelin/contracts/build/contracts/ERC721.json' import { List } from 'immutable' import contract from '@truffle/contract/index.js' +import { AbiItem } from 'web3-utils' import saveTokens from './saveTokens' @@ -53,8 +54,8 @@ export const containsMethodByHash = async (contractAddress: string, methodHash: } const getTokenValues = (tokenAddress) => - generateBatchRequests({ - abi: ERC20Detailed.abi, + generateBatchRequests<[undefined, string | undefined, string | undefined, string | undefined]>({ + abi: ERC20Detailed.abi as AbiItem[], address: tokenAddress, methods: ['decimals', 'name', 'symbol'], }) @@ -69,7 +70,7 @@ export const getTokenInfos = async (tokenAddress: string): Promise { const generateBatchRequests = require('src/logic/contracts/generateBatchRequests') const spyTokenInfos = fetchTokens.getTokenInfos.mockImplementationOnce(() => null) - const spyGenerateBatchRequest = generateBatchRequests.default.mockImplementationOnce(() => [decimals, symbol]) + const spyGenerateBatchRequest = generateBatchRequests.default.mockImplementationOnce(() => [ + undefined, + decimals, + symbol, + ]) // when const result = await getERC20DecimalsAndSymbol(tokenAddress) diff --git a/src/logic/tokens/utils/tokenHelpers.ts b/src/logic/tokens/utils/tokenHelpers.ts index 186b05a242..b7bb4b2fa9 100644 --- a/src/logic/tokens/utils/tokenHelpers.ts +++ b/src/logic/tokens/utils/tokenHelpers.ts @@ -1,3 +1,5 @@ +import { AbiItem } from 'web3-utils' + import { getNetworkInfo } from 'src/config' import generateBatchRequests from 'src/logic/contracts/generateBatchRequests' import { @@ -6,11 +8,11 @@ import { getERC721TokenContract, } from 'src/logic/tokens/store/actions/fetchTokens' import { makeToken, Token } from 'src/logic/tokens/store/model/token' +import { TokenState } from 'src/logic/tokens/store/reducer/tokens' import { ALTERNATIVE_TOKEN_ABI } from 'src/logic/tokens/utils/alternativeAbi' import { web3ReadOnly as web3 } from 'src/logic/wallets/getWeb3' import { isEmptyData } from 'src/logic/safe/store/actions/transactions/utils/transactionHelpers' import { TxServiceModel } from 'src/logic/safe/store/actions/transactions/fetchTransactions/loadOutgoingTransactions' -import { Map } from 'immutable' export const SAFE_TRANSFER_FROM_WITHOUT_DATA_HASH = '42842e0e' @@ -40,18 +42,13 @@ export const isTokenTransfer = (tx: TxServiceModel): boolean => { return !isEmptyData(tx.data) && tx.data?.substring(0, 10) === '0xa9059cbb' && Number(tx.value) === 0 } -export const isSendERC721Transaction = ( - tx: TxServiceModel, - txCode: string | null, - knownTokens: Map, -): boolean => { +export const isSendERC721Transaction = (tx: TxServiceModel, txCode?: string, knownTokens?: TokenState): boolean => { // "0x57f1887a8BF19b14fC0dF6Fd9B2acc9Af147eA85" - ens token contract, includes safeTransferFrom // but no proper ERC721 standard implemented return ( - (txCode && - txCode.includes(SAFE_TRANSFER_FROM_WITHOUT_DATA_HASH) && + (txCode?.includes(SAFE_TRANSFER_FROM_WITHOUT_DATA_HASH) && tx.to !== '0x57f1887a8BF19b14fC0dF6Fd9B2acc9Af147eA85') || - (isTokenTransfer(tx) && !knownTokens.get(tx.to)) + (isTokenTransfer(tx) && !knownTokens?.get(tx.to)) ) } @@ -75,14 +72,16 @@ export const getERC20DecimalsAndSymbol = async ( const storedTokenInfo = await getTokenInfos(tokenAddress) if (!storedTokenInfo) { - const [tokenDecimals, tokenSymbol] = await generateBatchRequests({ - abi: ALTERNATIVE_TOKEN_ABI, + const [, tokenDecimals, tokenSymbol] = await generateBatchRequests< + [undefined, string | undefined, string | undefined] + >({ + abi: ALTERNATIVE_TOKEN_ABI as AbiItem[], address: tokenAddress, methods: ['decimals', 'symbol'], }) - return { decimals: Number(tokenDecimals), symbol: tokenSymbol } + return { decimals: Number(tokenDecimals), symbol: tokenSymbol ?? 'UNKNOWN' } } - return { decimals: storedTokenInfo.decimals as number, symbol: storedTokenInfo.symbol } + return { decimals: Number(storedTokenInfo.decimals), symbol: storedTokenInfo.symbol } } catch (err) { console.error(`Failed to retrieve token info for ERC20 token ${tokenAddress}`) } @@ -92,8 +91,8 @@ export const getERC20DecimalsAndSymbol = async ( export const isSendERC20Transaction = async ( tx: TxServiceModel, - txCode: string | null, - knownTokens: Map, + txCode?: string, + knownTokens?: TokenState, ): Promise => { let isSendTokenTx = !isSendERC721Transaction(tx, txCode, knownTokens) && isTokenTransfer(tx) diff --git a/src/logic/wallets/getWeb3.ts b/src/logic/wallets/getWeb3.ts index c6c61ab4c4..ff1e26f7e0 100644 --- a/src/logic/wallets/getWeb3.ts +++ b/src/logic/wallets/getWeb3.ts @@ -28,9 +28,12 @@ export const WALLET_PROVIDER = { // With some wallets from web3connect you have to use their provider instance only for signing // And our own one to fetch data +const httpProviderOptions = { + timeout: 10_000, +} export const web3ReadOnly = new Web3( process.env.NODE_ENV !== 'test' - ? new Web3.providers.HttpProvider(getRpcServiceUrl()) + ? new Web3.providers.HttpProvider(getRpcServiceUrl(), httpProviderOptions) : window.web3?.currentProvider || 'ws://localhost:8545', ) diff --git a/src/store/index.ts b/src/store/index.ts index 79624d956e..a4095608f6 100644 --- a/src/store/index.ts +++ b/src/store/index.ts @@ -37,7 +37,7 @@ import incomingTransactions, { } from 'src/logic/safe/store/reducer/incomingTransactions' import safe, { SAFE_REDUCER_ID } from 'src/logic/safe/store/reducer/safe' import transactions, { TRANSACTIONS_REDUCER_ID } from 'src/logic/safe/store/reducer/transactions' -import { NFTAssets, NFTTokens } from 'src/logic/collectibles/sources/collectibles' +import { NFTAssets, NFTTokens } from 'src/logic/collectibles/sources/collectibles.d' import { SafeReducerMap } from 'src/routes/safe/store/reducer/types/safe' import allTransactions, { TRANSACTIONS, TransactionsState } from '../logic/safe/store/reducer/allTransactions' import { AddressBookState } from 'src/logic/addressBook/model/addressBook'