Skip to content

Update GitHub Actions workflow for Vite React deployment from subfolder#12

Closed
kumawatkaran523 wants to merge 47 commits intoStabilityNexus:mainfrom
kumawatkaran523:test-workflow
Closed

Update GitHub Actions workflow for Vite React deployment from subfolder#12
kumawatkaran523 wants to merge 47 commits intoStabilityNexus:mainfrom
kumawatkaran523:test-workflow

Conversation

@kumawatkaran523
Copy link
Copy Markdown
Contributor

@kumawatkaran523 kumawatkaran523 commented Sep 20, 2025

Summary by CodeRabbit

  • New Features

    • Batch invoice creation: create multiple invoices at once from a new “Batch Create” page.
    • Batch payments: select and pay multiple invoices together with smart batch suggestions.
    • Added “Batch Create” to the dashboard menu.
  • Improvements

    • Safer, clearer payment flows with better balance/allowance checks, error messages, and toasts.
    • Enhanced invoice details drawer with print/download.
    • Token carousel now uses a dynamic token list with improved logo fallbacks.
  • Chores

    • Migrated deployment workflow to Vite React for GitHub Pages and updated frontend paths/artifacts.

@kumawatkaran523 kumawatkaran523 changed the title Configure next.yml according to vite-react Update GitHub Actions workflow for Vite React deployment from subfolder Sep 20, 2025
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Sep 20, 2025

Walkthrough

Replaces GitHub Pages workflow for a Vite React frontend in ./frontend. Extends Chainvoice.sol with batch invoice creation and payment, new errors/events, and fee/treasury management. Frontend adds routes and pages for batch creation and batch payment, enhances ReceivedInvoice with batch flows, and updates TokenCarousel to use a dynamic token list.

Changes

Cohort / File(s) Summary
Deployment workflow
\.github/workflows/deploy.yml
Switch from Next.js to Vite-based GitHub Pages deployment; set working-directory to ./frontend; update caches, build, and artifact paths.
Smart contract: batch invoicing
contracts/src/Chainvoice.sol
Add batch errors/events, MAX_BATCH, batch create/pay functions, nonReentrant guards, CEI updates, fee/treasury setters and withdrawals, ERC20/native handling refinements.
Frontend routing & navigation
frontend/src/App.jsx, frontend/src/page/Home.jsx
Add routes/imports for batch pages; insert “Batch Create” menu item and minor style tweaks.
Token handling component
frontend/src/components/TokenCrousel.jsx
Replace static presets with useTokenList('1'); enhance token image fallback; minor carousel sourcing change.
Batch invoicing UI (new pages)
frontend/src/page/CreateInvoicesBatch.jsx, frontend/src/page/BatchPayment.jsx
New pages implementing batch invoice creation (encryption, token verify, submission) and batch payment (grouping, approvals, multi-token/native settlement, UI).
Received invoices: batch features
frontend/src/page/ReceivedInvoice.jsx
Add batch selection/suggestions, grouped payments with allowance/balance checks, centralized error handling, UI indicators, and state updates.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant U as User
  participant FE as Frontend (CreateInvoicesBatch)
  participant Lit as Lit Protocol
  participant C as Chainvoice Contract

  U->>FE: Enter invoices, select token, dates
  FE->>Lit: Encrypt per-invoice payloads (ACL)
  Lit-->>FE: Encrypted payloads + hashes
  FE->>C: createInvoicesBatch(tos, amounts, token, payloads, hashes)
  C-->>FE: emit InvoiceBatchCreated(ids)
  FE-->>U: Navigate to sent / show success
Loading
sequenceDiagram
  autonumber
  participant U as User
  participant FE as Frontend (BatchPayment/Received)
  participant ERC20 as ERC20 Token
  participant C as Chainvoice Contract

  U->>FE: Select invoices (same token)
  FE->>FE: Validate batch size, totals, fees
  alt ERC20 token
    FE->>ERC20: Check allowance
    alt Insufficient
      FE->>ERC20: approve(Chainvoice, total)
      ERC20-->>FE: Approval tx mined
    end
    FE->>C: payInvoicesBatch(invoiceIds)
  else Native
    FE->>C: payInvoicesBatch(invoiceIds) with value
  end
  C-->>FE: emit InvoiceBatchPaid + InvoicePaid[]
  FE-->>U: Update UI statuses, toasts
