Skip to content

Commit

Permalink
feat(mobile): staking view-only (#14561)
Browse files Browse the repository at this point in the history
  • Loading branch information
Nodonisko authored Sep 30, 2024
1 parent e39b315 commit fd47fd6
Show file tree
Hide file tree
Showing 46 changed files with 1,195 additions and 46 deletions.
6 changes: 6 additions & 0 deletions suite-common/wallet-utils/src/stakingUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,3 +52,9 @@ export const getAccountTotalStakingBalance = (account?: Account) => {
.plus(pool?.withdrawTotalAmount ?? '0')
.toFixed();
};

export const getEthereumCryptoBalanceWithStaking = (account: Account) => {
const stakingBalance = getAccountTotalStakingBalance(account);

return new BigNumber(account.formattedBalance).plus(stakingBalance).toString();
};
2 changes: 2 additions & 0 deletions suite-native/accounts/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@
"@suite-native/intl": "workspace:*",
"@suite-native/navigation": "workspace:*",
"@suite-native/settings": "workspace:*",
"@suite-native/staking": "workspace:*",
"@suite-native/toasts": "workspace:*",
"@suite-native/tokens": "workspace:*",
"@trezor/styles": "workspace:*",
"jotai": "1.9.1",
Expand Down
19 changes: 16 additions & 3 deletions suite-native/accounts/src/components/AccountSectionTitle.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
import React, { useMemo } from 'react';
import { useSelector } from 'react-redux';

import { HStack, VStack, Text } from '@suite-native/atoms';
import { FiatAmountFormatter } from '@suite-native/formatters';
import { selectCurrentFiatRates } from '@suite-common/wallet-core';
import { Account } from '@suite-common/wallet-types';
import { getAccountFiatBalance } from '@suite-common/wallet-utils';
import { HStack, Text, VStack } from '@suite-native/atoms';
import { CryptoAmountFormatter, FiatAmountFormatter } from '@suite-native/formatters';
import { selectFiatCurrencyCode } from '@suite-native/settings';
import { selectCurrentFiatRates } from '@suite-common/wallet-core';
import {
NativeStakingRootState,
selectAccountCryptoBalanceWithStaking,
} from '@suite-native/staking';

type AccountSectionTitleProps = {
account: Account;
Expand All @@ -20,6 +24,9 @@ export const AccountSectionTitle: React.FC<AccountSectionTitleProps> = ({
}) => {
const localCurrency = useSelector(selectFiatCurrencyCode);
const rates = useSelector(selectCurrentFiatRates);
const cryptoBalanceWithStaking = useSelector((state: NativeStakingRootState) =>
selectAccountCryptoBalanceWithStaking(state, account.key),
);

const fiatBalance = useMemo(() => {
return getAccountFiatBalance({ account, localCurrency, rates });
Expand All @@ -36,6 +43,12 @@ export const AccountSectionTitle: React.FC<AccountSectionTitleProps> = ({
adjustsFontSizeToFit
value={fiatBalance}
/>
<CryptoAmountFormatter
value={cryptoBalanceWithStaking}
network={account.symbol}
numberOfLines={1}
adjustsFontSizeToFit
/>
</VStack>
)}
</HStack>
Expand Down
36 changes: 32 additions & 4 deletions suite-native/accounts/src/components/AccountSelectBottomSheet.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,18 @@ import { FlashList } from '@shopify/flash-list';

import { BottomSheet } from '@suite-native/atoms';
import { prepareNativeStyle, useNativeStyles } from '@trezor/styles';
import { useToast } from '@suite-native/toasts';

import { AccountSelectBottomSheetSection, OnSelectAccount } from '../types';
import { AccountsListItem } from './AccountsList/AccountsListItem';
import { AccountSectionTitle } from './AccountSectionTitle';
import { AccountsListTokenItem } from './AccountsList/AccountsListTokenItem';
import { AccountsListStakingItem } from './AccountsList/AccountsListStakingItem';

type AccountSelectBottomSheetProps = {
data: AccountSelectBottomSheetSection[];
onSelectAccount: OnSelectAccount;
isStakingPressable?: boolean;
onClose: () => void;
};

Expand All @@ -21,8 +24,14 @@ const contentContainerStyle = prepareNativeStyle(utils => ({
}));

export const AccountSelectBottomSheet = React.memo(
({ data, onSelectAccount, onClose }: AccountSelectBottomSheetProps) => {
({
data,
onSelectAccount,
isStakingPressable = false,
onClose,
}: AccountSelectBottomSheetProps) => {
const { applyStyle } = useNativeStyles();
const { showToast } = useToast();

const renderItem = useCallback(
({ item }: { item: AccountSelectBottomSheetSection }) => {
Expand All @@ -35,12 +44,31 @@ export const AccountSelectBottomSheet = React.memo(
{...item}
hasBackground
showDivider
isInModal={true}
onPress={() => onSelectAccount(item)}
/>
);
case 'staking':
// TODO: Implement staking section
return null;
return (
<AccountsListStakingItem
{...item}
hasBackground
onPress={() => {
if (isStakingPressable) {
onSelectAccount({
account: item.account,
isStaking: true,
hasAnyKnownTokens: false,
});
} else {
showToast({
variant: 'warning',
message: 'Staking is not available in this context.',
});
}
}}
/>
);
case 'token':
const { token, account } = item;

Expand All @@ -61,7 +89,7 @@ export const AccountSelectBottomSheet = React.memo(
return null;
}
},
[onSelectAccount],
[isStakingPressable, onSelectAccount, showToast],
);

return (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,14 @@ type AccountsListProps = {
onSelectAccount: OnSelectAccount;
filterValue?: string;
hideTokensIntoModal?: boolean;
isStakingPressable?: boolean;
};

export const AccountsList = ({
onSelectAccount,
filterValue = '',
hideTokensIntoModal = false,
isStakingPressable = false,
}: AccountsListProps) => {
const groupedAccounts = useSelector((state: NativeAccountsRootState) =>
selectFilteredDeviceAccountsGroupedByNetworkAccountType(state, filterValue),
Expand Down Expand Up @@ -61,7 +63,6 @@ export const AccountsList = ({
<AccountsListItem
key={account.key}
account={account}
hideTokens={hideTokensIntoModal}
onPress={handleSetBottomSheetAccount}
/>
))}
Expand All @@ -71,6 +72,7 @@ export const AccountsList = ({
<TokenSelectBottomSheet
bottomSheetAccountAtom={bottomSheetAccountAtom}
onSelectAccount={onSelectAccount}
isStakingPressable={isStakingPressable}
/>
</>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,16 @@ import {
selectNumberOfAccountTokensWithFiatRates,
TokensRootState,
} from '@suite-native/tokens';
import { NativeStakingRootState, selectAccountHasStaking } from '@suite-native/staking';

import { NativeAccountsRootState, selectAccountFiatBalance } from '../../selectors';
import { OnSelectAccount } from '../../types';
import { AccountsListItemBase } from './AccountsListItemBase';
import { StakingBadge } from './StakingBadge';

export type AccountListItemProps = {
account: Account;
hideTokens?: boolean;
isInModal?: boolean;

onPress?: OnSelectAccount;
disabled?: boolean;
Expand Down Expand Up @@ -53,7 +55,7 @@ export const AccountsListItem = ({
account,
onPress,
disabled,
hideTokens = false,
isInModal = false,
hasBackground = false,
isFirst = false,
isLast = false,
Expand All @@ -69,6 +71,10 @@ export const AccountsListItem = ({
selectAccountHasAnyKnownToken(state, account.key),
);

const accountHasStaking = useSelector((state: NativeStakingRootState) =>
selectAccountHasStaking(state, account.key),
);

const fiatBalance = useSelector((state: NativeAccountsRootState) =>
selectAccountFiatBalance(state, account.key),
);
Expand All @@ -81,8 +87,9 @@ export const AccountsListItem = ({
}, [account, accountHasAnyTokens, onPress]);

const doesCoinSupportTokens = isCoinWithTokens(account.symbol);
const shouldShowAccountLabel = !doesCoinSupportTokens || hideTokens;
const shouldShowTokenBadge = accountHasAnyTokens && hideTokens;
const shouldShowAccountLabel = !doesCoinSupportTokens || !isInModal;
const shouldShowTokenBadge = accountHasAnyTokens && !isInModal;
const shouldShowStakingBadge = accountHasStaking && !isInModal;

return (
<AccountsListItemBase
Expand All @@ -105,6 +112,7 @@ export const AccountsListItem = ({
{formattedAccountType && (
<Badge label={formattedAccountType} size="small" elevation="1" />
)}
{shouldShowStakingBadge && <StakingBadge />}
{shouldShowTokenBadge && <TokenBadge accountKey={account.key} />}
</>
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { Account } from '@suite-common/wallet-types';
import { RoundedIcon } from '@suite-native/atoms';
import { CryptoAmountFormatter, CryptoToFiatAmountFormatter } from '@suite-native/formatters';
import { Translation } from '@suite-native/intl';

import { AccountsListItemBase } from './AccountsListItemBase';

type AccountsListStakingItemProps = {
account: Account;
stakingCryptoBalance: string;
onPress: () => void;

hasBackground?: boolean;
isFirst?: boolean;
isLast?: boolean;
};

export const AccountsListStakingItem = ({
account,
stakingCryptoBalance,
isLast,
...props
}: AccountsListStakingItemProps) => {
return (
<AccountsListItemBase
{...props}
isLast={isLast}
showDivider={!isLast}
icon={<RoundedIcon name="piggyBankFilled" color="iconSubdued" />}
title={<Translation id="accountList.staking" />}
mainValue={
<CryptoToFiatAmountFormatter
value={stakingCryptoBalance}
network={account.symbol}
isBalance
/>
}
secondaryValue={
<CryptoAmountFormatter
value={stakingCryptoBalance}
network={account.symbol}
numberOfLines={1}
adjustsFontSizeToFit
/>
}
/>
);
};
13 changes: 13 additions & 0 deletions suite-native/accounts/src/components/AccountsList/StakingBadge.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { RoundedIcon, RoundedIconProps } from '@suite-native/atoms';

export const StakingBadge = (props: Partial<RoundedIconProps>) => {
return (
<RoundedIcon
name="piggyBank"
color="textSubdued"
iconSize="small"
containerSize={22}
{...props}
/>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,13 @@ import { AccountSelectBottomSheet } from './AccountSelectBottomSheet';
type TokenSelectBottomSheetProps = {
bottomSheetAccountAtom: WritableAtom<Account | null, Account | null>;
onSelectAccount: OnSelectAccount;
isStakingPressable?: boolean;
};

export const TokenSelectBottomSheet = ({
bottomSheetAccountAtom,
onSelectAccount,
isStakingPressable = false,
}: TokenSelectBottomSheetProps) => {
const [selectedAccount, setSelectedAccount] = useAtom(bottomSheetAccountAtom);

Expand Down Expand Up @@ -44,6 +46,7 @@ export const TokenSelectBottomSheet = ({
onSelectAccount={handleSelectAccount}
data={data}
onClose={handleClose}
isStakingPressable={isStakingPressable}
/>
);
};
1 change: 1 addition & 0 deletions suite-native/accounts/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ export * from './components/AddAccountsButton';
export * from './components/AccountsList/AccountsList';
export * from './components/AccountsList/AccountsListItem';
export * from './components/AccountsList/AccountsListItemBase';
export * from './components/AccountsList/StakingBadge';
export * from './components/SearchableAccountsListScreenHeader';
export * from './components/SelectableNetworkItem';
export * from './components/AccountsList/AccountsListTokenItem';
Expand Down
19 changes: 13 additions & 6 deletions suite-native/accounts/src/selectors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import {
selectVisibleDeviceAccounts,
} from '@suite-common/wallet-core';
import { AccountKey, TokenInfoBranded } from '@suite-common/wallet-types';
import { getAccountFiatBalance } from '@suite-common/wallet-utils';
import { getAccountFiatBalance, getAccountTotalStakingBalance } from '@suite-common/wallet-utils';
import { SettingsSliceRootState, selectFiatCurrencyCode } from '@suite-native/settings';
import { isCoinWithTokens } from '@suite-native/tokens';

Expand Down Expand Up @@ -78,12 +78,10 @@ export const selectAccountFiatBalance = (state: NativeAccountsRootState, account
return '0';
}

// Staking should be true once we support it in Trezor Suite Lite
const totalBalance = getAccountFiatBalance({
account,
rates: fiatRates,
localCurrency,
shouldIncludeStaking: false,
});

return totalBalance;
Expand All @@ -92,7 +90,7 @@ export const selectAccountFiatBalance = (state: NativeAccountsRootState, account
const EMPTY_ARRAY: any[] = [];

export const selectAccountListSections = memoizeWithArgs(
(state: NativeAccountsRootState, accountKey?: AccountKey | null) => {
(state: NativeAccountsRootState, accountKey?: AccountKey | null, hideStaking?: boolean) => {
if (!accountKey) return EMPTY_ARRAY;
const account = selectAccountByKey(state, accountKey);
if (!account) return EMPTY_ARRAY;
Expand All @@ -102,6 +100,8 @@ export const selectAccountListSections = memoizeWithArgs(
const canHasTokens = isCoinWithTokens(account.symbol);
const tokens = selectFilterKnownTokens(state, account.symbol, account.tokens ?? []);
const hasAnyKnownTokens = canHasTokens && !!tokens.length;
const stakingBalance = getAccountTotalStakingBalance(account);
const hasStaking = stakingBalance !== '0' && !hideStaking;

if (canHasTokens) {
sections.push({
Expand All @@ -113,12 +113,19 @@ export const selectAccountListSections = memoizeWithArgs(
sections.push({
type: 'account',
account,
isLast: !hasAnyKnownTokens,
isLast: !hasAnyKnownTokens && !hasStaking,
isFirst: true,
hasAnyKnownTokens,
});

// TODO: staking here
if (hasStaking) {
sections.push({
type: 'staking',
account,
stakingCryptoBalance: stakingBalance,
isLast: !hasAnyKnownTokens,
});
}

if (hasAnyKnownTokens) {
tokens.forEach((token, index) => {
Expand Down
2 changes: 2 additions & 0 deletions suite-native/accounts/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export type GroupedByTypeAccounts = Record<string, [Account, ...Account[]]>;

export type OnSelectAccount = (params: {
account: Account;
isStaking?: boolean;
tokenAddress?: TokenAddress;
hasAnyKnownTokens: boolean;
}) => void;
Expand All @@ -23,6 +24,7 @@ export type AccountSelectBottomSheetSection = (
| {
type: 'staking';
account: Account;
stakingCryptoBalance: string;
}
| {
type: 'token';
Expand Down
Loading

0 comments on commit fd47fd6

Please sign in to comment.