Skip to content

Comments

fixes after QA review on PRO-3679/pulse-preview-screen#400

Merged
RanaBug merged 1 commit intostagingfrom
PRO-3679/pulse-preview-screen
Sep 18, 2025
Merged

fixes after QA review on PRO-3679/pulse-preview-screen#400
RanaBug merged 1 commit intostagingfrom
PRO-3679/pulse-preview-screen

Conversation

@RanaBug
Copy link
Collaborator

@RanaBug RanaBug commented Sep 18, 2025

Description

How Has This Been Tested?

Screenshots (if appropriate):

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)

Summary by CodeRabbit

  • New Features

    • Wallet balance now reflects stable currencies; MAX uses this value.
    • Buy button shows precise “Buy X TOKEN for $Y” with improved loading states.
    • Copy-to-clipboard for paying token address with visual confirmation.
    • Clearer messages for insufficient balance, liquidity, or no routes.
  • Bug Fixes

    • Pre-checks prevent attempts beyond wallet balance; errors reset on input changes.
    • Improved liquidity handling in buy/sell; MAX in sell respects token decimals.
    • Consistent currency formatting (e.g., $0.00).
  • Tests

    • Updated fixtures and expectations; added address to token data; adjusted async flows.

@RanaBug RanaBug requested a review from IAmKio September 18, 2025 10:37
@RanaBug RanaBug self-assigned this Sep 18, 2025
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Sep 18, 2025

Walkthrough

Introduces stable-currency balance checks and error handling in Buy, updates BuyButton labeling/disabled logic, adds copy-to-clipboard for paying token address, adjusts PreviewBuy header text, refines Sell MAX amount calculation and liquidity handling, extends PayingToken with address, and wires address through intent utils. Tests updated accordingly.

Changes

Cohort / File(s) Summary
Buy flow: stable balance, errors, debounce
src/apps/pulse/components/Buy/Buy.tsx
Adds stable-currency balance computation via STABLE_CURRENCIES; introduces insufficientWalletBalance state and pre-check in refreshBuyIntent; resets errors on input changes/debounce; updates MAX and displayed balance to use stable balance; consolidates error rendering; passes combined liquidity flag to BuyButton.
Buy button: formatting and disabled logic
src/apps/pulse/components/Buy/BuyButton.tsx
Adds HighDecimalsFormatted/limitDigitsNumber; expands getButtonText signature with optional isDisabled; shows spinner on loading; renders “Buy X SYMBOL for $Y” inline when valid; introduces isDisabled() gating on install/fetch/loading/liquidity; preserves enable-trading message.
Paying token UI: copy address
src/apps/pulse/components/Buy/PayingToken.tsx
Adds copy-to-clipboard for paying token address with 3s success indicator; restructures header to show name and symbol; shows truncated address or placeholder; uses CopyIcon/MdCheck; no API change.
Preview buy header text
src/apps/pulse/components/Buy/PreviewBuy.tsx
Changes header to static “USD Coin” with muted symbol beside it; presentational only.
Sell flow: liquidity and MAX amount
src/apps/pulse/components/Sell/Sell.tsx
In fetchSellOffer, handles notEnoughLiquidity by clearing offer/stopping loading; shows liquidity warning only when true; MAX uses token decimals (default 18) with floor and string conversion.
Types and intent wiring
src/apps/pulse/types/tokens.ts, src/apps/pulse/utils/intent.ts
Extends PayingToken with address: string; intent.getDispensableAssets now includes address in returned PayingToken items; import order adjusted (no semantic change).
Tests: Buy suite updates
src/apps/pulse/components/Buy/tests/Buy.test.tsx, src/apps/pulse/components/Buy/tests/BuyButton.test.tsx, src/apps/pulse/components/Buy/tests/PreviewBuy.test.tsx
Updates mocks to include PayingToken.address and portfolio with USDC; adapts expectations for new error message, debounce timing, wallet balance formatting, button text fragments, duplicate header copies, and copy buttons. Adds new Buy props setUsdAmount/setDispensableAssets in tests.
Tests: Sell suite update
src/apps/pulse/components/Sell/tests/Sell.test.tsx
Adjusts MAX button expectation from fixed 6 decimals to trimmed value (e.g., 100.5).

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor U as User
  participant B as Buy.tsx
  participant PU as Portfolio (assets)
  participant I as Intent API
  participant BB as BuyButton

  U->>B: Enter USD amount / select token
  B->>PU: getStableCurrencyBalance()
  PU-->>B: Sum(price × balance for STABLE_CURRENCIES)
  alt amount > stable balance
    B->>B: set insufficientWalletBalance = true
    B-->>U: Show "Insufficient wallet balance"
  else amount <= stable balance and token selected
    B->>I: refreshBuyIntent(debounced amount, token)
    I-->>B: intent or notEnoughLiquidity / no routes
    alt notEnoughLiquidity or no routes
      B-->>U: Show corresponding warning
    else intent OK
      B-->>U: Show quote details
    end
  end
  B->>BB: Props (states, notEnoughLiquidity || insufficientWalletBalance)
  BB-->>U: Button label (spinner | "Buy X SYMBOL for $Y" | "Buy SYMBOL")
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • ft: pulse app #351 — Touches the same Buy flow, STABLE_CURRENCIES usage, PayingToken.address, and intent-related wiring.
  • PRO-3679/pulse-preview-screen #397 — Updates Buy/Preview integration with similar prop propagation (e.g., setUsdAmount, setDispensableAssets) across the same components.

