Repository: Explore-Beyond-Innovations/ZeroXBridge_Frontend
Pull request #96: feat: implement claim and burn token flow
Author: login: kimcascante
Created: 2025-04-30T17:27:54Z | Merged: 2025-05-05T16:42:22Z

# Implement Claim and Burn Token Flow

## Description
This PR implements the two-step token redemption process for the ZeroX Bridge, allowing users to burn their xZB tokens on L2 and claim their original tokens on L1.

## Changes Made
- ✨ Added `ClaimTokens` component with L1 contract integration
- 🔄 Updated `BurnTokens` component with L2 contract integration
- 🔗 Implemented wallet connection handling
- ⏳ Added loading states and error handling
- 📝 Created type declarations for starknet-react
- 🛠️ Updated contract utilities for L1 and L2 interactions

## Implementation Details

### Two-Step Process
1. **Burn Step (L2)**
   - Users can burn their xZB tokens using the ZeroXBridgeL2 contract
   - Includes loading states and transaction feedback
   - Error handling for failed transactions

2. **Claim Step (L1)**
   - Users can claim their original tokens using the ZeroXBridgeL1 contract
   - Seamless integration with wallet connection
   - Transaction status tracking

### User Experience
- Clear UI flow explaining the process
- Status tracking between burn and claim steps
- Loading states and transaction feedback
- Error handling for failed transactions
- User guidance throughout the process

