refactor(suite): migrate staking dashboard into earn dashboard

This commit is contained in:
Jaroslav Hrách
2026-02-09 18:42:17 +01:00
committed by Jaroslav Hrách
parent 9407b71b0d
commit 13683a29ea
26 changed files with 432 additions and 221 deletions

View File

@@ -16,6 +16,7 @@ export const IMAGES = {
GAINS_GRAPH: 'gains-graph.svg',
GHOST: 'ghost.svg',
INVITY_LOGO: 'invity-logo.svg',
MORPHO_LOGO: 'morpho-logo.svg',
PLAY_STORE: 'play-store.svg',
RECOVERY_2x: 'recovery@2x.png',
STROKE_BORDER: 'stroke-border.svg',

View File

@@ -0,0 +1,16 @@
<svg width="99" height="20" viewBox="0 0 99 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path opacity="0.8" d="M2.41016 12.9433V18.4875C2.41016 18.8287 2.69886 18.9705 2.78869 19.0026C2.8785 19.0413 3.18003 19.125 3.44949 18.8739L7.64166 14.8432C7.99867 14.5001 8.34322 14.1393 8.60214 13.7171C8.72401 13.5187 8.77452 13.4069 8.77452 13.4069C9.03118 12.8853 9.03118 12.3831 8.78086 11.8808C8.40891 11.1339 7.45931 10.3741 6.02856 9.65283L3.58423 11.018C2.85927 11.4301 2.41016 12.1577 2.41016 12.9433Z" fill="#151719"/>
<path d="M0 0.612219V6.42687C0 7.1545 0.4876 7.79841 1.1805 8.00447C3.54147 8.68703 7.6539 10.1552 8.64835 12.3123C8.77657 12.5956 8.85359 12.8726 8.87941 13.1623C9.54017 11.9582 9.84174 10.5737 9.70057 9.16997C9.50803 7.18025 8.4558 5.37081 6.81348 4.21819L0.95595 0.116397C0.853285 0.039125 0.731389 0.000488281 0.609495 0.000488281C0.506832 0.000488281 0.417015 0.0198067 0.320786 0.0713209C0.128305 0.180788 0 0.380408 0 0.612219Z" fill="#151719"/>
<path opacity="0.8" d="M18.003 12.9433V18.4875C18.003 18.8287 17.7144 18.9705 17.6244 19.0026C17.5347 19.0413 17.233 19.125 16.9637 18.8739L12.6738 14.7495C12.3819 14.4687 12.1031 14.1718 11.8831 13.8315C11.7089 13.5622 11.6386 13.4069 11.6386 13.4069C11.382 12.8853 11.382 12.3831 11.6321 11.8808C12.0043 11.1339 12.9539 10.3741 14.3844 9.65283L16.8289 11.018C17.5603 11.4301 18.003 12.1577 18.003 12.9433Z" fill="#151719"/>
<path d="M20.4173 0.611731V6.42637C20.4173 7.154 19.9295 7.79792 19.2366 8.00398C16.8758 8.68653 12.7634 10.1547 11.7689 12.3118C11.6405 12.5951 11.5635 12.8721 11.5379 13.1618C10.877 11.9577 10.5756 10.5732 10.7167 9.1695C10.909 7.17975 11.9613 5.37034 13.6038 4.21771L19.4614 0.115906C19.564 0.0386345 19.6858 0 19.8077 0C19.9103 0 20.0003 0.0193183 20.0963 0.0708325C20.2889 0.1803 20.4173 0.379918 20.4173 0.611731Z" fill="#151719"/>
<path d="M2.41016 12.9433V18.4875C2.41016 18.8287 2.69886 18.9705 2.78868 19.0026C2.8785 19.0413 3.18003 19.125 3.44948 18.8739L7.64165 14.8432C7.99866 14.5001 8.34321 14.1393 8.60213 13.7171C8.72401 13.5187 8.77452 13.4069 8.77452 13.4069C9.03117 12.8853 9.03117 12.3831 8.78086 11.8808C8.4089 11.1339 7.4593 10.3741 6.02855 9.65283L3.58422 11.018C2.85926 11.4301 2.41016 12.1577 2.41016 12.9433Z" fill="#151719"/>
<path d="M0 0.612219V6.42687C0 7.1545 0.4876 7.79841 1.1805 8.00447C3.54147 8.68703 7.6539 10.1552 8.64835 12.3123C8.77657 12.5956 8.85359 12.8726 8.87941 13.1623C9.54017 11.9582 9.84174 10.5737 9.70057 9.16997C9.50803 7.18025 8.4558 5.37081 6.81348 4.21819L0.95595 0.116397C0.853285 0.039125 0.731389 0.000488281 0.609495 0.000488281C0.506832 0.000488281 0.417015 0.0198067 0.320786 0.0713209C0.128305 0.180788 0 0.380408 0 0.612219Z" fill="#151719"/>
<path d="M18.003 12.9433V18.4875C18.003 18.8287 17.7144 18.9705 17.6244 19.0026C17.5347 19.0413 17.233 19.125 16.9637 18.8739L12.6738 14.7495C12.3819 14.4687 12.1031 14.1718 11.8831 13.8315C11.7089 13.5622 11.6386 13.4069 11.6386 13.4069C11.382 12.8853 11.382 12.3831 11.6321 11.8808C12.0043 11.1339 12.9539 10.3741 14.3844 9.65283L16.8289 11.018C17.5603 11.4301 18.003 12.1577 18.003 12.9433Z" fill="#151719"/>
<path d="M20.4173 0.611731V6.42637C20.4173 7.154 19.9296 7.79792 19.2366 8.00398C16.8758 8.68653 12.7634 10.1547 11.769 12.3118C11.6405 12.5951 11.5635 12.8721 11.5379 13.1618C10.8771 11.9577 10.5756 10.5732 10.7167 9.1695C10.909 7.17975 11.9613 5.37034 13.6038 4.21771L19.4614 0.115906C19.564 0.0386345 19.6858 0 19.8077 0C19.9103 0 20.0003 0.0193183 20.0963 0.0708325C20.2889 0.1803 20.4173 0.379918 20.4173 0.611731Z" fill="#151719"/>
<path d="M30.3545 1.86816H32.5968L37.7939 13.8944H37.9479L43.1448 1.86816H45.3487V15.7334H43.7126V4.69899H43.5587L38.7948 15.7334H36.9085L32.1446 4.69899H31.9906V15.7334H30.3545V1.86816Z" fill="#151719"/>
<path d="M47.1558 10.8327C47.1558 7.52037 49.1672 5.69092 52.1506 5.69092C55.1244 5.69092 57.1455 7.52037 57.1455 10.8327C57.1455 14.1352 55.1244 15.9647 52.1506 15.9647C49.1672 15.9647 47.1558 14.1352 47.1558 10.8327ZM48.8688 10.8327C48.8688 13.259 50.1874 14.5782 52.1506 14.5782C54.1043 14.5782 55.4228 13.259 55.4228 10.8327C55.4228 8.39658 54.1043 7.08708 52.1506 7.08708C50.1874 7.08708 48.8688 8.39658 48.8688 10.8327Z" fill="#151719"/>
<path d="M58.7632 5.92182H60.3993V7.09651H60.5533C60.8902 6.40324 61.5061 5.8833 62.9786 5.8833H64.3452V7.34685H63.017C61.1789 7.34685 60.457 8.35786 60.457 10.351V15.7334H58.7632V5.92182Z" fill="#151719"/>
<path d="M65.6479 19.585V5.92191H67.3033V7.27954H67.4573C68.1887 6.14336 69.3821 5.70044 70.768 5.70044C73.3184 5.70044 75.272 7.4336 75.272 10.8325C75.272 14.2218 73.3184 15.955 70.768 15.955C69.411 15.955 68.2272 15.5217 67.4958 14.4337H67.3418V19.585H65.6479ZM67.284 10.8325C67.284 13.2108 68.5545 14.5492 70.4215 14.5492C72.2982 14.5492 73.5685 13.2108 73.5685 10.8325C73.5685 8.44461 72.2982 7.10623 70.4215 7.10623C68.5545 7.10623 67.284 8.44461 67.284 10.8325Z" fill="#151719"/>
<path d="M76.8936 1.86816H78.5874V7.13505H78.7414C79.4439 6.09515 80.6084 5.70037 81.9847 5.70037C84.2656 5.70037 85.7092 6.85582 85.7092 9.25335V15.7334H84.0154V9.41704C84.0154 7.81869 83.1396 7.11579 81.6094 7.11579C79.9348 7.11579 78.5874 8.10754 78.5874 10.2548V15.7334H76.8936V1.86816Z" fill="#151719"/>
<path d="M87.2329 10.8327C87.2329 7.52037 89.2443 5.69092 92.2277 5.69092C95.2016 5.69092 97.2226 7.52037 97.2226 10.8327C97.2226 14.1352 95.2016 15.9647 92.2277 15.9647C89.2443 15.9647 87.2329 14.1352 87.2329 10.8327ZM88.946 10.8327C88.946 13.259 90.2644 14.5782 92.2277 14.5782C94.1815 14.5782 95.4996 13.259 95.4996 10.8327C95.4996 8.39658 94.1815 7.08708 92.2277 7.08708C90.2644 7.08708 88.946 8.39658 88.946 10.8327Z" fill="#151719"/>
</svg>

After

Width:  |  Height:  |  Size: 5.5 KiB

View File

@@ -16,7 +16,6 @@ export const TOR_BOOTSTRAP = '@suite/tor-bootstrap';
export const ONION_LINKS = '@suite/onion-links';
export const APP_CHANGED = '@suite/app-changed';
export const SET_THEME = '@suite/set-theme';
export const SET_STAKING_DASHBOARD_COLLAPSED = '@suite/set-staking-dashboard-collapsed';
export const SET_SEND_FORM_PREFILL = '@suite/set-send-form-prefill';
export const SET_TRANSACTION_HISTORY_PREFILL = '@suite/set-transaction-history-prefill';
export const SET_ADDRESS_DISPLAY_TYPE = '@suite/set-display-address-type';

View File

@@ -107,7 +107,6 @@ const removeCoinjoinRelatedSetting = (state: AppState) => {
evmSettings: state.suite.evmSettings,
seenDisconnectNotificationForDeviceIds:
state.suite.seenDisconnectNotificationForDeviceIds,
stakingDashboardCollapsed: state.suite.stakingDashboardCollapsed,
},
'suite',
true,
@@ -394,7 +393,6 @@ export const saveSuiteSettings =
evmSettings: suite.evmSettings,
seenDisconnectNotificationForDeviceIds:
suite.seenDisconnectNotificationForDeviceIds,
stakingDashboardCollapsed: suite.stakingDashboardCollapsed,
},
'suite',
true,