Suggested reviewers

  • IAmKio

Poem

A nibble of coins in my carrot stash,
I count stable leaves—no risky cash.
Click! goes the copy, a cheerful hop,
“Buy for $Y,” I bop non-stop.
If liquidity’s low, I pause my dash—
Then MAX with decimals, a tidy stash.
Thump-thump—merge, and smash! 🥕🐇

Pre-merge checks and finishing touches

❌ Failed checks (2 warnings, 1 inconclusive)
Check name Status Explanation Resolution
Description Check ⚠️ Warning The PR description uses the repository template but leaves the "Description" and "How Has This Been Tested?" sections as placeholders ("-") and provides no testing steps, environment details, screenshots, or rationale for the changes. Although the Types of changes area marks this as a bug fix, the lack of a meaningful summary, test evidence, and explanation makes the description insufficient for reviewers to assess risk and correctness. Ask the author to complete the template by adding a concise summary of what changed and why, a list of affected files/areas, detailed testing steps and environment (including any automated tests run), and screenshots if UI was modified; also confirm the appropriate "Types of changes" checkbox(es) and link the PRO-3679 issue. If any public API or types changed (for example PayingToken.address), call that out explicitly and note any migration or consumer-action required.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
Title Check ❓ Inconclusive The title "fixes after QA review on PRO-3679/pulse-preview-screen" references the QA pass and the issue branch but is generic and does not summarize the primary changes in the diff. It is related to the branch/issue but lacks specificity about the main functional changes (e.g., stable-currency balance checks in Buy, PayingToken address/copy UI, and associated test/type updates), so it is not very helpful for someone scanning PR history. Please replace the generic title with a concise, specific summary of the main change and keep the issue reference, for example: "Buy: add stable-currency balance checks and wallet UI fixes (PRO-3679)". If the PR contains multiple unrelated fixes, either split them into separate PRs or make the title highlight the highest-impact change and reference the issue/branch.
✨ Finishing touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch PRO-3679/pulse-preview-screen

Tip

👮 Agentic pre-merge checks are now available in preview!

Pro plan users can now enable pre-merge checks in their settings to enforce checklists before merging PRs.

  • Built-in checks – Quickly apply ready-made checks to enforce title conventions, require pull request descriptions that follow templates, validate linked issues for compliance, and more.
  • Custom agentic checks – Define your own rules using CodeRabbit’s advanced agentic capabilities to enforce organization-specific policies and workflows. For example, you can instruct CodeRabbit’s agent to verify that API documentation is updated whenever API schema files are modified in a PR. Note: Upto 5 custom checks are currently allowed during the preview period. Pricing for this feature will be announced in a few weeks.

Please see the documentation for more information.

Example:

reviews:
  pre_merge_checks:
    custom_checks:
      - name: "Undocumented Breaking Changes"
        mode: "warning"
        instructions: |
          Pass/fail criteria: All breaking changes to public APIs, CLI flags, environment variables, configuration keys, database schemas, or HTTP/GraphQL endpoints must be documented in the "Breaking Change" section of the PR description and in CHANGELOG.md. Exclude purely internal or private changes (e.g., code not exported from package entry points or explicitly marked as internal).

Please share your feedback with us on this Discord post.


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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@cloudflare-workers-and-pages
Copy link

Deploying x with  Cloudflare Pages  Cloudflare Pages

Latest commit: b758ec7
Status: ✅  Deploy successful!
Preview URL: https://84f4a98f.x-e62.pages.dev
Branch Preview URL: https://pro-3679-pulse-preview-scree.x-e62.pages.dev

View logs

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
src/apps/pulse/components/Buy/PreviewBuy.tsx (1)

66-88: Remove unused “isCopied” state/effect.

Copy-to-clipboard for the buy token uses isBuyTokenAddressCopied. isCopied is dead code.

- const [isCopied, setIsCopied] = useState(false);
...
- useEffect(() => {
-   if (isCopied) {
-     const timer = setTimeout(() => {
-       setIsCopied(false);
-     }, 3000);
-     return () => clearTimeout(timer);
-   }
-   return undefined;
- }, [isCopied]);
src/apps/pulse/components/Buy/tests/Buy.test.tsx (1)

334-347: Test never awaits the click path; also button stays disabled due to empty dispensable assets.

  • The inner setTimeout is not awaited; the expect may never run.
  • Default mock returns empty arrays, keeping notEnoughLiquidity=true and the button disabled.

Apply this diff to await the debounce and enable the button:

-      // Wait for debounced effect and intent response
-      setTimeout(async () => {
-        const buyButton = screen.getByRole('button', { name: /Buy/i });
-        fireEvent.click(buyButton);
-
-        expect(mockProps.setPreviewBuy).toHaveBeenCalledWith(true);
-      }, 2000);
+      // Provide dispensable assets for this test
+      const intentUtils = await import('../../../utils/intent');
+      vi.spyOn(intentUtils, 'getDispensableAssets').mockReturnValue([
+        [{ asset: '0x1', chainId: 1, maxValue: '100000000000000000000' }],
+        [1n],
+        [mockPayingToken],
+      ]);
+
+      // Type a valid amount and flush debounce
+      const input = screen.getByPlaceholderText('0.00');
+      fireEvent.change(input, { target: { value: '100.00' } });
+      await vi.advanceTimersByTimeAsync(1100);
+
+      const buyButton = await screen.findByRole('button', { name: /Buy/i });
+      // Wait until intent resolves and button is enabled
+      await screen.findByText(/Buy/i);
+      expect(buyButton).not.toBeDisabled();
+      fireEvent.click(buyButton);
+      expect(mockProps.setPreviewBuy).toHaveBeenCalledWith(true);

Also add wait helpers import at top if missing:

import { fireEvent, render, screen } from '@testing-library/react';
+import { waitFor } from '@testing-library/react';
🧹 Nitpick comments (15)
src/apps/pulse/utils/intent.ts (2)

6-7: Return checksummed token addresses in PayingToken for consistency.

UI now displays/copies PayingToken.address. Use getAddress(...) here so every consumer gets a checksummed address.

-              address: tokenItem.address,
+              address: getAddress(tokenItem.address),

Also applies to: 67-76


45-66: Guard float math and simplify comparisons.

Minor: you can cache const inputUsd = Number(input) || 0; once and reuse for usdEq > inputUsd, avoiding repeated coercions.

src/apps/pulse/components/Sell/Sell.tsx (3)

96-109: Find balance by address+chain across all assets (avoid symbol collisions).

Relying on symbol first can fail if multiple assets share a symbol across chains. Search contracts across all assets by (address, chainId) directly.

