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

feat(mobile): staking view-only #14561

Merged
merged 1 commit into from
Sep 30, 2024
Merged
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/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
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.',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: If we expect this to ne visible to user, it would be good to add to intl

});
}
}}
/>
);
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;
vytick marked this conversation as resolved.
Show resolved Hide resolved
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
/>
}
/>
);
};
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
Loading