Repository navigation
Conversation
Add a bitcoin-only wallet detail screen opened from the home asset row, with the Liveline price chart, current price, percentage badge, holdings, wallet actions, and bitcoin-filtered recent activity. Share the existing swap coming-soon drawer between home and the detail page, and cover the bitcoin row navigation with a wallet screen regression test.
|
@bordalix this PR brings over the frontend for the bitcoin detail price/chart experience from the draft approach. We may need the app/backend to serve the actual bitcoin price and historical chart data instead of relying directly on external market APIs from the client. Could you help advise on the right way to serve that data? |
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. 🗂️ Base branches to auto review (1)
Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Deploying wallet-bitcoin with
|
| Latest commit: |
1820528
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://460ec5b6.wallet-bitcoin.pages.dev |
| Branch Preview URL: | https://wt-bitcoin-detail-page-20260.wallet-bitcoin.pages.dev |
Deploying wallet-mutinynet with
|
| Latest commit: |
1820528
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://25d95223.arkade-wallet.pages.dev |
| Branch Preview URL: | https://wt-bitcoin-detail-page-20260.arkade-wallet.pages.dev |
Deploying tmp-boltz-upstream-mainnet-arkade-wallet with
|
| Latest commit: |
1820528
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://fa26cbbb.tmp-boltz-upstream-mainnet-arkade-wallet.pages.dev |
| Branch Preview URL: | https://wt-bitcoin-detail-page-20260.tmp-boltz-upstream-mainnet-arkade-wallet.pages.dev |
ghost
left a comment
There was a problem hiding this comment.
Code Review — feat(wallet): add bitcoin detail page
Overall this is a well-structured UI feature: clean component decomposition, good accessibility (aria roles on tabs, reduced-motion support), and solid refactoring of SwapComingSoonSheet into a shared component. But there's one crash-level bug that blocks merge.
🔴 BUG — convertFiat does not exist (runtime crash)
src/screens/Wallet/BitcoinDetail.tsx:4 (line 594 in diff)
const { convertFiat, fiatDecimals, toFiat } = useContext(FiatContext)FiatContext exports { toFiat, fromFiat, fiatDecimals, updateFiatPrices }. There is no convertFiat property. Destructuring yields undefined.
This undefined is then passed through useBitcoinMarketChartData → fetchBitcoinMarketChart → fetchCoinbaseBitcoinAllChart → fetchCoinbaseBitcoinCandles, where it's called at BitcoinDetail.tsx:476 (line 1026 in diff):
[time * 1000, fiat === Fiats.USD ? close : convertFiat(close, Fiats.USD)]Impact: For any user whose fiat currency is not USD, selecting the "All" chart range will throw TypeError: convertFiat is not a function, crashing the component. USD users are accidentally safe because the ternary short-circuits.
Fix: Either add a convertFiat(amount, fromCurrency) method to FiatContext/FiatProvider, or build the conversion inline using the existing toFiat/fromFiat helpers. Something like:
const convertFromUSD = (usdAmount: number) => {
const sats = fromFiat(usdAmount) // if fromFiat were currency-aware...
return toFiat(sats)
}But note fromFiat uses the user's configured fiat, not a specified source currency — so you likely need a new helper that takes a source currency parameter, or fetch Coinbase candles in USD and convert via the existing price ratio.
🟡 Coinbase "All" chart — unbounded parallel requests
BitcoinDetail.tsx:442-448 (lines 992-997 in diff)
for (let start = ALL_CHART_START_TIME; start < now; start += chunkSecs) {
requests.push(fetchCoinbaseBitcoinCandles(start, end, fiat, convertFiat, signal))
}
const chunks = await Promise.all(requests)From 2015 to 2026 with 300-day chunks = ~14 parallel requests to api.exchange.coinbase.com. Coinbase's public API rate limit is 10 req/s per IP. This will likely trigger 429s on slower connections or under any existing load.
Suggestion: Use Promise.allSettled with a concurrency limiter (e.g., batch 3-4 at a time), or fetch sequentially. Also handle 429 responses with a retry/backoff rather than throwing.
🟡 No caching of chart data
Each time the user taps a range tab, useBitcoinMarketChartData fires a fresh fetch. Toggling between "1D" and "1W" repeatedly hammers CoinGecko/Coinbase on every tap.
Suggestion: Cache fetched data per (fiat, windowSecs) key in a ref or module-level Map, at least for the component's lifetime. The data doesn't go stale in seconds.
🟡 CoinGecko "All" fallback is misleading
BitcoinDetail.tsx:600 (line 1151 in diff)
function coinGeckoDaysForWindow(windowSecs: number): string[] {
if (isAllChartWindow(windowSecs)) return ['365']If Coinbase "All" fails (which it will for non-USD users per the bug above), the CoinGecko fallback requests 365 days but labels the tab "All". Users see ~1 year of data while the UI says "All time." Either fetch max from CoinGecko or label the fallback honestly.
🟡 balance passed to BigInt() without guard
BitcoinDetail.tsx:259 (line 809 in diff)
<span className='asset-detail-holding-amount'>{formatAssetAmount(BigInt(balance), 8)}</span>balance is typed as number from WalletContext. If it's ever NaN, fractional, or Infinity (e.g., during loading or error states), BigInt() throws. The rest of the codebase treats balance as an integer satoshi count, so this is low-risk, but a guard like BigInt(Math.floor(balance || 0)) is cheap insurance.
🟢 Minor / Nits
-
376 lines of CSS in
index.css— This is a growing monolith. Not blocking, but consider splitting per-screen CSS or using CSS modules before this file becomes unmanageable. -
useTokenColorruns once (BitcoinDetail.tsx:355, line 905 in diff) — TheuseEffecthas[token]as dependency, buttokenis a constant string'--orange-500'. This means it resolves the CSS custom property once on mount. If the user switches themes, the chart color won't update until the component remounts. Consider addingconfig.themeto the dependency array or listening for theme changes. -
Test coverage is minimal — The new test only covers navigation to the detail page (clicking the BTC row). There are no tests for
BitcoinDetailitself: chart data fetching, range tab switching, delta calculation, action button handlers, error states. The helper functions (calculateDelta,smoothChartData,bucketAveragePoints,coinGeckoDaysForWindow) are pure and easily unit-testable.
✅ What looks good
- Clean extraction of
SwapComingSoonSheetinto a shared component - Proper
AbortControllercleanup in the data-fetching effect - Good accessibility:
role="tablist",aria-selected,aria-hidden,aria-label prefers-reduced-motionrespected throughoutResizeObserverfeature detection before rendering Livelinecontain: contenton the page root for paint performance- Navigation registration is clean and follows existing patterns
Verdict: Request changes. The convertFiat bug is a crash for all non-USD users on the "All" tab. Fix that, and this is close to shippable.
Remove the invalid fiat conversion path from the bitcoin detail chart, use CoinGecko max data for non-USD all-time charts, cache chart responses per fiat/range, fetch Coinbase all-time chunks sequentially, and guard the holdings balance before BigInt conversion.
ghost
left a comment
There was a problem hiding this comment.
Follow-up Review — New Commit 2c53873
All six findings from my previous review have been addressed cleanly:
| Finding | Fix |
|---|---|
🔴 convertFiat crash (non-USD users) |
Removed entirely. Coinbase "All" path now gated on fiat === Fiats.USD; non-USD falls through to CoinGecko. No more phantom undefined function call. |
| 🟡 Unbounded parallel Coinbase requests | Sequential await in loop — no more 14-request burst. |
| 🟡 No chart caching | Module-level Map<string, LivelinePoint[]> keyed by fiat:windowSecs. |
| 🟡 CoinGecko "All" returned 365 days | Now returns 'max'. |
🟡 BigInt(balance) unguarded |
safeBalance via Number.isFinite + Math.floor + Math.max(0, ...). |
🟢 useTokenColor theme reactivity |
theme added as dependency + parameter. |
No new issues introduced. The fix commit is tight — 33 additions, 32 deletions, all in BitcoinDetail.tsx.
Minor note for future: the chart cache has no TTL, so data can go stale if the user stays on the page for a long session. Not blocking — just worth knowing.
✅ Approved. No protocol-critical code touched (this is a pure UI feature — chart, price display, navigation).
|
@bordalix fixed the chart hover drift João flagged. Liveline is now paused while the user is hovering/scrubbing the bitcoin chart, so holding the cursor/thumb at one point keeps the tooltip value fixed instead of advancing with the live time window. Added a regression test for pause-on-hover/resume-on-leave. |
ghost
left a comment
There was a problem hiding this comment.
Follow-up Review — Commit 1978776
Single-line addition: paused={chartInteracting} on the <Liveline> component, plus a new test.
What changed:
BitcoinDetail.tsx:208— passes existingchartInteractingstate aspausedprop to freeze the chart animation while the user is hovering/scrubbing. Clean use of already-wired pointer event handlers (setChartScrubbing).bitcoin-detail.test.tsx— new test covering the pause-on-hover behavior. MocksLiveline,ResizeObserver, andfetchcorrectly. Assertsdata-pausedtoggles onpointerEnter/pointerLeave.
Verdict: No protocol-critical code touched. Pure UI polish. The interaction state was already managed; this just threads it to the chart library. Test coverage is appropriate.
✅ LGTM — no issues found in the new commit.
ghost
left a comment
There was a problem hiding this comment.
Follow-up Review — Commit 1978776
Single-line addition: paused={chartInteracting} on the <Liveline> component, plus a new test.
What changed:
BitcoinDetail.tsx:208— passes existingchartInteractingstate aspausedprop to freeze the chart animation while the user is hovering/scrubbing. Clean use of already-wired pointer event handlers (setChartScrubbing).bitcoin-detail.test.tsx— new test covering the pause-on-hover behavior. MocksLiveline,ResizeObserver, andfetchcorrectly. Assertsdata-pausedtoggles onpointerEnter/pointerLeave.
Verdict: No protocol-critical code touched. Pure UI polish. The interaction state was already managed; this just threads it to the chart library. Test coverage is appropriate.
✅ LGTM — no issues found in the new commit.
ghost
left a comment
There was a problem hiding this comment.
Follow-up Review — Commits f2eedfd, 8c7ebb6
Two small production fixes and a batch of test hardening. No protocol-critical code touched.
Production changes (both clean) ✅
src/components/AssetCard.tsx:36 — Removed the ticker-as-name special-case (ticker && ticker !== 'BTC' ? ticker : ...). Now consistently uses name || truncatedAssetId || 'Asset'. All seven callsites already pass name, so no display regression.
src/components/TransactionsList.tsx:112 — Added ticker as a fallback in the label chain: accountTicker ?? ticker ?? meta?.name ?? truncated. Correct — for assets where accountTickerForAssetTicker() returns undefined but a raw ticker exists, this prevents falling through to the less-readable metadata name or truncated ID.
Test changes ✅
- Increased flaky timeouts (
4000→10000ms) - Made balance assertions deterministic: computes expected balances from
totalSent = amount + feesinstead of scraping the DOM with regex — much more robust - Removed
prettyNumberformatting from assertions to match actual rendered output - Fixed selectors for the updated transaction display format (dropped
- $prefix)
No issues found. Ship it.
ghost
left a comment
There was a problem hiding this comment.
Follow-up Review — Commits 97f0aa7, 9d782bd, 48cdbad, 732301f
Good refactor: replaces direct Coinbase/CoinGecko calls with a backend worker proxy (fetchHistoricalMarketData). Removes ~100 lines of client-side chunked fetching. Not protocol-critical — this is purely market-data UI. Three findings:
🟡 Missing AbortSignal passthrough — requests can't be cancelled
src/lib/marketData.ts:28-33
fetchHistoricalMarketData doesn't accept or forward an AbortSignal. The caller in BitcoinDetail.tsx:384-405 still creates an AbortController and checks signal.aborted after resolution, but the underlying fetch() is never abortable.
If a user rapidly switches chart tabs (1H → 1D → 1W → 1M), all 4 requests fire and complete — none are cancelled. The abort check after .then() prevents stale data from rendering, but the requests themselves are wasted. On slow connections this means unnecessary network load and delayed rendering of the final tab.
Suggested fix:
export const fetchHistoricalMarketData = async (
secs: number, fiat: Fiats, signal?: AbortSignal
): Promise<LivelinePoint[]> => {
// ...
const resp = await fetch(`${host}?${params.toString()}`, { signal })
// ...
}🟡 No response.ok check — silent failure on worker errors
src/lib/marketData.ts:31-32
const resp = await fetch(`${host}?${params.toString()}`)
const data = await resp.json()If the worker returns a 500/502/404, resp.json() will either throw on non-JSON bodies (uncaught, bubbles as a generic parse error) or parse an error object that fails validation and silently returns []. The old CoinGecko/Coinbase code explicitly checked response.ok and threw descriptive errors.
Suggested fix:
if (!resp.ok) throw new Error(`Market data fetch failed: ${resp.status}`)🟡 CHART_WINDOWS duplicated — drift risk
src/lib/marketData.ts:12-19 and src/screens/Wallet/BitcoinDetail.tsx:30-37
Both files define their own CHART_WINDOWS array. The secs values must match for secsToPeriod() to return the correct label. If someone later adds or reorders a window in one file but not the other, it silently falls back to 'oneDay'.
Consider exporting the canonical list from marketData.ts and importing it in BitcoinDetail.tsx, or at minimum exporting the secsToPeriod mapping so there's one source of truth for window → API period.
Not blocking. Default chart changed from 1H to 1W — makes sense for a detail page. Console.log removed. Worker URL has a TODO to move off personal subdomain (tracked). All clean. The three findings above are quality improvements, not blockers.
ghost
left a comment
There was a problem hiding this comment.
Follow-up Review — Commit 1820528
Addresses both findings from my last review:
- ✅ AbortSignal passthrough —
signal?: AbortSignaladded tofetchHistoricalMarketDataand forwarded tofetch(). Rapid tab-switching now cancels in-flight requests properly. - ✅
response.okcheck — Worker errors now throw a descriptiveErrorinstead of silently falling through to JSON parse failures.
Rename CHART_WINDOWS → PERIOD_WINDOWS in marketData.ts is a clarity improvement. The remaining duplication between PERIOD_WINDOWS (API labels) and CHART_WINDOWS in BitcoinDetail.tsx (display labels) is fine — they serve different purposes and the secs values match.
No new issues. LGTM.
8941b6e
into
wt-wallet-redesign-followups-20260520
* feat(wallet): redesign bitcoin home Port the scoped home redesign foundation and bitcoin-only wallet home from the draft branch. Adds shared motion and haptics helpers, redesigned home header/hero/actions/assets/upsells/activity preview, hides bottom navigation for home-launched wallet flows, and wires scan/swap interactions without pulling in passkeys or prototype asset accounts. * fix(wallet): use real assets on redesigned home * fix(wallet): polish settings and activity follow-ups Remove the bottom nav from the redesigned wallet flow and align the settings screens with the draft redesign, including the Arkade Mint entry under General. Refresh the full Activity page before showing an empty state, keep the home activity preview hidden when empty, and use the shared secondary/drawer styling for the swap coming-soon sheet. * chore(deps): update pnpm lockfile * test(e2e): follow redesigned navigation Update Playwright helpers and specs to navigate through the redesigned home header, settings entry points, and Boltz deep link instead of the removed bottom nav. * test(e2e): align home and settings assertions Use the settings header text rendered by the shared Header component and assert the redesigned zero-balance home through stable test ids. * test(e2e): navigate app screens without reload * tests fixes * Guard BigInt coercion to prevent render-time crashes * fix polling leak * lint * Add a fallback for --pill-navbar-footer-clearance in settings padding * Remove overriding aria-label on settings rows. * fix(settings): address Arkade Mint review feedback * fix tests * fix test * feat(wallet): add bitcoin detail page (#630) * feat(wallet): add bitcoin detail page Add a bitcoin-only wallet detail screen opened from the home asset row, with the Liveline price chart, current price, percentage badge, holdings, wallet actions, and bitcoin-filtered recent activity. Share the existing swap coming-soon drawer between home and the detail page, and cover the bitcoin row navigation with a wallet screen regression test. * fix(wallet): harden bitcoin chart loading Remove the invalid fiat conversion path from the bitcoin detail chart, use CoinGecko max data for non-USD all-time charts, cache chart responses per fiat/range, fetch Coinbase all-time chunks sequentially, and guard the holdings balance before BigInt conversion. * fix(wallet): pause bitcoin chart while hovering * fix tests * fix test * use graph worker * default chart period one week * remove console.log * new marketData file * fixes --------- Co-authored-by: Sahil Chaturvedi <sahilc0@users.noreply.github.com> Co-authored-by: João Bordalo <bordalix@users.noreply.github.com> * feat(wallet): align recent activity with prototype (#628) * chore(dev): support mnemonic wallet auto-init Allow local dev auto-init to use VITE_DEV_MNEMONIC in addition to VITE_DEV_NSEC, so demo wallets can be restored from the current seed phrase without using the broken legacy default key. * feat(wallet): align recent activity with prototype Update the home recent activity list, full activity view, and transaction receipt details to match the prototype visuals while keeping the shared Activity header from PR 627. Add swap/account asset rendering, receipt-style detail rows, and measured virtual rows for taller activity entries. * fix(wallet): address activity review feedback Guard the round waiting screen when no info logs exist, cancel delayed polling on unmount, preserve the safer settlement status flow, remove incomplete BRL fiat support, and share token ticker mapping helpers across activity and asset views. * fix send max with fiat ' + tests --------- Co-authored-by: Sahil Chaturvedi <sahilc0@users.noreply.github.com> Co-authored-by: João Bordalo <bordalix@users.noreply.github.com> * feat(send): align send form with redesign prototype (#629) Port the draft send-flow field shell, asset selector, amount max control, and button safety polish on top of PR 627. Add dev mnemonic auto-init support so local wallets can boot from mnemonic-based seeds without falling back to stale nsec state. Co-authored-by: Sahil Chaturvedi <sahilc0@users.noreply.github.com> Co-authored-by: João Bordalo <bordalix@users.noreply.github.com> * feat(wallet): align recent activity with prototype (#628) * chore(dev): support mnemonic wallet auto-init Allow local dev auto-init to use VITE_DEV_MNEMONIC in addition to VITE_DEV_NSEC, so demo wallets can be restored from the current seed phrase without using the broken legacy default key. * feat(wallet): align recent activity with prototype Update the home recent activity list, full activity view, and transaction receipt details to match the prototype visuals while keeping the shared Activity header from PR 627. Add swap/account asset rendering, receipt-style detail rows, and measured virtual rows for taller activity entries. * fix(wallet): address activity review feedback Guard the round waiting screen when no info logs exist, cancel delayed polling on unmount, preserve the safer settlement status flow, remove incomplete BRL fiat support, and share token ticker mapping helpers across activity and asset views. * fix send max with fiat ' + tests --------- Co-authored-by: Sahil Chaturvedi <sahilc0@users.noreply.github.com> Co-authored-by: João Bordalo <bordalix@users.noreply.github.com> * fix tests * fix navigation * remove border from video container in scan * change toggle bg color when selected to purple * fix(wallet): address home redesign review feedback * fix flacky test * fix flacky test * contracts view: copy encoded params, empty state, active/inactive sections (#645) * show encoded contract params and allow copying * show encoded contract params and allow copying * improve contracts view: empty state, active/inactive sections, label and createdAt * address review: guard encodeArkContract, createdAt fallback, unique card key Wrap encodeArkContract in try/catch via useMemo and render the parameters row only when encoding succeeds, so a contract with missing/malformed params can no longer white-screen the Contracts screen. Show 'Unknown' instead of an empty string when createdAt is absent. Use contract.address as the React key. Update tests with createdAt/params and add an empty-state case. * fix buttons overflow in input * fix other value when bip21 has amount * remove excessive bottom padding on content-shell * less sensible pull-to-refresh * fix typescript build errors (tsc -b) (#646) * fix typescript build errors (tsc -b) * arkana fixes * build fixes * remove console.log * validate asset mint amount is not too large * validate asset mint amount * validate mint values * fixes * refactor mint form * remove console.log * fix e2e tests * feat(settings): move advanced tools into settings (#652) * feat(settings): move advanced tools into settings Remove the root Apps surface and keep developer-focused tools under Settings > Advanced. Add Boltz and Arkade Mint entries there, rename the main settings group to Display, and update navigation tab ownership so these flows return through settings instead of an apps tab. Also refresh bun.lock to match the dependency versions declared on the PR 627 base and update affected settings/e2e tests. * re-order menu options * fix e2e tests * fix test --------- Co-authored-by: Sahil Chaturvedi <sahilc0@users.noreply.github.com> Co-authored-by: João Bordalo <bordalix@users.noreply.github.com> * feat(settings): support bitcoin currency units (#653) * feat(settings): support bitcoin currency units Add BTC as a selectable currency and replace display preferences with bitcoin unit options for BTC, sats, and BIP-177 notation. Format wallet totals, transactions, send/receive flows, portfolio rows, and the Bitcoin detail view with the selected bitcoin unit while keeping the detail market price in fiat. Convert fiat-like asset balances into selected-currency totals and add focused coverage for CHF asset conversion, settings options, formatting, and Bitcoin detail display. * fix e2e test * Several fixes --------- Co-authored-by: Sahil Chaturvedi <sahilc0@users.noreply.github.com> Co-authored-by: João Bordalo <bordalix@users.noreply.github.com> * fallback to btc currency if price feed fails * add useEffect missing dependencies to InputAmount * fix e2e test * arkana fixes * Fix Settings / Display * change Fiats type to Currencies change Settings menu option names * fix(wallet): address arkana wallet review * fix other value when clicking send max * update regtest link * update price chart proxy url * fix build errors * style(settings): polish contracts screen (#664) Redesign the dev-mode contracts screen with a full-width summary, clearer contract cards, copyable code fields, and subtle motion feedback. Update the contracts screen tests to cover the new summary and metadata layout. Co-authored-by: Sahil Chaturvedi <sahilc0@users.noreply.github.com> * feat(settings): add currency icons (#663) Add reusable leading content support to the settings Select component and use it on the currency picker so each option shows a circular bitcoin or country currency mark. Extend TokenLogo with the remaining fiat currency marks used by settings, add selector icon styling, and update the fiat settings tests to distinguish row icons from the selected-state checkmark. Co-authored-by: Sahil Chaturvedi <sahilc0@users.noreply.github.com> * Fixes * Remove onboarding button (#678) * remove 'complete boarding' button * Upgrade ts-sdk 0.4.36 - boltz-swap 0.3.41 (#676) * prevent double keys in local storage (#677) * prevent double keys in local storage * fix circular dependency * add tests * fix SVGs * remove "Complete boarding button" --------- Co-authored-by: pietro909 <2094604+pietro909@users.noreply.github.com> * Clean qrcode (#681) * remove 'complete boarding' button * fix SVGs * remove "Complete boarding button" * clean qr code ui * remove console.log * clean Reminder (#683) * clean Reminder * fix color * fix duplicate init with devMnemonic * fix test * update regtest commit * mini fixes * fix test * fix test * persist value; fix toggle currency (#705) * fix bitcoin balance in btc page * fix server url input * add error messages inline * fix tests * fix import * fix secondary value when not useFiat * fix flash of unlock screen (#710) * bug fix in privacyAmount * remove dead code * click on asset card to view asset * add test for clicking asset card in homepage * fixes in input amount * lnurl fix * add unit tests * bug fix * fix test * remove currencyDisplay from config (#713) * remove currencyDisplay from config * rabbit fixes * fix test * remove option from upsellsSection * only show btc and registered assets on homepage * fix import path * rename config.fiat to config.currency * fix test --------- Co-authored-by: Sahil Chaturvedi <sahilc0@users.noreply.github.com> Co-authored-by: João Bordalo <bordalix@users.noreply.github.com> Co-authored-by: pietro909 <2094604+pietro909@users.noreply.github.com>
Summary
Affected files and components
src/screens/Wallet/BitcoinDetail.tsxadds the bitcoin detail screen and chart/price data handling.src/screens/Wallet/AssetsSection.tsxroutes the bitcoin row into the detail page.src/components/SwapComingSoonSheet.tsxcentralizes the PR 627 swap coming-soon drawer.src/providers/navigation.tsxregisters the bitcoin detail route under the wallet tab.src/index.cssadds the detail page styles ported from the draft approach.package.json,bun.lock, andpnpm-lock.yamladdliveline.Testing
bunx vitest run src/test/screens/wallet/index.test.tsxbun run lintbun run buildwt-bitcoin-detail-page-20260521.arkade.localhost: clicked the bitcoin row, confirmed the detail page rendered with a chart canvas and Receive/Send/Swap/Scan actions, and verified Swap opens the coming-soon drawer.