Skip to content

feat(mobile): implement token details, ref LEA-3015 #1465

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

Merged
merged 2 commits into from
Jul 22, 2025

Conversation

pete-watters
Copy link
Contributor

@pete-watters pete-watters commented Jul 17, 2025

This PR adds the first draft of token details. It's close but some more work is needed regarding:

  • BTC balances split by address type
  • improved transitions between sheets, going back etc.
  • UI polish + final refactor to improve overall code

I have feature flagged the whole thing so it could be merged safely or not.

Here's a demo:

token-details.mp4

Copy link

linear bot commented Jul 17, 2025

@leather-bot
Copy link
Contributor

leather-bot commented Jul 17, 2025

Leather Web Build b0490d6https://pr-1465-leather-web.wallet-6d1.workers.dev

@leather-bot
Copy link
Contributor

This PR's build fingerprint differs from the latest production build's fingerprint. Merging this PR would require us to submit the build to the stores. (Note: Make sure your PR is up to date)

Copy link

codecov bot commented Jul 17, 2025

Codecov Report

Attention: Patch coverage is 0% with 804 lines in your changes missing coverage. Please review.

Project coverage is 14.45%. Comparing base (be6251b) to head (b0490d6).
Report is 2 commits behind head on dev.

Files with missing lines Patch % Lines
apps/mobile/src/features/token/address-list.tsx 0.00% 141 Missing ⚠️
.../mobile/src/features/token/token-receive-sheet.tsx 0.00% 79 Missing ⚠️
apps/mobile/src/features/token/token.tsx 0.00% 75 Missing ⚠️
apps/mobile/src/features/balances/balances.tsx 0.00% 53 Missing ⚠️
...ps/mobile/src/features/token/account-list-item.tsx 0.00% 51 Missing ⚠️
...e/src/features/token/components/token-activity.tsx 0.00% 49 Missing ⚠️
.../src/features/token/hooks/use-get-token-balance.ts 0.00% 48 Missing ⚠️
...c/features/token/components/token-price-change.tsx 0.00% 46 Missing ⚠️
...le/src/features/token/components/token-details.tsx 0.00% 40 Missing ⚠️
...e/src/features/token/components/token-overview.tsx 0.00% 39 Missing ⚠️
... and 17 more
Additional details and impacted files
@@            Coverage Diff             @@
##              dev    #1465      +/-   ##
==========================================
- Coverage   14.73%   14.45%   -0.29%     
==========================================
  Files         912      927      +15     
  Lines       37914    38660     +746     
  Branches     1672     1687      +15     
==========================================
  Hits         5587     5587              
- Misses      32327    33073     +746     
Files with missing lines Coverage Δ
...account-selector/account-selector-sheet-header.tsx 0.00% <ø> (ø)
...e/src/features/account/components/account-card.tsx 0.00% <ø> (ø)
...bile/src/features/account/components/app-icons.tsx 0.00% <ø> (ø)
...rc/features/account/components/browser-loading.tsx 0.00% <ø> (ø)
...le/src/features/balances/bitcoin/runes-balance.tsx 0.00% <ø> (ø)
...ps/mobile/src/features/browser/browser/browser.tsx 0.00% <ø> (ø)
apps/mobile/src/features/receive/navigation.tsx 0.00% <ø> (ø)
...ile/src/features/receive/screens/asset-details.tsx 0.00% <ø> (ø)
...bile/src/features/receive/screens/select-asset.tsx 0.00% <ø> (ø)
...ile/src/features/send/components/asset-display.tsx 0.00% <ø> (ø)
... and 31 more
Components Coverage Δ
bitcoin 63.40% <ø> (ø)
query 11.32% <ø> (ø)
utils 82.39% <ø> (ø)
crypto 68.14% <ø> (ø)
stacks 65.07% <ø> (ø)
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@pete-watters pete-watters force-pushed the feat/token-details branch 2 times, most recently from 092d688 to cc4e73a Compare July 17, 2025 15:07
@@ -43,7 +42,7 @@ export default function AccountActivityScreen() {
})}
</Screen.Title>
}
data={activity.value as OnChainActivity[]} // TODO: Unclear why was this cast. Needs clearing up.
data={activity.value.filter(activity => activity && 'asset' in activity)}
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Filtering for only OnChainActivity to avoid casting. I could probably do this in the Query itself


function onOpenToken({ asset, availableBalance, quoteBalance }: OnOpenTokenProps) {
setSheetData({ asset, availableBalance, quoteBalance });
// analytics.track('token_sheet_opened', { source: 'action_bar' });
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Keeping these as a placeholder. I'll add the analytics keys soon

tokenSheetRef.current?.present();
}

const onPressToken = tokenDetailsFlag ? onOpenToken : undefined;
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I have enabled tokenDetailsFlag in dev but off in production in launch darkly.

There is no way to trigger the TokenDetails sheet without entering here first

const availableBalance = value?.btc.availableBalance;
const quoteBalance = value?.quote.availableBalance;