-  // Find the asset in the portfolio
-  const assetData = walletPortfolioData.result.data.assets.find(
-    (asset) => asset.asset.symbol === token.symbol
-  );
-  if (!assetData) return 0;
-
-  // Find the contract balance for the specific token address and chain
-  const contractBalance = assetData.contracts_balances.find(
-    (contract) =>
-      contract.address.toLowerCase() === token.address.toLowerCase() &&
-      contract.chainId === `evm:${token.chainId}`
-  );
+  // Find the contract balance for the specific token address and chain
+  const contractBalance = walletPortfolioData.result.data.assets
+    .flatMap((a) => a.contracts_balances)
+    .find(
+      (contract) =>
+        contract.address.toLowerCase() === token.address.toLowerCase() &&
+        contract.chainId === `evm:${token.chainId}`
+    );

330-336: Avoid 10decimals float scaling; floor via string slicing to prevent precision bugs.**

10 ** 18 exceeds integer precision; Math.floor(balance * 1e18) can introduce rounding errors. Floor by truncating the fractional part to decimals digits as a string.

-  const decimals = token?.decimals || 18;
-  const multiplier = 10 ** decimals;
-  const amount =
-    Math.floor(tokenBalance * multiplier) / multiplier;
-  setTokenAmount(amount.toString());
-  setParentTokenAmount(amount.toString());
+  const decimals = token?.decimals ?? 18;
+  const [intPart, fracPart = ''] = tokenBalance.toString().split('.');
+  const trimmed = decimals > 0 && fracPart ? fracPart.slice(0, decimals) : '';
+  const amountStr = trimmed ? `${intPart}.${trimmed}` : intPart;
+  setTokenAmount(amountStr);
+  setParentTokenAmount(amountStr);

1-1: Nit: avoid shadowing global parseInt.

Importing parseInt from lodash can be confused with the global. Consider import { parseInt as lodashParseInt } and use lodashParseInt(item).

src/apps/pulse/components/Buy/PreviewBuy.tsx (1)

430-446: A11y: make the copy control a button with an aria‑label.

Improves keyboard navigation and accessibility without UI changes.

-  <CopyToClipboard ...>
-    <div className="flex items-center ml-1 cursor-pointer">
+  <CopyToClipboard ...>
+    <button
+      type="button"
+      aria-label="Copy buy token address"
+      className="flex items-center ml-1 cursor-pointer bg-transparent"
+    >
       {isBuyTokenAddressCopied ? (
         <MdCheck className="w-[10px] h-3 text-white" />
       ) : (
         <img src={CopyIcon} alt="copy-address-icon" className="w-[10px] h-3" />
       )}
-    </div>
+    </button>
   </CopyToClipboard>
src/apps/pulse/components/Buy/tests/PreviewBuy.test.tsx (1)

124-130: Works, but prefer role‑based query for the copy button.

Querying by aria-label (after adding it) is more robust than alt on the img.

-const copyButtons = screen.getAllByAltText('copy-address-icon');
+const copyButtons = screen.getAllByRole('button', { name: /copy .* address/i });
src/apps/pulse/components/Buy/PayingToken.tsx (1)

55-77: Checksum and a11y for the address/copy control.

  • Show/copy a checksummed address for consistency.
  • Use a button + aria-label for accessibility.