View File

@@ -81,10 +81,6 @@ export type SuiteAction =
type: typeof SUITE.SET_THEME;
variant: AppState['suite']['settings']['theme']['variant'];
}
| {
type: typeof SUITE.SET_STAKING_DASHBOARD_COLLAPSED;
isCollapsed: boolean;
}
| {
type: typeof SUITE.SET_TRANSACTION_HISTORY_PREFILL;
payload: string;
@@ -127,11 +123,6 @@ export const setTheme = (
variant,
});
export const setStakingDashboardCollapsed = (isCollapsed: boolean): SuiteAction => ({
type: SUITE.SET_STAKING_DASHBOARD_COLLAPSED,
isCollapsed,
});
export const setAddressDisplayType = (
option: AppState['suite']['settings']['addressDisplayType'],
): SuiteAction => ({

View File

@@ -0,0 +1,19 @@
import { Column } from '@trezor/components';
import { useSelector } from 'src/hooks/suite';
import { selectRouteName } from 'src/reducers/suite/routerReducer';
import { EarnStakingTable } from './staking/EarnStakingTable';
import { EarnYieldTable } from './yield/EarnYieldTable';
export const EarnDashboard = () => {
const routeName = useSelector(selectRouteName);
const isOnEarnPage = routeName === 'suite-earn';
return (
<Column gap={48}>
<EarnStakingTable />
{isOnEarnPage && <EarnYieldTable />}
</Column>
);
};

View File

@@ -4,7 +4,7 @@ import { NetworkSymbol, getNetwork } from '@suite-common/wallet-config';
import { Account } from '@suite-common/wallet-types';
import { Column } from '@trezor/components';
import { CoinLogo } from '@trezor/product-components';
import { spacings, spacingsPx, typography } from '@trezor/theme';
import { spacingsPx, typography } from '@trezor/theme';
import { AccountLabel, CoinBalance } from 'src/components/suite';
@@ -25,15 +25,12 @@ const AccountLabelContainer = styled.div`
white-space: nowrap;
`;
interface StakingDashboardAccountCellProps {
type EarnAccountCellProps = {
account?: Account;
symbol?: NetworkSymbol;
}
};
export const StakingDashboardAccountCell = ({
account,
symbol,
}: StakingDashboardAccountCellProps) => {
export const EarnAccountCell = ({ account, symbol }: EarnAccountCellProps) => {
const networkSymbol = account?.symbol ?? symbol;
if (!networkSymbol) return null;
@@ -41,10 +38,10 @@ export const StakingDashboardAccountCell = ({
return (
<AccountCellContainer>
<Column alignItems="center">
<CoinLogo size={24} symbol={networkSymbol} />
<CoinLogo size={32} symbol={networkSymbol} />
</Column>
<Column flex="1" overflow="hidden" gap={spacings.xxxs}>
<Column flex="1" overflow="hidden" gap={2}>
<AccountLabelContainer>
{account ? (
<AccountLabel

View File

@@ -0,0 +1,55 @@
import { ReactNode, Ref } from 'react';
import { Translation, TranslationKey } from '@suite/intl';
import { Badge, BadgeIntent } from '@trezor/components';
import { DashboardSection } from 'src/components/dashboard';
import { PoweredByBadge } from 'src/components/earn';
import { type EarnProviderId } from 'src/components/earn/providers/providerMetadata';
import { useSelector } from 'src/hooks/suite';
import { selectRouteName } from 'src/reducers/suite/routerReducer';
type EarnDashboardSectionProps = {
titleId: TranslationKey;
subheadingId: TranslationKey;
provider?: EarnProviderId;
statusBadge?: {
intent: BadgeIntent;
labelId: TranslationKey;
};
sectionRef?: Ref<HTMLDivElement>;
children: ReactNode;
};
export const EarnDashboardSection = ({
titleId,
subheadingId,
provider,
statusBadge,
sectionRef,
children,
}: EarnDashboardSectionProps) => {
const routeName = useSelector(selectRouteName);
const isOnEarnPage = routeName === 'suite-earn';
const actions = isOnEarnPage && provider ? <PoweredByBadge provider={provider} /> : undefined;
return (
<DashboardSection
heading={
<>
<Translation id={titleId} />
{statusBadge && (
<Badge intent={statusBadge.intent} margin={{ left: 12 }}>
<Translation id={statusBadge.labelId} />
</Badge>
)}
</>
}
subheading={<Translation id={subheadingId} />}
actions={actions}
ref={sectionRef}
>
{children}
</DashboardSection>
);
};

View File

@@ -0,0 +1,31 @@
import { Translation } from '@suite/intl';
import { Table } from '@trezor/components';
type EarnDashboardTableHeaderProps = {
showRewardsColumns?: boolean;
};
export const EarnDashboardTableHeader = ({
showRewardsColumns = true,
}: EarnDashboardTableHeaderProps) => (
<Table.Header>
<Table.Row>
<Table.Cell>
<Translation id="TR_EARN_DASHBOARD_TABLE_ACCOUNT_BALANCE" />
</Table.Cell>
<Table.Cell>
<Translation id="TR_EARN_DASHBOARD_TABLE_APY" />
</Table.Cell>
<Table.Cell>
{showRewardsColumns && <Translation id="TR_EARN_DASHBOARD_TABLE_YEARLY_REWARDS" />}
</Table.Cell>
<Table.Cell>
{showRewardsColumns && (
<Translation id="TR_EARN_DASHBOARD_TABLE_POTENTIAL_REWARDS" />
)}
</Table.Cell>
{/* Actions column */}
<Table.Cell />
</Table.Row>
</Table.Header>
);

View File

@@ -3,32 +3,27 @@ import { useFormatters } from '@suite-common/formatters';
import { NetworkSymbol } from '@suite-common/wallet-config';
import { H4, TextVariant } from '@trezor/components';
interface StakingDashboardRewardsAmountProps {
accountSymbol: NetworkSymbol;
type EarnRewardsAmountProps = {
symbol: NetworkSymbol;
rewards: string;
apy: number | null;
variant?: TextVariant;
}
};
export const StakingDashboardRewardsAmount = ({
accountSymbol,
rewards,
apy,
variant,
}: StakingDashboardRewardsAmountProps) => {
export const EarnRewardsAmount = ({ symbol, rewards, apy, variant }: EarnRewardsAmountProps) => {
const { CryptoAmountFormatter } = useFormatters();
if (!apy)
return (
<H4 variant={variant}>
<Translation id="TR_STAKE_APY_REQUIRED" />
<Translation id="TR_EARN_APY_REQUIRED" />
</H4>
);
return (
<H4 variant={variant}>
{CryptoAmountFormatter.format(rewards, {
symbol: accountSymbol,
symbol,
isBalance: true,
withSymbol: true,
isEllipsisAppended: false,

View File

@@ -28,10 +28,10 @@ import { useAnalytics } from 'src/support/useAnalytics';
import { ApyValue } from 'src/views/wallet/staking/components/ApyValue';
import { formatApyValue } from 'src/views/wallet/staking/utils/formatStakeValues';
import { StakingDashboardAccountCell } from './StakingDashboardAccountCell';
import { StakingDashboardRewardsAmount } from './StakingDashboardRewardsAmount';
import { EarnAccountCell } from '../common/EarnAccountCell';
import { EarnRewardsAmount } from '../common/EarnRewardsAmount';
export const StakingDashboardAccountRow = ({ account }: { account: Account }) => {
export const EarnStakingAccountRow = ({ account }: { account: Account }) => {
const dispatch = useDispatch();
const { CryptoAmountFormatter } = useFormatters();
const analytics = useAnalytics();
@@ -155,8 +155,8 @@ export const StakingDashboardAccountRow = ({ account }: { account: Account }) =>
<Table.Cell>
<Row width="100%" alignItems="center" justifyContent="space-between">
<Column alignItems="flex-start">
<StakingDashboardRewardsAmount
accountSymbol={account.symbol}
<EarnRewardsAmount
symbol={account.symbol}
rewards={isStakingActive ? currentRewards : '0'}
apy={apy}
/>
@@ -164,7 +164,7 @@ export const StakingDashboardAccountRow = ({ account }: { account: Account }) =>
{isStakingActive && (
<Paragraph typographyStyle="hint" variant="tertiary">
<Translation
id="TR_STAKING_DASHBOARD_STAKED"
id="TR_EARN_STAKING_DASHBOARD_STAKED"
values={{
amount: formatCryptoAmount(stakingBalance),
displaySymbol,
@@ -191,8 +191,8 @@ export const StakingDashboardAccountRow = ({ account }: { account: Account }) =>
<Table.Cell>
<Column>
{apy && (
<StakingDashboardRewardsAmount
accountSymbol={account.symbol}
<EarnRewardsAmount
symbol={account.symbol}
rewards={potentialRewards}
apy={apy}
variant="primary"
@@ -202,7 +202,7 @@ export const StakingDashboardAccountRow = ({ account }: { account: Account }) =>
{!isCardanoNetworkType && apy && (
<Paragraph typographyStyle="hint" variant="tertiary">
<Translation
id="TR_STAKING_DASHBOARD_IF_YOU_ADD"
id="TR_EARN_STAKING_DASHBOARD_IF_YOU_ADD"
values={{
amount: formatCryptoAmount(accountBalance),
displaySymbol,
@@ -218,7 +218,7 @@ export const StakingDashboardAccountRow = ({ account }: { account: Account }) =>
return (
<Table.Row onClick={navigateToStaking}>
<Table.Cell>
<StakingDashboardAccountCell account={account} />
<EarnAccountCell account={account} />
</Table.Cell>
<Table.Cell>
@@ -234,7 +234,7 @@ export const StakingDashboardAccountRow = ({ account }: { account: Account }) =>
<Table.Cell colSpan={2}>
<Paragraph typographyStyle="body" variant="tertiary">
<Translation
id="TR_STAKING_DASHBOARD_MINIMUM_STAKE"
id="TR_EARN_STAKING_DASHBOARD_MINIMUM_STAKE"
values={{
amount: minStakingAmount?.toString(),
displaySymbol,
@@ -266,8 +266,8 @@ export const StakingDashboardAccountRow = ({ account }: { account: Account }) =>
<Translation
id={
state === 'staking-active'
? 'TR_STAKING_DASHBOARD_STAKE_MORE'
: 'TR_STAKING_DASHBOARD_STAKE_NOW'
? 'TR_EARN_STAKING_DASHBOARD_STAKE_MORE'
: 'TR_EARN_STAKING_DASHBOARD_STAKE_NOW'
}
/>
</Button>
@@ -281,7 +281,7 @@ export const StakingDashboardAccountRow = ({ account }: { account: Account }) =>
<Table.Cell>
<Paragraph typographyStyle="body" variant="tertiary">
<Translation id="TR_STAKING_DASHBOARD_MAXIMUM_STAKE" />
<Translation id="TR_EARN_STAKING_DASHBOARD_MAXIMUM_STAKE" />
</Paragraph>
</Table.Cell>
@@ -305,7 +305,7 @@ export const StakingDashboardAccountRow = ({ account }: { account: Account }) =>
<Table.Cell>
<Paragraph typographyStyle="body" variant="tertiary">
<Translation
id="TR_STAKING_DASHBOARD_MINIMUM_STAKE"
id="TR_EARN_STAKING_DASHBOARD_MINIMUM_STAKE"
values={{
amount: minStakingAmount?.toString(),
displaySymbol,
@@ -334,7 +334,7 @@ export const StakingDashboardAccountRow = ({ account }: { account: Account }) =>
<Icon name="warning" size={24} variant="warning" />
<Paragraph typographyStyle="body" variant="warning">
<Translation
id="TR_STAKING_DASHBOARD_OUTDATED_PROVIDER"
id="TR_EARN_STAKING_DASHBOARD_OUTDATED_PROVIDER"
values={{ apy: formatApyValue(apy) }}
/>
</Paragraph>

View File

@@ -8,9 +8,9 @@ import { openModal } from 'src/actions/suite/modalActions';
import { useDevice, useDispatch, useSelector } from 'src/hooks/suite';
import { ApyValue } from 'src/views/wallet/staking/components/ApyValue';
import { StakingDashboardAccountCell } from './StakingDashboardAccountCell';
import { EarnAccountCell } from '../common/EarnAccountCell';
export const StakingDashboardActivateRow = ({ symbol }: { symbol: NetworkSymbol }) => {
export const EarnStakingActivateRow = ({ symbol }: { symbol: NetworkSymbol }) => {
const dispatch = useDispatch();
const { device } = useDevice();
const apy = useSelector(state => selectPoolStatsApyData(state, undefined, symbol));
@@ -38,7 +38,7 @@ export const StakingDashboardActivateRow = ({ symbol }: { symbol: NetworkSymbol
return (
<Table.Row>
<Table.Cell>
<StakingDashboardAccountCell symbol={symbol} />
<EarnAccountCell symbol={symbol} />
</Table.Cell>
<Table.Cell>
@@ -48,7 +48,7 @@ export const StakingDashboardActivateRow = ({ symbol }: { symbol: NetworkSymbol
<Table.Cell colSpan={2}>
<Paragraph typographyStyle="body" variant="tertiary">
<Translation
id="TR_STAKING_DASHBOARD_MINIMUM_STAKE"
id="TR_EARN_STAKING_DASHBOARD_MINIMUM_STAKE"
values={{
amount: minStakingAmount?.toString(),
displaySymbol,
@@ -64,7 +64,7 @@ export const StakingDashboardActivateRow = ({ symbol }: { symbol: NetworkSymbol
isDisabled={isDiscoveryRunning}
>
<Translation
id="TR_STAKING_DASHBOARD_ACTIVATE"
id="TR_EARN_STAKING_DASHBOARD_ACTIVATE"
values={{ networkName: name }}
/>
</Button>

View File

@@ -1,4 +1,3 @@
import { Translation, TranslationKey } from '@suite/intl';
import { NetworkSymbol, StakingNetworkSymbol } from '@suite-common/wallet-config';
import {
selectAccountIsStakingActive,
@@ -15,45 +14,20 @@ import {
isCardanoStakedWithFiveBinaries,
toFiatCurrency,
} from '@suite-common/wallet-utils';
import { Badge, BadgeIntent, Card, Table } from '@trezor/components';
import { Card, Table } from '@trezor/components';
import { BigNumber, arrayPartition } from '@trezor/utils';
import { setStakingDashboardCollapsed } from 'src/actions/suite/suiteActions';
import { OutlineHighlight } from 'src/components/OutlineHighlight';
import { DashboardSection } from 'src/components/dashboard';
import { PoweredByBadge } from 'src/components/wallet';
import { DashboardAnchor } from 'src/constants/suite/anchors';
import { useDispatch, useSelector } from 'src/hooks/suite';
import { useSelector } from 'src/hooks/suite';
import { useAnchor } from 'src/hooks/suite/useAnchor';
import { useMessageSystemStaking } from 'src/hooks/suite/useMessageSystemStaking';
import { selectRouteName } from 'src/reducers/suite/routerReducer';
import { StakingDashboardAccountRow } from './StakingDashboardAccountRow';
import { StakingDashboardActivateRow } from './StakingDashboardActivateRow';
const getBadgeState = (
isStakingActive: boolean,
accounts: Account[],
): { intent: BadgeIntent; label: TranslationKey } => {
if (!isStakingActive) {
return {
intent: 'neutral',
label: 'TR_STAKING_DASHBOARD_NOT_ACTIVE',
};
}
if (accounts.some(account => isCardanoStakedWithFiveBinaries(account))) {
return {
intent: 'warning',
label: 'TR_STAKING_DASHBOARD_OUTDATED',
};
}
return {
intent: 'brand',
label: 'TR_STAKING_DASHBOARD_ACTIVE',
};
};
import { EarnStakingAccountRow } from './EarnStakingAccountRow';
import { EarnStakingActivateRow } from './EarnStakingActivateRow';
import { EarnDashboardSection } from '../common/EarnDashboardSection';
import { EarnDashboardTableHeader } from '../common/EarnDashboardTableHeader';
import { getEarnDashboardBadgeState } from '../utils/earnDashboardBadgeUtils';
const useCryptoCurrentRate = (symbol: NetworkSymbol) => {
const baseCurrency = useSelector(selectBaseCurrency);
@@ -63,18 +37,7 @@ const useCryptoCurrentRate = (symbol: NetworkSymbol) => {
return currentRate?.rate;
};
interface StakingDashboardProps {
collapsible?: boolean;
}
export const StakingDashboard = ({ collapsible = true }: StakingDashboardProps) => {
const dispatch = useDispatch();
const routeName = useSelector(selectRouteName);
const isOnEarnPage = routeName === 'suite-earn';
const collapsed = useSelector(state => state.suite.stakingDashboardCollapsed);
export const EarnStakingTable = () => {
const { anchorRef, shouldHighlight } = useAnchor(DashboardAnchor.Staking);
const ethCurrentRate = useCryptoCurrentRate('eth');
@@ -185,82 +148,55 @@ export const StakingDashboard = ({ collapsible = true }: StakingDashboardProps)
const ethNotActivated =
deviceSupportedNetworkSymbols.includes('eth') &&
!stakingAccounts.find(account => account.symbol === 'eth');
!stakingAccounts.some(account => account.symbol === 'eth') &&
!isEthStakingDisabled;
const solNotActivated =
deviceSupportedNetworkSymbols.includes('sol') &&
!stakingAccounts.find(account => account.symbol === 'sol');
!stakingAccounts.some(account => account.symbol === 'sol') &&
!isSolStakingDisabled;
const adaNotActivated =
deviceSupportedNetworkSymbols.includes('ada') &&
!stakingAccounts.find(account => account.symbol === 'ada');
!stakingAccounts.some(account => account.symbol === 'ada') &&
!isAdaStakingDisabled;
const stakingAccountsNotActivated = ethNotActivated && solNotActivated && adaNotActivated;
const onCollapseChange = (collapsed: boolean) => {
if (!collapsible) return;
dispatch(setStakingDashboardCollapsed(collapsed));
};
const badge = getBadgeState(isStakingActive, stakingAccounts);
const badge = getEarnDashboardBadgeState({
isSectionActive: isStakingActive,
isSectionOutdated: stakingAccounts.some(account =>
isCardanoStakedWithFiveBinaries(account),
),
activeLabelId: 'TR_EARN_DASHBOARD_ACTIVE',
notActiveLabelId: 'TR_EARN_DASHBOARD_NOT_ACTIVE',
outdatedLabelId: 'TR_EARN_STAKING_DASHBOARD_OUTDATED',
});
return (
<OutlineHighlight shouldHighlight={shouldHighlight}>
<DashboardSection
heading={
<>
<Translation id="TR_STAKING_DASHBOARD_TITLE" />
<Badge intent={badge.intent} margin={{ left: 12 }}>
<Translation id={badge.label} />
</Badge>
</>
}
subheading={<Translation id="TR_STAKING_DASHBOARD_TEXT" />}
collapsible={collapsible}
defaultCollapsed={collapsible ? collapsed : false}
onCollapseChange={onCollapseChange}
actions={isOnEarnPage ? <PoweredByBadge provider="everstake" /> : undefined}
ref={anchorRef}
<EarnDashboardSection
titleId="TR_EARN_STAKING_DASHBOARD_TITLE"
subheadingId="TR_EARN_STAKING_DASHBOARD_TEXT"
provider="everstake"
statusBadge={badge}
sectionRef={anchorRef}
>
<Card paddingType="none">
<Table isRowHighlightedOnHover margin={{ top: 8 }}>
<Table.Header>
<Table.Row>
<Table.Cell>
<Translation id="TR_STAKING_DASHBOARD_TABLE_ACCOUNT_BALANCE" />
</Table.Cell>
<Table.Cell>
<Translation id="TR_STAKING_DASHBOARD_TABLE_APY" />
</Table.Cell>
<Table.Cell>
{!stakingAccountsNotActivated && (
<Translation id="TR_STAKING_DASHBOARD_TABLE_YEARLY_REWARDS" />
)}
</Table.Cell>
<Table.Cell>
{!stakingAccountsNotActivated && (
<Translation id="TR_STAKING_DASHBOARD_TABLE_POTENTIAL_REWARDS" />
)}
</Table.Cell>
<Table.Cell></Table.Cell>
</Table.Row>
</Table.Header>
<EarnDashboardTableHeader
showRewardsColumns={!stakingAccountsNotActivated}
/>
<Table.Body>
{sortedAccounts.map(account => (
<StakingDashboardAccountRow account={account} key={account.key} />
<EarnStakingAccountRow account={account} key={account.key} />
))}
{ethNotActivated && !isEthStakingDisabled && (
<StakingDashboardActivateRow symbol="eth" />
)}
{solNotActivated && !isSolStakingDisabled && (
<StakingDashboardActivateRow symbol="sol" />
)}
{adaNotActivated && !isAdaStakingDisabled && (
<StakingDashboardActivateRow symbol="ada" />
)}
{ethNotActivated && <EarnStakingActivateRow symbol="eth" />}
{adaNotActivated && <EarnStakingActivateRow symbol="ada" />}
{solNotActivated && <EarnStakingActivateRow symbol="sol" />}
</Table.Body>
</Table>
</Card>
</DashboardSection>
</EarnDashboardSection>
</OutlineHighlight>
);
};

View File

@@ -0,0 +1,42 @@
import { TranslationKey } from '@suite/intl';
import { BadgeIntent } from '@trezor/components';
type EarnDashboardBadgeState = {
intent: BadgeIntent;
labelId: TranslationKey;
};
type GetEarnDashboardBadgeStateParams = {
isSectionActive: boolean;
activeLabelId: TranslationKey;
notActiveLabelId: TranslationKey;
isSectionOutdated?: boolean;
outdatedLabelId?: TranslationKey;
};
export const getEarnDashboardBadgeState = ({
isSectionActive,
activeLabelId,
notActiveLabelId,
isSectionOutdated,
outdatedLabelId,
}: GetEarnDashboardBadgeStateParams): EarnDashboardBadgeState => {
if (!isSectionActive) {
return {
intent: 'neutral',
labelId: notActiveLabelId,
};
}
if (isSectionOutdated && outdatedLabelId) {
return {
intent: 'warning',
labelId: outdatedLabelId,
};
}
return {
intent: 'brand',
labelId: activeLabelId,
};
};

View File

@@ -0,0 +1,105 @@
import { Translation } from '@suite/intl';
import { selectVisibleDeviceAccounts } from '@suite-common/wallet-core';
import { Button, Card, Paragraph, Row, Table } from '@trezor/components';
import { BigNumber } from '@trezor/utils';
import { useSelector } from 'src/hooks/suite';
import { EarnAccountCell } from '../common/EarnAccountCell';
import { EarnDashboardSection } from '../common/EarnDashboardSection';
import { EarnDashboardTableHeader } from '../common/EarnDashboardTableHeader';
import { getEarnDashboardBadgeState } from '../utils/earnDashboardBadgeUtils';
export const EarnYieldTable = () => {
const visibleAccounts = useSelector(selectVisibleDeviceAccounts);
const ethereumAccounts = visibleAccounts.filter(account => account.symbol === 'eth');
const isYieldActive = ethereumAccounts.some(account =>
new BigNumber(account.formattedBalance).gt(0),
);
const badge = getEarnDashboardBadgeState({
isSectionActive: isYieldActive,
activeLabelId: 'TR_EARN_DASHBOARD_ACTIVE',
notActiveLabelId: 'TR_EARN_DASHBOARD_NOT_ACTIVE',
});
return (
<EarnDashboardSection
titleId="TR_EARN_YIELD_DASHBOARD_TITLE"
subheadingId="TR_EARN_YIELD_DASHBOARD_TEXT"
provider="morpho"
statusBadge={badge}
>
<Card paddingType="none">
<Table isRowHighlightedOnHover margin={{ top: 8 }}>
<EarnDashboardTableHeader />
<Table.Body>
{ethereumAccounts.length === 0 ? (
<Table.Row>
<Table.Cell colSpan={5}>
<Paragraph typographyStyle="body" variant="tertiary">
<Translation id="TR_ACCOUNT_NO_ACCOUNTS" />
</Paragraph>
</Table.Cell>
</Table.Row>
) : (
ethereumAccounts.map(account => {
const hasBalance = new BigNumber(account.formattedBalance).gt(0);
return (
<Table.Row key={account.key}>
<Table.Cell>
<EarnAccountCell account={account} />
</Table.Cell>
<Table.Cell>
<Paragraph typographyStyle="body" variant="tertiary">
<Translation id="TR_EARN_NOT_AVAILABLE" />
</Paragraph>
</Table.Cell>
<Table.Cell>
<Paragraph typographyStyle="body" variant="tertiary">
<Translation id="TR_EARN_NOT_AVAILABLE" />
</Paragraph>
</Table.Cell>
<Table.Cell>
<Paragraph typographyStyle="body" variant="tertiary">
<Translation id="TR_EARN_NOT_AVAILABLE" />
</Paragraph>
</Table.Cell>
<Table.Cell align="end">
<Row justifyContent="flex-end" gap={8}>
{hasBalance ? (
<>
<Button size="small">
<Translation id="TR_EARN_YIELD_DASHBOARD_SUPPLY_MORE" />
</Button>
<Button
size="small"
intent="brand"
priority="secondary"
>
<Translation id="TR_EARN_YIELD_DASHBOARD_WITHDRAW" />
</Button>
</>
) : (
<Button size="small">
<Translation id="TR_EARN_YIELD_DASHBOARD_SUPPLY_NOW" />
</Button>
)}
</Row>
</Table.Cell>
</Table.Row>
);
})
)}
</Table.Body>
</Table>
</Card>
</EarnDashboardSection>
);
};

View File

@@ -6,9 +6,12 @@ export { EarnProviderConsentModal } from './modals/EarnProviderConsent/EarnProvi
export { StakingEarnProviderConsentModal } from './modals/EarnProviderConsent/StakingEarnProviderConsentModal';
export { YieldEarnProviderConsentModal } from './modals/EarnProviderConsent/YieldEarnProviderConsentModal';
export { UpdateEarnProviderConsentModal } from './modals/EarnProviderConsent/UpdateEarnProviderConsentModal';
export { EarnDashboard } from './EarnDashboard/EarnDashboard';
export { EarnSupplyingInfo } from './modals/EarnInANutshell/components/EarnSupplyingInfo';
export { EarnWithdrawingInfo } from './modals/EarnInANutshell/components/EarnWithdrawingInfo';
export { VotingDelegations } from './VotingDelegations/VotingDelegations';
export { VotingDelegationsOptions } from './VotingDelegations/VotingDelegationsOptions';
export { PoweredByBadge } from './providers/PoweredByBadge';

View File

@@ -1,21 +1,20 @@
import styled from 'styled-components';
import { Translation } from '@suite/intl';
import { Image, ImageType, Row, Text } from '@trezor/components';
import { Image, Row, Text } from '@trezor/components';
const PROVIDERS = {
everstake: {
logo: 'EVERSTAKE_LOGO',
},
} as const satisfies Record<string, { logo: ImageType }>;
import {
type EarnProviderId,
earnProviderMetadata,
} from 'src/components/earn/providers/providerMetadata';
const ImageWrapper = styled.div`
filter: ${({ theme }) => (theme.variant === 'dark' ? 'invert(1)' : 'none')};
`;
interface PoweredByBadgeProps {
provider: keyof typeof PROVIDERS;
}
type PoweredByBadgeProps = {
provider: EarnProviderId;
};
export function PoweredByBadge({ provider }: PoweredByBadgeProps) {
return (
@@ -24,7 +23,7 @@ export function PoweredByBadge({ provider }: PoweredByBadgeProps) {
<Translation id="TR_STAKE_PROVIDED_BY" />
</Text>
<ImageWrapper>
<Image image={PROVIDERS[provider].logo} width={100} height={40} />
<Image image={earnProviderMetadata[provider].logo} width={100} height={40} />
</ImageWrapper>
</Row>
);

View File

@@ -0,0 +1,19 @@
import { ImageType } from '@trezor/components';
type ProviderMetadata = {
name: string;
logo: ImageType;
};
export const earnProviderMetadata = {
everstake: {
name: 'Everstake',
logo: 'EVERSTAKE_LOGO',
},
morpho: {
name: 'Morpho',
logo: 'MORPHO_LOGO',
},
} as const satisfies Record<string, ProviderMetadata>;
export type EarnProviderId = keyof typeof earnProviderMetadata;

View File

@@ -3,7 +3,6 @@ import { CoinjoinAccountDiscoveryProgress } from './CoinjoinAccountDiscoveryProg
import { DiscoveryProgress } from './DiscoveryProgress';
import { InputError } from './InputError';
import { Pagination } from './Pagination';
import { PoweredByBadge } from './PoweredByBadge';
import { TransactionTimestamp } from './TransactionTimestamp';
import { UtxoAnonymity } from './UtxoAnonymity';
import { WalletLayout } from './WalletLayout/WalletLayout';
@@ -19,5 +18,4 @@ export {
Pagination,
TransactionTimestamp,
CoinjoinAccountDiscoveryProgress,
PoweredByBadge,
};

View File

@@ -315,7 +315,6 @@ const storageMiddleware = (api: MiddlewareAPI<Dispatch, AppState>) => {
case SUITE.SET_ADDRESS_DISPLAY_TYPE:
case SUITE.SET_AUTODETECT:
case SUITE.SET_SIDEBAR_WIDTH:
case SUITE.SET_STAKING_DASHBOARD_COLLAPSED:
case SUITE.TOGGLE_DEVICE_AUTHENTICITY_CHECK:
case SUITE.TOGGLE_FIRMWARE_REVISION_CHECK:
case SUITE.TOGGLE_FIRMWARE_HASH_CHECK:

View File

@@ -129,7 +129,6 @@ export interface SuiteState {
recentlyConnectedDeviceRef: string | null; // TODO use type DeviceRef from suite-types; currently WIP in https://github.com/trezor/trezor-suite/pull/20955
recentlyDisconnectedDevice: string | null;
seenDisconnectNotificationForDeviceIds: string[];
stakingDashboardCollapsed: boolean;
}
const initialState: SuiteState = {
@@ -212,7 +211,6 @@ const initialState: SuiteState = {
recentlyConnectedDeviceRef: null,
recentlyDisconnectedDevice: null,
seenDisconnectNotificationForDeviceIds: [],
stakingDashboardCollapsed: false,
};
export const suiteInitialState = initialState;
@@ -249,10 +247,6 @@ const suiteReducer = (state: SuiteState = initialState, action: Action): SuiteSt
...draft.settings,
...action.payload.suiteSettings?.settings,
};
if (typeof action.payload.suiteSettings?.stakingDashboardCollapsed === 'boolean') {
draft.stakingDashboardCollapsed =
action.payload.suiteSettings.stakingDashboardCollapsed;
}
break;
case STORAGE.ERROR:
draft.lifecycle = { status: 'db-error', error: action.payload };
@@ -327,10 +321,6 @@ const suiteReducer = (state: SuiteState = initialState, action: Action): SuiteSt
draft.settings.theme.variant = action.variant;
break;
case SUITE.SET_STAKING_DASHBOARD_COLLAPSED:
draft.stakingDashboardCollapsed = action.isCollapsed;
break;
case SUITE.SET_SEND_FORM_PREFILL:
draft.prefillFields.sendForm = action.payload.contractAddress;
break;

View File

@@ -70,7 +70,6 @@ export interface SuiteDBSchema extends DBSchema {
flags: SuiteState['flags'];
evmSettings: SuiteState['evmSettings'];
seenDisconnectNotificationForDeviceIds: SuiteState['seenDisconnectNotificationForDeviceIds'];
stakingDashboardCollapsed: SuiteState['stakingDashboardCollapsed'];
};
};
historicRates: {

View File

@@ -4,6 +4,7 @@ import { Context } from '@suite-common/message-system';
import { Column } from '@trezor/components';
import { spacings, spacingsPx } from '@trezor/theme';
import { EarnDashboard } from 'src/components/earn';
import { PageHeader } from 'src/components/suite/layouts/SuiteLayout';
import { ContextMessage } from 'src/components/wallet/WalletLayout/AccountBanners/ContextMessage';
import { useLayout } from 'src/hooks/suite';
@@ -12,7 +13,6 @@ import { AssetsView } from './AssetsView/AssetsView';
import { DashboardFooter } from './DashboardFooter';
import { DashboardPromoBanner } from './DashboardPromoBanner/DashboardPromoBanner';
import { PortfolioCard } from './PortfolioCard/PortfolioCard';
import { StakingDashboard } from './StakingDashboard/StakingDashboard';
import { useNotificationForDisconnectedDevice } from './useNotificationForDisconnectedDevice';
const Container = styled.div`
@@ -33,7 +33,7 @@ export const Dashboard = () => {
</Container>
<DashboardPromoBanner />
<AssetsView />
<StakingDashboard />
<EarnDashboard />
<DashboardFooter />
</Column>
);

View File

@@ -1,10 +1,9 @@
import { EarnDashboard } from 'src/components/earn';
import { PageHeader } from 'src/components/suite/layouts/SuiteLayout';
import { useLayout } from 'src/hooks/suite';
import { StakingDashboard } from '../dashboard/StakingDashboard/StakingDashboard';
export const Earn = () => {
useLayout('Earn', <PageHeader />);
return <StakingDashboard collapsible={false} />;
return <EarnDashboard />;
};

View File

@@ -9,8 +9,8 @@ import {
HELP_CENTER_SOL_STAKING,
} from '@trezor/urls';
import { PoweredByBadge } from 'src/components/earn';
import { LearnMoreButton } from 'src/components/suite/LearnMoreButton';
import { PoweredByBadge } from 'src/components/wallet';
import { useSelector } from 'src/hooks/suite';
import { selectSelectedAccount } from 'src/reducers/wallet/selectedAccountReducer';

View File

@@ -8896,25 +8896,45 @@ export const messages = defineMessages({
id: 'TR_TO',
defaultMessage: 'To',
},
TR_STAKING_DASHBOARD_TITLE: {
id: 'TR_STAKING_DASHBOARD_TITLE',
TR_EARN_STAKING_DASHBOARD_TITLE: {
id: 'TR_EARN_STAKING_DASHBOARD_TITLE',
defaultMessage: 'Staking',
},
TR_STAKING_DASHBOARD_TEXT: {
id: 'TR_STAKING_DASHBOARD_TEXT',
TR_EARN_STAKING_DASHBOARD_TEXT: {
id: 'TR_EARN_STAKING_DASHBOARD_TEXT',
defaultMessage:
'Grow your crypto by locking it to help secure the network—and earn rewards in return.',
},
TR_STAKING_DASHBOARD_ACTIVE: {
id: 'TR_STAKING_DASHBOARD_ACTIVE',
TR_EARN_YIELD_DASHBOARD_TITLE: {
id: 'TR_EARN_YIELD_DASHBOARD_TITLE',
defaultMessage: 'Stablecoin yield',
},
TR_EARN_YIELD_DASHBOARD_TEXT: {
id: 'TR_EARN_YIELD_DASHBOARD_TEXT',
defaultMessage: 'Put your stablecoins to work and earn rewards.',
},
TR_EARN_YIELD_DASHBOARD_SUPPLY_MORE: {
id: 'TR_EARN_YIELD_DASHBOARD_SUPPLY_MORE',
defaultMessage: 'Supply more',
},
TR_EARN_YIELD_DASHBOARD_WITHDRAW: {
id: 'TR_EARN_YIELD_DASHBOARD_WITHDRAW',
defaultMessage: 'Withdraw',
},
TR_EARN_YIELD_DASHBOARD_SUPPLY_NOW: {
id: 'TR_EARN_YIELD_DASHBOARD_SUPPLY_NOW',
defaultMessage: 'Supply now',
},
TR_EARN_DASHBOARD_ACTIVE: {
id: 'TR_EARN_DASHBOARD_ACTIVE',
defaultMessage: 'Active',
},
TR_STAKING_DASHBOARD_NOT_ACTIVE: {
id: 'TR_STAKING_DASHBOARD_NOT_ACTIVE',
TR_EARN_DASHBOARD_NOT_ACTIVE: {
id: 'TR_EARN_DASHBOARD_NOT_ACTIVE',
defaultMessage: 'Inactive',
},
TR_STAKING_DASHBOARD_OUTDATED: {
id: 'TR_STAKING_DASHBOARD_OUTDATED',
TR_EARN_STAKING_DASHBOARD_OUTDATED: {
id: 'TR_EARN_STAKING_DASHBOARD_OUTDATED',
defaultMessage: 'Outdated provider',
},
TR_STAKING_MODAL_OUTDATED: {
@@ -8930,52 +8950,52 @@ export const messages = defineMessages({
id: 'TR_STAKING_MODAL_OUTDATED_BUTTON',
defaultMessage: 'Update provider',
},
TR_STAKING_DASHBOARD_TABLE_ACCOUNT_BALANCE: {
id: 'TR_STAKING_DASHBOARD_TABLE_ACCOUNT_BALANCE',
defaultMessage: 'Account',
TR_EARN_DASHBOARD_TABLE_ACCOUNT_BALANCE: {
id: 'TR_EARN_DASHBOARD_TABLE_ACCOUNT_BALANCE',
defaultMessage: 'Account & balance',
},
TR_STAKING_DASHBOARD_TABLE_APY: {
id: 'TR_STAKING_DASHBOARD_TABLE_APY',
TR_EARN_DASHBOARD_TABLE_APY: {
id: 'TR_EARN_DASHBOARD_TABLE_APY',
defaultMessage: 'APY',
},
TR_STAKING_DASHBOARD_TABLE_YEARLY_REWARDS: {
id: 'TR_STAKING_DASHBOARD_TABLE_YEARLY_REWARDS',
TR_EARN_DASHBOARD_TABLE_YEARLY_REWARDS: {
id: 'TR_EARN_DASHBOARD_TABLE_YEARLY_REWARDS',
defaultMessage: 'Your yearly rewards',
},
TR_STAKING_DASHBOARD_TABLE_POTENTIAL_REWARDS: {
id: 'TR_STAKING_DASHBOARD_TABLE_POTENTIAL_REWARDS',
TR_EARN_DASHBOARD_TABLE_POTENTIAL_REWARDS: {
id: 'TR_EARN_DASHBOARD_TABLE_POTENTIAL_REWARDS',
defaultMessage: 'Potential rewards',
},
TR_STAKING_DASHBOARD_STAKE_NOW: {
id: 'TR_STAKING_DASHBOARD_STAKE_NOW',
TR_EARN_STAKING_DASHBOARD_STAKE_NOW: {
id: 'TR_EARN_STAKING_DASHBOARD_STAKE_NOW',
defaultMessage: 'Stake now',
},
TR_STAKING_DASHBOARD_STAKE_MORE: {
id: 'TR_STAKING_DASHBOARD_STAKE_MORE',
TR_EARN_STAKING_DASHBOARD_STAKE_MORE: {
id: 'TR_EARN_STAKING_DASHBOARD_STAKE_MORE',
defaultMessage: 'Stake more',
},
TR_STAKING_DASHBOARD_ACTIVATE: {
id: 'TR_STAKING_DASHBOARD_ACTIVATE',
TR_EARN_STAKING_DASHBOARD_ACTIVATE: {
id: 'TR_EARN_STAKING_DASHBOARD_ACTIVATE',
defaultMessage: 'Activate {networkName}',
},
TR_STAKING_DASHBOARD_MINIMUM_STAKE: {
id: 'TR_STAKING_DASHBOARD_MINIMUM_STAKE',
TR_EARN_STAKING_DASHBOARD_MINIMUM_STAKE: {
id: 'TR_EARN_STAKING_DASHBOARD_MINIMUM_STAKE',
defaultMessage: 'Minimum {amount} {displaySymbol} required to stake',
},
TR_STAKING_DASHBOARD_MAXIMUM_STAKE: {
id: 'TR_STAKING_DASHBOARD_MAXIMUM_STAKE',
TR_EARN_STAKING_DASHBOARD_MAXIMUM_STAKE: {
id: 'TR_EARN_STAKING_DASHBOARD_MAXIMUM_STAKE',
defaultMessage: 'Maximum staked',
},
TR_STAKING_DASHBOARD_IF_YOU_ADD: {
id: 'TR_STAKING_DASHBOARD_IF_YOU_ADD',
TR_EARN_STAKING_DASHBOARD_IF_YOU_ADD: {
id: 'TR_EARN_STAKING_DASHBOARD_IF_YOU_ADD',
defaultMessage: 'if you add {amount} {displaySymbol}',
},
TR_STAKING_DASHBOARD_STAKED: {
id: 'TR_STAKING_DASHBOARD_STAKED',
TR_EARN_STAKING_DASHBOARD_STAKED: {
id: 'TR_EARN_STAKING_DASHBOARD_STAKED',
defaultMessage: '{amount} {displaySymbol} staked',
},
TR_STAKING_DASHBOARD_OUTDATED_PROVIDER: {
id: 'TR_STAKING_DASHBOARD_OUTDATED_PROVIDER',
TR_EARN_STAKING_DASHBOARD_OUTDATED_PROVIDER: {
id: 'TR_EARN_STAKING_DASHBOARD_OUTDATED_PROVIDER',
defaultMessage: 'Update to Everstake and earn ~{apy}% APY',
},
TR_STAKING_BANNER_DETAIL_TITLE: {
@@ -9205,8 +9225,8 @@ export const messages = defineMessages({
id: 'TR_STAKE_N_A',
defaultMessage: 'N/A',
},
TR_STAKE_APY_REQUIRED: {
id: 'TR_STAKE_APY_REQUIRED',
TR_EARN_APY_REQUIRED: {
id: 'TR_EARN_APY_REQUIRED',
defaultMessage: 'APY required to calculate rewards',
},
TR_STAKE_APY_DESC: {