if (!availableBalance || !quoteBalance) {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I need to clean this up

@@ -83,6 +87,14 @@ function Sip10BalanceWrapper({ data, mode = 'full' }: Sip10BalanceWrapperProps)
contractId={item.asset.contractId}
quoteBalance={item.quote.totalBalance}
imageCanonicalUri={item.asset.imageCanonicalUri}
onPress={() => {
// pass balance and quote balance to the sheet from here
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I am passing the balances to the sheet via a callback as we already have that information at this point.

Without doing this we would need to call the balance hooks again in the sheet and then have 6 different setups for each scenario (excluding Runes) - BTC, STX and SIP-10 both all balances and account balance.

accountName={account.name}
walletName={
<Text variant="caption01" lineHeight={16}>
{/* Should perhaps refactor account to have a wallet name? Avoids using the wallet store here */}
Copy link
Contributor Author

Choose a reason for hiding this comment

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

We need to use WalletLoader to get the wallet name. We could probably add that to the account object

</Text>
}
// FIXME LEA-3015: refactor address prop to not be address - leftPrimary or something like that
address={
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'm re-using AccountListItemComponent but it needs to be refactored to be more generic

/>
}
balance={
// FIXME LEA-3015: isQuoteCurrency is crashing for non BTC tokens
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I need to fix this to handle SIP-10 balances in this context
Screenshot 2025-07-17 at 19 23 07

<TokenDetailsCard
title={
<Box flexDirection="row" alignItems="center" gap="2">
{/* FIXME - this icon needs to be 16x16 but require refactors to make it work */}
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I need to refactor the icons so they can accept a smaller size of 16x16 to fit this design

Screenshot 2025-07-17 at 19 22 59

@@ -0,0 +1,77 @@
import { AccountBalance, useAccountBalance } from '@/queries/balance/account-balance.query';
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'll be removing this file completely. I replaced this with passing balances as props as I think that's cleaner than these custom hooks

const availableBalance = tokenBalance?.availableBalance;
const quoteBalance = tokenBalance?.quoteBalance;

if (tokenId === 'BTC') {
Copy link
Contributor Author

@pete-watters pete-watters Jul 17, 2025

Choose a reason for hiding this comment

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

This balance section of this code will be re-written once we have balances split by BTC address type.

For now it's using useGetAccountTokenBalance which will be removed and has both BTC balance listed as the same aggregate balance:

Screenshot 2025-07-17 at 19 31 10

<Screen>
<Screen.Header
blurOverlay={false}
// topElement={isErrorTotalBalance && <FetchErrorCallout />}
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I need to add error handling in case of incorrect balances / timeout etc.

.filter(activity => activity && 'asset' in activity)
.filter(activity => filterByTicker(activity, ticker))
.filter(activity => {
if (isDefined(accountIndex) && isDefined(fingerprint)) {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

When an account is selected, this re-renders and filters activity using that account ID.

We have another query for account specific activity by asset but this data is already here


<TokenDetailsTable
name={`${capitalize(asset.chain)} (${asset.symbol})`}
// for Layer design has 'Layer 1 (Bitcoin)' but no other examples. Only showing 'Layer 1' for now based on previous use of getChainLayerFromAssetProtocol
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I need to check with design and get examples of different tokens. The design only has BTC and looks like this:

Screenshot 2025-07-17 at 19 35 54

I will check the copy with design but decided to use a function we already had for now getChainLayerFromAssetProtocol
Screenshot 2025-07-17 at 19 36 21

ticker={asset.symbol}
accountIndex={accountIndex}
fingerprint={fingerprint}
// TokenDetails is Activity ListHeader to avoid nested scrolling errors
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This page is structured to be centered around the ActivityList FlatList.

I pass all the non-activity content as the ListHeader so that scrolling works smoothly on both and it doesn't give errors.

@edgarkhanzadian edgarkhanzadian force-pushed the feat/token-details branch 2 times, most recently from b9df0ec to 4f67d72 Compare July 22, 2025 11:23
Copy link
Collaborator

@edgarkhanzadian edgarkhanzadian left a comment

Choose a reason for hiding this comment

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

Thank you @pete-watters ! I think this is good to merge but not to release for now (feature flag is helping tremendously here!). Let's merge this and then open smaller PRs to fix some issues

}: TokenActivityProps) {
const scrollViewAdjustmentOffset = 56;
const { refreshing, onRefresh } = useRefreshHandler();
const activity = useTotalActivity();
Copy link
Collaborator

Choose a reason for hiding this comment

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

I think this is going to be a big issue for performance on bigger wallets. To my knowledge we have a separate service for BTC/STX/SIP10 activities, so we'd rather use that

Comment on lines +59 to +62
data={activity.value
.filter(activity => activity && 'asset' in activity)
.filter(activity => filterByTicker(activity, ticker))
.filter(activity => {
Copy link
Collaborator

Choose a reason for hiding this comment

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

i'd throw this filters into a useMemo as it might be a performance issue to filter these all out

@edgarkhanzadian edgarkhanzadian added this pull request to the merge queue Jul 22, 2025
Merged via the queue into dev with commit 6acd2c1 Jul 22, 2025
23 checks passed
@edgarkhanzadian edgarkhanzadian deleted the feat/token-details branch July 22, 2025 13:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants