Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ type TokenCellTitleProps = {
token: TokenFiatDisplayInfo;
};

const accountTypeLabel: Partial<Record<KeyringAccountType, string>> = {
export const accountTypeLabel: Partial<Record<KeyringAccountType, string>> = {
[BtcAccountType.P2pkh]: 'Legacy',
[BtcAccountType.P2sh]: 'Nested SegWit',
[BtcAccountType.P2wpkh]: 'Native SegWit',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ export default function Asset({
tooltipText,
tokenFiatAmount,
chainId,
accountType,
assetItemProps = {},
isDestinationToken = false,
}: AssetProps) {
Expand Down Expand Up @@ -77,6 +78,7 @@ export default function Asset({
tokenChainImage={getImageForChainId(chainId)}
isDestinationToken={isDestinationToken}
address={address}
accountType={accountType}
{...assetItemProps}
/>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Token, TokenListToken } from '@metamask/assets-controllers';
import { type Hex, type CaipChainId } from '@metamask/utils';
import { type KeyringAccountType } from '@metamask/keyring-api';
import type {
AssetType,
TokenStandard,
Expand Down Expand Up @@ -62,6 +63,7 @@ export type NativeAsset = {
export type AssetWithDisplayData<T extends ERC20Asset | NativeAsset> = T & {
balance: string; // raw balance
string: string | undefined; // normalized balance as a stringified number
accountType?: KeyringAccountType; // Bitcoin account type (e.g., P2wpkh for Native SegWit)
} & Pick<TokenListToken, 'decimals'> & {
tokenFiatAmount?: TokenWithFiatAmount['tokenFiatAmount'];
};
Expand Down
34 changes: 8 additions & 26 deletions ui/components/multichain/token-list-item/token-list-item.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@ import { useHistory } from 'react-router-dom';
import classnames from 'classnames';
import { getNativeTokenAddress } from '@metamask/assets-controllers';
import { type Hex } from '@metamask/utils';
import { type KeyringAccountType } from '@metamask/keyring-api';
import {
AlignItems,
BackgroundColor,
BlockSize,
BorderRadius,
Display,
FlexDirection,
FontWeight,
Expand Down Expand Up @@ -36,6 +36,7 @@ import {
ModalOverlay,
SensitiveText,
SensitiveTextLength,
Tag,
Text,
} from '../../component-library';
import { getMarketData, getCurrencyRates } from '../../../selectors';
Expand All @@ -56,6 +57,7 @@ import { setEditedNetwork } from '../../../store/actions';
import { NETWORK_TO_SHORT_NETWORK_NAME_MAP } from '../../../../shared/constants/bridge';
import { getNetworkConfigurationsByChainId } from '../../../../shared/modules/selectors/networks';
import { selectNoFeeAssets } from '../../../ducks/bridge/selectors';
import { accountTypeLabel } from '../../app/assets/token-cell/cells/token-cell-title';
import { PercentageChange } from './price/percentage-change/percentage-change';
import { StakeableLink } from './stakeable-link';

Expand All @@ -79,6 +81,7 @@ type TokenListItemProps = {
privacyMode?: boolean;
nativeCurrencySymbol?: string;
isDestinationToken?: boolean;
accountType?: KeyringAccountType;
};

export const TokenListItemComponent = ({
Expand All @@ -98,6 +101,7 @@ export const TokenListItemComponent = ({
isTitleHidden = false,
address = null,
showPercentage = false,
accountType,
privacyMode = false,
nativeCurrencySymbol,
isDestinationToken = false,
Expand Down Expand Up @@ -279,32 +283,10 @@ export const TokenListItemComponent = ({
)}
</Text>
)}
{isNoFeeAsset && (
<Box
backgroundColor={BackgroundColor.backgroundSection}
borderRadius={BorderRadius.SM}
paddingInline={1}
paddingTop={0}
paddingBottom={0}
style={{
height: '20px',
display: 'flex',
alignItems: 'center',
}}
>
<Text
variant={TextVariant.bodySm}
fontWeight={FontWeight.Medium}
color={TextColor.textAlternative}
style={{
lineHeight: '20px',
whiteSpace: 'nowrap',
}}
>
{t('bridgeNoMMFee')}
</Text>
</Box>
{accountType && accountTypeLabel[accountType] && (
<Tag label={accountTypeLabel[accountType]} />
)}
{isNoFeeAsset && <Tag label={t('bridgeNoMMFee')} />}
</Box>

{showScamWarning ? (
Expand Down
25 changes: 18 additions & 7 deletions ui/ducks/bridge/selectors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -327,13 +327,24 @@ export const getToChain = createSelector(
getToChains,
(state: BridgeAppState) => state.bridge?.toChainId,
],
(fromChain, toChains, toChainId) =>
toChainId
? toChains.find(
({ chainId }) =>
chainId === toChainId || formatChainIdToCaip(chainId) === toChainId,
)
: fromChain,
(fromChain, toChains, toChainId) => {
// If user has explicitly selected a destination, use it
if (toChainId) {
return toChains.find(
({ chainId }) =>
chainId === toChainId || formatChainIdToCaip(chainId) === toChainId,
);
}

// Bitcoin can only bridge to EVM chains, not to Bitcoin
// So if source is Bitcoin, default to first available EVM chain instead
if (fromChain && isBitcoinChainId(fromChain.chainId)) {
return toChains[0];
}

// For all other chains, default to same chain (swap mode)
return fromChain;
},
);

export const getDefaultTokenPair = createDeepEqualSelector(
Expand Down
2 changes: 2 additions & 0 deletions ui/ducks/bridge/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
type ChainId,
type GenericQuoteRequest,
} from '@metamask/bridge-controller';
import { type KeyringAccountType } from '@metamask/keyring-api';
import { type TxAlert } from '../../../shared/types/security-alerts-api';

export type BridgeToken = {
Expand All @@ -21,6 +22,7 @@ export type BridgeToken = {
tokenFiatAmount?: number | null;
occurrences?: number;
aggregators?: string[];
accountType?: KeyringAccountType;
};

export type BridgeState = {
Expand Down
20 changes: 20 additions & 0 deletions ui/hooks/bridge/useTokensWithFiltering.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import type {
import { getAssetImageUrl, toAssetId } from '../../../shared/lib/asset-utils';
import { MULTICHAIN_TOKEN_IMAGE_MAP } from '../../../shared/constants/multichain/networks';
import type { BridgeToken } from '../../ducks/bridge/types';
import { getInternalAccountsByScope } from '../../selectors/accounts';

// This transforms the token object from the bridge-api into the format expected by the AssetPicker
const buildTokenData = (
Expand Down Expand Up @@ -133,6 +134,20 @@ export const useTokensWithFiltering = (
const { assetsWithBalance: multichainTokensWithBalance } =
useMultichainBalances(accountAddress);

// Get Bitcoin account for the selected chain to access its account type
// Match by address to ensure we get the correct account type for the specific account
const bitcoinAccount = useSelector((state: BridgeAppState) => {
if (!chainId || !isBitcoinChainId(chainId) || !accountAddress) {
return undefined;
}
const caipChainId = formatChainIdToCaip(chainId);
const accounts = getInternalAccountsByScope(state, caipChainId);
// Find the specific account that matches the accountAddress
return accounts.find(
(acc) => acc.address.toLowerCase() === accountAddress.toLowerCase(),
);
});

const cachedTokens = useSelector(
(state: BridgeAppState) => state.metamask.tokensChainsCache,
);
Expand Down Expand Up @@ -313,6 +328,10 @@ export const useTokensWithFiltering = (
token.address,
formatChainIdToCaip(token.chainId),
)),
...(isBitcoinChainId(token.chainId) &&
bitcoinAccount?.type && {
accountType: bitcoinAccount.type,
}),
};
} else {
yield {
Expand Down Expand Up @@ -376,6 +395,7 @@ export const useTokensWithFiltering = (
tokenList,
tokenToExclude,
selectedToken,
bitcoinAccount,
],
);
return {
Expand Down
Loading