Skip to content
Closed
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
3 changes: 3 additions & 0 deletions apps/next/src/localization/locales/en/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@
"Choose Verification Method": "Choose Verification Method",
"Choose a recovery method": "Choose a recovery method",
"Choose a recovery method associated with your wallet.": "Choose a recovery method associated with your wallet.",
"Claim": "Claim",
"Clear all": "Clear all",
"Click for more details": "Click for more details",
"Click on the “Get signature” button after signing the transaction with your Keystone device": "Click on the “Get signature” button after signing the transaction with your Keystone device",
Expand Down Expand Up @@ -187,6 +188,7 @@
"Core Concierge": "Core Concierge",
"Core always finds the best price from the top liquidity providers. A fee of {{coreFee}} is automatically factored into this quote.": "Core always finds the best price from the top liquidity providers. A fee of {{coreFee}} is automatically factored into this quote.",
"Core functionality may be unstable with custom RPC URLs": "Core functionality may be unstable with custom RPC URLs",
"Core has detected stuck funds": "Core has detected stuck funds",
"Core has entered an unexpected state. Please restart the browser if the issue persists.": "Core has entered an unexpected state. Please restart the browser if the issue persists.",
"Core is committed to protecting your privacy. We will never sell or share your data. If you wish, you can disable this at any time in the settings menu.": "Core is committed to protecting your privacy. We will never sell or share your data. If you wish, you can disable this at any time in the settings menu.",
"Core is no longer connected to your Keystone device. Reconnect to continue.": "Core is no longer connected to your Keystone device. Reconnect to continue.",
Expand Down Expand Up @@ -838,6 +840,7 @@
"You cannot add a new recovery method for your wallet! Try again later!": "You cannot add a new recovery method for your wallet! Try again later!",
"You do not have enough funds to cover the network fees.": "You do not have enough funds to cover the network fees.",
"You have been logged out do to inactivity": "You have been logged out do to inactivity",
"You have {{amount}} AVAX stuck in atomic memory from incomplete cross-chain transfers": "You have {{amount}} AVAX stuck in atomic memory from incomplete cross-chain transfers",
"You hid all your collectibles": "You hid all your collectibles",
"You may need to enable popups to continue, you can find this setting near the address bar.": "You may need to enable popups to continue, you can find this setting near the address bar.",
"You must allow access to scan the QR code.": "You must allow access to scan the QR code.",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
import { FC, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { useHistory, useLocation } from 'react-router-dom';
import {
alpha,
CircularProgress,
Expand All @@ -12,16 +15,15 @@ import {
useBalancesContext,
useNetworkContext,
} from '@core/ui';
import { FC, useState } from 'react';

import { TESTNET_MODE_BACKGROUND_COLOR } from '@/config/constants';
import { NoScrollStack } from '@/components/NoScrollStack';
import { TestnetModeOverlay } from '@/components/TestnetModeOverlay';

import AccountInfo from './components/AccountInfo';
import { EmptyState } from './components/EmptyState';
import { PortfolioDetails } from './components/PortolioDetails';
import { useTranslation } from 'react-i18next';
import { TESTNET_MODE_BACKGROUND_COLOR } from '@/config/constants';
import { TestnetModeOverlay } from '@/components/TestnetModeOverlay';
import { useHistory, useLocation } from 'react-router-dom';
import { AtomicFundsBalance } from './components/AtomicFundsBalance';

export type TabName = 'assets' | 'collectibles' | 'defi' | 'activity';

Expand All @@ -41,7 +43,11 @@ export const PortfolioHome: FC = () => {
activeTabFromParams ?? 'assets',
);
const { networks, isDeveloperMode } = useNetworkContext();
const { totalBalance, balances } = useBalancesContext();
const { totalBalance, balances, getAtomicBalance } = useBalancesContext();
const walletId =
accounts.active?.type === 'primary' ? accounts.active.walletId : undefined;
const atomicBalance = getAtomicBalance(walletId);
const atomicBalanceExists = !!atomicBalance;
const isLoading = !totalBalance;
const isAccountEmpty =
!hasAccountBalances(
Expand Down Expand Up @@ -90,6 +96,15 @@ export const PortfolioHome: FC = () => {
balance={totalBalance}
isDeveloperMode={isDeveloperMode}
/>
{!!walletId &&
atomicBalanceExists &&
(atomicBalance.isLoading ? (
<CenteredSpinner />
) : (
<AtomicFundsBalance
atomicBalance={atomicBalance.balanceDisplayValue!}
/>
))}
<Stack flexGrow={1} gap={2.5}>
{isLoading ? (
<CenteredSpinner />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import { FC } from 'react';
import { FiAlertCircle } from 'react-icons/fi';
import { Box, Button, Stack, Typography, useTheme } from '@avalabs/k2-alpine';
import { useTranslation } from 'react-i18next';
import { Card } from '@/components/Card';
import { CORE_WEB_BASE_URL } from '@/config';

type Props = {
atomicBalance: number;
};

// TODO: Multiple token support
export const AtomicFundsBalance: FC<Props> = ({ atomicBalance }) => {
const theme = useTheme();
const { t } = useTranslation();
if (!atomicBalance) {
return <></>;
}

return (
<Card>
<Stack
direction="row"
gap={1}
alignItems="center"
sx={{
px: theme.spacing(1.5),
py: theme.spacing(1),
}}
>
<Box flexShrink={0} lineHeight={1} color="error.main">
<FiAlertCircle size={24} />
</Box>
<Stack direction="row" alignItems="center" gap={1}>
<Stack gap={0.5}>
<Typography variant="body3" color="text.primary">
{t('Core has detected stuck funds')}
</Typography>
<Typography variant="body3" color="text.secondary">
{t(
'You have {{amount}} AVAX stuck in atomic memory from incomplete cross-chain transfers',
{
amount: atomicBalance,
},
)}
</Typography>
</Stack>
<Button
size="xsmall"
variant="contained"
color="primary"
onClick={() => {
window.open(
`${CORE_WEB_BASE_URL}/portfolio`,
'_blank',
'noreferrer',
);
}}
>
{t('Claim')}
</Button>
</Stack>
</Stack>
</Card>
);
};
2 changes: 2 additions & 0 deletions packages/common/src/feature-flags.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ export const DISABLED_FLAG_VALUES: FeatureFlags = {
[FeatureGates.CORE_ASSISTANT]: false,
[FeatureGates.SWAP_USE_MARKR]: false,
[FeatureVars.MARKR_SWAP_GAS_BUFFER]: '100',
[FeatureGates.BALANCE_SERVICE_INTEGRATION]: false,
};

// Default flags are used when posthog is not available
Expand Down Expand Up @@ -127,6 +128,7 @@ export const DEFAULT_FLAGS: FeatureFlags = {
[FeatureGates.CORE_ASSISTANT]: true,
[FeatureGates.SWAP_USE_MARKR]: true,
[FeatureVars.MARKR_SWAP_GAS_BUFFER]: '120',
[FeatureGates.BALANCE_SERVICE_INTEGRATION]: false,
};

export const FEATURE_FLAGS_OVERRIDES_KEY = '__feature-flag-overrides__';
11 changes: 11 additions & 0 deletions packages/common/src/utils/balance/balanceToDecimal.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { balanceToDecimal } from './balanceToDecimal';

describe('balanceToDecimal', () => {
it('calculates the balance correctly for a balance less than the decimals', () => {
expect(balanceToDecimal('1', 5)).toBe(0.00001);
});

it('calculates the balance correctly for a balance greater than the decimals', () => {
expect(balanceToDecimal('100000000000000000000', 18)).toBe(100);
});
});
25 changes: 25 additions & 0 deletions packages/common/src/utils/balance/balanceToDecimal.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
const BALANCE_DECIMALS = 5;

const parseResult = (result: string | number): number => {
return Number(parseFloat(String(result)).toFixed(BALANCE_DECIMALS));
};

export const balanceToDecimal = (
balance: string | number,
decimals: string | number,
): number => {
const balanceString = String(balance);
const decimalsNumber = Number(decimals);
const balanceLength = balanceString.length;

if (balanceLength <= decimalsNumber) {
const paddedBalanceString = balanceString.padStart(decimalsNumber, '0');

return parseResult(`0.${paddedBalanceString.slice(0, decimalsNumber)}`);
} else {
const integerPart = balanceString.slice(0, balanceLength - decimalsNumber);
const fractionalPart = balanceString.slice(balanceLength - decimalsNumber);

return parseResult(`${integerPart}.${fractionalPart}`);
}
};
1 change: 1 addition & 0 deletions packages/common/src/utils/balance/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ export * from './groupTokensByType';
export * from './isTokenWithBalanceAVM';
export * from './isTokenWithBalancePVM';
export * from './getMaxUtxos';
export * from './balanceToDecimal';
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export type Options<
export const postV1BalanceGetBalances = <ThrowOnError extends boolean = false>(
options: Options<PostV1BalanceGetBalancesData, ThrowOnError>,
) => {
return (options.client ?? client).post<
return (options.client ?? client).sse.post<
PostV1BalanceGetBalancesResponses,
unknown,
ThrowOnError
Expand Down
Loading
Loading