Loading

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~120+ minutes

Possibly related PRs

Suggested reviewers

  • adityabhattad2021

Poem

I thump my paw—batch bills align,
Encrypt, emit, in tidy line.
Tokens spin in carousel light,
Approvals squeak, then swift take flight.
Fees hop home to treasury burrow—
Invoices paid by dawn’s first furrow.
🐇✨

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The title accurately and concisely describes the primary change: updating the GitHub Actions workflow to deploy a Vite React app from a subfolder. The deploy.yml changes in the diff switch from a Next.js Pages workflow to a Vite build, set working-directory to ./frontend, update artifact and cache paths, and remove Next.js-specific settings, which matches the title. This phrasing is specific enough for a teammate to understand the main intent of the changeset.
Docstring Coverage ✅ Passed No functions found in the changes. Docstring coverage check skipped.
✨ Finishing touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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: 5

Caution

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

⚠️ Outside diff range comments (1)
frontend/src/components/TokenCrousel.jsx (1)

51-55: Use stable, unique key: token.contract_address (not token.address).

Hook useTokenList returns contract_address. Using token.address risks undefined keys and re-mounting.

-              key={`${token.address}-${index}`}
+              key={`${token.contract_address}-${index}`}
🧹 Nitpick comments (21)
frontend/src/components/TokenCrousel.jsx (2)

71-76: Zero-address check uses the wrong field.

Compare against token.contract_address (lowercased) to avoid false negatives.

-                  {token.address ===
-                    "0x0000000000000000000000000000000000000000" && (
+                  {token.contract_address?.toLowerCase() ===
+                    "0x0000000000000000000000000000000000000000" && (

19-26: Guard animation when content width is 0 to prevent tight RAF loops.

When tokens is empty, position wraps every frame. Add early return.

   useEffect(() => {
-    const carousel = carouselRef.current;
+    const carousel = carouselRef.current;
+    if (!carousel) return;
+    if (!tokens?.length) return;
@@
-  }, []);
+  }, [tokens?.length]);

Also applies to: 45-45

frontend/src/page/Home.jsx (1)

15-15: Remove unused imports (CreditCard, Layers3, PlusCircle) if not used.

Keeps bundle lean and avoids linter noise.

frontend/src/App.jsx (1)

36-37: Unused import: BatchPayment.

Either wire the route or remove the import.

-import BatchPayment from "./page/BatchPayment"; // New import needed

Optionally add a route later:

+<Route path="batch-payment" element={<BatchPayment />} />
.github/workflows/deploy.yml (3)

57-57: Cache dependency path should cover both npm and yarn.

Current setting always points to package-lock.json, so yarn installs won’t benefit.

-          cache-dependency-path: frontend/package-lock.json
+          cache-dependency-path: |
+            frontend/package-lock.json
+            frontend/yarn.lock

37-46: Consider pnpm detection and aligning setup-node cache with detected manager.

Broaden detection and ensure consistency across steps.

           if [ -f "${{ github.workspace }}/frontend/yarn.lock" ]; then
             echo "manager=yarn" >> $GITHUB_OUTPUT
             echo "command=install" >> $GITHUB_OUTPUT
             echo "runner=yarn" >> $GITHUB_OUTPUT
             exit 0
+          elif [ -f "${{ github.workspace }}/frontend/pnpm-lock.yaml" ]; then
+            echo "manager=pnpm" >> $GITHUB_OUTPUT
+            echo "command=install" >> $GITHUB_OUTPUT
+            echo "runner=pnpm" >> $GITHUB_OUTPUT
+            exit 0
           elif [ -f "${{ github.workspace }}/frontend/package.json" ]; then

Also update cache key patterns to include config/assets for better cache busting:

-          key: ${{ runner.os }}-vite-${{ hashFiles('frontend/package-lock.json', 'frontend/yarn.lock') }}-${{ hashFiles('frontend/**.[jt]s', 'frontend/**.[jt]sx') }}
+          key: ${{ runner.os }}-vite-${{ hashFiles('frontend/package-lock.json', 'frontend/yarn.lock', 'frontend/pnpm-lock.yaml') }}-${{ hashFiles('frontend/**.[jt]s', 'frontend/**.[jt]sx', 'frontend/**.css', 'frontend/**.html', 'frontend/vite.config.*') }}

66-73: Caching dist is optional and may be unnecessary.

Since you always build before upload, caching frontend/dist rarely helps and can waste cache space.

-            frontend/dist
-            frontend/node_modules/.vite
+            frontend/node_modules/.vite
frontend/src/page/CreateInvoicesBatch.jsx (2)

268-274: Use imported Contract directly (avoid ethers.Contract) and handle bad addresses.

Also validate token address before constructing the contract.

-        const contract = new ethers.Contract(address, ERC20_ABI, provider);
+        if (!ethers.isAddress(address)) throw new Error("Invalid token address");
+        const contract = new Contract(address, ERC20_ABI, provider);

39-41: Toast library mismatch with the rest of the app (react-hot-toast vs react-toastify).

App.jsx uses react-hot-toast Toaster; this file uses react-toastify. Unify to one library.

-import { toast } from "react-toastify";
-import "react-toastify/dist/ReactToastify.css";
+import { toast } from "react-hot-toast";
frontend/src/page/BatchPayment.jsx (6)

816-820: Null-guard address formatting to avoid runtime crashes

formatAddress assumes a non-empty string. If invoice.user?.address is undefined/null, this will throw during render.

Apply:

-const formatAddress = (address) => {
-  return `${address.substring(0, 10)}...${address.substring(
-    address.length - 10
-  )}`;
-};
+const formatAddress = (addr) => {
+  if (!addr || typeof addr !== "string" || addr.length < 12) return addr || "";
+  return `${addr.slice(0, 10)}...${addr.slice(-10)}`;
+};

800-814: Harden network switching and use consistent UX (toast vs alert)

Guard for missing window.ethereum and prefer toast over alert for consistency with the rest of the UI.

 const switchNetwork = async () => {
   try {
     setNetworkLoading(true);
-    await window.ethereum.request({
+    if (!window?.ethereum) {
+      toast.error("No injected wallet found. Please switch to Sepolia manually.");
+      return;
+    }
+    await window.ethereum.request({
       method: "wallet_switchEthereumChain",
       params: [{ chainId: "0xaa36a7" }], // Sepolia chain ID
     });
     setError(null);
+    toast.success("Successfully switched to Sepolia network!");
   } catch (error) {
     console.error("Network switch failed:", error);
-    alert("Failed to switch network. Please switch to Sepolia manually.");
+    toast.error("Failed to switch network. Please switch to Sepolia manually in your wallet.");
   } finally {
     setNetworkLoading(false);
   }
 };

728-731: Replace blocking alerts with non-blocking toasts

Keep feedback patterns consistent and non-intrusive.

- await approveTx.wait();
- alert(`Approval for ${tokenSymbol} completed! Now processing payment...`);
+ await approveTx.wait();
+ toast.success(`Approval for ${tokenSymbol} completed! Now processing payment...`);
 ...
- await tx.wait();
- alert(`Payment successful in ${tokenSymbol}!`);
+ await tx.wait();
+ toast.success(`Payment successful! Paid with ${tokenSymbol}`);
 ...
- await tx.wait();
- alert("Payment successful in ETH!");
+ await tx.wait();
+ toast.success("Payment successful! Paid with ETH");

Also applies to: 737-749


169-217: Balance pre-checks may use stale fee; pass on-chain fee explicitly

checkPaymentCapability multiplies by component state fee, which may be 0 or stale if the fetch hasn’t completed. Fetch fee from the contract once and pass it in.

-const checkPaymentCapability = async (group, signer) => {
+const checkPaymentCapability = async (group, signer, feePerInvoice) => {
   const { tokenAddress, symbol, invoices, totalAmount } = group;
   const userAddress = await signer.getAddress();

   if (tokenAddress === ethers.ZeroAddress) {
     // Check ETH balance
     const balance = await signer.provider.getBalance(userAddress);
-    const totalFee = BigInt(fee) * BigInt(invoices.length);
+    const totalFee = BigInt(feePerInvoice) * BigInt(invoices.length);
     const totalRequired =
       ethers.parseUnits(totalAmount.toString(), 18) + totalFee;
     ...
   } else {
     // Check ERC20 balance
     ...
     // Check ETH balance for fees
     const ethBalance = await signer.provider.getBalance(userAddress);
-    const totalFee = BigInt(fee) * BigInt(invoices.length);
+    const totalFee = BigInt(feePerInvoice) * BigInt(invoices.length);
     if (ethBalance < totalFee) {
       ...
     }
   }
};

And in handleBatchPayment before the pre-check loop:

-  const grouped = getGroupedInvoices();
+  const grouped = getGroupedInvoices();
+  const feePerInvoice = await contract.fee();
   // PRE-CHECK ALL BALANCES BEFORE ANY TRANSACTIONS
   toast.info("Checking balances...");
   const errors = [];
   for (const [tokenKey, group] of grouped.entries()) {
     try {
-      await checkPaymentCapability(group, signer);
+      await checkPaymentCapability(group, signer, feePerInvoice);
     } catch (error) {
       errors.push(`${group.symbol}: ${error.message}`);
     }
   }

Also applies to: 547-567


346-351: Prefer explicit BigInt-safe comparison for chainId

ethers v6 returns chainId as BigInt. Use Number(...) or a BigInt literal to avoid implicit coercion pitfalls.

- if (network.chainId != 11155111) {
+ if (Number(network.chainId) !== 11155111) {

73-101: DRY: Extract shared invoice/token helpers into a reusable module

getTokenInfo/getTokenSymbol, detectBatchFromMetadata, getGroupedInvoices, handlePrint, and switchNetwork duplicate logic in ReceivedInvoice.jsx. Centralize into a shared util to reduce drift.

Would you like me to factor these into src/lib/invoices.tsx (or utils) and wire both screens to it?

Also applies to: 102-166, 276-306, 772-799, 800-814

frontend/src/page/ReceivedInvoice.jsx (3)

871-875: Null-guard address formatting to avoid runtime crashes

Same risk as in BatchPayment: invoice.user?.address can be falsy.

-const formatAddress = (address) => {
-  return `${address.substring(0, 10)}...${address.substring(
-    address.length - 10
-  )}`;
-};
+const formatAddress = (addr) => {
+  if (!addr || typeof addr !== "string" || addr.length < 12) return addr || "";
+  return `${addr.slice(0, 10)}...${addr.slice(-10)}`;
+};

631-637: Make chainId comparison explicit (ethers v6 returns BigInt)

Avoid implicit coercion; use Number(...) or 11155111n.

-if (network.chainId != 11155111) {
+if (Number(network.chainId) !== 11155111) {

236-274: Ensure fee used in balance checks is current

checkBalance relies on state fee which may be unset/stale; fetch from contract and pass it explicitly to avoid false positives/negatives.

-const checkBalance = async (tokenAddress, amount, symbol, signer) => {
+const checkBalance = async (tokenAddress, amount, symbol, signer, feeOverride) => {
+  const effectiveFee = feeOverride ?? fee;
   const userAddress = await signer.getAddress();
   if (tokenAddress === ethers.ZeroAddress) {
     const balance = await signer.provider.getBalance(userAddress);
-    const totalRequired = ethers.parseUnits(amount.toString(), 18) + BigInt(fee);
+    const totalRequired = ethers.parseUnits(amount.toString(), 18) + BigInt(effectiveFee);
     ...
   } else {
     ...
-    if (ethBalance < BigInt(fee)) {
-      const requiredEthFee = ethers.formatEther(fee);
+    if (ethBalance < BigInt(effectiveFee)) {
+      const requiredEthFee = ethers.formatEther(effectiveFee);
       ...
     }
   }
};

Use it where invoked:

- await checkBalance(tokenAddress, amountDue, tokenSymbol, signer);
+ const feeOnChain = await contract.fee();
+ await checkBalance(tokenAddress, amountDue, tokenSymbol, signer, feeOnChain);

And before the batch pre-check loop:

- toast.info("Checking balances...");
+ toast.info("Checking balances...");
+ const feeOnChain = await contract.fee();
  for (const [tokenKey, group] of grouped.entries()) {
    try {
-     await checkBalance(group.tokenAddress, group.totalAmount, group.symbol, signer);
+     await checkBalance(group.tokenAddress, group.totalAmount, group.symbol, signer, feeOnChain);

Also applies to: 398-406, 487-507

contracts/src/Chainvoice.sol (3)

84-101: Enforce positive amount in single-invoice creation (parity with batch create)

createInvoice does not validate amountDue > 0, while createInvoicesBatch does. Zero-amount invoices would still require paying the fee, which is likely undesirable/inconsistent.

 function createInvoice(
     address to,
     uint256 amountDue,
     address tokenAddress,
     string memory encryptedInvoiceData,
     string memory encryptedHash
 ) external {
     require(to != address(0), "Recipient address is zero");
     require(to != msg.sender, "Self-invoicing not allowed");
+    require(amountDue > 0, "Amount zero");

73-81: Avoid duplicated ERC20 validation; use the helper or remove it

You added _isERC20 but still inline the staticcall checks in both create paths. Either use _isERC20(tokenAddress) to centralize validation or drop the helper to reduce dead code.

Example:

- if (tokenAddress != address(0)) {
-     require(tokenAddress.code.length > 0, "Not a contract address");
-     (bool success, ) = tokenAddress.staticcall(
-         abi.encodeWithSignature("balanceOf(address)", address(this))
-     );
-     require(success, "Not an ERC20 token");
- }
+ if (tokenAddress != address(0)) {
+     require(_isERC20(tokenAddress), "Not an ERC20 token");
+ }

And same for createInvoicesBatch.

Also applies to: 94-101, 141-148


385-395: Anyone can withdraw to treasury (intentional?)

withdrawFees isn’t onlyOwner. Funds always go to treasuryAddress, so this isn’t theft-prone, but it allows grief-triggered withdrawals at arbitrary times. Confirm this is intentional; otherwise gate with onlyOwner.

-function withdrawFees() external {
+function withdrawFees() external onlyOwner {
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4bbd83a and 35c1996.

📒 Files selected for processing (8)
  • .github/workflows/deploy.yml (2 hunks)
  • contracts/src/Chainvoice.sol (5 hunks)
  • frontend/src/App.jsx (2 hunks)
  • frontend/src/components/TokenCrousel.jsx (2 hunks)
  • frontend/src/page/BatchPayment.jsx (1 hunks)
  • frontend/src/page/CreateInvoicesBatch.jsx (1 hunks)
  • frontend/src/page/Home.jsx (4 hunks)
  • frontend/src/page/ReceivedInvoice.jsx (19 hunks)
🧰 Additional context used
🧬 Code graph analysis (4)
frontend/src/page/BatchPayment.jsx (1)
frontend/src/page/ReceivedInvoice.jsx (24)
  • page (72-72)
  • walletClient (74-74)
  • receivedInvoices (77-77)
  • selectedInvoices (91-91)
  • fee (78-78)
  • error (79-79)
  • drawerState (96-99)
  • getTokenInfo (175-182)
  • getTokenSymbol (184-187)
  • detectBatchFromMetadata (189-199)
  • findBatchSuggestions (201-234)
  • selectBatchSuggestion (339-343)
  • payEntireBatch (345-364)
  • handleBatchPayment (469-590)
  • handleSelectInvoice (313-326)
  • handleSelectAll (328-333)
  • unpaidInvoices (882-884)
  • handleClearAll (335-337)
  • getGroupedInvoices (276-302)
  • grouped (886-886)
  • payInvoice (367-466)
  • toggleDrawer (819-831)
  • handlePrint (833-850)
  • switchNetwork (852-869)
frontend/src/components/TokenCrousel.jsx (1)
frontend/src/hooks/useTokenList.js (2)
  • useTokenList (18-86)
  • tokens (19-19)
frontend/src/page/CreateInvoicesBatch.jsx (10)
frontend/src/page/BatchPayment.jsx (6)
  • walletClient (39-39)
  • useAccount (40-40)
  • loading (41-41)
  • litClientRef (48-48)
  • showWalletAlert (51-51)
  • error (46-46)
frontend/src/page/ReceivedInvoice.jsx (6)
  • walletClient (74-74)
  • useAccount (75-75)
  • loading (76-76)
  • litClientRef (81-81)
  • showWalletAlert (84-84)
  • error (79-79)
frontend/src/components/WalletConnectionAlert.jsx (1)
  • WalletConnectionAlert (7-56)
frontend/src/components/ui/label.jsx (1)
  • Label (11-13)
frontend/src/components/ui/button.jsx (1)
  • Button (37-45)
frontend/src/components/ui/popover.jsx (3)
  • Popover (6-6)
  • PopoverTrigger (8-8)
  • PopoverContent (12-24)
frontend/src/components/ui/input.jsx (1)
  • Input (5-16)
frontend/src/components/TokenPicker.jsx (1)
  • TokenPicker (175-382)
frontend/src/components/ui/copyButton.jsx (1)
  • CopyButton (5-39)
frontend/src/lib/utils.js (1)
  • cn (4-6)
frontend/src/page/ReceivedInvoice.jsx (2)
frontend/src/page/SentInvoice.jsx (11)
  • columns (51-58)
  • drawerState (346-349)
  • error (69-69)
  • getTokenInfo (82-90)
  • fee (68-68)
  • walletClient (63-63)
  • switchNetwork (406-420)
  • showWalletAlert (76-76)
  • paymentLoading (72-72)
  • toggleDrawer (351-363)
  • handlePrint (365-376)
frontend/src/page/BatchPayment.jsx (27)
  • selectedInvoices (43-43)
  • batchLoading (44-44)
  • batchSuggestions (53-53)
  • drawerState (56-59)
  • error (46-46)
  • getTokenInfo (74-81)
  • getTokenSymbol (84-87)
  • detectBatchFromMetadata (90-100)
  • findBatchSuggestions (103-167)
  • fee (45-45)
  • getGroupedInvoices (277-305)
  • grouped (831-831)
  • receivedInvoices (42-42)
  • handleSelectInvoice (250-263)
  • handleSelectAll (265-270)
  • unpaidInvoices (827-829)
  • handleClearAll (272-274)
  • selectBatchSuggestion (220-224)
  • payEntireBatch (227-247)
  • handleBatchPayment (540-678)
  • payInvoice (681-770)
  • walletClient (39-39)
  • switchNetwork (800-814)
  • showWalletAlert (51-51)
  • paymentLoading (49-49)
  • toggleDrawer (773-785)
  • handlePrint (787-798)
🔇 Additional comments (8)
frontend/src/page/Home.jsx (1)

111-112: Template string is fine; current concatenation is OK.

No action needed; just noting style change is harmless.

frontend/src/App.jsx (1)

89-92: Route wiring for batch creation looks good.

The new /dashboard/batch-invoice route renders CreateInvoicesBatch.

frontend/src/page/CreateInvoicesBatch.jsx (2)

400-424: Lit config: chain hardcoded to "ethereum" and sessionSigs unused.

  • Consider mapping the active chain to Lit’s expected chain name.
  • If encryptString requires sessionSigs, pass them; otherwise drop the unused call.

Do you intend to target only Ethereum mainnet for access control? If not, map chainId to the appropriate Lit chain string and either pass sessionSigs to encryptString or remove the dead code.

Also applies to: 434-466


739-773: Token selection UX is solid; custom‑token verification flow reads well.

Nice feedback and copy actions.

Also applies to: 795-811, 821-851, 853-867

frontend/src/page/ReceivedInvoice.jsx (3)

112-172: Unified error parsing looks solid

Nice defensive normalization of common provider/contract error shapes. This should reduce noisy messages.


819-869: Good UX polish on network switching and error snackbar

Snackbar pattern and toasts are consistent and accessible; props and autoHide are reasonable.

Also applies to: 930-967


748-795: Invoice drawer: safe defaults for token visuals

Graceful logo fallback and clear fee/total display. LGTM.

Also applies to: 1796-1841

contracts/src/Chainvoice.sol (1)

246-318: Batch payment CEI and invariants look correct

  • Token-homogeneous enforcement (MixedTokenBatch).
  • All-or-nothing semantics with effects-before-interactions and nonReentrant.
  • Correct native vs ERC20 fee/value handling.

If you want, I can generate Foundry/Hardhat tests to cover:

  • Mixed token array reverts with MixedTokenBatch.
  • ERC20 insufficient allowance reverts with InsufficientAllowance.
  • Native incorrect msg.value reverts with IncorrectNativeValue.
  • Max batch size boundary (50/51).

Comment thread frontend/src/components/TokenCrousel.jsx
Comment thread frontend/src/page/CreateInvoicesBatch.jsx
Comment thread frontend/src/page/CreateInvoicesBatch.jsx
Comment thread frontend/src/page/CreateInvoicesBatch.jsx
Comment thread frontend/src/page/Home.jsx
@kumawatkaran523 kumawatkaran523 deleted the test-workflow branch September 20, 2025 13:06
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.

1 participant