+import { getAddress } from 'viem';
...
+  const safeAddress = (() => {
+    try {
+      return payingToken.address ? getAddress(payingToken.address) : '';
+    } catch {
+      return payingToken.address || '';
+    }
+  })();
...
-  <div className="flex items-center text-[13px] font-normal text-white/50">
-    <span>
-      {payingToken.address
-        ? `${payingToken.address.slice(0, 6)}...${payingToken.address.slice(-4)}`
-        : 'Address not available'}
-    </span>
-    {payingToken.address && (
+  <div className="flex items-center text-[13px] font-normal text-white/50">
+    <span>
+      {safeAddress
+        ? `${safeAddress.slice(0, 6)}...${safeAddress.slice(-4)}`
+        : 'Address not available'}
+    </span>
+    {safeAddress && (
       <CopyToClipboard
-        text={payingToken.address}
+        text={safeAddress}
         onCopy={() => setIsAddressCopied(true)}
       >
-        <div className="flex items-center ml-1 cursor-pointer">
+        <button
+          type="button"
+          aria-label="Copy paying token address"
+          className="flex items-center ml-1 cursor-pointer bg-transparent"
+        >
           {isAddressCopied ? (
             <MdCheck className="w-[10px] h-3 text-white" />
           ) : (
             <img
               src={CopyIcon}
               alt="copy-address-icon"
               className="w-[10px] h-3"
             />
           )}
-        </div>
+        </button>
       </CopyToClipboard>
     )}
src/apps/pulse/components/Buy/tests/Buy.test.tsx (1)

268-294: Assertion targets wrong message after first input; verify both banners are cleared.
The first error shown for 999999 is “Insufficient wallet balance”, not “Not enough liquidity”. After changing to 100.00, assert both are absent to avoid false positives.

Apply this diff:

-      // The liquidity warning should be cleared immediately when user types
-      expect(
-        screen.queryByText('Not enough liquidity')
-      ).not.toBeInTheDocument();
+      // Errors should clear immediately when user types
+      expect(screen.queryByText('Insufficient wallet balance')).not.toBeInTheDocument();
+      expect(screen.queryByText('Not enough liquidity')).not.toBeInTheDocument();
src/apps/pulse/components/Buy/Buy.tsx (5)

80-113: Optimize and harden stable balance computation.
Current logic re-scans arrays and recomputes on every render; also assumes price/balance are numbers. Memoize and guard undefineds.

Apply this diff:

-  // Helper function to calculate stable currency balance
-  const getStableCurrencyBalance = () => {
-    return (
-      walletPortfolioData?.result.data.assets
-        ?.filter((asset) =>
-          asset.contracts_balances.some((contract) =>
-            STABLE_CURRENCIES.some(
-              (stable) =>
-                stable.address.toLowerCase() ===
-                  contract.address.toLowerCase() &&
-                stable.chainId === Number(contract.chainId.split(':').at(-1))
-            )
-          )
-        )
-        .reduce((total, asset) => {
-          const stableContracts = asset.contracts_balances.filter((contract) =>
-            STABLE_CURRENCIES.some(
-              (stable) =>
-                stable.address.toLowerCase() ===
-                  contract.address.toLowerCase() &&
-                stable.chainId === Number(contract.chainId.split(':').at(-1))
-            )
-          );
-          return (
-            total +
-            stableContracts.reduce(
-              (sum, contract) => sum + asset.price * contract.balance,
-              0
-            )
-          );
-        }, 0) || 0
-    );
-  };
+  // Helper: memoized stable currency USD balance
+  const stableCurrencyBalance = (() => {
+    const assets = walletPortfolioData?.result.data.assets ?? [];
+    if (!assets.length) return 0;
+    const stableKeys = new Set(
+      STABLE_CURRENCIES.map(
+        (s) => `${s.chainId}:${s.address.toLowerCase()}`
+      )
+    );
+    let total = 0;
+    for (const asset of assets) {
+      const price = Number(asset.price) || 0;
+      for (const c of asset.contracts_balances ?? []) {
+        const chainNum = Number(String(c.chainId ?? '').split(':').at(-1));
+        const key = `${chainNum}:${String(c.address || '').toLowerCase()}`;
+        if (stableKeys.has(key)) {
+          total += price * (Number(c.balance) || 0);
+        }
+      }
+    }
+    return total;
+  })();

Note: If you prefer, extract to useMemo with assets as a dependency.


198-207: Use memoized stableCurrencyBalance instead of recomputing.
Minor tidy-up and avoids drift in future refactors.

Apply this diff:

-    const inputAmount = parseFloat(debouncedUsdAmount);
-    const stableCurrencyBalance = getStableCurrencyBalance();
+    const inputAmount = parseFloat(debouncedUsdAmount);

And reuse stableCurrencyBalance from above comparison:

-    if (inputAmount > stableCurrencyBalance) {
+    if (inputAmount > stableCurrencyBalance) {

(No functional change; remove the local declaration.)


217-220: Early return on notEnoughLiquidity can lock out recovery.
You already reset notEnoughLiquidity in the debounce effect, but guarding here by state may short‑circuit retries if the closure captured true. Prefer relying on current dispensableAssets/permittedChains checks instead.

Apply this diff:

-    if (notEnoughLiquidity) {
-      return;
-    }

271-275: On token change, clear amount and errors to prevent stale state (mirrors Sell behavior).
Matches the team’s pattern from Sell to avoid stale validations when switching tokens.

Add a small effect:

useEffect(() => {
  if (!token) return;
  setUsdAmount('');
  setDebouncedUsdAmount('');
  setNoEnoughLiquidity(false);
  setInsufficientWalletBalance(false);
  setExpressIntentResponse(null);
}, [token]);

449-466: Expose a data-testid for the error banner to stabilize tests.
Text assertions are brittle; provide a stable hook.

Apply this diff:

-              return (
-                <>
+              return (
+                <>
                   <div className="flex items-center justify-center">
                     <img src={WarningIcon} alt="warning" />
                   </div>
 
                   <div
+                    data-testid="pulse-buy-error-banner"
                     style={{
                       textDecoration: 'underline',
                       color: '#FF366C',
                       fontSize: 12,
                       marginLeft: 5,
                     }}
                   >
                     {message}
                   </div>
                 </>
               );
src/apps/pulse/components/Buy/BuyButton.tsx (1)

121-143: Avoid recomputing isDisabled multiple times.
Hoist to a const to prevent double evaluation and keep styles/label consistent.

Apply this diff:

-  return (
-    <button
-      className="flex-1 items-center justify-center"
-      onClick={handleBuySubmit}
-      disabled={isDisabled()}
-      style={{
-        backgroundColor: isDisabled() ? '#29292F' : '#8A77FF',
-        color: isDisabled() ? 'grey' : '#FFFFFF',
-        borderRadius: 8,
-      }}
-      type="button"
-    >
-      {getButtonText(
+  const disabled = isDisabled();
+  return (
+    <button
+      className="flex-1 items-center justify-center"
+      onClick={handleBuySubmit}
+      disabled={disabled}
+      style={{
+        backgroundColor: disabled ? '#29292F' : '#8A77FF',
+        color: disabled ? 'grey' : '#FFFFFF',
+        borderRadius: 8,
+      }}
+      type="button"
+    >
+      {getButtonText(
         isLoading,
         isInstalling,
         isFetching,
         areModulesInstalled,
         token,
         debouncedUsdAmount,
-        payingTokens.length > 0 ? payingTokens[0] : undefined,
-        isDisabled()
+        payingTokens.length > 0 ? payingTokens[0] : undefined,
+        disabled
       )}
     </button>
   );
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3b2b2f4 and b758ec7.

⛔ Files ignored due to path filters (5)
  • src/apps/pulse/components/App/tests/__snapshots__/AppWrapper.test.tsx.snap is excluded by !**/*.snap
  • src/apps/pulse/components/App/tests/__snapshots__/HomeScreen.test.tsx.snap is excluded by !**/*.snap
  • src/apps/pulse/components/Buy/tests/__snapshots__/Buy.test.tsx.snap is excluded by !**/*.snap
  • src/apps/pulse/components/Buy/tests/__snapshots__/BuyButton.test.tsx.snap is excluded by !**/*.snap
  • src/apps/pulse/components/Buy/tests/__snapshots__/PreviewBuy.test.tsx.snap is excluded by !**/*.snap
📒 Files selected for processing (11)
  • src/apps/pulse/components/Buy/Buy.tsx (10 hunks)
  • src/apps/pulse/components/Buy/BuyButton.tsx (2 hunks)
  • src/apps/pulse/components/Buy/PayingToken.tsx (2 hunks)
  • src/apps/pulse/components/Buy/PreviewBuy.tsx (1 hunks)
  • src/apps/pulse/components/Buy/tests/Buy.test.tsx (5 hunks)
  • src/apps/pulse/components/Buy/tests/BuyButton.test.tsx (2 hunks)
  • src/apps/pulse/components/Buy/tests/PreviewBuy.test.tsx (4 hunks)
  • src/apps/pulse/components/Sell/Sell.tsx (3 hunks)
  • src/apps/pulse/components/Sell/tests/Sell.test.tsx (1 hunks)
  • src/apps/pulse/types/tokens.ts (1 hunks)
  • src/apps/pulse/utils/intent.ts (2 hunks)
🧰 Additional context used
🧠 Learnings (4)
📓 Common learnings
Learnt from: RanaBug
PR: pillarwallet/x#391
File: src/apps/pulse/components/Sell/Sell.tsx:113-130
Timestamp: 2025-09-09T12:40:15.629Z
Learning: In the Pulse app Sell component, when a user changes/switches tokens, the input amount automatically resets to 0, which means liquidity validation state doesn't become stale when tokens change.
📚 Learning: 2025-09-09T12:40:15.629Z
Learnt from: RanaBug
PR: pillarwallet/x#391
File: src/apps/pulse/components/Sell/Sell.tsx:113-130
Timestamp: 2025-09-09T12:40:15.629Z
Learning: In the Pulse app Sell component, when a user changes/switches tokens, the input amount automatically resets to 0, which means liquidity validation state doesn't become stale when tokens change.

Applied to files:

  • src/apps/pulse/components/Buy/PreviewBuy.tsx
  • src/apps/pulse/components/Sell/tests/Sell.test.tsx
  • src/apps/pulse/components/Buy/Buy.tsx
  • src/apps/pulse/components/Sell/Sell.tsx
📚 Learning: 2025-03-28T09:22:22.712Z
Learnt from: RanaBug
PR: pillarwallet/x#275
File: src/apps/the-exchange/components/DropdownTokensList/DropdownTokenList.tsx:180-195
Timestamp: 2025-03-28T09:22:22.712Z
Learning: In the Exchange app, `swapTokenList` and `receiveTokenList` are derived from `searchTokenResult` when search is active, so including `searchToken` in the useEffect dependency array that uses these lists would be redundant as the lists will update when search results change.

Applied to files:

  • src/apps/pulse/components/Buy/Buy.tsx
📚 Learning: 2025-08-12T07:42:24.656Z
Learnt from: IAmKio
PR: pillarwallet/x#351
File: src/apps/pulse/utils/intent.ts:44-53
Timestamp: 2025-08-12T07:42:24.656Z
Learning: In the Pulse app's intent utilities (src/apps/pulse/utils/intent.ts), the team has chosen to use floating-point arithmetic for token amount calculations despite potential precision issues, accepting JavaScript's decimal place limitations as a valid trade-off for their use case.

Applied to files:

  • src/apps/pulse/utils/intent.ts
  • src/apps/pulse/components/Sell/Sell.tsx
  • src/apps/pulse/components/Buy/BuyButton.tsx
🧬 Code graph analysis (4)
src/apps/pulse/components/Buy/PayingToken.tsx (1)
src/apps/pulse/types/tokens.ts (1)
  • PayingToken (12-21)
src/apps/pulse/components/Buy/Buy.tsx (1)
src/apps/pulse/constants/tokens.ts (1)
  • STABLE_CURRENCIES (13-15)
src/apps/pulse/components/Buy/BuyButton.tsx (2)
src/apps/pulse/types/tokens.ts (2)
  • SelectedToken (1-10)
  • PayingToken (12-21)
src/utils/number.tsx (1)
  • limitDigitsNumber (42-69)
src/apps/pulse/components/Buy/tests/Buy.test.tsx (1)
src/apps/pulse/hooks/useModularSdk.ts (1)
  • useModularSdk (17-129)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: unit-tests
  • GitHub Check: lint
  • GitHub Check: build
🔇 Additional comments (16)
src/apps/pulse/components/Sell/Sell.tsx (2)

83-86: Correct: stop fetching when liquidity is insufficient.

Short-circuit + explicit reset of local offer prevents stale quotes. Looks good.


277-279: Error message precedence reads well.

relayError takes priority, else show liquidity warning. Good UX.

src/apps/pulse/components/Sell/tests/Sell.test.tsx (1)

171-172: Test update matches new MAX formatting.

Expectation now aligns with precision logic. Good.

src/apps/pulse/components/Buy/PreviewBuy.tsx (1)

365-371: Disable Refresh when no dispensable assets.

Prevents a no-op call and clarifies UI state.
[suggest_minor_issue]

- disabled={
-   !buyToken ||
-   !totalPay ||
-   isRefreshingPreview ||
-   isWaitingForSignature
- }
+ disabled={
+   !buyToken ||
+   !totalPay ||
+   dispensableAssets.length === 0 ||
+   isRefreshingPreview ||
+   isWaitingForSignature
+ }
src/apps/pulse/components/Buy/tests/BuyButton.test.tsx (1)

69-74: Test refactor to fragment assertions is correct.

Matches new button composition.

src/apps/pulse/components/Buy/tests/PreviewBuy.test.tsx (1)

109-110: Keep copy-icon assertions; count remains two.

Still valid with buy header + paying token copy controls.

src/apps/pulse/components/Buy/PayingToken.tsx (1)

20-33: Copy feedback lifecycle is sound.

Timeout reset after 3s is appropriate and isolated per item.

src/apps/pulse/components/Buy/tests/Buy.test.tsx (2)

60-61: Mock PayingToken now includes address — good alignment with types.
Matches the PayingToken shape update; no issues.


299-300: Updated zero-balance display to $0.00 — consistent with UI.
Expectation matches new formatting; good.

src/apps/pulse/components/Buy/Buy.tsx (5)

71-73: New insufficientWalletBalance state — good separation from liquidity.
Clear distinction between balance vs. routing/liquidity; reads well with the UI messages.


119-121: Reset both error flags on input change — good.
Ensures fresh validation on every keystroke.


496-496: Balance display now reflects stable-currency sum — good UX improvement.
Shows spendable USD rather than total portfolio.


521-522: MAX uses stable-currency balance — correct behavior.
Prevents attempting to spend non-stable assets.


558-559: Disabling Buy on either liquidity or balance errors — good guardrail.
Correctly blocks invalid submissions.

src/apps/pulse/components/Buy/BuyButton.tsx (2)

28-35: Spinner on loading/install/fetch — solid UX.
Prevents flicker and shows progress consistently.


41-69: Inline “Buy X SYMBOL for $Y” summary is a nice upgrade.
Formatting via HighDecimalsFormatted and digit limiting reads well.

Comment on lines +20 to 21
address: string;
};
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

🧩 Analysis chain

PayingToken now requires address — good addition; confirm all producers updated.

This tightens the public contract. Ensure all constructors/mocks across the codebase set address to avoid TS compile breaks at call sites.

Run a quick scan to spot any remaining PayingToken literals missing address:


🏁 Script executed:

#!/bin/bash
rg -n --type=ts -C2 '\bPayingToken\b' | sed -n '1,200p'

Length of output: 9168


PayingToken now requires address — update all literals/mocks.

Several test mocks still omit the required address field (this will break TypeScript). Add an address property to all PayingToken literals.

Files to update:

  • src/apps/pulse/components/Buy/tests/BuyButton.test.tsx (mockPayingToken)
  • src/apps/pulse/components/Buy/tests/PreviewBuy.test.tsx (mockPayingToken)
  • src/apps/pulse/components/Buy/tests/Buy.test.tsx (mockPayingToken)

Also scan the repo for other PayingToken object literals/constructors and add address where missing.

🤖 Prompt for AI Agents
In src/apps/pulse/types/tokens.ts around lines 20 to 21, the PayingToken type
now requires an address: string field; update all PayingToken literals/mocks to
include a valid address string. Specifically, add an address property to
mockPayingToken in src/apps/pulse/components/Buy/tests/BuyButton.test.tsx,
PreviewBuy.test.tsx, and Buy.test.tsx, and scan the repo for any other
PayingToken object literals or constructors to add a suitable address value (can
be a test ENS or hex like "0x000...") so TypeScript no longer errors on missing
address.

Copy link
Collaborator

@IAmKio IAmKio left a comment

Choose a reason for hiding this comment

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

LGTM

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.

2 participants