-
Notifications
You must be signed in to change notification settings - Fork 0
Wagmi integration (WIP) #124
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
bugbot run |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR introduces a comprehensive Wagmi integration for Formo Analytics, enabling automatic wallet event tracking with minimal setup for Web3 applications. The integration provides multiple approaches including drop-in replacement hooks and a unified provider system to accommodate different developer needs and migration strategies.
Key Changes
- Unified
WagmiFormoProvider
that combines Formo Analytics and Wagmi integration in a single provider - Drop-in replacement hooks (
useSignMessage
,useSendTransaction
) with identical APIs to Wagmi but automatic event tracking - Dynamic Wagmi imports for graceful degradation when Wagmi is not installed
Reviewed Changes
Copilot reviewed 18 out of 18 changed files in this pull request and generated 9 comments.
Show a summary per file
File | Description |
---|---|
src/integrations/wagmi/index.ts |
Main entry point exporting provider, hooks, and types for the Wagmi integration |
src/integrations/wagmi/drop-in-hooks.ts |
Drop-in replacement hooks that wrap Wagmi hooks with automatic Formo event tracking |
src/integrations/wagmi/WagmiFormoProvider.tsx |
Unified provider component that combines Formo Analytics with automatic Wagmi detection |
src/integrations/index.ts |
Integration module entry point exporting all available integrations |
src/index.ts |
Updated main entry to include integrations export |
package.json |
Added optional peer dependencies for wagmi and viem |
examples/wagmi-enhanced/ , examples/wagmi-drop-in/ , examples/wagmi-basic/ |
Complete example applications demonstrating different integration approaches |
docs/WAGMI_INTEGRATION.md |
Comprehensive documentation for the Wagmi integration |
README.md |
Updated main README with Wagmi integration overview |
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
type UseSignMessageParameters = any; | ||
type UseSendTransactionParameters = any; | ||
|
Copilot
AI
Sep 16, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using any
types defeats the purpose of TypeScript and makes the code harder to maintain. Consider importing actual types conditionally or creating proper type definitions that match Wagmi's interfaces.
type UseSignMessageParameters = any; | |
type UseSendTransactionParameters = any; | |
import type { UseSignMessageParameters as WagmiUseSignMessageParameters, UseSendTransactionParameters as WagmiUseSendTransactionParameters } from "wagmi"; | |
// Fallback types in case wagmi is not installed (for type checking only) | |
// You may want to refine these to match Wagmi's actual interfaces if needed. | |
type UseSignMessageParameters = WagmiUseSignMessageParameters; | |
type UseSendTransactionParameters = WagmiUseSendTransactionParameters; |
Copilot uses AI. Check for mistakes.
type UseSignMessageParameters = any; | ||
type UseSendTransactionParameters = any; | ||
|
||
// Dynamic imports for wagmi hooks - these will be undefined if wagmi is not installed | ||
let useWagmiSignMessage: any; | ||
let useWagmiSendTransaction: any; | ||
let useWagmiAccount: any; | ||
let useWagmiChainId: any; |
Copilot
AI
Sep 16, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using any
types for the imported hooks removes type safety. Consider using proper type annotations or conditional typing to maintain type safety while allowing graceful degradation.
type UseSignMessageParameters = any; | |
type UseSendTransactionParameters = any; | |
// Dynamic imports for wagmi hooks - these will be undefined if wagmi is not installed | |
let useWagmiSignMessage: any; | |
let useWagmiSendTransaction: any; | |
let useWagmiAccount: any; | |
let useWagmiChainId: any; | |
import type { useSignMessage as UseSignMessageType, useSendTransaction as UseSendTransactionType, useAccount as UseAccountType, useChainId as UseChainIdType } from "wagmi"; | |
type UseSignMessageParameters = Parameters<UseSignMessageType>[0]; | |
type UseSendTransactionParameters = Parameters<UseSendTransactionType>[0]; | |
// Dynamic imports for wagmi hooks - these will be undefined if wagmi is not installed | |
let useWagmiSignMessage: typeof UseSignMessageType | undefined; | |
let useWagmiSendTransaction: typeof UseSendTransactionType | undefined; | |
let useWagmiAccount: typeof UseAccountType | undefined; | |
let useWagmiChainId: typeof UseChainIdType | undefined; |
Copilot uses AI. Check for mistakes.
try { | ||
const wagmi = require("wagmi"); | ||
useWagmiSignMessage = wagmi.useSignMessage; | ||
useWagmiSendTransaction = wagmi.useSendTransaction; | ||
useWagmiAccount = wagmi.useAccount; | ||
useWagmiChainId = wagmi.useChainId; | ||
} catch (error) { | ||
// Wagmi is not installed - hooks will throw helpful errors | ||
} |
Copilot
AI
Sep 16, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using require()
in a TypeScript/ES6 module is inconsistent with modern module patterns. Consider using dynamic import()
with proper error handling instead.
Copilot uses AI. Check for mistakes.
let useAccount: any; | ||
let useChainId: any; | ||
let useConnectorClient: any; | ||
let useConfig: any; |
Copilot
AI
Sep 16, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using any
types removes type safety. Consider using proper type annotations or conditional typing to maintain type safety while allowing optional dependencies.
let useAccount: any; | |
let useChainId: any; | |
let useConnectorClient: any; | |
let useConfig: any; | |
let useAccount: ((...args: any[]) => any) | undefined; | |
let useChainId: ((...args: any[]) => any) | undefined; | |
let useConnectorClient: ((...args: any[]) => any) | undefined; | |
let useConfig: ((...args: any[]) => any) | undefined; |
Copilot uses AI. Check for mistakes.
try { | ||
const wagmi = require("wagmi"); | ||
useAccount = wagmi.useAccount; | ||
useChainId = wagmi.useChainId; | ||
useConnectorClient = wagmi.useConnectorClient; | ||
useConfig = wagmi.useConfig; | ||
} catch (error) { | ||
// Wagmi is not installed - will fall back to regular FormoAnalyticsProvider | ||
} |
Copilot
AI
Sep 16, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using require()
in a TypeScript/ES6 module is inconsistent with modern module patterns. Consider using dynamic import()
with proper error handling instead.
Copilot uses AI. Check for mistakes.
}); | ||
|
||
// Debounce timer | ||
const debounceTimer = useRef<NodeJS.Timeout>(); |
Copilot
AI
Sep 16, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using NodeJS.Timeout
assumes a Node.js environment, but this code may run in browsers. Consider using number
type for better cross-platform compatibility, as setTimeout
returns number
in browsers.
const debounceTimer = useRef<NodeJS.Timeout>(); | |
const debounceTimer = useRef<number | undefined>(); |
Copilot uses AI. Check for mistakes.
<div className="feature-grid"> | ||
<div className="feature-item"> | ||
<h4>🎯 Single Provider</h4> | ||
<p>Replaces both FormoAnalyticsProvider + WagmiFormoProvider</p> |
Copilot
AI
Sep 16, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This comment is inconsistent with the actual implementation. The enhanced provider is WagmiFormoProvider
which replaces FormoAnalyticsProvider + WagmiFormoProvider
, but the text suggests it replaces something else. The documentation should be clarified.
<p>Replaces both FormoAnalyticsProvider + WagmiFormoProvider</p> | |
<p>Replaces the combination of FormoAnalyticsProvider and WagmiFormoProvider</p> |
Copilot uses AI. Check for mistakes.
examples/wagmi-enhanced/README.md
Outdated
```tsx | ||
// Layout 1: Wagmi outside (recommended) | ||
<WagmiProvider> | ||
<FormoAnalyticsProviderWithWagmi> |
Copilot
AI
Sep 16, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The component name FormoAnalyticsProviderWithWagmi
used in documentation doesn't match the actual exported component name WagmiFormoProvider
. This inconsistency could confuse developers following the examples.
Copilot uses AI. Check for mistakes.
examples/wagmi-drop-in/README.md
Outdated
|
||
Edit `App.tsx` and replace `"your-formo-write-key"`: | ||
```tsx | ||
<FormoAnalyticsProviderWithWagmi writeKey="your-actual-write-key"> |
Copilot
AI
Sep 16, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The component name FormoAnalyticsProviderWithWagmi
used in documentation doesn't match the actual exported component name WagmiFormoProvider
. This inconsistency could confuse developers following the examples.
Copilot uses AI. Check for mistakes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
Copilot reviewed 18 out of 18 changed files in this pull request and generated 4 comments.
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
type UseSignMessageParameters = any; | ||
type UseSendTransactionParameters = any; |
Copilot
AI
Sep 17, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using any
type defeats the purpose of TypeScript type safety. Consider importing proper types from Wagmi or defining more specific interfaces to maintain type safety.
type UseSignMessageParameters = any; | |
type UseSendTransactionParameters = any; | |
import type { UseSignMessageParameters, UseSendTransactionParameters } from "wagmi"; |
Copilot uses AI. Check for mistakes.
<li>✅ <strong>Single Provider</strong> - No need for separate WagmiFormoProvider</li> | ||
<li>✅ <strong>Automatic Detection</strong> - Detects Wagmi context automatically</li> | ||
<li>✅ <strong>Flexible Layout</strong> - Works with Wagmi outside Formo provider</li> | ||
<li>✅ <strong>Zero Config</strong> - Just wrap with FormoAnalyticsProviderWithWagmi</li> |
Copilot
AI
Sep 17, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The comment mentions 'FormoAnalyticsProviderWithWagmi' but this provider name doesn't match what's actually used in the code (WagmiFormoProvider). This inconsistency could confuse developers.
<li>✅ <strong>Zero Config</strong> - Just wrap with FormoAnalyticsProviderWithWagmi</li> | |
<li>✅ <strong>Zero Config</strong> - Just wrap with WagmiFormoProvider</li> |
Copilot uses AI. Check for mistakes.
examples/wagmi-enhanced/README.md
Outdated
<FormoAnalyticsProviderWithWagmi> | ||
<WagmiProvider> | ||
<App /> | ||
</WagmiProvider> | ||
</FormoAnalyticsProviderWithWagmi> |
Copilot
AI
Sep 17, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
References to 'FormoAnalyticsProviderWithWagmi' throughout the documentation are inconsistent with the actual component name 'WagmiFormoProvider' used in the implementation.
Copilot uses AI. Check for mistakes.
examples/wagmi-drop-in/README.md
Outdated
|
||
Edit `App.tsx` and replace `"your-formo-write-key"`: | ||
```tsx | ||
<FormoAnalyticsProviderWithWagmi writeKey="your-actual-write-key"> |
Copilot
AI
Sep 17, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
References to 'FormoAnalyticsProviderWithWagmi' are inconsistent with the actual component name 'WagmiFormoProvider' used in the implementation.
Copilot uses AI. Check for mistakes.
const formo = useFormo(); | ||
const { address } = useWagmiAccount(); | ||
const chainId = useWagmiChainId(); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Bug: Wagmi Hooks Fail to Detect Installation
The if (!useWagmiX)
checks in useSignMessage
, useSendTransaction
, and useFormoWallet
are ineffective. The useWagmiX
variables are always assigned a function (either the real Wagmi hook or an error-throwing fallback) in the try-catch
block, making them truthy. This means if Wagmi isn't installed, calls to useWagmiAccount()
and useWagmiChainId()
within these hooks will throw generic errors instead of the intended descriptive "wagmi is not installed" message.
Additional Locations (2)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
Copilot reviewed 18 out of 18 changed files in this pull request and generated 5 comments.
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
try { | ||
const wagmi = require("wagmi"); | ||
useWagmiSignMessage = wagmi.useSignMessage; | ||
useWagmiSendTransaction = wagmi.useSendTransaction; | ||
useWagmiAccount = wagmi.useAccount; | ||
useWagmiChainId = wagmi.useChainId; | ||
} catch (error) { |
Copilot
AI
Sep 18, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using require()
in TypeScript modules is not recommended. Consider using dynamic imports with import()
which are more TypeScript-friendly and provide better type safety.
Copilot uses AI. Check for mistakes.
if (!useWagmiSignMessage) { | ||
throw new Error("useSignMessage requires wagmi to be installed. Please install wagmi: npm install wagmi"); | ||
} |
Copilot
AI
Sep 18, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The conditional check !useWagmiSignMessage
will always be false after line 76 assignment. The function will be assigned either the wagmi hook or an error-throwing function, never undefined. This check should be removed since the error is already handled in the catch block.
if (!useWagmiSignMessage) { | |
throw new Error("useSignMessage requires wagmi to be installed. Please install wagmi: npm install wagmi"); | |
} |
Copilot uses AI. Check for mistakes.
if (!useWagmiSendTransaction) { | ||
throw new Error("useSendTransaction requires wagmi to be installed. Please install wagmi: npm install wagmi"); | ||
} |
Copilot
AI
Sep 18, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The conditional check !useWagmiSendTransaction
will always be false after line 78 assignment. The function will be assigned either the wagmi hook or an error-throwing function, never undefined. This check should be removed since the error is already handled in the catch block.
if (!useWagmiSendTransaction) { | |
throw new Error("useSendTransaction requires wagmi to be installed. Please install wagmi: npm install wagmi"); | |
} |
Copilot uses AI. Check for mistakes.
if (!useWagmiAccount) { | ||
throw new Error("useFormoWallet requires wagmi to be installed. Please install wagmi: npm install wagmi"); | ||
} |
Copilot
AI
Sep 18, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The conditional check !useWagmiAccount
will always be false after line 79 assignment. The function will be assigned either the wagmi hook or an error-throwing function, never undefined. This check should be removed since the error is already handled in the catch block.
if (!useWagmiAccount) { | |
throw new Error("useFormoWallet requires wagmi to be installed. Please install wagmi: npm install wagmi"); | |
} |
Copilot uses AI. Check for mistakes.
if (!formo || !address || !chainId) return; | ||
|
Copilot
AI
Sep 18, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[nitpick] The early return condition combines multiple unrelated checks. Consider separating these into individual checks with specific error handling or logging for each missing dependency to improve debuggability.
if (!formo || !address || !chainId) return; | |
if (!formo) { | |
logger.error("connectWithTracking: Missing Formo Analytics instance (formo is undefined)"); | |
return; | |
} | |
if (!address) { | |
logger.error("connectWithTracking: Missing wallet address (address is undefined)"); | |
return; | |
} | |
if (!chainId) { | |
logger.error("connectWithTracking: Missing chain ID (chainId is undefined)"); | |
return; | |
} |
Copilot uses AI. Check for mistakes.
Still testing
Design should be modular and easy to install