## Screenshots
![image](https://github.com/user-attachments/assets/7d0e6485-c417-4de9-96a6-5c2a997da0ad)

## Checklist
- [x] I have starred the repository ⭐
- [x] My code follows the project's style guidelines
- [x] I have tested the changes thoroughly
- [x] I have updated the documentation as needed
- [x] My changes generate no new warnings

## Related Issues
Closes #88 

## Additional Notes
- The implementation uses the latest version of starknet-react
- All contract interactions are properly typed
- Error messages are user-friendly and informative

<!-- This is an auto-generated comment: release notes by coderabbit.ai -->
## Summary by CodeRabbit

- **New Features**
  - Added a workflow requiring users to burn tokens before claiming, with a warning message if tokens have not been burned.
  - Introduced loading state indicators and visual feedback during asynchronous operations for burn and claim actions.
  - Action buttons are now disabled during processing and when prerequisites are not met.
  - Integrated Ethereum wallet connection and balance display within the burn and claim interface.
  - Enabled support for ETH and ERC20 token deposits with real-time balance and gas fee checks.
  - Added user-friendly error messages and input validation for burn amounts, including a "MAX" button for quick input.
  - Enhanced contract interactions for burning and claiming tokens with asynchronous handling and error management.
  - Introduced an Ethereum wallet connection provider with automatic account detection and event handling.
  - Added a strongly typed Ethereum smart contract interface with robust balance and gas fee validations.

- **Bug Fixes**
  - Improved input validation and error handling for contract interactions during burn and claim actions.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

Linked issue #88: Implement Claim and Burn Functionality
### Before applying for this issue, please star our repository! ⭐

## Description 📹
The flow for the claim and burn is that when users choose to burn their xZB tokens to reclaim their original tokens, they first burn their tokens using the burn function, and then they go and claim their L1 tokens. We need to integrate the claim and burn functions with the frontend to enable this workflow.

## Objective
Integrate burn and claim functionality into the frontend, creating a seamless user experience for the token redemption process.

## ✅ Proposed Actions

### 1️⃣ Fork and Create a Branch
```sh
git checkout -b feat-claim-burn-flow

```

2️⃣ Implementation Requirements

- [ ]  Integrate with the burn function from [ZeroXBridgeL2 contract](https://github.com/Explore-Beyond-Innovations/ZeroXBridge_Contracts/blob/38b249399591082fd1d37a6a6d998e098f451f36/contracts/L2/src/ZeroXBridgeL2.cairo#L87)
- [ ]  Integrate with the claim function from [ZeroXBridgeL1 contract](https://github.com/Explore-Beyond-Innovations/ZeroXBridge_Contracts/blob/38b249399591082fd1d37a6a6d998e098f451f36/contracts/L1/src/ZeroXBridgeL1.sol#L216)
- [ ]  Create a clear UI flow explaining the two-step process
- [ ]  Implement status tracking between burn and claim steps
- [ ]  Add loading states and success/error notifications
- [ ]  Ensure users understand the sequence and requirements for each step

3️⃣ Testing Requirements

- [ ]  Test the burn functionality with various token amounts
- [ ]  Test the claim functionality after burning
- [ ]  Verify transaction success feedback for both operations
- [ ]  Test error handling for failed transactions
- [ ]  Ensure clear user guidance throughout the process

📋 Required Guidelines

Assignment: Submit a PR only if you are assigned to this issue
Timeframe: Complete within 24 hours of assignment
Closing the Issue: Include Close #[issue_id] in PR description
Review Process: Mark PR ready for review and address feedback promptly

🔗 References

[ZeroXBridgeL2 burn function](https://github.com/Explore-Beyond-Innovations/ZeroXBridge_Contracts/blob/38b249399591082fd1d37a6a6d998e098f451f36/contracts/L2/src/ZeroXBridgeL2.cairo#L87)
[ZeroXBridgeL1 claim function](https://github.com/Explore-Beyond-Innovations/ZeroXBridge_Contracts/blob/38b249399591082fd1d37a6a6d998e098f451f36/contracts/L1/src/ZeroXBridgeL1.sol#L216)
Linked issue comments: user: login: OthmanImam
created_at: 2025-04-24T13:37:03Z
body: Hi Sir,

I'm Usman Adamu, a full-stack developer.
I want to carefully implement this issue if assigned.

Best regards,
@OthmanImam
author_association: NONE
user: login: MerlinTheWhiz
created_at: 2025-04-24T13:48:07Z
body: Hey @Dprof-in-tech ! I’m ready to fully integrate the burn + claim flow with a smooth, user-friendly frontend. I understand the importance of status tracking, UX clarity, and quick turnaround — I’ll deliver a clean UI with proper feedback and error handling within 24 hours.
author_association: NONE
user: login: kimcascante
created_at: 2025-04-24T14:09:10Z
body: Hello! I’m Kim Cascante, a member of Dojo Coding ⛩️
With experience in React, Typescript, and blockchain development, here’s my approach for this issue:

1. Fork and create a branch to start the integration.
2. Integrate the burn and claim functions from the ZeroXBridgeL2 and ZeroXBridgeL1 contracts.
3. Implement a UI flow that clearly explains the two step process (burn & claim).
4. Test the functionality and error handling thoroughly.
5. Submit a well-documented Pull Request.

Excited to apply my skills and help enhance the user experience! 
author_association: CONTRIBUTOR
user: login: Michael-Nwachukwu
created_at: 2025-04-24T16:04:40Z
body: I’d love to handle this integration!

The current claim-and-burn flow works contract-side but lacks a smooth frontend experience. My goal will be to wire up the burn function on L2 and the claim function on L1 into a clear, intuitive UI flow that guides users through reclaiming their original tokens via xZB burns.

Here’s my approach:

- Star ⭐️ this repository: DONE ✅

- Integrate the respective functions from ZeroXBridgeL2 and ZeroXBridgeL1 contracts.

- Design a user-friendly two-step flow with proper state tracking, loading indicators, and success/error handling.

- Ensure users are informed at each stage — from burn initiation to claim confirmation.

I can get started immediately and aim to have a clean PR up in 24hrs max. 

Let me know if I can proceed
author_association: NONE
user: login: hoangkianh
created_at: 2025-04-25T11:07:49Z
body: Can I start working on this?
author_association: NONE
user: login: Ugo-X
created_at: 2025-04-25T22:00:44Z
body: assigned @kimcascante  Please send a PR in 24 hours.
author_association: CONTRIBUTOR
user: login: kimcascante
created_at: 2025-04-28T04:53:17Z
body: @Ugo-X hello! I am working on this, I will open a PR soon
author_association: CONTRIBUTOR
user: login: Ugo-X
created_at: 2025-04-29T10:19:17Z
body: > [@Ugo-X](https://github.com/Ugo-X) hello! I am working on this, I will open a PR soon

4 days for a 24 hours PR?
Will be unassigning in the next 4 hours if there is no PR on your issue!

author_association: CONTRIBUTOR

Diff:
diff --git a/app/components/Ethereum-provider.tsx b/app/components/Ethereum-provider.tsx
new file mode 100644
index 0000000..bf9e3f3
--- /dev/null
+++ b/app/components/Ethereum-provider.tsx
@@ -0,0 +1,103 @@
+"use client";
+
+import { createContext, useContext, useEffect, useState } from "react";
+import { ethers } from "ethers";
+
+interface EthereumContextType {
+  provider: ethers.BrowserProvider | null;
+  signer: ethers.JsonRpcSigner | null;
+  isConnected: boolean;
+  connectWallet: () => Promise<void>;
+  address: string | null;
+}
+
+const EthereumContext = createContext<EthereumContextType>({
+  provider: null,
+  signer: null,
+  isConnected: false,
+  connectWallet: async () => {},
+  address: null,
+});
+
+export const EthereumProvider = ({ children }: { children: React.ReactNode }) => {
+  const [provider, setProvider] = useState<ethers.BrowserProvider | null>(null);
+  const [signer, setSigner] = useState<ethers.JsonRpcSigner | null>(null);
+  const [isConnected, setIsConnected] = useState(false);
+  const [address, setAddress] = useState<string | null>(null);
+
+  const connectWallet = async () => {
+    try {
+      if (typeof window.ethereum === "undefined") {
+        throw new Error("Please install MetaMask");
+      }
+
+      const provider = new ethers.BrowserProvider(window.ethereum);
+      await provider.send("eth_requestAccounts", []);
+      const signer = await provider.getSigner();
+      const address = await signer.getAddress();
+
+      setProvider(provider);
+      setSigner(signer);
+      setAddress(address);
+      setIsConnected(true);
+    } catch (error) {
+      console.error("Error connecting wallet:", error);
+    }
+  };
+
+  useEffect(() => {
+    const checkConnection = async () => {
+      if (typeof window.ethereum !== "undefined") {
+        const provider = new ethers.BrowserProvider(window.ethereum);
+        const accounts = await provider.send("eth_accounts", []);
+        
+        if (accounts.length > 0) {
+          const signer = await provider.getSigner();
+          const address = await signer.getAddress();
+          
+          setProvider(provider);
+          setSigner(signer);
+          setAddress(address);
+          setIsConnected(true);
+        }
+      }
+    };
+
+    checkConnection();
+
+    // Listen for account changes
+    if (window.ethereum) {
+      window.ethereum.on("accountsChanged", () => {
+        checkConnection();
+      });
+    }
+
+    return () => {
+      if (window.ethereum) {
+        window.ethereum.removeListener("accountsChanged", checkConnection);
+      }
+    };
+  }, []);
+
+  return (
+    <EthereumContext.Provider
+      value={{
+        provider,
+        signer,
+        isConnected,
+        connectWallet,
+        address,
+      }}
+    >
+      {children}
+    </EthereumContext.Provider>
+  );
+};
+
+export const useEthereum = () => {
+  const context = useContext(EthereumContext);
+  if (context === undefined) {
+    throw new Error("useEthereum must be used within an EthereumProvider");
+  }
+  return context;
+}; 
\ No newline at end of file
diff --git a/app/components/claim-burn.tsx b/app/components/claim-burn.tsx
index 07b1cf1..26f3f87 100644
--- a/app/components/claim-burn.tsx
+++ b/app/components/claim-burn.tsx
@@ -1,6 +1,8 @@
-import React, { useState } from "react";
+import React, { useState, useEffect } from "react";
 import { ChevronDown, Info } from "lucide-react";
 import Image from "next/image";
+import { useEthereum } from "./Ethereum-provider";
+import { ethers } from "ethers";
 
 interface TokenData {
   available: number;
@@ -13,6 +15,7 @@ interface Asset {
   name: string;
   symbol: string;
   icon: string;
+  address?: string;
 }
 
 interface XZBInterfaceProps {
@@ -21,6 +24,7 @@ interface XZBInterfaceProps {
   onBurn: (amount: string, asset: string) => void;
   isConnected: boolean | undefined;
   isDarkMode: boolean;
+  isLoading?: boolean;
 }
 
 const SAMPLE_ASSETS: Asset[] = [
@@ -29,18 +33,21 @@ const SAMPLE_ASSETS: Asset[] = [
     name: "Ethereum",
     symbol: "ETH",
     icon: "/token.svg",
+    address: "0x0000000000000000000000000000000000000000" // ETH address
   },
   {
     id: "2",
     name: "USD Coin",
     symbol: "USDC",
     icon: "/token.svg",
+    address: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48" // USDC address
   },
   {
     id: "3",
     name: "Tether",
     symbol: "USDT",
     icon: "/token.svg",
+    address: "0xdAC17F958D2ee523a2206206994597C13D831ec7" // USDT address
   },
 ];
 
@@ -50,11 +57,55 @@ const XZBInterface: React.FC<XZBInterfaceProps> = ({
   onBurn,
   isConnected,
   isDarkMode,
+  isLoading,
 }) => {
   const [activeTab, setActiveTab] = useState<"claim" | "burn">("claim");
   const [selectedAsset, setSelectedAsset] = useState<Asset | null>(null);
   const [burnAmount, setBurnAmount] = useState<string>("");
   const [isAssetSelectorOpen, setIsAssetSelectorOpen] = useState(false);
+  const [hasBurned, setHasBurned] = useState(false);
+  const [error, setError] = useState<string | null>(null);
+  const [isProcessing, setIsProcessing] = useState(false);
+  const [userEthBalance, setUserEthBalance] = useState<string | null>(null);
+  const [maxAmount, setMaxAmount] = useState<string>("");
+  
+  const { 
+    isConnected: isEthereumConnected, 
+    connect: connectEthereum,
+    depositAsset,
+    claimTokens,
+    address: ethereumAddress,
+    provider
+  } = useEthereum();
+
+  // Reset error when tab changes
+  useEffect(() => {
+    setError(null);
+  }, [activeTab]);
+
+  // Add effect to fetch ETH balance when connected
+  useEffect(() => {
+    const fetchBalance = async () => {
+      if (isEthereumConnected && ethereumAddress && provider) {
+        try {
+          const balance = await provider.getBalance(ethereumAddress);
+          const balanceInEth = ethers.formatEther(balance);
+          setUserEthBalance(balanceInEth);
+          // Set max amount slightly less than balance to account for gas
+          const maxForGas = Number(balanceInEth) * 0.95; // Leave 5% for gas
+          setMaxAmount(maxForGas.toString());
+        } catch (error) {
+          console.error("Error fetching balance:", error);
+          setUserEthBalance(null);
+        }
+      } else {
+        setUserEthBalance(null);
+        setMaxAmount("");
+      }
+    };
+
+    fetchBalance();
+  }, [isEthereumConnected, ethereumAddress, provider]);
 
   const calculateRedemptionAmount = (amount: string) => {
     const value = parseFloat(amount) || 0;
@@ -64,6 +115,169 @@ const XZBInterface: React.FC<XZBInterfaceProps> = ({
   const handleAssetSelect = (asset: Asset) => {
     setSelectedAsset(asset);
     setIsAssetSelectorOpen(false);
+    setError(null);
+  };
+
+  // Update input validation
+  const handleAmountChange = (e: React.ChangeEvent<HTMLInputElement>) => {
+    const value = e.target.value;
+    if (value === "" || /^\d*\.?\d*$/.test(value)) { // Allow empty or decimal numbers
+      setBurnAmount(value);
+      
+      // Clear error if amount is valid
+      if (selectedAsset?.symbol === "ETH" && userEthBalance) {
+        const inputAmount = Number(value);
+        const maxAllowed = Number(maxAmount);
+        
+        if (inputAmount > maxAllowed) {
+          setError(`Amount exceeds available balance (${Number(userEthBalance).toFixed(5)} ETH). Please enter a smaller amount.`);
+        } else {
+          setError(null);
+        }
+      }
+    }
+  };
+
+  // Update MAX button handler
+  const handleMaxClick = () => {
+    if (selectedAsset?.symbol === "ETH" && maxAmount) {
+      setBurnAmount(maxAmount);
+      setError(null);
+    } else {
+      setBurnAmount(tokenData.balance.toString());
+    }
+  };
+
+  const handleBurn = async (amount: string, assetId: string) => {
+    try {
+      setError(null);
+      setIsProcessing(true);
+
+      // Check if wallet is connected
+      if (!isConnected) {
+        throw new Error("Please connect your wallet first");
+      }
+
+      // Check if Ethereum wallet is connected for L1
+      if (!isEthereumConnected || !ethereumAddress) {
+        try {
+          await connectEthereum();
+          await new Promise(resolve => setTimeout(resolve, 1000));
+          
+          if (!isEthereumConnected || !ethereumAddress) {
+            throw new Error("Failed to connect Ethereum wallet");
+          }
+        } catch (_) {
+          throw new Error("Please connect your Ethereum wallet first");
+        }
+      }
+
+      if (!selectedAsset) {
+        throw new Error("Please select an asset first");
+      }
+
+      if (!amount || parseFloat(amount) <= 0) {
+        throw new Error("Please enter a valid amount");
+      }
+
+      // Determine asset type (0 for ETH, 1 for ERC20)
+      const assetType = selectedAsset.symbol === "ETH" ? 0 : 1;
+      
+      // Get asset address
+      const tokenAddress = selectedAsset.address || "0x0000000000000000000000000000000000000000";
+
+      // For ETH transfers, validate balance before proceeding
+      if (assetType === 0) {
+        const balance = await provider?.getBalance(ethereumAddress);
+        if (!balance) {
+          throw new Error("Could not get your ETH balance");
+        }
+
+        const amountInWei = ethers.parseEther(amount);
+        if (balance < amountInWei) {
+          const balanceInEth = ethers.formatEther(balance);
+          throw new Error(
+            `Insufficient ETH balance. You have ${Number(balanceInEth).toFixed(5)} ETH but trying to send ${amount} ETH. Please reduce the amount or add more ETH to your wallet.`
+          );
+        }
+      }
+
+      console.log("Initiating burn transaction:", {
+        assetType,
+        tokenAddress,
+        amount,
+        userAddress: ethereumAddress,
+        isEthereumConnected,
+        hasAddress: !!ethereumAddress
+      });
+
+      // Call depositAsset function
+      const txHash = await depositAsset(
+        assetType,
+        tokenAddress,
+        amount
+      );
+      
+      console.log("Transaction hash:", txHash);
+      setHasBurned(true);
+      onBurn(amount, assetId);
+    } catch (error) {
+      console.error("Error in handleBurn:", error);
+      const errorMessage = error instanceof Error ? error.message : "An error occurred while burning tokens";
+      setError(errorMessage);
+      
+      // If it's an insufficient funds error, add a suggestion
+      if (errorMessage.includes("Insufficient")) {
+        setTimeout(() => {
+          setError(errorMessage + "\n\nTip: Try reducing the amount or adding more funds to your wallet.");
+        }, 100);
+      }
+    } finally {
+      setIsProcessing(false);
+    }
+  };
+
+  const handleClaim = async () => {
+    try {
+      setError(null);
+      setIsProcessing(true);
+
+      if (!isEthereumConnected || !ethereumAddress) {
+        await connectEthereum();
+        return;
+      }
+
+      await claimTokens();
+      onClaim(selectedAsset?.id || "");
+    } catch (error) {
+      console.error("Error in handleClaim:", error);
+      setError(error instanceof Error ? error.message : "An error occurred while claiming tokens");
+    } finally {
+      setIsProcessing(false);
+    }
+  };
+
+  const handleConnect = async () => {
+    try {
+      setError(null);
+      setIsProcessing(true);
+
+      if (activeTab === "claim" && !isEthereumConnected) {
+        await connectEthereum();
+        // Wait a bit for the connection to be established
+        await new Promise(resolve => setTimeout(resolve, 1000));
+        
+        // Check if connection was successful
+        if (!isEthereumConnected || !ethereumAddress) {
+          throw new Error("Failed to connect Ethereum wallet");
+        }
+      }
+    } catch (error) {
+      console.error("Error connecting:", error);
+      setError(error instanceof Error ? error.message : "An error occurred while connecting");
+    } finally {
+      setIsProcessing(false);
+    }
   };
 
   return (
@@ -113,6 +327,12 @@ const XZBInterface: React.FC<XZBInterfaceProps> = ({
           isDarkMode ? "bg-[#21192F]" : "bg-[#F8F4FF]"
         } rounded-3xl lg:px-[37px] lg:pt-5 pb-[30px] pt-[30px] px-6 w-full`}
       >
+        {error && (
+          <div className={`${isDarkMode ? "bg-[#E25876] text-white" : "bg-[#FFE5EA] text-[#E25876]"} rounded-xl py-4 px-6 text-center`}>
+            <p>{error}</p>
+          </div>
+        )}
+
         {/* Title */}
         <h2 className="text-sm lg:text-lg font-medium">
           {activeTab === "claim"
@@ -120,6 +340,21 @@ const XZBInterface: React.FC<XZBInterfaceProps> = ({
             : "Burn Your xZB Tokens Now"}
         </h2>
 
+        {/* Burn First Warning */}
+        {activeTab === "claim" && !hasBurned && (
+          <div
+            className={`${
+              isDarkMode
+                ? "bg-[#E25876] border border-dashed border-white"
+                : "bg-[#FFE5EA]"
+            } rounded-xl py-4 px-6 text-center`}
+          >
+            <p className={`${isDarkMode ? "text-white" : "text-[#E25876]"}`}>
+              Please burn your tokens first before claiming. This ensures proper token redemption.
+            </p>
+          </div>
+        )}
+
         {/* Balance Display */}
         <div>
           <p
@@ -146,18 +381,19 @@ const XZBInterface: React.FC<XZBInterfaceProps> = ({
 
         {activeTab === "burn" && (
           <div>
-            <p
-              className={`${
-                isDarkMode ? "text-gray-400" : "text-[#53436D]"
-              } text-xs mb:text-sm mb-2 lg:mb-1`}
-            >
+            <p className={`${isDarkMode ? "text-gray-400" : "text-[#53436D]"} text-xs mb:text-sm mb-2 lg:mb-1`}>
               Enter amount to Burn
+              {selectedAsset?.symbol === "ETH" && userEthBalance && (
+                <span className="ml-2 text-xs">
+                  (Available: {Number(userEthBalance).toFixed(5)} ETH)
+                </span>
+              )}
             </p>
             <div className="relative">
               <input
                 type="text"
                 value={burnAmount}
-                onChange={(e) => setBurnAmount(e.target.value)}
+                onChange={handleAmountChange}
                 className={`w-full font-semibold ${
                   isDarkMode
                     ? "bg-[#1F1333] text-[#8B8B8B] placeholder:text-[#8B8B8B]"
@@ -166,8 +402,11 @@ const XZBInterface: React.FC<XZBInterfaceProps> = ({
                 placeholder="Enter Amount"
               />
               <button
-                className="absolute right-4 top-1/2 -translate-y-1/2 text-[#6c5dd3] text-xs lg:text-sm"
-                onClick={() => setBurnAmount(tokenData.balance.toString())}
+                className={`absolute right-4 top-1/2 -translate-y-1/2 text-[#6c5dd3] text-xs lg:text-sm ${
+                  (!selectedAsset || (selectedAsset.symbol === "ETH" && !userEthBalance)) ? "opacity-50 cursor-not-allowed" : ""
+                }`}
+                onClick={handleMaxClick}
+                disabled={!selectedAsset || (selectedAsset.symbol === "ETH" && !userEthBalance)}
               >
                 MAX
               </button>
@@ -322,23 +561,41 @@ const XZBInterface: React.FC<XZBInterfaceProps> = ({
           <button
             className={`w-full bg-gradient-to-b from-[#A26DFF] to-[#09050E] hover:bg-[#5a4eb8] rounded-2xl p-[14px] lg:p-4 font-bold lg:font-medium transition-colors ${
               !isDarkMode && "text-white"
-            }`}
-            onClick={() =>
-              activeTab === "claim"
-                ? onClaim(selectedAsset?.id || "")
-                : onBurn(burnAmount, selectedAsset?.id || "")
+            } ${(isLoading || isProcessing) ? "opacity-50 cursor-not-allowed" : ""}`}
+            onClick={async () => {
+              if (activeTab === "claim") {
+                if (!isEthereumConnected) {
+                  await handleConnect();
+                } else {
+                  await handleClaim();
+                }
+              } else {
+                await handleBurn(burnAmount, selectedAsset?.id || "");
+              }
+            }}
+            disabled={
+              isLoading || 
+              isProcessing ||
+              (activeTab === "claim" && !hasBurned) || 
+              (activeTab === "burn" && (!burnAmount || !selectedAsset || parseFloat(burnAmount) <= 0))
             }
           >
-            {activeTab === "claim" ? "Claim xZB" : "Burn xZB"}
+            {isLoading || isProcessing
+              ? "Processing..." 
+              : activeTab === "claim" 
+                ? (isEthereumConnected ? "Claim xZB" : "Connect Ethereum Wallet") 
+                : "Burn xZB"
+            }
           </button>
         ) : (
           <button
             className={`w-full bg-gradient-to-b from-[#A26DFF] to-[#09050E] hover:bg-[#5a4eb8] rounded-2xl p-[14px] lg:p-4 font-bold lg:font-medium transition-colors ${
               !isDarkMode && "text-white"
             }`}
-            onClick={()=>{return}}
+            onClick={handleConnect}
+            disabled={isProcessing}
           >
-            Connect Wallet
+            {isProcessing ? "Connecting..." : "Connect Wallet"}
           </button>
         )}
       </div>
diff --git a/app/contracts/ZeroXBridgeL1.ts b/app/contracts/ZeroXBridgeL1.ts
new file mode 100644
index 0000000..08a5dd8
--- /dev/null
+++ b/app/contracts/ZeroXBridgeL1.ts
@@ -0,0 +1,136 @@
+import { ethers } from "ethers";
+
+export const ZeroXBridgeL1ABI = [
+  "function registerUser(bytes calldata signature, uint256 starknetPubKey) external",
+  "function claim_tokens() external",
+  "function deposit_asset(uint8 assetType, address tokenAddress, uint256 amount, address user) external payable returns (bytes32)",
+  "function userRecord(address) external view returns (uint256)",
+  "function claimableFunds(address) external view returns (uint256)",
+  "event UserRegistered(address indexed user, uint256 starknetPubKey)",
+  "event ClaimEvent(address indexed user, uint256 amount)",
+  "event DepositEvent(address indexed token, uint8 assetType, uint256 amount, address indexed user, bytes32 commitmentHash)"
+] as const;
+
+export class ZeroXBridgeL1 extends ethers.Contract {
+  private _signer: ethers.Signer | null = null;
+
+  constructor(address: string, signerOrProvider: ethers.Signer | ethers.Provider) {
+    super(address, ZeroXBridgeL1ABI, signerOrProvider);
+    // Check if the signerOrProvider has a getAddress method (which indicates it's a signer)
+    if (signerOrProvider && typeof (signerOrProvider as any).getAddress === 'function') {
+      this._signer = signerOrProvider as ethers.Signer;
+    }
+  }
+
+  async registerUser(signature: string, starknetPubKey: string): Promise<ethers.ContractTransactionResponse> {
+    if (!this._signer) throw new Error("No signer available");
+    return await this.getFunction("registerUser")(signature, starknetPubKey);
+  }
+
+  async claim_tokens(): Promise<ethers.ContractTransactionResponse> {
+    if (!this._signer) throw new Error("No signer available");
+    return await this.getFunction("claim_tokens")();
+  }
+
+  async deposit_asset(
+    assetType: number,
+    tokenAddress: string,
+    amount: ethers.BigNumberish,
+    options: { value?: ethers.BigNumberish } = {}
+  ): Promise<ethers.ContractTransactionResponse> {
+    if (!this._signer) throw new Error("No signer available");
+    
+    const address = await this._signer.getAddress();
+    
+    try {
+      // Get the user's ETH balance first
+      const balance = await this._signer.provider?.getBalance(address);
+      if (!balance) throw new Error("Could not get user balance");
+
+      // Convert amount to BigInt for consistent comparison
+      const amountBigInt = ethers.getBigInt(amount);
+      
+      // For ETH deposits
+      if (assetType === 0) {
+        // Validate amount
+        if (amountBigInt <= 0n) {
+          throw new Error("Amount must be greater than 0");
+        }
+
+        // Check if user has enough ETH for the transfer
+        if (balance < amountBigInt) {
+          throw new Error(
+            `Insufficient ETH balance. You have ${ethers.formatEther(balance)} ETH but trying to send ${ethers.formatEther(amountBigInt)} ETH`
+          );
+        }
+
+        // Set value equal to amount for ETH transfers
+        options.value = amountBigInt;
+      }
+
+      // Get current gas price first
+      const feeData = await this._signer.provider?.getFeeData();
+      if (!feeData || !feeData.gasPrice) {
+        throw new Error("Could not get gas price");
+      }
+
+      // Estimate gas
+      const gasEstimate = await this.getFunction("deposit_asset").estimateGas(
+        assetType,
+        tokenAddress,
+        amount,
+        address,
+        options
+      );
+
+      // Add 20% buffer to gas estimate using bigint arithmetic
+      const gasLimit = (gasEstimate * 120n) / 100n;
+
+      // Calculate total cost (gas * gasPrice + value for ETH transfers)
+      const gasCost = gasLimit * feeData.gasPrice;
+      const totalCost = assetType === 0 ? gasCost + amountBigInt : gasCost;
+
+      // Final balance check
+      if (balance < totalCost) {
+        const needed = ethers.formatEther(totalCost);
+        const has = ethers.formatEther(balance);
+        const gasEth = ethers.formatEther(gasCost);
+        const transferEth = assetType === 0 ? ethers.formatEther(amountBigInt) : '0';
+        
+        throw new Error(
+          `Insufficient funds for transaction. You need ${needed} ETH total (${gasEth} ETH for gas + ${transferEth} ETH for transfer) but have ${has} ETH`
+        );
+      }
+
+      // Execute the transaction
+      return await this.getFunction("deposit_asset")(
+        assetType,
+        tokenAddress,
+        amount,
+        address,
+        { ...options, gasLimit }
+      );
+    } catch (error) {
+      if (error instanceof Error) {
+        // Preserve our custom error messages
+        if (error.message.includes("Insufficient") || error.message.includes("Amount must be")) {
+          throw error;
+        }
+        // Handle other errors
+        if (error.message.includes("insufficient funds")) {
+          throw new Error("Insufficient funds for transaction. Please ensure you have enough ETH to cover both the transfer amount and gas fees.");
+        }
+        throw new Error(`Failed to deposit asset: ${error.message}`);
+      }
+      throw error;
+    }
+  }
+
+  async userRecord(address: string): Promise<ethers.BigNumber> {
+    return await this.getFunction("userRecord")(address);
+  }
+
+  async claimableFunds(address: string): Promise<ethers.BigNumber> {
+    return await this.getFunction("claimableFunds")(address);
+  }
+} 
\ No newline at end of file
diff --git a/app/dashboard/claim-burn/page.tsx b/app/dashboard/claim-burn/page.tsx
index 2e13af0..63678dd 100644
--- a/app/dashboard/claim-burn/page.tsx
+++ b/app/dashboard/claim-burn/page.tsx
@@ -2,12 +2,15 @@
 "use client";
 import XZBInterface from "@/app/components/claim-burn";
 import { useTheme } from "@/app/ThemeContext";
-import { useAccount, useReadContract } from "@starknet-react/core";
+import { useAccount, useContract } from "@starknet-react/core";
+import { shortString } from "starknet";
+import { useReadContract } from "@starknet-react/core";
 import { useEffect, useState } from "react";
 
 const Index = () => {
-  const { isConnected } = useAccount();
+   const { isConnected, address, account } = useAccount();
   const { isDarkMode } = useTheme();
+    const [isLoading, setIsLoading] = useState(false);
   const [xzbSupplyRate, setXzbSupplyRate] = useState("");
   const [dynamicRate, setDynamicRate] = useState("");
 
@@ -17,12 +20,84 @@ const Index = () => {
     usdValue: 2475,
   };
 
-  const handleClaim = (asset: string) => {
-    console.log("Claiming with asset:", asset);
+  // Contract address - replace with your actual deployed contract address
+  const contractAddress = "0x06799866e50962817ce737ed1c2611e64fdfd34a1934edd3960322e79a22fd96"; // Example address, replace with actual
+
+  // Initialize contract
+  const { contract } = useContract({
+    address: contractAddress,
+    abi: [
+      {
+        name: "burn",
+        type: "function",
+        inputs: [
+          { name: "amount", type: "felt" },
+          { name: "asset", type: "felt" }
+        ],
+        outputs: [],
+        state_mutability: "external"
+      }
+    ]
+  });
+
+  const handleClaim = async (asset: string) => {
+    try {
+      setIsLoading(true);
+      // Implement claim logic here
+      console.log("Claiming with asset:", asset);
+    } catch (error) {
+      console.error("Error claiming:", error);
+    } finally {
+      setIsLoading(false);
+    }
   };
 
-  const handleBurn = (amount: string, asset: string) => {
-    console.log("Burning amount:", amount, "for asset:", asset);
+  const handleBurn = async (amount: string, asset: string) => {
+    try {
+      setIsLoading(true);
+      if (!address) {
+        throw new Error("No wallet connected");
+      }
+
+      if (!contract) {
+        throw new Error("Contract not initialized");
+      }
+
+      if (!account) {
+        throw new Error("No account available");
+      }
+
+      // Validate amount
+      const parsedAmount = parseFloat(amount);
+      if (isNaN(parsedAmount) || parsedAmount <= 0) {
+        throw new Error("Invalid amount");
+      }
+
+      // Convert amount to the correct format for the contract
+      const amountInWei = BigInt(Math.floor(parsedAmount * 1e18)).toString();
+
+      // Validate asset
+      if (!asset) {
+        throw new Error("No asset selected");
+      }
+
+      // Convert asset to felt
+      const assetFelt = shortString.encodeShortString(asset);
+
+      // Call the burn function using the account
+      const result = await account.execute({
+        contractAddress,
+        entrypoint: "burn",
+        calldata: [amountInWei, assetFelt]
+      });
+
+      console.log("Burn transaction:", result);
+    } catch (error) {
+      console.error("Error burning tokens:", error);
+      // You might want to show this error to the user
+    } finally {
+      setIsLoading(false);
+    }
   };
 
   const address = `0x${""}`;
@@ -105,6 +180,7 @@ const Index = () => {
           onBurn={handleBurn}
           isConnected={isConnected}
           isDarkMode={isDarkMode}
+          isLoading={isLoading}
         />
       </div>
     </div>


Reviews:
user: login: coderabbitai[bot]
body: **Actionable comments posted: 6**

<details>
<summary>🔭 Outside diff range comments (1)</summary><blockquote>

<details>
<summary>app/components/claim-burn.tsx (1)</summary><blockquote>

`359-368`: _⚠️ Potential issue_

**Empty onClick handler for wallet connection button.**

The wallet connection button has an empty onClick handler, which won't trigger any action.

This button needs to initiate wallet connection:

```diff
<button
  className={`w-full bg-gradient-to-b from-[#A26DFF] to-[#09050E] hover:bg-[#5a4eb8] rounded-2xl p-[14px] lg:p-4 font-bold lg:font-medium transition-colors ${
    !isDarkMode && "text-white"
  }`}
-  onClick={()=>{return}}
+  onClick={() => {
+    // This should trigger wallet connection
+    // Example: if you have a connect function from useConnectors() or similar
+    // connect();
+  }}
>
  Connect Wallet
</button>
```

You'll need to add wallet connection handling, likely using a hook or function from your wallet connection library.

</blockquote></details>

</blockquote></details>

<details>
<summary>📜 Review details</summary>

**Configuration used: CodeRabbit UI**
**Review profile: CHILL**
**Plan: Pro**

<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between 24ca3a74ae64dbb1a815bd1baa1760baac58945c and 8b28f303781f6f20dd25067afe9f3a95c92da3da.

</details>

<details>
<summary>📒 Files selected for processing (2)</summary>

* `app/components/claim-burn.tsx` (5 hunks)
* `app/dashboard/claim-burn/page.tsx` (2 hunks)

</details>

<details>
<summary>🧰 Additional context used</summary>

<details>
<summary>🧬 Code Graph Analysis (1)</summary>

<details>
<summary>app/dashboard/claim-burn/page.tsx (1)</summary><blockquote>

<details>
<summary>app/ThemeContext.tsx (1)</summary>

* `useTheme` (36-42)

</details>

</blockquote></details>

</details>

</details>

<details>
<summary>🔇 Additional comments (14)</summary><blockquote>

<details>
<summary>app/dashboard/claim-burn/page.tsx (6)</summary>

`4-6`: **Good selection of imports for Starknet integration.**

The added imports are appropriate for implementing the burn and claim functionality with Starknet. Using `shortString` for encoding is essential for proper contract interaction.

---

`9-9`: **Properly destructured useAccount hook for contract interaction.**

The destructuring now includes `address` and `account`, which are necessary for contract interactions. This is a good practice for accessing wallet information.

---

`11-11`: **Added loading state management.**

Adding the loading state is important for providing user feedback during asynchronous blockchain operations.

---

`51-70`: **Good error handling and input validation.**

The validation checks for wallet connection, contract initialization, account availability, and amount validation are thorough and well-implemented.

---

`75-82`: **Proper validation and encoding for asset parameter.**

The asset validation and encoding to felt format is correctly implemented.

---

`112-112`: **Loading state correctly passed to child component.**

The loading state is properly passed to the XZBInterface component, which is essential for UI feedback.

</details>
<details>
<summary>app/components/claim-burn.tsx (8)</summary>

`24-24`: **Good addition of optional loading prop.**

Adding the optional `isLoading` prop allows for better coordination between parent and child components during asynchronous operations.

---

`60-60`: **Added workflow state tracking.**

The addition of the `hasBurned` state is crucial for enforcing the correct sequence of operations in the two-step process.

---

`73-76`: **Good implementation of burn handler with state update.**

The `handleBurn` function properly calls the parent component's `onBurn` function and updates the workflow state, which is crucial for the two-step process.

---

`132-145`: **Helpful workflow guidance for users.**

The warning message when users haven't burned tokens yet provides clear guidance on the required sequence of operations.

This is a good UX improvement that helps users understand the process.

---

`349-350`: **Good implementation of loading state styling.**

The button styling changes appropriately during loading operations, providing visual feedback to users.

---

`351-354`: **Use burn handler correctly in onClick.**

The onClick handler now uses the local `handleBurn` function for burn operations, which ensures the workflow state is updated correctly.

---

`355-355`: **Button correctly disabled based on workflow state.**

The button is properly disabled when the user is on the claim tab but hasn't completed the burn step, or when a transaction is in progress.

---

`357-357`: **Dynamic button label provides clear user feedback.**

The button label changes appropriately based on the current action and loading state, which is important for user understanding.

</details>

</blockquote></details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->
state: COMMENTED
author_association: NONE
submitted_at: 2025-04-30T17:31:01Z
user: login: Dprof-in-tech
body: Good day maam.

This is beautiful but you seem to have missed adding the implementation for claiming on the L1

The L1 here is Ethereum 
state: CHANGES_REQUESTED
author_association: COLLABORATOR
submitted_at: 2025-05-01T11:40:58Z
user: login: coderabbitai[bot]
body: **Actionable comments posted: 6**

<details>
<summary>🔭 Outside diff range comments (1)</summary><blockquote>

<details>
<summary>app/components/claim-burn.tsx (1)</summary><blockquote>

`560-589`: _🛠️ Refactor suggestion_

**UI disables claim permanently after page reload**

`hasBurned` lives only in component state. A page refresh forgets prior burns, forcing the user to repeat the action even if the bridge has already registered it.


Derive burn status from on-chain data (e.g. `userRecord` / `claimableFunds`) instead of a volatile boolean.

</blockquote></details>

</blockquote></details>

<details>
<summary>🧹 Nitpick comments (6)</summary><blockquote>

<details>
<summary>app/contracts/ZeroXBridgeL1.ts (2)</summary><blockquote>

`86-92`: **Gas-limit buffer risks silent overflow & wastes gas**

Multiplying by `120n` and dividing by `100n` is safe, but adding a fixed percentage buffer (`+20%`) causes many transactions to over-provision gas (costly on L2).  
Safer pattern:

```ts
const gasLimit = gasEstimate + (gasEstimate / 5n); // +20% headroom
```

This avoids the intermediate product that can overflow when `gasEstimate` is close to `2**256`.

---

`114-124`: **Error wrapping drops original stack**

Wrapping all unknown errors with `new Error(...)` loses the original stack trace, making on-chain debugging painful.


```diff
-throw new Error(`Failed to deposit asset: ${error.message}`);
+throw new Error(`Failed to deposit asset: ${error.message}`, { cause: error });
```

Using the `cause` option (Node >= 16.9 / modern browsers) keeps the original stack for later inspection.

</blockquote></details>
<details>
<summary>app/components/Ethereum-provider.tsx (1)</summary><blockquote>

`195-204`: **Re-instantiating the contract each call is unnecessary**

`depositAsset` spins up a new `ZeroXBridgeL1` instance on every invocation.  
Reuse the already initialised `contract` in state to avoid ABI re-parsing overhead and keep events subscriptions consistent.

</blockquote></details>
<details>
<summary>app/components/claim-burn.tsx (3)</summary><blockquote>

`62-62`: **Defaulting to “claim” contradicts enforced burn-first flow**

`activeTab` initialises to `"claim"` yet the button is disabled until the user burns.  
Starting in the “Burn” tab prevents a confusing dead-end for first-time users.


```diff
-const [activeTab, setActiveTab] = useState<"claim" | "burn">("claim");
+const [activeTab, setActiveTab] = useState<"claim" | "burn">("burn");
```

---

`88-99`: **Balance fetch runs without provider guard**

`provider?.getBalance` is called, but an undefined provider yields `balance = undefined`, triggering the “Could not get user balance” error path each render while disconnected.


Short-circuit the effect when `!provider`:

```ts
if (!provider || !isEthereumConnected || !ethereumAddress) return;
```

---

`129-137`: **Inefficient re-validation on every keystroke**

Parsing `Number(value)` and `Number(maxAmount)` on each key press inside `handleAmountChange` causes unnecessary renders.  Consider memoising the numeric balance once and comparing with `parseFloat(value)`.

</blockquote></details>

</blockquote></details>

<details>
<summary>📜 Review details</summary>

**Configuration used: CodeRabbit UI**
**Review profile: CHILL**
**Plan: Pro**

<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between 8b28f303781f6f20dd25067afe9f3a95c92da3da and 7d577ff4afa2b2074da34fb06a9396a1140249dd.

</details>

<details>
<summary>📒 Files selected for processing (3)</summary>

* `app/components/Ethereum-provider.tsx` (1 hunks)
* `app/components/claim-burn.tsx` (10 hunks)
* `app/contracts/ZeroXBridgeL1.ts` (1 hunks)

</details>

<details>
<summary>🧰 Additional context used</summary>

<details>
<summary>🧬 Code Graph Analysis (2)</summary>

<details>
<summary>app/components/Ethereum-provider.tsx (1)</summary><blockquote>

<details>
<summary>app/contracts/ZeroXBridgeL1.ts (2)</summary>

* `ZeroXBridgeL1` (14-136)
* `registerUser` (25-28)

</details>

</blockquote></details>
<details>
<summary>app/components/claim-burn.tsx (1)</summary><blockquote>

<details>
<summary>app/components/Ethereum-provider.tsx (1)</summary>

* `useEthereum` (30-32)

</details>

</blockquote></details>

</details>

</details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->
state: COMMENTED
author_association: NONE
submitted_at: 2025-05-02T02:35:12Z
user: login: coderabbitai[bot]
body: **Actionable comments posted: 2**

<details>
<summary>🧹 Nitpick comments (5)</summary><blockquote>

<details>
<summary>app/components/Ethereum-provider.tsx (5)</summary><blockquote>

`30-32`: **Enhance error handling for wallet detection.**

The current implementation only checks if MetaMask is installed. However, users might use other wallets that support the EIP-1193 provider interface. Consider providing a more generic error message.


```diff
- if (typeof window.ethereum === "undefined") {
-   throw new Error("Please install MetaMask");
+ if (typeof window.ethereum === "undefined") {
+   throw new Error("No Ethereum wallet detected. Please install MetaMask or another web3 wallet");
```

---

`43-44`: **Improve error handling in connectWallet function.**

The current implementation only logs errors to the console. Consider adding a way to propagate errors to the UI or provide more specific error handling.


```diff
  setIsConnected(true);
} catch (error) {
  console.error("Error connecting wallet:", error);
+ // Return the error so consumers can handle it
+ return error instanceof Error 
+   ? error 
+   : new Error('Unknown error connecting to wallet');
}
```

Then, update the TypeScript interface to reflect this change:

```diff
interface EthereumContextType {
  provider: ethers.BrowserProvider | null;
  signer: ethers.JsonRpcSigner | null;
  isConnected: boolean;
- connectWallet: () => Promise<void>;
+ connectWallet: () => Promise<Error | void>;
  address: string | null;
}
```

---

`98-101`: **Fix context undefined check in useEthereum hook.**

Since you've provided default values in `createContext`, the context will never actually be `undefined`. The current check is unnecessary or might need to be adjusted.


```diff
export const useEthereum = () => {
  const context = useContext(EthereumContext);
- if (context === undefined) {
+ // No need for this check since we provided default values in createContext
+ // If you want to enforce usage within the provider, check if a real provider is available
+ if (!context || context.connectWallet === EthereumContext._currentValue.connectWallet) {
    throw new Error("useEthereum must be used within an EthereumProvider");
  }
  return context;
};
```

Alternatively, to simplify: 

```diff
export const useEthereum = () => {
  const context = useContext(EthereumContext);
- if (context === undefined) {
-   throw new Error("useEthereum must be used within an EthereumProvider");
- }
  return context;
};
```

---

`22-27`: **Consider exposing current transaction status for better UI feedback.**

Users need visual feedback during blockchain transactions. Adding transaction status state would help create a better user experience.


```diff
export const EthereumProvider = ({ children }: { children: React.ReactNode }) => {
  const [provider, setProvider] = useState<ethers.BrowserProvider | null>(null);
  const [signer, setSigner] = useState<ethers.JsonRpcSigner | null>(null);
  const [isConnected, setIsConnected] = useState(false);
  const [address, setAddress] = useState<string | null>(null);
+ const [transactionStatus, setTransactionStatus] = useState<'idle' | 'pending' | 'success' | 'error'>('idle');
+ const [transactionHash, setTransactionHash] = useState<string | null>(null);
```

Then update the context interface and provider value to include these new properties.

---

`30-46`: **Add disconnect wallet functionality for improved user experience.**

The current implementation only provides a way to connect wallets, but users might want to disconnect or switch wallets.


Consider adding a disconnect function:

```diff
interface EthereumContextType {
  provider: ethers.BrowserProvider | null;
  signer: ethers.JsonRpcSigner | null;
  isConnected: boolean;
  connectWallet: () => Promise<void>;
+ disconnectWallet: () => void;
  address: string | null;
}

// Add to EthereumProvider component
const disconnectWallet = () => {
  setProvider(null);
  setSigner(null);
  setAddress(null);
  setIsConnected(false);
  // Note: This doesn't actually disconnect the wallet at the MetaMask level
  // as MetaMask doesn't provide a way to programmatically disconnect
  // This just resets the local state
};

// Add to context value
<EthereumContext.Provider
  value={{
    provider,
    signer,
    isConnected,
    connectWallet,
+   disconnectWallet,
    address,
  }}
>
```

</blockquote></details>

</blockquote></details>

<details>
<summary>📜 Review details</summary>

**Configuration used: CodeRabbit UI**
**Review profile: CHILL**
**Plan: Pro**

<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between 7d577ff4afa2b2074da34fb06a9396a1140249dd and 013019170e1471cd03307b87a124be4b91caa254.

</details>

<details>
<summary>📒 Files selected for processing (1)</summary>

* `app/components/Ethereum-provider.tsx` (1 hunks)

</details>

<details>
<summary>🔇 Additional comments (1)</summary><blockquote>

<details>
<summary>app/components/Ethereum-provider.tsx (1)</summary>

`1-5`: **LGTM! Good use of client directive for browser-only code.**

The `"use client"` directive is correctly placed at the top of the file, which is essential for components that use browser-specific APIs like `window.ethereum`.

</details>

</blockquote></details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->
state: COMMENTED
author_association: NONE
submitted_at: 2025-05-05T04:09:59Z
user: login: Dprof-in-tech
body: Thank you for your contribution
state: APPROVED
author_association: COLLABORATOR
submitted_at: 2025-05-05T16:42:13Z

Review comments:
diff_hunk: @@ -1,28 +1,100 @@
 "use client";
 import XZBInterface from "@/app/components/claim-burn";
 import { useTheme } from "@/app/ThemeContext";
-import { useAccount } from "@starknet-react/core";
-
+import { useAccount, useContract } from "@starknet-react/core";
+import { useState } from "react";
+import { shortString } from "starknet";
 
 const Index = () => {
-  const {isConnected} = useAccount()
+  const { isConnected, address, account } = useAccount();
   const { isDarkMode } = useTheme();
+  const [isLoading, setIsLoading] = useState(false);
 
   const tokenData = {
     available: 2468,
     balance: 12468,
     usdValue: 2475,
   };
 
-  const handleClaim = (asset: string) => {
-    console.log("Claiming with asset:", asset);
-  };
+  // Contract address - replace with your actual deployed contract address
+  const contractAddress = "0x06799866e50962817ce737ed1c2611e64fdfd34a1934edd3960322e79a22fd96"; // Example address, replace with actual
+
+  // Initialize contract
+  const { contract } = useContract({
+    address: contractAddress,
+    abi: [
+      {
+        name: "burn",
+        type: "function",
+        inputs: [
+          { name: "amount", type: "felt" },
+          { name: "asset", type: "felt" }
+        ],
+        outputs: [],
+        state_mutability: "external"
+      }
+    ]
+  });
path: app/dashboard/claim-burn/page.tsx
user: login: coderabbitai[bot]
body: _🛠️ Refactor suggestion_

**Hardcoded contract address needs to be environment-specific.**

The contract address is hardcoded, which could cause issues when deploying to different environments.

Consider using environment variables for contract addresses:

```diff
-// Contract address - replace with your actual deployed contract address
-const contractAddress = "0x06799866e50962817ce737ed1c2611e64fdfd34a1934edd3960322e79a22fd96"; // Example address, replace with actual
+// Contract address from environment variables
+const contractAddress = process.env.NEXT_PUBLIC_ZEROX_L2_CONTRACT_ADDRESS || "";
```

Also consider creating a separate constants file for contract ABIs to improve maintainability.


<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

`````suggestion
  // Contract address from environment variables
  const contractAddress = process.env.NEXT_PUBLIC_ZEROX_L2_CONTRACT_ADDRESS || "";

  // Initialize contract
  const { contract } = useContract({
    address: contractAddress,
    abi: [
      {
        name: "burn",
        type: "function",
        inputs: [
          { name: "amount", type: "felt" },
          { name: "asset", type: "felt" }
        ],
        outputs: [],
        state_mutability: "external"
      }
    ]
  });
`````

</details>

<!-- suggestion_end -->

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-04-30T17:30:59Z
author_association: NONE
diff_hunk: @@ -1,28 +1,100 @@
 "use client";
 import XZBInterface from "@/app/components/claim-burn";
 import { useTheme } from "@/app/ThemeContext";
-import { useAccount } from "@starknet-react/core";
-
+import { useAccount, useContract } from "@starknet-react/core";
+import { useState } from "react";
+import { shortString } from "starknet";
 
 const Index = () => {
-  const {isConnected} = useAccount()
+  const { isConnected, address, account } = useAccount();
   const { isDarkMode } = useTheme();
+  const [isLoading, setIsLoading] = useState(false);
 
   const tokenData = {
     available: 2468,
     balance: 12468,
     usdValue: 2475,
   };
 
-  const handleClaim = (asset: string) => {
-    console.log("Claiming with asset:", asset);
-  };
+  // Contract address - replace with your actual deployed contract address
+  const contractAddress = "0x06799866e50962817ce737ed1c2611e64fdfd34a1934edd3960322e79a22fd96"; // Example address, replace with actual
+
+  // Initialize contract
+  const { contract } = useContract({
+    address: contractAddress,
+    abi: [
+      {
+        name: "burn",
+        type: "function",
+        inputs: [
+          { name: "amount", type: "felt" },
+          { name: "asset", type: "felt" }
+        ],
+        outputs: [],
+        state_mutability: "external"
+      }
+    ]
+  });
 
-  const handleBurn = (amount: string, asset: string) => {
-    console.log("Burning amount:", amount, "for asset:", asset);
+  const handleClaim = async (asset: string) => {
+    try {
+      setIsLoading(true);
+      // Implement claim logic here
+      console.log("Claiming with asset:", asset);
+    } catch (error) {
+      console.error("Error claiming:", error);
+    } finally {
+      setIsLoading(false);
+    }
   };
 
+  const handleBurn = async (amount: string, asset: string) => {
+    try {
+      setIsLoading(true);
+      if (!address) {
+        throw new Error("No wallet connected");
+      }
+
+      if (!contract) {
+        throw new Error("Contract not initialized");
+      }
+
+      if (!account) {
+        throw new Error("No account available");
+      }
+
+      // Validate amount
+      const parsedAmount = parseFloat(amount);
+      if (isNaN(parsedAmount) || parsedAmount <= 0) {
+        throw new Error("Invalid amount");
+      }
 
+      // Convert amount to the correct format for the contract
+      const amountInWei = BigInt(Math.floor(parsedAmount * 1e18)).toString();
+
+      // Validate asset
+      if (!asset) {
+        throw new Error("No asset selected");
+      }
+
+      // Convert asset to felt
+      const assetFelt = shortString.encodeShortString(asset);
+
+      // Call the burn function using the account
+      const result = await account.execute({
+        contractAddress,
+        entrypoint: "burn",
+        calldata: [amountInWei, assetFelt]
+      });
+
+      console.log("Burn transaction:", result);
+    } catch (error) {
+      console.error("Error burning tokens:", error);
+      // You might want to show this error to the user
+    } finally {
+      setIsLoading(false);
+    }
path: app/dashboard/claim-burn/page.tsx
user: login: coderabbitai[bot]
body: _🛠️ Refactor suggestion_

**Contract execution lacks transaction confirmation and user feedback.**

The code executes the transaction but doesn't wait for confirmation or provide user feedback about transaction status.

Consider enhancing the transaction handling:

```diff
// Call the burn function using the account
const result = await account.execute({
  contractAddress,
  entrypoint: "burn",
  calldata: [amountInWei, assetFelt]
});

console.log("Burn transaction:", result);
+
+// Add transaction tracking
+try {
+  // Wait for transaction to be confirmed
+  await provider.waitForTransaction(result.transaction_hash);
+  console.log("Transaction confirmed:", result.transaction_hash);
+  
+  // You can add UI notification or state update here to indicate success
+} catch (txError) {
+  console.error("Transaction failed:", txError);
+  throw new Error("Transaction failed to confirm. Please check explorer for details.");
+}
```


<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

`````suggestion
      // Call the burn function using the account
      const result = await account.execute({
        contractAddress,
        entrypoint: "burn",
        calldata: [amountInWei, assetFelt]
      });

      console.log("Burn transaction:", result);

      // Add transaction tracking
      try {
        // Wait for transaction to be confirmed
        await provider.waitForTransaction(result.transaction_hash);
        console.log("Transaction confirmed:", result.transaction_hash);
        
        // You can add UI notification or state update here to indicate success
      } catch (txError) {
        console.error("Transaction failed:", txError);
        throw new Error("Transaction failed to confirm. Please check explorer for details.");
      }
    } catch (error) {
      console.error("Error burning tokens:", error);
      // You might want to show this error to the user
    } finally {
      setIsLoading(false);
    }
`````

</details>

<!-- suggestion_end -->

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-04-30T17:31:00Z
author_association: NONE
diff_hunk: @@ -1,28 +1,100 @@
 "use client";
 import XZBInterface from "@/app/components/claim-burn";
 import { useTheme } from "@/app/ThemeContext";
-import { useAccount } from "@starknet-react/core";
-
+import { useAccount, useContract } from "@starknet-react/core";
+import { useState } from "react";
+import { shortString } from "starknet";
 
 const Index = () => {
-  const {isConnected} = useAccount()
+  const { isConnected, address, account } = useAccount();
   const { isDarkMode } = useTheme();
+  const [isLoading, setIsLoading] = useState(false);
 
   const tokenData = {
     available: 2468,
     balance: 12468,
     usdValue: 2475,
   };
 
-  const handleClaim = (asset: string) => {
-    console.log("Claiming with asset:", asset);
-  };
+  // Contract address - replace with your actual deployed contract address
+  const contractAddress = "0x06799866e50962817ce737ed1c2611e64fdfd34a1934edd3960322e79a22fd96"; // Example address, replace with actual
+
+  // Initialize contract
+  const { contract } = useContract({
+    address: contractAddress,
+    abi: [
+      {
+        name: "burn",
+        type: "function",
+        inputs: [
+          { name: "amount", type: "felt" },
+          { name: "asset", type: "felt" }
+        ],
+        outputs: [],
+        state_mutability: "external"
+      }
+    ]
+  });
 
-  const handleBurn = (amount: string, asset: string) => {
-    console.log("Burning amount:", amount, "for asset:", asset);
+  const handleClaim = async (asset: string) => {
+    try {
+      setIsLoading(true);
+      // Implement claim logic here
+      console.log("Claiming with asset:", asset);
+    } catch (error) {
+      console.error("Error claiming:", error);
+    } finally {
+      setIsLoading(false);
+    }
   };
path: app/dashboard/claim-burn/page.tsx
user: login: coderabbitai[bot]
body: _⚠️ Potential issue_

**Incomplete implementation of claim functionality.**

The `handleClaim` function is set up correctly with loading state management, but the actual claim logic is missing.

The function currently only logs to console without implementing the actual token claiming functionality. Based on the PR objectives, you need to implement the L1 contract interaction here:

```diff
const handleClaim = async (asset: string) => {
  try {
    setIsLoading(true);
-   // Implement claim logic here
-   console.log("Claiming with asset:", asset);
+   if (!address) {
+     throw new Error("No wallet connected");
+   }
+
+   // L1 contract interaction would go here
+   // Consider using ethers.js or web3.js for L1 interaction
+   
+   // Example implementation:
+   // const l1Provider = new ethers.providers.Web3Provider(window.ethereum);
+   // const l1Signer = l1Provider.getSigner();
+   // const l1Contract = new ethers.Contract(L1_CONTRACT_ADDRESS, L1_ABI, l1Signer);
+   // const tx = await l1Contract.claimTokens(asset);
+   // await tx.wait();
+   
+   console.log("Successfully claimed tokens for asset:", asset);
  } catch (error) {
    console.error("Error claiming:", error);
+   // Consider adding user-friendly error messaging here
  } finally {
    setIsLoading(false);
  }
};
```


<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

`````suggestion
  const handleClaim = async (asset: string) => {
    try {
      setIsLoading(true);
      if (!address) {
        throw new Error("No wallet connected");
      }

      // L1 contract interaction would go here
      // Consider using ethers.js or web3.js for L1 interaction

      // Example implementation:
      // const l1Provider = new ethers.providers.Web3Provider(window.ethereum);
      // const l1Signer = l1Provider.getSigner();
      // const l1Contract = new ethers.Contract(L1_CONTRACT_ADDRESS, L1_ABI, l1Signer);
      // const tx = await l1Contract.claimTokens(asset);
      // await tx.wait();

      console.log("Successfully claimed tokens for asset:", asset);
    } catch (error) {
      console.error("Error claiming:", error);
      // Consider adding user-friendly error messaging here
    } finally {
      setIsLoading(false);
    }
  };
`````

</details>

<!-- suggestion_end -->

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-04-30T17:31:00Z
author_association: NONE
diff_hunk: @@ -1,28 +1,100 @@
 "use client";
 import XZBInterface from "@/app/components/claim-burn";
 import { useTheme } from "@/app/ThemeContext";
-import { useAccount } from "@starknet-react/core";
-
+import { useAccount, useContract } from "@starknet-react/core";
+import { useState } from "react";
+import { shortString } from "starknet";
 
 const Index = () => {
-  const {isConnected} = useAccount()
+  const { isConnected, address, account } = useAccount();
   const { isDarkMode } = useTheme();
+  const [isLoading, setIsLoading] = useState(false);
 
   const tokenData = {
     available: 2468,
     balance: 12468,
     usdValue: 2475,
   };
 
-  const handleClaim = (asset: string) => {
-    console.log("Claiming with asset:", asset);
-  };
+  // Contract address - replace with your actual deployed contract address
+  const contractAddress = "0x06799866e50962817ce737ed1c2611e64fdfd34a1934edd3960322e79a22fd96"; // Example address, replace with actual
+
+  // Initialize contract
+  const { contract } = useContract({
+    address: contractAddress,
+    abi: [
+      {
+        name: "burn",
+        type: "function",
+        inputs: [
+          { name: "amount", type: "felt" },
+          { name: "asset", type: "felt" }
+        ],
+        outputs: [],
+        state_mutability: "external"
+      }
+    ]
+  });
 
-  const handleBurn = (amount: string, asset: string) => {
-    console.log("Burning amount:", amount, "for asset:", asset);
+  const handleClaim = async (asset: string) => {
+    try {
+      setIsLoading(true);
+      // Implement claim logic here
+      console.log("Claiming with asset:", asset);
+    } catch (error) {
+      console.error("Error claiming:", error);
+    } finally {
+      setIsLoading(false);
+    }
   };
 
+  const handleBurn = async (amount: string, asset: string) => {
+    try {
+      setIsLoading(true);
+      if (!address) {
+        throw new Error("No wallet connected");
+      }
+
+      if (!contract) {
+        throw new Error("Contract not initialized");
+      }
+
+      if (!account) {
+        throw new Error("No account available");
+      }
+
+      // Validate amount
+      const parsedAmount = parseFloat(amount);
+      if (isNaN(parsedAmount) || parsedAmount <= 0) {
+        throw new Error("Invalid amount");
+      }
 
+      // Convert amount to the correct format for the contract
+      const amountInWei = BigInt(Math.floor(parsedAmount * 1e18)).toString();
+
path: app/dashboard/claim-burn/page.tsx
user: login: coderabbitai[bot]
body: _🛠️ Refactor suggestion_

**Potential precision loss in amount conversion.**

Using `Math.floor` could lead to precision loss when converting amounts.

Consider using a more precise conversion approach:

```diff
-// Convert amount to the correct format for the contract
-const amountInWei = BigInt(Math.floor(parsedAmount * 1e18)).toString();
+// Convert amount to the correct format for the contract
+// Using string operations to avoid floating point precision issues
+const amountInWei = BigInt(
+  parsedAmount.toString().includes('.')
+    ? parsedAmount.toString().replace('.', '').padEnd(
+        parsedAmount.toString().length - parsedAmount.toString().indexOf('.') - 1 + 18,
+        '0'
+      )
+    : parsedAmount.toString() + '0'.repeat(18)
+).toString();
```

Alternatively, consider using a library like ethers.js `parseUnits` or a dedicated BigNumber library for more reliable handling of token amounts.


<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

`````suggestion
      // Convert amount to the correct format for the contract
      // Using string operations to avoid floating point precision issues
      const amountInWei = BigInt(
        parsedAmount.toString().includes('.')
          ? parsedAmount.toString().replace('.', '').padEnd(
              parsedAmount.toString().length - parsedAmount.toString().indexOf('.') - 1 + 18,
              '0'
            )
          : parsedAmount.toString() + '0'.repeat(18)
      ).toString();
`````

</details>

<!-- suggestion_end -->

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-04-30T17:31:00Z
author_association: NONE
diff_hunk: @@ -1,28 +1,100 @@
 "use client";
 import XZBInterface from "@/app/components/claim-burn";
 import { useTheme } from "@/app/ThemeContext";
-import { useAccount } from "@starknet-react/core";
-
+import { useAccount, useContract } from "@starknet-react/core";
+import { useState } from "react";
+import { shortString } from "starknet";
 
 const Index = () => {
-  const {isConnected} = useAccount()
+  const { isConnected, address, account } = useAccount();
   const { isDarkMode } = useTheme();
+  const [isLoading, setIsLoading] = useState(false);
 
   const tokenData = {
     available: 2468,
     balance: 12468,
     usdValue: 2475,
   };
 
-  const handleClaim = (asset: string) => {
-    console.log("Claiming with asset:", asset);
-  };
+  // Contract address - replace with your actual deployed contract address
+  const contractAddress = "0x06799866e50962817ce737ed1c2611e64fdfd34a1934edd3960322e79a22fd96"; // Example address, replace with actual
+
+  // Initialize contract
+  const { contract } = useContract({
+    address: contractAddress,
+    abi: [
+      {
+        name: "burn",
+        type: "function",
+        inputs: [
+          { name: "amount", type: "felt" },
+          { name: "asset", type: "felt" }
+        ],
+        outputs: [],
+        state_mutability: "external"
+      }
+    ]
+  });
 
-  const handleBurn = (amount: string, asset: string) => {
-    console.log("Burning amount:", amount, "for asset:", asset);
+  const handleClaim = async (asset: string) => {
+    try {
+      setIsLoading(true);
+      // Implement claim logic here
+      console.log("Claiming with asset:", asset);
+    } catch (error) {
+      console.error("Error claiming:", error);
+    } finally {
+      setIsLoading(false);
+    }
   };
 
+  const handleBurn = async (amount: string, asset: string) => {
+    try {
+      setIsLoading(true);
+      if (!address) {
+        throw new Error("No wallet connected");
+      }
+
+      if (!contract) {
+        throw new Error("Contract not initialized");
+      }
+
+      if (!account) {
+        throw new Error("No account available");
+      }
+
+      // Validate amount
+      const parsedAmount = parseFloat(amount);
+      if (isNaN(parsedAmount) || parsedAmount <= 0) {
+        throw new Error("Invalid amount");
+      }
 
+      // Convert amount to the correct format for the contract
+      const amountInWei = BigInt(Math.floor(parsedAmount * 1e18)).toString();
+
+      // Validate asset
+      if (!asset) {
+        throw new Error("No asset selected");
+      }
+
+      // Convert asset to felt
+      const assetFelt = shortString.encodeShortString(asset);
+
+      // Call the burn function using the account
+      const result = await account.execute({
+        contractAddress,
+        entrypoint: "burn",
+        calldata: [amountInWei, assetFelt]
+      });
+
+      console.log("Burn transaction:", result);
+    } catch (error) {
+      console.error("Error burning tokens:", error);
+      // You might want to show this error to the user
+    } finally {
+      setIsLoading(false);
+    }
path: app/dashboard/claim-burn/page.tsx
user: login: coderabbitai[bot]
body: _🛠️ Refactor suggestion_

**Error handling should provide user-friendly feedback.**

The current error handling only logs to console without providing user-facing error messages.

Enhance error handling with user-friendly messages:

```diff
} catch (error) {
  console.error("Error burning tokens:", error);
- // You might want to show this error to the user
+ // Extract user-friendly error message
+ let errorMessage = "Failed to burn tokens. Please try again.";
+ 
+ if (error instanceof Error) {
+   // Handle specific error types
+   if (error.message.includes("User rejected")) {
+     errorMessage = "Transaction was rejected. Please try again.";
+   } else if (error.message.includes("insufficient funds")) {
+     errorMessage = "Insufficient funds to complete this transaction.";
+   }
+ }
+ 
+ // Set error message in state for UI display
+ // Consider adding a state variable like setErrorMessage(errorMessage);
}
```


<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

`````suggestion
    } catch (error) {
      console.error("Error burning tokens:", error);
      // Extract user-friendly error message
      let errorMessage = "Failed to burn tokens. Please try again.";

      if (error instanceof Error) {
        // Handle specific error types
        if (error.message.includes("User rejected")) {
          errorMessage = "Transaction was rejected. Please try again.";
        } else if (error.message.includes("insufficient funds")) {
          errorMessage = "Insufficient funds to complete this transaction.";
        }
      }

      // Set error message in state for UI display
      // Consider adding a state variable like setErrorMessage(errorMessage);
    } finally {
      setIsLoading(false);
    }
`````

</details>

<!-- suggestion_end -->

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-04-30T17:31:00Z
author_association: NONE
diff_hunk: @@ -50,14 +51,17 @@ const XZBInterface: React.FC<XZBInterfaceProps> = ({
   onBurn,
   isConnected,
   isDarkMode,
+  isLoading,
 }) => {
   const [activeTab, setActiveTab] = useState<"claim" | "burn">("claim");
   const [selectedAsset, setSelectedAsset] = useState<Asset | null>(null);
   const [burnAmount, setBurnAmount] = useState<string>("");
   const [isAssetSelectorOpen, setIsAssetSelectorOpen] = useState(false);
+  const [hasBurned, setHasBurned] = useState(false);
 
   const calculateRedemptionAmount = (amount: string) => {
     const value = parseFloat(amount) || 0;
+    const amountInWei = BigInt(Math.floor(value * 1e18)).toString();
path: app/components/claim-burn.tsx
user: login: coderabbitai[bot]
body: _⚠️ Potential issue_

**Unused BigInt conversion in redemption calculation.**

The code converts the amount to BigInt but doesn't use it in the return value calculation.

This conversion appears to be unnecessary in this function:

```diff
const calculateRedemptionAmount = (amount: string) => {
  const value = parseFloat(amount) || 0;
-  const amountInWei = BigInt(Math.floor(value * 1e18)).toString();
  return (value * 0.97).toFixed(2); // 3% fee
};
```

If you need this conversion elsewhere, consider extracting it to a separate utility function rather than calculating it here without using it.

<!-- This is an auto-generated comment by CodeRabbit -->

✅ Addressed in commit 7d577ff
created_at: 2025-04-30T17:31:00Z
author_association: NONE
diff_hunk: @@ -0,0 +1,136 @@
+import { ethers } from "ethers";
+
+export const ZeroXBridgeL1ABI = [
+  "function registerUser(bytes calldata signature, uint256 starknetPubKey) external",
+  "function claim_tokens() external",
+  "function deposit_asset(uint8 assetType, address tokenAddress, uint256 amount, address user) external payable returns (bytes32)",
+  "function userRecord(address) external view returns (uint256)",
+  "function claimableFunds(address) external view returns (uint256)",
+  "event UserRegistered(address indexed user, uint256 starknetPubKey)",
+  "event ClaimEvent(address indexed user, uint256 amount)",
+  "event DepositEvent(address indexed token, uint8 assetType, uint256 amount, address indexed user, bytes32 commitmentHash)"
+] as const;
+
+export class ZeroXBridgeL1 extends ethers.Contract {
+  private _signer: ethers.Signer | null = null;
+
+  constructor(address: string, signerOrProvider: ethers.Signer | ethers.Provider) {
+    super(address, ZeroXBridgeL1ABI, signerOrProvider);
+    // Check if the signerOrProvider has a getAddress method (which indicates it's a signer)
+    if (signerOrProvider && typeof (signerOrProvider as any).getAddress === 'function') {
+      this._signer = signerOrProvider as ethers.Signer;
+    }
+  }
path: app/contracts/ZeroXBridgeL1.ts
user: login: coderabbitai[bot]
body: _🛠️ Refactor suggestion_

**Fragile signer-detection in constructor**

Relying on the existence of a `getAddress` function to discriminate between a `Signer` and a `Provider` is brittle: many provider subclasses expose that method (e.g. `JsonRpcProvider` with `getSigner`). Prefer the explicit `ethers.Signer.isSigner(obj)` helper (or `Signer.isSigner(obj)` in v6) to avoid false positives that will surface as late-runtime “no signer” errors inside methods such as `deposit_asset`.

```diff
-if (signerOrProvider && typeof (signerOrProvider as any).getAddress === 'function') {
-  this._signer = signerOrProvider as ethers.Signer;
-}
+if (ethers.Signer.isSigner(signerOrProvider)) {
+  this._signer = signerOrProvider;
+}
```


<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

`````suggestion
  constructor(address: string, signerOrProvider: ethers.Signer | ethers.Provider) {
    super(address, ZeroXBridgeL1ABI, signerOrProvider);
    // Check if the signerOrProvider has a getAddress method (which indicates it's a signer)
    if (ethers.Signer.isSigner(signerOrProvider)) {
      this._signer = signerOrProvider;
    }
  }
`````

</details>

<!-- suggestion_end -->

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-05-02T02:35:11Z
author_association: NONE
diff_hunk: @@ -0,0 +1,136 @@
+import { ethers } from "ethers";
+
+export const ZeroXBridgeL1ABI = [
+  "function registerUser(bytes calldata signature, uint256 starknetPubKey) external",
+  "function claim_tokens() external",
+  "function deposit_asset(uint8 assetType, address tokenAddress, uint256 amount, address user) external payable returns (bytes32)",
+  "function userRecord(address) external view returns (uint256)",
+  "function claimableFunds(address) external view returns (uint256)",
+  "event UserRegistered(address indexed user, uint256 starknetPubKey)",
+  "event ClaimEvent(address indexed user, uint256 amount)",
+  "event DepositEvent(address indexed token, uint8 assetType, uint256 amount, address indexed user, bytes32 commitmentHash)"
+] as const;
+
+export class ZeroXBridgeL1 extends ethers.Contract {
+  private _signer: ethers.Signer | null = null;
+
+  constructor(address: string, signerOrProvider: ethers.Signer | ethers.Provider) {
+    super(address, ZeroXBridgeL1ABI, signerOrProvider);
+    // Check if the signerOrProvider has a getAddress method (which indicates it's a signer)
+    if (signerOrProvider && typeof (signerOrProvider as any).getAddress === 'function') {
+      this._signer = signerOrProvider as ethers.Signer;
+    }
+  }
+
+  async registerUser(signature: string, starknetPubKey: string): Promise<ethers.ContractTransactionResponse> {
+    if (!this._signer) throw new Error("No signer available");
+    return await this.getFunction("registerUser")(signature, starknetPubKey);
+  }
+
+  async claim_tokens(): Promise<ethers.ContractTransactionResponse> {
+    if (!this._signer) throw new Error("No signer available");
+    return await this.getFunction("claim_tokens")();
+  }
+
+  async deposit_asset(
+    assetType: number,
+    tokenAddress: string,
+    amount: ethers.BigNumberish,
+    options: { value?: ethers.BigNumberish } = {}
+  ): Promise<ethers.ContractTransactionResponse> {
+    if (!this._signer) throw new Error("No signer available");
+    
+    const address = await this._signer.getAddress();
+    
+    try {
+      // Get the user's ETH balance first
+      const balance = await this._signer.provider?.getBalance(address);
+      if (!balance) throw new Error("Could not get user balance");
+
+      // Convert amount to BigInt for consistent comparison
+      const amountBigInt = ethers.getBigInt(amount);
+      
+      // For ETH deposits
+      if (assetType === 0) {
+        // Validate amount
+        if (amountBigInt <= 0n) {
+          throw new Error("Amount must be greater than 0");
+        }
+
+        // Check if user has enough ETH for the transfer
+        if (balance < amountBigInt) {
+          throw new Error(
+            `Insufficient ETH balance. You have ${ethers.formatEther(balance)} ETH but trying to send ${ethers.formatEther(amountBigInt)} ETH`
+          );
+        }
+
+        // Set value equal to amount for ETH transfers
+        options.value = amountBigInt;
+      }
+
+      // Get current gas price first
+      const feeData = await this._signer.provider?.getFeeData();
+      if (!feeData || !feeData.gasPrice) {
+        throw new Error("Could not get gas price");
+      }
+
+      // Estimate gas
+      const gasEstimate = await this.getFunction("deposit_asset").estimateGas(
+        assetType,
+        tokenAddress,
+        amount,
+        address,
+        options
+      );
path: app/contracts/ZeroXBridgeL1.ts
user: login: coderabbitai[bot]
body: _🛠️ Refactor suggestion_

**`estimateGas` call passes overrides in the wrong position**

`contract.getFunction("deposit_asset").estimateGas` expects the transaction overrides _after_ the four solidity parameters.  
Passing `options` as the 5ᵗʰ argument is correct, but **you also pass it when parameters are encoded for the real tx further below with an extra spread**.  Any properties already inside `options` (e.g. `value`) will therefore be ignored during gas estimation, yielding an underestimate for native-ETH deposits and breaking the subsequent balance checks.


```diff
-const gasEstimate = await this.getFunction("deposit_asset").estimateGas(
+const gasEstimate = await this.getFunction("deposit_asset").estimateGas(
   assetType,
   tokenAddress,
   amount,
   address,
-  options
+  { ...options }   // ensure same overrides set used for the real call
 );
```
Consider extracting a small helper to build the overrides once, then reuse it for both `estimateGas` and the actual send.


<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

`````suggestion
      const gasEstimate = await this.getFunction("deposit_asset").estimateGas(
        assetType,
        tokenAddress,
        amount,
        address,
        { ...options }   // ensure same overrides set used for the real call
      );
`````

</details>

<!-- suggestion_end -->

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-05-02T02:35:11Z
author_association: NONE
diff_hunk: @@ -0,0 +1,242 @@
+"use client";
+import React, { createContext, useContext, useEffect, useState } from "react";
+import { ethers } from "ethers";
+import { ZeroXBridgeL1 } from "../contracts/ZeroXBridgeL1";
+
+interface EthereumContextType {
+  provider: ethers.BrowserProvider | null;
+  signer: ethers.JsonRpcSigner | null;
+  address: string | null;
+  isConnected: boolean;
+  connect: () => Promise<void>;
+  disconnect: () => void;
+  registerUser: (starknetPubKey: string) => Promise<void>;
+  claimTokens: () => Promise<void>;
+  depositAsset: (assetType: number, tokenAddress: string, amount: string) => Promise<string>;
+}
+
+const EthereumContext = createContext<EthereumContextType>({
+  provider: null,
+  signer: null,
+  address: null,
+  isConnected: false,
+  connect: async () => {},
+  disconnect: () => {},
+  registerUser: async () => {},
+  claimTokens: async () => {},
+  depositAsset: async () => "",
+});
+
+export function useEthereum() {
+  return useContext(EthereumContext);
+}
+
+export function EthereumProvider({ children }: { children: React.ReactNode }) {
+  const [provider, setProvider] = useState<ethers.BrowserProvider | null>(null);
+  const [signer, setSigner] = useState<ethers.JsonRpcSigner | null>(null);
+  const [address, setAddress] = useState<string | null>(null);
+  const [isConnected, setIsConnected] = useState(false);
+  const [contract, setContract] = useState<ZeroXBridgeL1 | null>(null);
+
+  // Contract address - replace with your deployed contract address
+  const contractAddress = "0x0000000000000000000000000000000000000000";
path: app/components/Ethereum-provider.tsx
user: login: coderabbitai[bot]
body: _⚠️ Potential issue_

**Placeholder contract address will break production**

`0x000…000` is used as a stub but every contract interaction (burn, claim, register) will revert against the zero-address.  
Expose this value through environment variables (e.g. `process.env.NEXT_PUBLIC_L1_BRIDGE_ADDR`) or configuration to avoid accidental main-net deploys with an invalid address.

```diff
-const contractAddress = "0x0000000000000000000000000000000000000000";
+const contractAddress = process.env.NEXT_PUBLIC_L1_BRIDGE_ADDR as string;
+if (!ethers.isAddress(contractAddress)) {
+  throw new Error("Missing or invalid L1 bridge address (NEXT_PUBLIC_L1_BRIDGE_ADDR)");
+}
```


<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

`````suggestion
  const contractAddress = process.env.NEXT_PUBLIC_L1_BRIDGE_ADDR as string;
  if (!ethers.isAddress(contractAddress)) {
    throw new Error("Missing or invalid L1 bridge address (NEXT_PUBLIC_L1_BRIDGE_ADDR)");
  }
`````

</details>

<!-- suggestion_end -->

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-05-02T02:35:11Z
author_association: NONE
diff_hunk: @@ -0,0 +1,242 @@
+"use client";
+import React, { createContext, useContext, useEffect, useState } from "react";
+import { ethers } from "ethers";
+import { ZeroXBridgeL1 } from "../contracts/ZeroXBridgeL1";
+
+interface EthereumContextType {
+  provider: ethers.BrowserProvider | null;
+  signer: ethers.JsonRpcSigner | null;
+  address: string | null;
+  isConnected: boolean;
+  connect: () => Promise<void>;
+  disconnect: () => void;
+  registerUser: (starknetPubKey: string) => Promise<void>;
+  claimTokens: () => Promise<void>;
+  depositAsset: (assetType: number, tokenAddress: string, amount: string) => Promise<string>;
+}
+
+const EthereumContext = createContext<EthereumContextType>({
+  provider: null,
+  signer: null,
+  address: null,
+  isConnected: false,
+  connect: async () => {},
+  disconnect: () => {},
+  registerUser: async () => {},
+  claimTokens: async () => {},
+  depositAsset: async () => "",
+});
+
+export function useEthereum() {
+  return useContext(EthereumContext);
+}
+
+export function EthereumProvider({ children }: { children: React.ReactNode }) {
+  const [provider, setProvider] = useState<ethers.BrowserProvider | null>(null);
+  const [signer, setSigner] = useState<ethers.JsonRpcSigner | null>(null);
+  const [address, setAddress] = useState<string | null>(null);
+  const [isConnected, setIsConnected] = useState(false);
+  const [contract, setContract] = useState<ZeroXBridgeL1 | null>(null);
+
+  // Contract address - replace with your deployed contract address
+  const contractAddress = "0x0000000000000000000000000000000000000000";
+
+  useEffect(() => {
+    // Check if MetaMask is installed
+    if (typeof window.ethereum !== "undefined") {
+      try {
+        const provider = new ethers.BrowserProvider(window.ethereum);
+        setProvider(provider);
+
+        // Check if already connected
+        window.ethereum.request({ method: "eth_accounts" }).then((accounts: string[]) => {
+          if (accounts.length > 0) {
+            handleConnect(provider);
+          }
+        });
+
+        // Listen for account changes
+        window.ethereum.on("accountsChanged", (accounts: string[]) => {
+          if (accounts.length === 0) {
+            handleDisconnect();
+          } else {
+            handleConnect(provider);
+          }
+        });
+      } catch (error) {
+        console.error("Error initializing Ethereum provider:", error);
+      }
+    } else {
+      console.error("MetaMask is not installed");
+    }
+
+    return () => {
+      if (window.ethereum) {
+        window.ethereum.removeAllListeners();
+      }
+    };
path: app/components/Ethereum-provider.tsx
user: login: coderabbitai[bot]
body: _🛠️ Refactor suggestion_

**`removeAllListeners()` wipes unrelated listeners**

Calling `window.ethereum.removeAllListeners()` on unmount indiscriminately removes handlers added by _other_ parts of the dApp (or even third-party libraries).


Store the concrete callbacks you register (`onAccountsChanged`, …) and detach them individually:

```diff
- window.ethereum.removeAllListeners();
+ window.ethereum.removeListener("accountsChanged", accountsChangedCb);
```


<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

`````suggestion
      if (window.ethereum) {
-        window.ethereum.removeAllListeners();
+        window.ethereum.removeListener("accountsChanged", accountsChangedCb);
      }
    };
`````

</details>

<!-- suggestion_end -->

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-05-02T02:35:11Z
author_association: NONE
diff_hunk: @@ -0,0 +1,242 @@
+"use client";
+import React, { createContext, useContext, useEffect, useState } from "react";
+import { ethers } from "ethers";
+import { ZeroXBridgeL1 } from "../contracts/ZeroXBridgeL1";
+
+interface EthereumContextType {
+  provider: ethers.BrowserProvider | null;
+  signer: ethers.JsonRpcSigner | null;
+  address: string | null;
+  isConnected: boolean;
+  connect: () => Promise<void>;
+  disconnect: () => void;
+  registerUser: (starknetPubKey: string) => Promise<void>;
+  claimTokens: () => Promise<void>;
+  depositAsset: (assetType: number, tokenAddress: string, amount: string) => Promise<string>;
+}
+
+const EthereumContext = createContext<EthereumContextType>({
+  provider: null,
+  signer: null,
+  address: null,
+  isConnected: false,
+  connect: async () => {},
+  disconnect: () => {},
+  registerUser: async () => {},
+  claimTokens: async () => {},
+  depositAsset: async () => "",
+});
+
+export function useEthereum() {
+  return useContext(EthereumContext);
+}
+
+export function EthereumProvider({ children }: { children: React.ReactNode }) {
+  const [provider, setProvider] = useState<ethers.BrowserProvider | null>(null);
+  const [signer, setSigner] = useState<ethers.JsonRpcSigner | null>(null);
+  const [address, setAddress] = useState<string | null>(null);
+  const [isConnected, setIsConnected] = useState(false);
+  const [contract, setContract] = useState<ZeroXBridgeL1 | null>(null);
+
+  // Contract address - replace with your deployed contract address
+  const contractAddress = "0x0000000000000000000000000000000000000000";
+
+  useEffect(() => {
+    // Check if MetaMask is installed
+    if (typeof window.ethereum !== "undefined") {
+      try {
+        const provider = new ethers.BrowserProvider(window.ethereum);
+        setProvider(provider);
+
+        // Check if already connected
+        window.ethereum.request({ method: "eth_accounts" }).then((accounts: string[]) => {
+          if (accounts.length > 0) {
+            handleConnect(provider);
+          }
+        });
+
+        // Listen for account changes
+        window.ethereum.on("accountsChanged", (accounts: string[]) => {
+          if (accounts.length === 0) {
+            handleDisconnect();
+          } else {
+            handleConnect(provider);
+          }
+        });
+      } catch (error) {
+        console.error("Error initializing Ethereum provider:", error);
+      }
+    } else {
+      console.error("MetaMask is not installed");
+    }
+
+    return () => {
+      if (window.ethereum) {
+        window.ethereum.removeAllListeners();
+      }
+    };
+  }, []);
+
+  const handleConnect = async (provider: ethers.BrowserProvider) => {
+    try {
+      const signer = await provider.getSigner();
+      const address = await signer.getAddress();
+      setSigner(signer);
+      setAddress(address);
+      setIsConnected(true);
+
+      // Initialize contract with signer
+      const contract = new ZeroXBridgeL1(contractAddress, signer);
+      setContract(contract);
+    } catch (error) {
+      console.error("Error in handleConnect:", error);
+      if (error instanceof Error) {
+        console.error("Error details:", {
+          name: error.name,
+          message: error.message,
+          stack: error.stack,
+          cause: error.cause
+        });
+      }
+      throw error;
+    }
+  };
+
+  const connect = async () => {
+    if (!provider) {
+      console.error("Ethereum provider not initialized");
+      return;
+    }
+
+    try {
+      // Request account access
+      const accounts = await window.ethereum.request({ method: "eth_requestAccounts" });
+      
+      if (accounts.length === 0) {
+        throw new Error("No accounts found");
+      }
+
+      await handleConnect(provider);
+    } catch (error) {
+      console.error("Error in connect:", error);
+      if (error instanceof Error) {
+        console.error("Error details:", {
+          name: error.name,
+          message: error.message,
+          stack: error.stack,
+          cause: error.cause
+        });
+      }
+      throw error;
+    }
+  };
+
+  const disconnect = () => {
+    setSigner(null);
+    setAddress(null);
+    setIsConnected(false);
+    setContract(null);
+  };
+
+  const registerUser = async (starknetPubKey: string) => {
+    if (!contract || !signer || !address) {
+      throw new Error("Contract, signer or address not initialized");
+    }
+
+    try {
+      // Create the message to sign
+      const message = ethers.solidityPackedKeccak256(
+        ["string", "address", "uint256"],
+        ["UserRegistration", address, starknetPubKey]
+      );
+
+      // Sign the message
+      const signature = await signer.signMessage(ethers.getBytes(message));
+      
+      // Convert signature to bytes
+      const signatureBytes = ethers.getBytes(signature);
+
+      // Call the contract
+      const tx = await contract.registerUser(signatureBytes, starknetPubKey);
+      await tx.wait();
+    } catch (error) {
+      console.error("Error registering user:", error);
+      if (error instanceof Error) {
+        console.error("Error details:", {
+          name: error.name,
+          message: error.message,
+          stack: error.stack,
+          cause: error.cause
+        });
+      }
+      throw error;
+    }
+  };
+
+  const claimTokens = async () => {
+    if (!contract || !signer) {
+      throw new Error("Contract or signer not initialized");
+    }
+
+    try {
+      const tx = await contract.claim_tokens();
+      await tx.wait();
+    } catch (error) {
+      console.error("Error claiming tokens:", error);
+      throw error;
+    }
+  };
+
+  const depositAsset = async (assetType: number, tokenAddress: string, amount: string) => {
+    if (!provider) {
+      throw new Error("Provider not initialized. Please connect your wallet first.");
+    }
+
+    try {
+      // Get a fresh signer
+      const currentSigner = await provider.getSigner();
+      if (!currentSigner) {
+        throw new Error("No signer available. Please connect your wallet first.");
+      }
+
+      // Initialize contract with fresh signer
+      const contract = new ZeroXBridgeL1(contractAddress, currentSigner);
+      
+      // Convert amount to BigNumber
+      const amountInWei = ethers.parseEther(amount);
+      
+      // For ETH deposits (assetType === 0), pass the same amount as both value and parameter
path: app/components/Ethereum-provider.tsx
user: login: coderabbitai[bot]
body: _🛠️ Refactor suggestion_

**`parseEther` used for every token – breaks 6-decimals tokens (USDC/USDT)**

`ethers.parseEther` assumes 18 decimals.  USDC / USDT have 6. Deposits for those assets will overshoot the desired amount by 1e12.


Introduce a `decimals` field in `Asset`, pick the right parser, and use `parseUnits(amount, decimals)`:

```diff
-const amountInWei = ethers.parseEther(amount);
+const decimals = selectedAsset?.decimals ?? 18;
+const amountInWei = ethers.parseUnits(amount, decimals);
```
Remember to propagate `decimals` through `SAMPLE_ASSETS` and ERC-20 metadata fetchers.


> Committable suggestion skipped: line range outside the PR's diff.

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-05-02T02:35:11Z
author_association: NONE
diff_hunk: @@ -64,6 +115,169 @@ const XZBInterface: React.FC<XZBInterfaceProps> = ({
   const handleAssetSelect = (asset: Asset) => {
     setSelectedAsset(asset);
     setIsAssetSelectorOpen(false);
+    setError(null);
+  };
+
+  // Update input validation
+  const handleAmountChange = (e: React.ChangeEvent<HTMLInputElement>) => {
+    const value = e.target.value;
+    if (value === "" || /^\d*\.?\d*$/.test(value)) { // Allow empty or decimal numbers
+      setBurnAmount(value);
+      
+      // Clear error if amount is valid
+      if (selectedAsset?.symbol === "ETH" && userEthBalance) {
+        const inputAmount = Number(value);
+        const maxAllowed = Number(maxAmount);
+        
+        if (inputAmount > maxAllowed) {
+          setError(`Amount exceeds available balance (${Number(userEthBalance).toFixed(5)} ETH). Please enter a smaller amount.`);
+        } else {
+          setError(null);
+        }
+      }
+    }
+  };
+
+  // Update MAX button handler
+  const handleMaxClick = () => {
+    if (selectedAsset?.symbol === "ETH" && maxAmount) {
+      setBurnAmount(maxAmount);
+      setError(null);
+    } else {
+      setBurnAmount(tokenData.balance.toString());
+    }
+  };
+
+  const handleBurn = async (amount: string, assetId: string) => {
+    try {
+      setError(null);
+      setIsProcessing(true);
+
+      // Check if wallet is connected
+      if (!isConnected) {
+        throw new Error("Please connect your wallet first");
+      }
+
+      // Check if Ethereum wallet is connected for L1
+      if (!isEthereumConnected || !ethereumAddress) {
+        try {
+          await connectEthereum();
+          await new Promise(resolve => setTimeout(resolve, 1000));
+          
+          if (!isEthereumConnected || !ethereumAddress) {
+            throw new Error("Failed to connect Ethereum wallet");
+          }
+        } catch (_) {
+          throw new Error("Please connect your Ethereum wallet first");
+        }
+      }
+
+      if (!selectedAsset) {
+        throw new Error("Please select an asset first");
+      }
+
+      if (!amount || parseFloat(amount) <= 0) {
+        throw new Error("Please enter a valid amount");
+      }
+
+      // Determine asset type (0 for ETH, 1 for ERC20)
+      const assetType = selectedAsset.symbol === "ETH" ? 0 : 1;
+      
+      // Get asset address
+      const tokenAddress = selectedAsset.address || "0x0000000000000000000000000000000000000000";
+
+      // For ETH transfers, validate balance before proceeding
+      if (assetType === 0) {
+        const balance = await provider?.getBalance(ethereumAddress);
+        if (!balance) {
+          throw new Error("Could not get your ETH balance");
+        }
+
+        const amountInWei = ethers.parseEther(amount);
+        if (balance < amountInWei) {
+          const balanceInEth = ethers.formatEther(balance);
+          throw new Error(
+            `Insufficient ETH balance. You have ${Number(balanceInEth).toFixed(5)} ETH but trying to send ${amount} ETH. Please reduce the amount or add more ETH to your wallet.`
+          );
+        }
+      }
+
path: app/components/claim-burn.tsx
user: login: coderabbitai[bot]
body: _🛠️ Refactor suggestion_

**Double ETH balance check – but none for ERC-20 allowance**

You validate ETH balance locally (`getBalance`) and the contract repeats the same check.  
For ERC-20 tokens there is _no_ allowance/ balance check, leading to inevitable on-chain reverts if the allowance is insufficient.


Add an `ERC20` allowance + balance pre-check via the token’s `balanceOf` / `allowance` to provide UX-friendly errors before the user pays gas.

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-05-02T02:35:12Z
author_association: NONE
diff_hunk: @@ -0,0 +1,103 @@
+"use client";
+
+import { createContext, useContext, useEffect, useState } from "react";
+import { ethers } from "ethers";
+
+interface EthereumContextType {
+  provider: ethers.BrowserProvider | null;
+  signer: ethers.JsonRpcSigner | null;
+  isConnected: boolean;
+  connectWallet: () => Promise<void>;
+  address: string | null;
+}
+
+const EthereumContext = createContext<EthereumContextType>({
+  provider: null,
+  signer: null,
+  isConnected: false,
+  connectWallet: async () => {},
+  address: null,
+});
+
+export const EthereumProvider = ({ children }: { children: React.ReactNode }) => {
+  const [provider, setProvider] = useState<ethers.BrowserProvider | null>(null);
+  const [signer, setSigner] = useState<ethers.JsonRpcSigner | null>(null);
+  const [isConnected, setIsConnected] = useState(false);
+  const [address, setAddress] = useState<string | null>(null);
+
+  const connectWallet = async () => {
+    try {
+      if (typeof window.ethereum === "undefined") {
+        throw new Error("Please install MetaMask");
+      }
+
+      const provider = new ethers.BrowserProvider(window.ethereum);
+      await provider.send("eth_requestAccounts", []);
+      const signer = await provider.getSigner();
+      const address = await signer.getAddress();
+
+      setProvider(provider);
+      setSigner(signer);
+      setAddress(address);
+      setIsConnected(true);
+    } catch (error) {
+      console.error("Error connecting wallet:", error);
+    }
+  };
+
+  useEffect(() => {
+    const checkConnection = async () => {
+      if (typeof window.ethereum !== "undefined") {
+        const provider = new ethers.BrowserProvider(window.ethereum);
+        const accounts = await provider.send("eth_accounts", []);
+        
+        if (accounts.length > 0) {
+          const signer = await provider.getSigner();
+          const address = await signer.getAddress();
+          
+          setProvider(provider);
+          setSigner(signer);
+          setAddress(address);
+          setIsConnected(true);
+        }
+      }
+    };
+
+    checkConnection();
+
+    // Listen for account changes
+    if (window.ethereum) {
+      window.ethereum.on("accountsChanged", () => {
+        checkConnection();
+      });
+    }
+
+    return () => {
+      if (window.ethereum) {
+        window.ethereum.removeListener("accountsChanged", checkConnection);
+      }
+    };
path: app/components/Ethereum-provider.tsx
user: login: coderabbitai[bot]
body: _⚠️ Potential issue_

**Fix event listener cleanup to use the same function reference.**

The current implementation registers an anonymous function as the event handler but tries to remove `checkConnection` directly in the cleanup, which won't work because they're different function references. Instead, you should store and remove the same function reference.


```diff
  // Listen for account changes
  if (window.ethereum) {
-    window.ethereum.on("accountsChanged", () => {
-      checkConnection();
-    });
+    const handleAccountsChanged = () => {
+      checkConnection();
+    };
+    window.ethereum.on("accountsChanged", handleAccountsChanged);
+
+    return () => {
+      if (window.ethereum) {
+        window.ethereum.removeListener("accountsChanged", handleAccountsChanged);
+      }
+    };
  }

- return () => {
-   if (window.ethereum) {
-     window.ethereum.removeListener("accountsChanged", checkConnection);
-   }
- };
```


<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

`````suggestion
    // Listen for account changes
    if (window.ethereum) {
      const handleAccountsChanged = () => {
        checkConnection();
      };
      window.ethereum.on("accountsChanged", handleAccountsChanged);

      return () => {
        if (window.ethereum) {
          window.ethereum.removeListener("accountsChanged", handleAccountsChanged);
        }
      };
    }
`````

</details>

<!-- suggestion_end -->

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-05-05T04:09:58Z
author_association: NONE
diff_hunk: @@ -0,0 +1,103 @@
+"use client";
+
+import { createContext, useContext, useEffect, useState } from "react";
+import { ethers } from "ethers";
+
+interface EthereumContextType {
+  provider: ethers.BrowserProvider | null;
+  signer: ethers.JsonRpcSigner | null;
+  isConnected: boolean;
+  connectWallet: () => Promise<void>;
+  address: string | null;
+}
+
+const EthereumContext = createContext<EthereumContextType>({
+  provider: null,
+  signer: null,
+  isConnected: false,
+  connectWallet: async () => {},
+  address: null,
+});
+
+export const EthereumProvider = ({ children }: { children: React.ReactNode }) => {
+  const [provider, setProvider] = useState<ethers.BrowserProvider | null>(null);
+  const [signer, setSigner] = useState<ethers.JsonRpcSigner | null>(null);
+  const [isConnected, setIsConnected] = useState(false);
+  const [address, setAddress] = useState<string | null>(null);
+
+  const connectWallet = async () => {
+    try {
+      if (typeof window.ethereum === "undefined") {
+        throw new Error("Please install MetaMask");
+      }
+
+      const provider = new ethers.BrowserProvider(window.ethereum);
+      await provider.send("eth_requestAccounts", []);
+      const signer = await provider.getSigner();
+      const address = await signer.getAddress();
+
+      setProvider(provider);
+      setSigner(signer);
+      setAddress(address);
+      setIsConnected(true);
+    } catch (error) {
+      console.error("Error connecting wallet:", error);
+    }
+  };
+
+  useEffect(() => {
+    const checkConnection = async () => {
+      if (typeof window.ethereum !== "undefined") {
+        const provider = new ethers.BrowserProvider(window.ethereum);
+        const accounts = await provider.send("eth_accounts", []);
+        
+        if (accounts.length > 0) {
+          const signer = await provider.getSigner();
+          const address = await signer.getAddress();
+          
+          setProvider(provider);
+          setSigner(signer);
+          setAddress(address);
+          setIsConnected(true);
+        }
+      }
+    };
+
+    checkConnection();
+
+    // Listen for account changes
+    if (window.ethereum) {
+      window.ethereum.on("accountsChanged", () => {
+        checkConnection();
+      });
+    }
+
+    return () => {
+      if (window.ethereum) {
+        window.ethereum.removeListener("accountsChanged", checkConnection);
+      }
+    };
+  }, []);
path: app/components/Ethereum-provider.tsx
user: login: coderabbitai[bot]
body: _🛠️ Refactor suggestion_

**Add network/chain validation and event handling.**

The current implementation doesn't validate if the user is connected to the correct network or handle network changes. This could lead to failed transactions if the user is on the wrong network.


Add network validation and chain change handling:

```diff
useEffect(() => {
  const checkConnection = async () => {
    if (typeof window.ethereum !== "undefined") {
      const provider = new ethers.BrowserProvider(window.ethereum);
      const accounts = await provider.send("eth_accounts", []);
+     
+     // Check if user is on the correct network
+     const network = await provider.getNetwork();
+     const isCorrectNetwork = network.chainId === BigInt(process.env.NEXT_PUBLIC_REQUIRED_CHAIN_ID || '1'); // Default to mainnet
      
      if (accounts.length > 0) {
        const signer = await provider.getSigner();
        const address = await signer.getAddress();
        
        setProvider(provider);
        setSigner(signer);
        setAddress(address);
        setIsConnected(true);
+       setIsCorrectNetwork(isCorrectNetwork);
      }
    }
  };

  checkConnection();

  // Listen for account changes
  if (window.ethereum) {
    const handleAccountsChanged = () => {
      checkConnection();
    };
    window.ethereum.on("accountsChanged", handleAccountsChanged);
    
+   // Listen for chain/network changes
+   const handleChainChanged = () => {
+     checkConnection();
+   };
+   window.ethereum.on("chainChanged", handleChainChanged);

    return () => {
      if (window.ethereum) {
        window.ethereum.removeListener("accountsChanged", handleAccountsChanged);
+       window.ethereum.removeListener("chainChanged", handleChainChanged);
      }
    };
  }
}, []);
```

Don't forget to add the corresponding state variable:

```diff
const [isConnected, setIsConnected] = useState(false);
const [address, setAddress] = useState<string | null>(null);
+ const [isCorrectNetwork, setIsCorrectNetwork] = useState(false);
```

And update the context interface and provider:

```diff
interface EthereumContextType {
  provider: ethers.BrowserProvider | null;
  signer: ethers.JsonRpcSigner | null;
  isConnected: boolean;
  connectWallet: () => Promise<void>;
  address: string | null;
+ isCorrectNetwork: boolean;
+ switchNetwork: () => Promise<void>;
}

// Add the switchNetwork function to the component
const switchNetwork = async () => {
  if (!window.ethereum) return;
  
  try {
    await window.ethereum.request({
      method: 'wallet_switchEthereumChain',
      params: [{ chainId: `0x${parseInt(process.env.NEXT_PUBLIC_REQUIRED_CHAIN_ID || '1').toString(16)}` }],
    });
  } catch (error) {
    console.error('Failed to switch network:', error);
  }
};

// Update the context value
<EthereumContext.Provider
  value={{
    provider,
    signer,
    isConnected,
    connectWallet,
    address,
+   isCorrectNetwork,
+   switchNetwork,
  }}
>
```

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-05-05T04:09:58Z
author_association: NONE

PR comments:
user: login: coderabbitai[bot]
created_at: 2025-04-30T17:28:01Z
body: <!-- This is an auto-generated comment: summarize by coderabbit.ai -->
<!-- walkthrough_start -->

## Walkthrough

The changes introduce a two-step claim and burn workflow for token redemption in the frontend. The `XZBInterface` component and its props are updated to handle loading states and track whether the burn step has been completed. The main dashboard page now integrates with the relevant smart contract's `burn` function, validates user inputs, manages asynchronous operations, and provides user feedback through loading indicators and warnings. The UI enforces the correct sequence by requiring users to burn tokens before claiming and disables actions during processing. Error handling and contract interaction logic are implemented for both burn and claim operations.

## Changes

| File(s)                                           | Change Summary                                                                                                   |
|--------------------------------------------------|-----------------------------------------------------------------------------------------------------------------|
| app/components/claim-burn.tsx                     | Extended `XZBInterfaceProps` with `isLoading`; added `hasBurned` state; introduced `handleBurn`; updated UI to enforce burn-before-claim, manage loading state, and display warnings. |
| app/dashboard/claim-burn/page.tsx                 | Added contract interaction for `burn`; implemented loading state; validated wallet/account/inputs; handled async operations and error logging; passed `isLoading` to child component. |
| app/components/Ethereum-provider.tsx              | Added Ethereum context provider managing wallet connection, contract interaction, and exposing functions for connect, disconnect, registerUser, claimTokens, and depositAsset with detailed error handling. |
| app/contracts/ZeroXBridgeL1.ts                     | Added typed contract wrapper class with methods for user registration, token claiming, and asset depositing including balance and gas fee checks, plus ABI export. |

## Sequence Diagram(s)

```mermaid
sequenceDiagram
    participant User
    participant XZBInterface (UI)
    participant DashboardPage
    participant Contract

    User->>XZBInterface (UI): Enter amount & asset, click "Burn"
    XZBInterface (UI)->>DashboardPage: handleBurn(amount, asset)
    DashboardPage->>Contract: burn(amount, asset) (async)
    Contract-->>DashboardPage: Transaction result
    DashboardPage-->>XZBInterface (UI): Update hasBurned, set isLoading=false

    User->>XZBInterface (UI): Click "Claim" (after burn)
    XZBInterface (UI)->>DashboardPage: handleClaim(asset)
    DashboardPage->>Contract: claim(asset) (async)
    Contract-->>DashboardPage: Transaction result
    DashboardPage-->>XZBInterface (UI): Update UI, set isLoading=false
```

## Assessment against linked issues

| Objective                                                                                                 | Addressed | Explanation                                                                                   |
|-----------------------------------------------------------------------------------------------------------|-----------|-----------------------------------------------------------------------------------------------|
| Integrate with the burn function from ZeroXBridgeL2 contract (#88)                                        | ✅        |                                                                                               |
| Integrate with the claim function from ZeroXBridgeL1 contract (#88)                                       | ❓        | Claim function integration is prepared but actual contract interaction is a placeholder.       |
| Create a clear UI flow explaining the two-step process; status tracking; loading states; user guidance (#88) | ✅        |                                                                                               |
| Implement error handling and transaction feedback for burn and claim (#88)                                 | ✅        |                                                                                               |

## Poem

> In the meadow of code, a rabbit hops with glee,  
> Claim and burn now dance in seamless harmony.  
> Buttons wait their turn, as tokens take the stage,  
> Loading spinners twirl, the UI sets the gauge.  
> With every hop and click, success is in the air—  
> The bridge is strong, the process fair!  
> 🐇✨

<!-- walkthrough_end -->
<!-- This is an auto-generated comment: all tool run failures by coderabbit.ai -->

> [!WARNING]
> There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.
> 
> <details>
> <summary>🔧 ESLint</summary>
> 
> > If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.
> 
> <details>
> <summary>app/dashboard/claim-burn/page.tsx</summary>
> 
> 
> Oops! Something went wrong! :(
> 
> ESLint: 9.26.0
> 
> ESLint couldn't find the plugin "eslint-plugin-react-hooks".
> 
> (The package "eslint-plugin-react-hooks" was not found when loaded as a Node module from the directory "".)
> 
> It's likely that the plugin isn't installed correctly. Try reinstalling by running the following:
> 
>     npm install eslint-plugin-react-hooks@latest --save-dev
> 
> The plugin "eslint-plugin-react-hooks" was referenced from the config file in " » eslint-config-next/core-web-vitals » /node_modules/.pnpm/eslint-config-next@15.1.7_eslint@9.26.0_typescript@5.8.3/node_modules/eslint-config-next/index.js".
> 
> If you still can't figure out the problem, please see https://eslint.org/docs/latest/use/troubleshooting.
> 
> 
> </details>
> 
> </details>

<!-- end of auto-generated comment: all tool run failures by coderabbit.ai -->


---

<details>
<summary>📜 Recent review details</summary>

**Configuration used: CodeRabbit UI**
**Review profile: CHILL**
**Plan: Pro**

<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between 013019170e1471cd03307b87a124be4b91caa254 and e741e2b324823e3bf858b8851cfbaf0591dc478b.

</details>

<details>
<summary>📒 Files selected for processing (1)</summary>

* `app/dashboard/claim-burn/page.tsx` (3 hunks)

</details>

<details>
<summary>🚧 Files skipped from review as they are similar to previous changes (1)</summary>

* app/dashboard/claim-burn/page.tsx

</details>

</details>
<!-- internal state start -->


<!-- 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 -->

<!-- internal state end -->
<!-- finishing_touch_checkbox_start -->

<details open="true">
<summary>✨ Finishing Touches</summary>

- [ ] <!-- {"checkboxId": "7962f53c-55bc-4827-bfbf-6a18da830691"} --> 📝 Generate Docstrings

</details>

<!-- finishing_touch_checkbox_end -->
<!-- tips_start -->

---

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.

<details>
<summary>❤️ Share</summary>

- [X](https://twitter.com/intent/tweet?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A&url=https%3A//coderabbit.ai)
- [Mastodon](https://mastodon.social/share?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A%20https%3A%2F%2Fcoderabbit.ai)
- [Reddit](https://www.reddit.com/submit?title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&text=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code.%20Check%20it%20out%3A%20https%3A//coderabbit.ai)
- [LinkedIn](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fcoderabbit.ai&mini=true&title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&summary=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code)

</details>

<details>
<summary>🪧 Tips</summary>

### Chat

There are 3 ways to chat with [CodeRabbit](https://coderabbit.ai?utm_source=oss&utm_medium=github&utm_campaign=Explore-Beyond-Innovations/ZeroXBridge_Frontend&utm_content=96):

- Review comments: Directly reply to a review comment made by CodeRabbit. Example:
  - `I pushed a fix in commit <commit_id>, please review it.`
  - `Generate unit testing code for this file.`
  - `Open a follow-up GitHub issue for this discussion.`
- Files and specific lines of code (under the "Files changed" tab): Tag `@coderabbitai` in a new review comment at the desired location with your query. Examples:
  - `@coderabbitai generate unit testing code for this file.`
  -	`@coderabbitai modularize this function.`
- PR comments: Tag `@coderabbitai` in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
  - `@coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.`
  - `@coderabbitai read src/utils.ts and generate unit testing code.`
  - `@coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.`
  - `@coderabbitai help me debug CodeRabbit configuration file.`

### Support

Need help? Create a ticket on our [support page](https://www.coderabbit.ai/contact-us/support) for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

### CodeRabbit Commands (Invoked using PR comments)

- `@coderabbitai pause` to pause the reviews on a PR.
- `@coderabbitai resume` to resume the paused reviews.
- `@coderabbitai review` to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
- `@coderabbitai full review` to do a full review from scratch and review all the files again.
- `@coderabbitai summary` to regenerate the summary of the PR.
- `@coderabbitai generate docstrings` to [generate docstrings](https://docs.coderabbit.ai/finishing-touches/docstrings) for this PR.
- `@coderabbitai generate sequence diagram` to generate a sequence diagram of the changes in this PR.
- `@coderabbitai resolve` resolve all the CodeRabbit review comments.
- `@coderabbitai configuration` to show the current CodeRabbit configuration for the repository.
- `@coderabbitai help` to get help.

### Other keywords and placeholders

- Add `@coderabbitai ignore` anywhere in the PR description to prevent this PR from being reviewed.
- Add `@coderabbitai summary` to generate the high-level summary at a specific location in the PR description.
- Add `@coderabbitai` anywhere in the PR title to generate the title automatically.

### CodeRabbit Configuration File (`.coderabbit.yaml`)

- You can programmatically configure CodeRabbit by adding a `.coderabbit.yaml` file to the root of your repository.
- Please see the [configuration documentation](https://docs.coderabbit.ai/guides/configure-coderabbit) for more information.
- If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: `# yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json`

### Documentation and Community

- Visit our [Documentation](https://docs.coderabbit.ai) for detailed information on how to use CodeRabbit.
- Join our [Discord Community](http://discord.gg/coderabbit) to get help, request features, and share feedback.
- Follow us on [X/Twitter](https://twitter.com/coderabbitai) for updates and announcements.

</details>

<!-- tips_end -->
author_association: NONE
user: login: Dprof-in-tech
created_at: 2025-05-01T11:53:10Z
body: in the main branch, there has been a code update with a hooks file that manages the account states for each wallet, you might want to check it out
author_association: COLLABORATOR
user: login: kimcascante
created_at: 2025-05-02T02:31:27Z
body: @Dprof-in-tech could you please review again?



https://github.com/user-attachments/assets/be74ca0c-155a-464a-9fb9-3beedaf963d5


author_association: CONTRIBUTOR
user: login: Dprof-in-tech
created_at: 2025-05-02T05:55:25Z
body: hey, please can you send me a text on telegram?

https://t.me/dprof_in_tech
author_association: COLLABORATOR