diff --git a/src/components/scenes/Fio/FioRequestConfirmationScene.tsx b/src/components/scenes/Fio/FioRequestConfirmationScene.tsx index 1ac6bccf3ee..b788342b293 100644 --- a/src/components/scenes/Fio/FioRequestConfirmationScene.tsx +++ b/src/components/scenes/Fio/FioRequestConfirmationScene.tsx @@ -273,7 +273,7 @@ export class FioRequestConfirmationConnected extends React.Component< this.resetSlider() showError( `${lstrings.fio_request_error_header}: "${ - error.json?.fields?.[0]?.error ?? '' + error.json?.fields?.[0]?.error ?? String(error) }"` ) } diff --git a/src/components/scenes/Fio/FioRequestListScene.tsx b/src/components/scenes/Fio/FioRequestListScene.tsx index da51ab8888c..812064643a2 100644 --- a/src/components/scenes/Fio/FioRequestListScene.tsx +++ b/src/components/scenes/Fio/FioRequestListScene.tsx @@ -5,8 +5,7 @@ import { ActivityIndicator, SectionList, View } from 'react-native' import { sprintf } from 'sprintf-js' import { refreshAllFioAddresses } from '../../../actions/FioAddressActions' -import { FIO_ASSET_MAP } from '../../../constants/FioConstants' -import { SPECIAL_CURRENCY_INFO } from '../../../constants/WalletAndCurrencyConstants' +import { fioCodeToEdgeAsset } from '../../../constants/FioConstants' import { formatDate, SHORT_DATE_FMT } from '../../../locales/intl' import { lstrings } from '../../../locales/strings' import { getExchangeDenomByCurrencyCode } from '../../../selectors/DenominationSelectors' @@ -20,13 +19,11 @@ import { import { addToFioAddressCache, cancelFioRequest, - convertFIOToEdgeCodes, FIO_FAKE_RECORD_OBT_DATA_REQUEST, FIO_NO_BUNDLED_ERR_CODE, fioMakeSpend, fioSignAndBroadcast } from '../../../util/FioAddressUtils' -import { tokenIdsToCurrencyCodes } from '../../../util/utils' import { SceneWrapper } from '../../common/SceneWrapper' import { ButtonsModal } from '../../modals/ButtonsModal' import { WalletListModal, WalletListResult } from '../../modals/WalletListModal' @@ -383,47 +380,58 @@ class FioRequestList extends React.Component { return } const { account, onSelectWallet } = this.props - const availableWallets: Array<{ id: string; currencyCode: string }> = [] - for (const walletId of Object.keys(account.currencyWallets)) { - const wallet = account.currencyWallets[walletId] - const { chainCode, tokenCode } = convertFIOToEdgeCodes( - account, - wallet.currencyInfo.pluginId, - fioRequest.content.chain_code.toUpperCase(), - fioRequest.content.token_code.toUpperCase() - ) - const walletCurrencyCode = wallet.currencyInfo.currencyCode.toUpperCase() - if (walletCurrencyCode === tokenCode) { - availableWallets.push({ id: walletId, currencyCode: tokenCode }) - if (availableWallets.length > 1) { - await this.renderDropUp(fioRequest) - return + const edgeAsset = fioCodeToEdgeAsset( + account, + fioRequest.content.chain_code.toUpperCase(), + fioRequest.content.token_code.toUpperCase() + ) + + // Find matching wallets: + if (edgeAsset != null) { + const { pluginId, tokenId } = edgeAsset + const walletIds = Object.keys(account.currencyWallets).filter( + walletId => { + const wallet = account.currencyWallets[walletId] + return ( + wallet.currencyInfo.pluginId === pluginId && + (tokenId == null || wallet.enabledTokenIds.includes(tokenId)) + ) } - } - const enabledTokens = tokenIdsToCurrencyCodes( - wallet.currencyConfig, - wallet.enabledTokenIds ) - if ( - walletCurrencyCode === chainCode && - enabledTokens.includes(tokenCode) - ) { - availableWallets.push({ id: walletId, currencyCode: tokenCode }) - if (availableWallets.length > 1) { - await this.renderDropUp(fioRequest) - return + + // Just do the send if we have one choice: + if (walletIds.length === 1) { + const [walletId] = walletIds + const wallet = account.currencyWallets[walletId] + + const currencyCode = getCurrencyCode(wallet, tokenId) + onSelectWallet(walletId, currencyCode) + await this.sendCrypto(fioRequest, walletId, currencyCode) + return + } + + // Show a modal if we have multiple choices: + if (walletIds.length > 1) { + const result = await Airship.show(bridge => ( + + )) + if (result?.type === 'wallet') { + const { walletId, tokenId } = result + const wallet = account.currencyWallets[walletId] + const currencyCode = getCurrencyCode(wallet, tokenId) + onSelectWallet(walletId, currencyCode) + await this.sendCrypto(fioRequest, walletId, currencyCode) } + return } } - if (availableWallets.length) { - onSelectWallet(availableWallets[0].id, availableWallets[0].currencyCode) - await this.sendCrypto( - fioRequest, - availableWallets[0].id, - availableWallets[0].currencyCode - ) - return - } + + // Nothing matched, so show an error: await Airship.show<'ok' | undefined>(bridge => ( { )) } - renderDropUp = async (selectedFioPendingRequest: FioRequest) => { - const { account, onSelectWallet } = this.props - const { content } = selectedFioPendingRequest - const pluginId = - Object.keys(FIO_ASSET_MAP).find( - pluginId => - FIO_ASSET_MAP[pluginId].chainCode === content.chain_code.toUpperCase() - ) ?? - Object.keys(SPECIAL_CURRENCY_INFO).find( - pluginId => - SPECIAL_CURRENCY_INFO[pluginId].chainCode === - content.chain_code.toUpperCase() - ) - if (pluginId == null) { - showError( - sprintf( - lstrings.fio_request_unknown_chain_code, - content.chain_code.toUpperCase() - ) - ) - return - } - - const { tokenCode } = convertFIOToEdgeCodes( - account, - pluginId, - content.chain_code.toUpperCase(), - content.token_code.toUpperCase() - ) - const tokenId = getTokenIdForced(account, pluginId, tokenCode) - const allowedAssets = [{ pluginId, tokenId }] - - const result = await Airship.show(bridge => ( - - )) - if (result?.type === 'wallet') { - const { walletId, tokenId } = result - const wallet = account.currencyWallets[walletId] - const currencyCode = getCurrencyCode(wallet, tokenId) - onSelectWallet(walletId, currencyCode) - await this.sendCrypto(selectedFioPendingRequest, walletId, currencyCode) - } - } - sendCrypto = async ( pendingRequest: FioRequest, walletId: string, diff --git a/src/constants/FioConstants.ts b/src/constants/FioConstants.ts index 2ac8a1875bb..d13b7faa8d4 100644 --- a/src/constants/FioConstants.ts +++ b/src/constants/FioConstants.ts @@ -1,17 +1,27 @@ -/** - * Special mapping that defines `chain_codes` and `token_codes` for FIO tx's - * that do not fit the typical pattern of using currency codes - */ +import { EdgeAccount } from 'edge-core-js' + +import { EdgeAsset } from '../types/types' +import { getTokenId } from '../util/CurrencyInfoHelpers' +import { infoServerData } from '../util/network' export interface FioAsset { chainCode: string - tokenCodes: { [address: string]: string } + tokenCodes: { [tokenId: string]: string } } + +/** + * Special mapping that defines `chain_codes` and `token_codes` for FIO tx's + * that do not fit the typical pattern of using currency codes + */ export const FIO_ASSET_MAP: { [pluginId: string]: FioAsset } = { abstract: { chainCode: 'ABSTRACT', tokenCodes: {} }, + ethereum: { + chainCode: 'ETH', // Make this explicit so L2's don't take it + tokenCodes: {} + }, ethereumpo: { chainCode: 'ETHEREUMPO', tokenCodes: {} @@ -47,3 +57,44 @@ export const FIO_ASSET_MAP: { [pluginId: string]: FioAsset } = { } } } + +export const fioCodeToEdgeAsset = ( + account: EdgeAccount, + fioChainCode: string, + fioTokenCode: string +): EdgeAsset | undefined => { + const fioAssets = infoServerData.rollup?.fioAssets ?? FIO_ASSET_MAP + + const pluginId = + // Check the table first: + Object.keys(fioAssets).find( + pluginId => fioAssets[pluginId].chainCode === fioChainCode + ) ?? + // Otherwise, just match the main currency code: + Object.keys(account.currencyConfig).find( + pluginId => + account.currencyConfig[pluginId].currencyInfo.currencyCode === + fioChainCode + ) + + // Bail out if we don't know about this chain: + if (pluginId == null) return + + // Find the token being asked for: + const fioTokens = fioAssets[pluginId]?.tokenCodes ?? {} + const tokenId = + // If the token code matches the chain code, we want the main asset: + fioTokenCode === fioAssets[pluginId]?.chainCode + ? null + : // Otherwise, check the special token mappings for this chain: + Object.keys(fioTokens).find( + tokenId => fioTokens[tokenId] === fioTokenCode + ) ?? + // Otherwise, do a normal token lookup: + getTokenId(account.currencyConfig[pluginId], fioTokenCode) + + // Bail out if we couldn't find a matching token or main asset (null): + if (tokenId === undefined) return + + return { pluginId, tokenId } +} diff --git a/src/util/CurrencyInfoHelpers.ts b/src/util/CurrencyInfoHelpers.ts index 59fd31c02b2..b0139492fc9 100644 --- a/src/util/CurrencyInfoHelpers.ts +++ b/src/util/CurrencyInfoHelpers.ts @@ -99,7 +99,9 @@ export const getTokenIdForced = ( ): EdgeTokenId => { const tokenId = getTokenId(account.currencyConfig[pluginId], currencyCode) if (tokenId === undefined) - throw new Error('getTokenIdForced: tokenId not found') + throw new Error( + `getTokenIdForced: tokenId not found for ${currencyCode} in ${pluginId}` + ) return tokenId } diff --git a/src/util/FioAddressUtils.ts b/src/util/FioAddressUtils.ts index 30d1a51f292..94eb7d7ad35 100644 --- a/src/util/FioAddressUtils.ts +++ b/src/util/FioAddressUtils.ts @@ -1333,7 +1333,7 @@ export const convertEdgeToFIOCodes = ( edgeTokenCode: string ) => { const fioAssets = infoServerData.rollup?.fioAssets ?? FIO_ASSET_MAP - const fioChainCode = fioAssets[pluginId].chainCode ?? edgeChainCode + const fioChainCode = fioAssets[pluginId]?.chainCode ?? edgeChainCode const fioTokenCode = edgeTokenCode === edgeChainCode ? fioChainCode : edgeTokenCode diff --git a/src/util/utils.ts b/src/util/utils.ts index 1fda52fc2b1..efbdec11262 100644 --- a/src/util/utils.ts +++ b/src/util/utils.ts @@ -633,20 +633,6 @@ export const getPluginIdFromChainCode = ( return pluginId } -export function tokenIdsToCurrencyCodes( - currencyConfig: EdgeCurrencyConfig, - tokenIds: string[] -): string[] { - const { builtinTokens = {}, customTokens = {} } = currencyConfig - - const out: string[] = [] - for (const tokenId of tokenIds) { - const token = customTokens[tokenId] ?? builtinTokens[tokenId] - if (token != null) out.push(token.currencyCode) - } - return out -} - export interface MiniCurrencyConfig { allTokens: EdgeTokenMap currencyInfo: EdgeCurrencyInfo