Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Solana staking view only #17296

Open
wants to merge 2 commits into
base: develop
Choose a base branch
from
Open
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
6 changes: 6 additions & 0 deletions suite-common/wallet-utils/src/solanaStakingUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,12 @@ export const getSolAccountTotalStakingBalance = (account: Account) => {
return formatNetworkAmount(totalStakingBalance, account.symbol);
};

export const getSolanaCryptoBalanceWithStaking = (account: Account) => {
const stakingBalance = getSolAccountTotalStakingBalance(account);

return new BigNumber(account.formattedBalance).plus(stakingBalance ?? 0).toString();
};

export const calculateSolanaStakingReward = (accountBalance?: string, apy?: string) => {
if (!accountBalance || !apy) return '0';

Expand Down
3 changes: 3 additions & 0 deletions suite-native/intl/src/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1244,12 +1244,15 @@ export const en = {
},
staked: 'Staked',
rewards: 'Rewards',
rewardsPerEpoch: 'Rewards per Epoch',
apy: 'Annual percentage yield',
stakingCanBeManaged: 'Staking can be currently managed only in',
trezorDesktop: 'Trezor Suite for desktop.',
stakePendingCard: {
totalStakePending: 'Total stake pending',
addingToStakingPool: 'Adding to staking pool',
activatingStake: 'Activating stake',
totalStakeActivating: 'Total stake activating',
transactionPending: 'Transaction pending',
unknownStatus: 'Unknown status',
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { TouchableOpacity } from 'react-native';
import { useSelector } from 'react-redux';

import { BASE_CRYPTO_MAX_DISPLAYED_DECIMALS } from '@suite-common/formatters';
import { NetworkSymbol } from '@suite-common/wallet-config';
import { AccountsRootState, selectAccountNetworkSymbol } from '@suite-common/wallet-core';
import { Box, Card, Text } from '@suite-native/atoms';
import { CryptoAmountFormatter, CryptoToFiatAmountFormatter } from '@suite-native/formatters';
Expand All @@ -15,20 +16,34 @@ import {
import { NativeStakingRootState } from '@suite-native/staking/src/types';
import { prepareNativeStyle, useNativeStyles } from '@trezor/styles';

type StakePendingCardProps = {
accountKey: string;
handleToggleBottomSheet: (value: boolean) => void;
};
const stakingItemStyle = prepareNativeStyle(utils => ({
flexDirection: 'row',
alignItems: 'center',
gap: utils.spacings.sp4,
}));

const valuesContainerStyle = prepareNativeStyle(utils => ({
maxWidth: '40%',
maxWidth: '45%',
flexShrink: 0,
alignItems: 'flex-end',
paddingLeft: utils.spacings.sp8,
}));

const getCardAlertProps = (isStakeConfirming: boolean, isStakePending: boolean) => {
const isSolana = (symbol: NetworkSymbol) => ['sol', 'dsol'].includes(symbol);

const getCardAlertProps = (
symbol: NetworkSymbol | null,
isStakeConfirming: boolean,
isStakePending: boolean,
) => {
if (!symbol) {
return { alertTitle: undefined, alertVariant: undefined } as const;
}

if (isStakeConfirming && !isStakePending) {
return {
alertTitle: <Translation id="staking.stakePendingCard.transactionPending" />,
Expand All @@ -37,7 +52,11 @@ const getCardAlertProps = (isStakeConfirming: boolean, isStakePending: boolean)
}
if (!isStakeConfirming && isStakePending) {
return {
alertTitle: <Translation id="staking.stakePendingCard.addingToStakingPool" />,
alertTitle: isSolana(symbol) ? (
<Translation id="staking.stakePendingCard.activatingStake" />
) : (
<Translation id="staking.stakePendingCard.addingToStakingPool" />
),
alertVariant: 'loading',
} as const;
}
Expand All @@ -48,10 +67,12 @@ const getCardAlertProps = (isStakeConfirming: boolean, isStakePending: boolean)
} as const;
};

type StakePendingCardProps = {
accountKey: string;
handleToggleBottomSheet: (value: boolean) => void;
};
const getTitle = (symbol: NetworkSymbol) =>
isSolana(symbol) ? (
<Translation id="staking.stakePendingCard.totalStakeActivating" />
) : (
<Translation id="staking.stakePendingCard.totalStakePending" />
);

export const StakePendingCard = ({
accountKey,
Expand All @@ -75,20 +96,20 @@ export const StakePendingCard = ({
);

const cardAlertProps = useMemo(
() => getCardAlertProps(isStakeConfirming, isStakePending),
[isStakeConfirming, isStakePending],
() => getCardAlertProps(symbol, isStakeConfirming, isStakePending),
[symbol, isStakeConfirming, isStakePending],
);

if (!symbol || !cardAlertProps.alertVariant) return null;

const title = getTitle(symbol);

return (
<TouchableOpacity onPress={() => handleToggleBottomSheet(true)}>
<Card {...cardAlertProps}>
<Box style={applyStyle(stakingItemStyle)}>
<Box flex={1} flexDirection="row" alignItems="center">
<Text>
<Translation id="staking.stakePendingCard.totalStakePending" />
</Text>
<Text>{title}</Text>
</Box>
<Box style={applyStyle(valuesContainerStyle)}>
<CryptoAmountFormatter
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,12 @@ export const StakingBalancesOverviewCard = ({

if (!symbol) return null;

const rewardsTitle = ['sol', 'dsol'].includes(symbol) ? (
<Translation id="staking.rewardsPerEpoch" />
) : (
<Translation id="staking.rewards" />
);

return (
<TouchableOpacity onPress={() => handleToggleBottomSheet(true)}>
<Card style={applyStyle(stakingCardStyle)}>
Expand Down Expand Up @@ -99,7 +105,7 @@ export const StakingBalancesOverviewCard = ({
<Box style={applyStyle(stakingItemStyle)}>
<Icon name="plusCircle" color="textSubdued" size="medium" />
<Text color="textSubdued" variant="label">
<Translation id="staking.rewards" />
{rewardsTitle}
</Text>
</Box>
<CryptoAmountFormatter
Expand Down
56 changes: 42 additions & 14 deletions suite-native/staking/src/selectors.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
import type { NetworkSymbol } from '@suite-common/wallet-config';
import { selectAccountByKey } from '@suite-common/wallet-core';
import {
selectAccountByKey,
selectPoolStatsApyData,
selectSolAccountHasStaked,
} from '@suite-common/wallet-core';
import { Account, AccountKey } from '@suite-common/wallet-types';
import { getEthereumCryptoBalanceWithStaking } from '@suite-common/wallet-utils';
import {
getEthereumCryptoBalanceWithStaking,
getSolanaCryptoBalanceWithStaking,
} from '@suite-common/wallet-utils';

import {
selectEthereumAPYByAccountKey,
selectEthereumAccountHasStaking,
selectEthereumIsStakeConfirmingByAccountKey,
selectEthereumIsStakePendingByAccountKey,
Expand All @@ -13,6 +19,13 @@ import {
selectEthereumTotalStakePendingByAccountKey,
selectVisibleDeviceEthereumAccountsWithStakingByNetworkSymbol,
} from './ethereumStakingSelectors';
import {
selectExpectedRewardsForEpoch,
selectSolanaIsStakePendingByAccountKey,
selectSolanaStakedBalanceByAccountKey,
selectSolanaTotalStakePendingByAccountKey,
selectVisibleDeviceSolanaAccountsWithStakingByNetworkSymbol,
} from './solanaStakingSelectors';
import { NativeStakingRootState } from './types';
import { doesCoinSupportStaking } from './utils';

Expand All @@ -32,6 +45,9 @@ export const selectDeviceAccountsWithStaking = (
case 'thol':
case 'tsep':
return selectVisibleDeviceEthereumAccountsWithStakingByNetworkSymbol(state, 'eth');
case 'dsol':
case 'sol':
return selectVisibleDeviceSolanaAccountsWithStakingByNetworkSymbol(state, 'sol');
default:
// This throws error if any symbol is not handled.
symbol satisfies never;
Expand All @@ -57,6 +73,9 @@ export const getAccountCryptoBalanceWithStaking = (account: Account | null) => {
case 'thol':
case 'tsep':
return getEthereumCryptoBalanceWithStaking(account);
case 'dsol':
case 'sol':
return getSolanaCryptoBalanceWithStaking(account);
default:
// This is to make sure that all cases are handled.
account.symbol satisfies never;
Expand Down Expand Up @@ -87,6 +106,9 @@ export const selectAccountHasStaking = (state: NativeStakingRootState, accountKe
case 'thol':
case 'tsep':
return selectEthereumAccountHasStaking(state, accountKey);
case 'dsol':
case 'sol':
return selectSolAccountHasStaked(state, accountKey);
default:
// This throws error if any symbol is not handled.
symbol satisfies never;
Expand All @@ -110,6 +132,9 @@ export const selectIsStakePendingByAccountKey = (
case 'thol':
case 'tsep':
return selectEthereumIsStakePendingByAccountKey(state, accountKey);
case 'dsol':
case 'sol':
return selectSolanaIsStakePendingByAccountKey(state, accountKey);
default:
// This throws error if any symbol is not handled.
symbol satisfies never;
Expand All @@ -133,6 +158,9 @@ export const selectIsStakeConfirmingByAccountKey = (
case 'thol':
case 'tsep':
return selectEthereumIsStakeConfirmingByAccountKey(state, accountKey);
case 'dsol':
case 'sol':
return false; // there are no pending txns for solana staking;
default:
// This throws error if any symbol is not handled.
symbol satisfies never;
Expand All @@ -148,17 +176,7 @@ export const selectAPYByAccountKey = (state: NativeStakingRootState, accountKey:
return null;
}

switch (symbol) {
case 'eth':
case 'thol':
case 'tsep':
return selectEthereumAPYByAccountKey(state, accountKey);
default:
// This throws error if any symbol is not handled.
symbol satisfies never;

return null;
}
return selectPoolStatsApyData(state, symbol);
};

export const selectStakedBalanceByAccountKey = (
Expand All @@ -176,6 +194,9 @@ export const selectStakedBalanceByAccountKey = (
case 'thol':
case 'tsep':
return selectEthereumStakedBalanceByAccountKey(state, accountKey);
case 'dsol':
case 'sol':
return selectSolanaStakedBalanceByAccountKey(state, accountKey);
default:
// This throws error if any symbol is not handled.
symbol satisfies never;
Expand All @@ -199,6 +220,10 @@ export const selectRewardsBalanceByAccountKey = (
case 'thol':
case 'tsep':
return selectEthereumRewardsBalanceByAccountKey(state, accountKey);
case 'dsol':
case 'sol':
// on solana we show rewards per one epoch
return selectExpectedRewardsForEpoch(state, accountKey);
default:
// This throws error if any symbol is not handled.
symbol satisfies never;
Expand All @@ -222,6 +247,9 @@ export const selectTotalStakePendingByAccountKey = (
case 'thol':
case 'tsep':
return selectEthereumTotalStakePendingByAccountKey(state, accountKey);
case 'dsol':
case 'sol':
return selectSolanaTotalStakePendingByAccountKey(state, accountKey);
default:
// This throws error if any symbol is not handled.
symbol satisfies never;
Expand Down
Loading
Loading