Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 57 additions & 23 deletions frontend/src/page/CreateInvoice.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ function CreateInvoice() {
};

processUrlToken();
}, [searchParams, tokens, loadingTokens, account.address]);
}, [searchParams, walletClient, tokens, loadingTokens, account.address]);

useEffect(() => {
const total = itemData.reduce((sum, item) => {
Expand Down Expand Up @@ -236,31 +236,65 @@ function CreateInvoice() {
]);
};

const verifyToken = async (address) => {
setTokenVerificationState("verifying");

try {
if (typeof window !== "undefined" && window.ethereum) {
const provider = new BrowserProvider(window.ethereum);
const contract = new ethers.Contract(address, ERC20_ABI, provider);

const [symbol, name, decimals] = await Promise.all([
contract.symbol().catch(() => "UNKNOWN"),
contract.name().catch(() => "Unknown Token"),
contract.decimals().catch(() => 18),
]);

setVerifiedToken({ address, symbol, name, decimals });
setTokenVerificationState("success");
} else {
console.error("No Ethereum provider found");

const verifyToken = async (address, targetChainId = null) => {
setTokenVerificationState("verifying");

// Determine which chain to verify on
const chainIdToUse = targetChainId || searchParams.get("chain") || account?.chainId;

try {
let provider;


// for UNKNOWN symbol and name unknown update this rpc with some better one
const rpcUrls = {
1: "https://eth.llamarpc.com", // Ethereum (very fast)
61: "https://etc.rivet.link", // Ethereum Classic
137: "https://polygon.llamarpc.com", // Polygon
56: "https://bsc.llamarpc.com", // BNB Smart Chain
8453: "https://base.llamarpc.com", // Base
11155111: "https://rpc.ankr.com/eth_sepolia", // Sepolia
};
if (typeof window !== "undefined" && isConnected) {
// Fallback to wallet provider if no chainId specified
provider = new BrowserProvider(walletClient);
// If chainId is available, always use public RPC (works without wallet)
} else if (chainIdToUse) {
const rpcUrl = rpcUrls[chainIdToUse];

if (!rpcUrl) {
console.error(`Unsupported chain ${chainIdToUse}. Supported chains: Ethereum (1), Ethereum Classic (61), Polygon (137), BNB Smart Chain (56), Base (8453), Sepolia (11155111)`);
setTokenVerificationState("error");
return;
}
} catch (error) {
console.error("Verification failed:", error);
setTokenVerificationState("error");
// Use JsonRpcProvider with timeout for faster response
provider = new ethers.JsonRpcProvider(rpcUrl, Number(chainIdToUse));
}
};

const contract = new ethers.Contract(address, ERC20_ABI, provider);
Comment on lines +259 to +276
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Potential runtime error when provider is not initialized.

If the user is not connected (isConnected is false) and no chainIdToUse is available (no URL chain param and no account.chainId), then provider is never assigned. Line 276 will throw when attempting to create the contract.

Additionally, walletClient can be undefined even when isConnected is true due to async loading from useWalletClient().

🐛 Proposed fix to handle edge cases
     if (typeof window !== "undefined" && isConnected) {
-      // Fallback to wallet provider if no chainId specified
-      provider = new BrowserProvider(walletClient);
+      if (!walletClient) {
+        console.error("Wallet client not ready yet");
+        setTokenVerificationState("error");
+        return;
+      }
+      provider = new BrowserProvider(walletClient);
     // If chainId is available, always use public RPC (works without wallet)
     } else if (chainIdToUse) {
       const rpcUrl = rpcUrls[chainIdToUse];
       
       if (!rpcUrl) {
         console.error(`Unsupported chain ${chainIdToUse}. Supported chains: Ethereum (1), Ethereum Classic (61), Polygon (137), BNB Smart Chain (56), Base (8453), Sepolia (11155111)`);
         setTokenVerificationState("error");
         return;
       }
       
       // Use JsonRpcProvider with timeout for faster response
       provider = new ethers.JsonRpcProvider(rpcUrl, Number(chainIdToUse));
+    } else {
+      console.error("Cannot verify token: no wallet connected and no chain specified");
+      setTokenVerificationState("error");
+      return;
     }
📝 Committable suggestion

‼️ 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.

Suggested change
if (typeof window !== "undefined" && isConnected) {
// Fallback to wallet provider if no chainId specified
provider = new BrowserProvider(walletClient);
// If chainId is available, always use public RPC (works without wallet)
} else if (chainIdToUse) {
const rpcUrl = rpcUrls[chainIdToUse];
if (!rpcUrl) {
console.error(`Unsupported chain ${chainIdToUse}. Supported chains: Ethereum (1), Ethereum Classic (61), Polygon (137), BNB Smart Chain (56), Base (8453), Sepolia (11155111)`);
setTokenVerificationState("error");
return;
}
} catch (error) {
console.error("Verification failed:", error);
setTokenVerificationState("error");
// Use JsonRpcProvider with timeout for faster response
provider = new ethers.JsonRpcProvider(rpcUrl, Number(chainIdToUse));
}
};
const contract = new ethers.Contract(address, ERC20_ABI, provider);
if (typeof window !== "undefined" && isConnected) {
if (!walletClient) {
console.error("Wallet client not ready yet");
setTokenVerificationState("error");
return;
}
// Fallback to wallet provider if no chainId specified
provider = new BrowserProvider(walletClient);
// If chainId is available, always use public RPC (works without wallet)
} else if (chainIdToUse) {
const rpcUrl = rpcUrls[chainIdToUse];
if (!rpcUrl) {
console.error(`Unsupported chain ${chainIdToUse}. Supported chains: Ethereum (1), Ethereum Classic (61), Polygon (137), BNB Smart Chain (56), Base (8453), Sepolia (11155111)`);
setTokenVerificationState("error");
return;
}
// Use JsonRpcProvider with timeout for faster response
provider = new ethers.JsonRpcProvider(rpcUrl, Number(chainIdToUse));
} else {
console.error("Cannot verify token: no wallet connected and no chain specified");
setTokenVerificationState("error");
return;
}
const contract = new ethers.Contract(address, ERC20_ABI, provider);
🤖 Prompt for AI Agents
In `@frontend/src/page/CreateInvoice.jsx` around lines 259 - 276, The code can
call new ethers.Contract(address, ERC20_ABI, provider) with provider undefined
if neither isConnected/walletClient nor chainIdToUse/rpcUrl are available (and
walletClient can be undefined even when isConnected). Fix by
validating/initializing provider before constructing the contract: when
isConnected check that walletClient is defined before using new
BrowserProvider(walletClient) (otherwise fall back to a public JsonRpcProvider
or setTokenVerificationState("error") and return), and if !isConnected ensure
chainIdToUse exists and rpcUrls[chainIdToUse] exists; only call
ethers.Contract(address, ERC20_ABI, provider) after provider is guaranteed
non-null.


const [symbol, name, decimals] = await Promise.all([
contract.symbol().catch(() => "UNKNOWN"),
contract.name().catch(() => "Unknown Token"),
contract.decimals().catch(() => 18),
]);

console.log([symbol, name, decimals]);
setVerifiedToken({
address,
symbol,
name,
decimals: Number(decimals),
chainId: chainIdToUse
});
setTokenVerificationState("success");
} catch (error) {
console.error("Verification failed:", error);
setTokenVerificationState("error");
}
};

const createInvoiceRequest = async (data) => {
if (!isConnected || !walletClient) {
Expand Down