Skip to content

invoice request link when visitor has no wallet (fixes #63)#87

Merged
kumawatkaran523 merged 3 commits intoStabilityNexus:mainfrom
Piyushbijarania:issue-63
Jan 28, 2026
Merged

invoice request link when visitor has no wallet (fixes #63)#87
kumawatkaran523 merged 3 commits intoStabilityNexus:mainfrom
Piyushbijarania:issue-63

Conversation

@Piyushbijarania
Copy link
Copy Markdown
Contributor

@Piyushbijarania Piyushbijarania commented Jan 28, 2026

When a user opens a “Generate Invoice Request” link without a connected wallet , the Create Invoice page now uses the chain from the URL for the token list and for token verification via public RPC, so the form loads and verifies the token correctly.

Summary by CodeRabbit

  • New Features

    • Pre-fill invoice fields (amount, description) from URL; fills first line item if empty.
    • Allow specifying network via URL to drive token list and token-picker behavior.
    • Token verification now prefers public RPC endpoints when available, with automatic fallback to the connected wallet.
  • Bug Fixes

    • Token list, picker and verification consistently follow the selected network context and keep computed item amounts synchronized.

✏️ Tip: You can customize this high-level summary in your review settings.

…Nexus#63)

We now use the chain from the URL for the token list and for verification (via public RPC), so the create-invoice form works in incognito or without a wallet. Amount and description from the link are pre-filled when the first line is empty.
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Jan 28, 2026

📝 Walkthrough

Walkthrough

Adds a dual-path token verification flow: if a public RPC exists for a target chainId use a JsonRpcProvider; otherwise fall back to the wallet BrowserProvider. Introduces chainIdForTokens from URL/account, uses it for token lists/verification, and prefills the first line item from URL params.

Changes

Cohort / File(s) Summary
CreateInvoice: verification, RPC routing & token context
frontend/src/page/CreateInvoice.jsx
Added CHAIN_ID_TO_PUBLIC_RPC and imported JsonRpcProvider; changed verifyToken(address, chainIdForRpc) to prefer a public RPC provider when available, falling back to BrowserProvider (wallet); introduced chainIdForTokens (URL chain or account chainId) and switched token-list fetching/verification and TokenPicker props to use it; prefill invoice first line item from URL amount/description; updated related effect dependencies and callsites.

Sequence Diagram

sequenceDiagram
    participant UI as CreateInvoice UI
    participant Comp as CreateInvoice Component
    participant Selector as RPC Selector
    participant Public as JsonRpcProvider
    participant Wallet as BrowserProvider
    participant Token as ERC20 Contract

    UI->>Comp: request verifyToken(address, chainIdForRpc)
    Comp->>Selector: lookup CHAIN_ID_TO_PUBLIC_RPC(chainIdForRpc)
    alt public RPC found
        Selector->>Public: instantiate JsonRpcProvider(rpcUrl)
        Public->>Token: call name/symbol/decimals
        Token-->>Public: token metadata
        Public-->>Comp: metadata
    else no public RPC
        Selector->>Wallet: use BrowserProvider(wallet)
        Wallet->>Token: call name/symbol/decimals
        Token-->>Wallet: token metadata
        Wallet-->>Comp: metadata
    end
    Comp->>Comp: validate & update token state
    Comp-->>UI: render token details / errors
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested reviewers

  • adityabhattad2021

Poem

🐰 Hopping through chains with a curious hop,
Public RPCs fetch tokens without a stop,
If wallets are quiet, I gently fallback,
URL crumbs fill invoices—no need to backtrack,
Tiny paws tap keys, and the ledger goes hop-hop.

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: enabling invoice request links to work when visitors lack a connected wallet by using the chain URL parameter.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

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.

Copy link
Copy Markdown

@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: 2

Caution

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

⚠️ Outside diff range comments (1)
frontend/src/page/CreateInvoice.jsx (1)

894-902: Missing chainIdForRpc parameter breaks custom token verification without wallet.

When users manually enter a custom token address, verifyToken(address) is called without the chain ID parameter. This means visitors without a connected wallet cannot verify manually-entered tokens, as the function will fall through to the error state.

🐛 Proposed fix
 onChange={(e) => {
   const address = e.target.value;
   setCustomTokenAddress(address);
   if (!address || !ethers.isAddress(address)) {
     setTokenVerificationState("idle");
     setVerifiedToken(null);
   } else if (ethers.isAddress(address)) {
-    verifyToken(address);
+    verifyToken(address, chainIdForTokens);
   }
 }}
🤖 Fix all issues with AI agents
In `@frontend/src/page/CreateInvoice.jsx`:
- Around line 119-138: The issue is that pre-filled item values are not shown
because the Input components are uncontrolled—add controlled value props bound
to itemData so inputs reflect state; update all item inputs (description, qty,
unitPrice, discount, tax) in both mobile and desktop layouts to set value from
itemData[index].<field> (e.g., value derived from itemData[index].description,
.qty, .unitPrice, .discount, .tax) and keep existing onChange handlers
(handleItemData) and the setItemData logic intact so the pre-filled state is
visible and editable.
- Around line 289-296: The current Promise.all with .catch fallbacks can mark
non-ERC20 addresses as verified; change the logic in the token verification
block so you first attempt to call contract.symbol() (and await it without
swallowing errors) and only if symbol resolves to a non-empty string proceed to
fetch name() and decimals() and call setVerifiedToken({ address, symbol, name,
decimals }) and setTokenVerificationState("success"); if symbol throws or
returns an empty/whitespace string, setTokenVerificationState("error" or
"invalid") and do not call setVerifiedToken. Use the existing contract.symbol(),
contract.name(), contract.decimals(), setVerifiedToken and
setTokenVerificationState identifiers to locate and update the code.
🧹 Nitpick comments (1)
frontend/src/page/CreateInvoice.jsx (1)

53-61: Public RPC endpoints may have availability/rate-limit constraints.

The hardcoded RPCs are reasonable for read-only verification, but consider:

  • These endpoints may have rate limits or downtime
  • Missing coverage for some popular chains (Arbitrum, Optimism, Avalanche)

For improved resilience, consider adding fallback RPCs or using a public RPC aggregator service in the future.

Comment thread frontend/src/page/CreateInvoice.jsx
Comment thread frontend/src/page/CreateInvoice.jsx Outdated
Copy link
Copy Markdown

@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: 1

Caution

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

⚠️ Outside diff range comments (1)
frontend/src/page/CreateInvoice.jsx (1)

901-913: Pass chainIdForTokens to custom-token verification.

Manual custom-token entry currently calls verifyToken(address) without the chainId, which forces a wallet-based path and breaks the no-wallet flow. This prevents verification in incognito/no-wallet scenarios.

✅ Proposed fix
} else if (ethers.isAddress(address)) {
-  verifyToken(address);
+  verifyToken(address, chainIdForTokens);
}
🤖 Fix all issues with AI agents
In `@frontend/src/page/CreateInvoice.jsx`:
- Around line 112-161: In verifyToken, clear any previously verified token
immediately when beginning a new check and also on failure: call
setVerifiedToken(null) right after setTokenVerificationState("verifying") to
avoid stale data, and ensure setVerifiedToken(null) is also invoked in the error
paths (both the catch block and the branches that
setTokenVerificationState("error")) before returning; reference the verifyToken
function and the state setters setTokenVerificationState and setVerifiedToken
when applying this change.
🧹 Nitpick comments (1)
frontend/src/page/CreateInvoice.jsx (1)

53-61: Consider centralizing public RPC endpoints.

Embedding RPC URLs in this component makes updates harder and requires a frontend deploy for endpoint changes. Consider moving CHAIN_ID_TO_PUBLIC_RPC to a shared config/module (or env-backed config) to improve maintainability.

Comment thread frontend/src/page/CreateInvoice.jsx
Copy link
Copy Markdown

@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: 0

Caution

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

⚠️ Outside diff range comments (1)
frontend/src/page/CreateInvoice.jsx (1)

892-904: Missing chainIdForTokens argument in manual token verification.

When a user manually enters a custom token address, verifyToken(address) is called without the chainIdForTokens parameter. This means public RPC won't be used, and verification will fail for users without a connected wallet. Other call sites (lines 186, 223, 229) correctly pass chainIdForTokens.

🐛 Proposed fix
                         } else if (ethers.isAddress(address)) {
-                          verifyToken(address);
+                          verifyToken(address, chainIdForTokens);
                         }
🧹 Nitpick comments (3)
frontend/src/page/CreateInvoice.jsx (3)

53-61: Consider resilience for public RPC endpoints.

Hardcoded public RPC URLs may become unavailable or rate-limited. Consider adding fallback endpoints or graceful degradation when the primary RPC fails.


197-207: Consider using public RPC for decimals fetch.

This code path uses BrowserProvider directly to fetch missing decimals, which won't work for wallet-less visitors. While there's a fallback to verifyToken (which uses public RPC), using public RPC here would be more consistent with the PR's goal.

♻️ Suggested improvement
             if (decimals === undefined || decimals === null) {
               try {
-                if (typeof window !== "undefined" && window.ethereum) {
-                  const provider = new BrowserProvider(window.ethereum);
-                  const contract = new ethers.Contract(urlTokenAddress, ERC20_ABI, provider);
-                  decimals = await contract.decimals();
-                }
+                const rpcUrl = CHAIN_ID_TO_PUBLIC_RPC[chainIdForTokens];
+                let provider;
+                if (rpcUrl) {
+                  provider = new JsonRpcProvider(rpcUrl);
+                } else if (typeof window !== "undefined" && window.ethereum) {
+                  provider = new BrowserProvider(window.ethereum);
+                }
+                if (provider) {
+                  const contract = new ethers.Contract(urlTokenAddress, ERC20_ABI, provider);
+                  decimals = await contract.decimals();
+                }
               } catch (err) {
                 console.warn("Failed to fetch decimals for preselected token:", err);
               }
             }

1122-1127: Consider using pre-computed amount from state.

The disabled amount field recalculates the value inline using parseFloat, which may produce different results than the handleItemData calculation (which uses parseUnits for precision). For consistency, use the pre-computed itemData[index].amount.

♻️ Suggested change
                       <Input
                         type="text"
                         placeholder="0.00"
                         className="w-full bg-gray-100 border-gray-300 text-gray-700 font-semibold"
                         name="amount"
                         disabled
-                        value={String(
-                          (parseFloat(itemData[index]?.qty) || 0) *
-                            (parseFloat(itemData[index]?.unitPrice) || 0) -
-                            (parseFloat(itemData[index]?.discount) || 0) +
-                            (parseFloat(itemData[index]?.tax) || 0)
-                        )}
+                        value={itemData[index]?.amount ?? "0"}
                       />

Apply the same change to the desktop layout amount field (lines 1219-1224).

@kumawatkaran523 kumawatkaran523 merged commit 6964784 into StabilityNexus:main Jan 28, 2026
1 check passed
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