+ {!!walletInfo && canDeriveSolanaWallet && spotEnabled && solanaAddress && (
+ <$AddressCopyButton
+ value={solanaAddress}
+ size={ButtonSize.XSmall}
+ shape={ButtonShape.Pill}
+ copyIconPosition="end"
action={ButtonAction.Base}
- href={`${mintscanBase}/account/${dydxAddress}`}
- iconName={IconName.LinkOut}
- shape={ButtonShape.Square}
- type={ButtonType.Link}
- />
-
- $AddressRow>
- {walletInfo &&
- walletInfo.name !== WalletType.Privy &&
- walletInfo.name !== WalletType.Keplr && (
- <$AddressRow>
-
-
- {walletIcon}
-
- <$Column>
- <$label>{stringGetter({ key: STRING_KEYS.SOURCE_ADDRESS })}$label>
- <$Address>{displayAddress}$Address>
- $Column>
- $AddressRow>
+ >
+
+ {stringGetter({ key: STRING_KEYS.SPOT })}
+ $AddressCopyButton>
)}
+ <$AddressCopyButton
+ value={dydxAddress}
+ size={ButtonSize.XSmall}
+ shape={ButtonShape.Pill}
+ copyIconPosition="end"
+ action={ButtonAction.Base}
+ >
+
+ {stringGetter({ key: STRING_KEYS.PERPETUALS })}
+ $AddressCopyButton>
+
+
<$Balances>
@@ -287,6 +268,25 @@ export const AccountMenu = () => {
withOnboarding
/>
+ {canDeriveSolanaWallet && spotEnabled && (
+
+
+ <$label>
+ Spot Sol Balance
+
+ $label>
+ <$BalanceOutput
+ type={OutputType.Asset}
+ value={
+ spotWalletData?.solBalance
+ ? spotWalletData.solBalance / LAMPORTS_PER_SOL
+ : 0
+ }
+ />
+
+
+
+ )}
$Balances>
{showConfirmPendingDeposit && (
<$ConfirmPendingDeposit>
@@ -452,59 +452,9 @@ export const AccountMenu = () => {
);
};
-const DydxDerivedAddress = ({
- address,
- chain,
- dydxAddress,
-}: {
- address?: string;
- chain?: WalletNetworkType.Solana | WalletNetworkType.Evm;
- dydxAddress?: string;
-}) => {
- const stringGetter = useStringGetter();
-
- const tooltipText =
- chain === WalletNetworkType.Solana
- ? stringGetter({
- key: TOOLTIP_STRING_KEYS.DYDX_ADDRESS_FROM_SOLANA_BODY,
- params: {
- DYDX_ADDRESS:
{truncateAddress(dydxAddress)},
- SOLANA_ADDRESS: truncateAddress(address, ''),
- },
- })
- : stringGetter({
- key: TOOLTIP_STRING_KEYS.DYDX_ADDRESS_FROM_ETHEREUM_BODY,
- params: {
- DYDX_ADDRESS:
{truncateAddress(dydxAddress)},
- EVM_ADDRESS: truncateAddress(address, '0x'),
- },
- });
-
- return (
-
- {tooltipText}
-
- }
- >
- <$label>{stringGetter({ key: STRING_KEYS.DYDX_CHAIN_ADDRESS })}$label>
-
- );
-};
-
const $Column = styled.div`
${layoutMixins.column}
`;
-const $AddressRow = styled.div`
- ${layoutMixins.row}
-
- gap: 0.5rem;
-
- ${$Column} {
- margin-right: 0.5rem;
- }
-`;
const $label = styled.div`
${layoutMixins.row}
@@ -581,7 +531,6 @@ const $IconButton = styled(IconButton)`
`}
`;
-const $CopyButton = styled(CopyButton)`
- --button-padding: 0 0.25rem;
- --button-border: solid var(--border-width) var(--color-layer-6);
+const $AddressCopyButton = styled(CopyButton)`
+ --button-padding: 0 0.375rem;
`;
diff --git a/src/views/menus/AccountMenu/SpotActions.tsx b/src/views/menus/AccountMenu/SpotActions.tsx
new file mode 100644
index 0000000000..dae0e9e7d7
--- /dev/null
+++ b/src/views/menus/AccountMenu/SpotActions.tsx
@@ -0,0 +1,74 @@
+import { memo } from 'react';
+
+import { Item } from '@radix-ui/react-dropdown-menu';
+import styled, { css } from 'styled-components';
+
+import { ButtonAction, ButtonShape } from '@/constants/buttons';
+import { DialogTypes } from '@/constants/dialogs';
+import { STRING_KEYS } from '@/constants/localization';
+
+import { useStringGetter } from '@/hooks/useStringGetter';
+
+import { IconName } from '@/components/Icon';
+import { IconButton } from '@/components/IconButton';
+import { WithTooltip } from '@/components/WithTooltip';
+import { useMaxWithdrawableSol } from '@/views/dialogs/TransferDialogs/WithdrawDialog2/withdrawSpotHooks';
+
+import { useAppDispatch } from '@/state/appTypes';
+import { openDialog } from '@/state/dialogs';
+
+import { isTruthy } from '@/lib/isTruthy';
+
+export const SpotActions = memo(() => {
+ const dispatch = useAppDispatch();
+ const stringGetter = useStringGetter();
+ const maxWithdrawable = useMaxWithdrawableSol();
+ const hasBalance = maxWithdrawable > 0;
+
+ return (
+
+ {[
+ {
+ dialog: DialogTypes.Deposit2({}),
+ iconName: IconName.Deposit,
+ tooltipStringKey: STRING_KEYS.DEPOSIT,
+ },
+ hasBalance && {
+ dialog: DialogTypes.Withdraw2({}),
+ iconName: IconName.Withdraw,
+ tooltipStringKey: STRING_KEYS.WITHDRAW,
+ },
+ ]
+ .filter(isTruthy)
+ .map(({ iconName, tooltipStringKey, dialog }) => (
+ -
+
+ <$IconButton
+ key={dialog.type}
+ action={ButtonAction.Base}
+ shape={ButtonShape.Square}
+ iconName={iconName}
+ onClick={() => dispatch(openDialog(dialog))}
+ />
+
+
+ ))}
+
+ );
+});
+
+const $IconButton = styled(IconButton)`
+ --button-padding: 0 0.25rem;
+ --button-border: solid var(--border-width) var(--color-layer-6);
+
+ ${({ iconName }) =>
+ iconName != null &&
+ [IconName.Withdraw, IconName.Deposit].includes(iconName) &&
+ css`
+ --button-icon-size: 1.375em;
+ `}
+`;
diff --git a/src/views/tables/MarketsTable/FavoriteButton.tsx b/src/views/tables/MarketsTable/FavoriteButton.tsx
index bc91bb2ab0..baa7241779 100644
--- a/src/views/tables/MarketsTable/FavoriteButton.tsx
+++ b/src/views/tables/MarketsTable/FavoriteButton.tsx
@@ -9,28 +9,45 @@ import { useAppSelectorWithArgs } from '@/hooks/useParameterizedSelector';
import { IconName } from '@/components/Icon';
import { IconButton } from '@/components/IconButton';
-import { favoriteMarket, unfavoriteMarket } from '@/state/appUiConfigs';
-import { getIsMarketFavorited } from '@/state/appUiConfigsSelectors';
+import {
+ favoriteMarket,
+ favoriteSpotToken,
+ unfavoriteMarket,
+ unfavoriteSpotToken,
+} from '@/state/appUiConfigs';
+import { getIsMarketFavorited, getIsSpotTokenFavorited } from '@/state/appUiConfigsSelectors';
import { track } from '@/lib/analytics/analytics';
export const FavoriteButton = ({
className,
marketId,
+ variant = 'perp',
}: {
className?: string;
marketId: string;
+ variant?: 'perp' | 'spot';
}) => {
const dispatch = useDispatch();
- const isMarketFavorited = useAppSelectorWithArgs(getIsMarketFavorited, marketId);
+ const isSpotFavorited = useAppSelectorWithArgs(getIsSpotTokenFavorited, marketId);
+ const isPerpFavorited = useAppSelectorWithArgs(getIsMarketFavorited, marketId);
+ const isMarketFavorited = variant === 'spot' ? isSpotFavorited : isPerpFavorited;
const onToggle = (newIsFavorited: boolean) => {
if (newIsFavorited) {
- dispatch(favoriteMarket(marketId));
- track(AnalyticsEvents.FavoriteMarket({ marketId }));
+ if (variant === 'spot') {
+ dispatch(favoriteSpotToken(marketId));
+ } else {
+ dispatch(favoriteMarket(marketId));
+ track(AnalyticsEvents.FavoriteMarket({ marketId }));
+ }
} else {
- dispatch(unfavoriteMarket(marketId));
- track(AnalyticsEvents.UnfavoriteMarket({ marketId }));
+ if (variant === 'spot') {
+ dispatch(unfavoriteSpotToken(marketId));
+ } else {
+ dispatch(unfavoriteMarket(marketId));
+ track(AnalyticsEvents.UnfavoriteMarket({ marketId }));
+ }
}
};
diff --git a/tailwind.config.js b/tailwind.config.js
index 30e35a85ce..57b253e4e9 100644
--- a/tailwind.config.js
+++ b/tailwind.config.js
@@ -19,6 +19,8 @@ export default {
black: 'var(--color-black)',
green: 'var(--color-green)',
red: 'var(--color-red)',
+ 'red-faded': 'var(--color-red-faded)',
+ 'green-faded': 'var(--color-green-faded)',
'white-faded': 'var(--color-white-faded)',
'color-layer-0': 'var(--color-layer-0)',
@@ -130,6 +132,7 @@ export default {
},
borderRadius: ({ theme }) => ({
...theme('spacing'),
+ full: '9999px',
}),
extend: {
animation: {