Skip to content

Commit bc9d1ac

Browse files
vortex-huepbkompaszL03TJ3
authored
Feat: Integrate Reown AppKit; replace Web3 Onboard; add wallet priorities and Google socials (#604)
* chore: remove onboard provider * feat: add appkit provider * chore: replace hooks * chore: onboard -> appkit * feat(appkit): integrate Reown AppKit; remove Web3 Onboard; wallet priority (GoodWallet, Valora), Google socials, MiniPay labeling; migrate connect flows to AppKit * fix: yarn lingui and revert back to last commit * Address review: CELO default chain helper, explorer defaults, MiniPay refactor, useConnectionInfo, restore XDC, clean TODOs, fix keys and ESLint warnings * Refactor: useConnectionInfo rollout (partial), clarify SwapCelo handleError, add wallet QA checklist * refactor(appkit): rollout useConnectionInfo across components (WalletChat, AccountDetails, Web3ReactManager, Web3Network) * fix: complete AppKit integration with security improvements * chore: lingui * fix: remove walletConnect connector to resolve double modal issue * fix: address code review comments - default chain fallbacks, enum usage, and bug fixes * fix: align Reown networks with NetworkModal using feature flags * refactor: use dynamic SupportedChains check instead of hardcoded list * fix: set all networks enabled and force CELO as first network * Apply suggestions from code review * fix: handleConnect return value and restore reserveEnabled check * fix: use correct wallet ID hashes for featured wallets * trigger deployment * feat: add MiniPay support via injected connector and update tunnel config * feat: add custom MiniPay connector with auto-connect support * fix: conditionally include MiniPay connector only when detected - Only add MiniPay connector to array when MiniPay is actually detected - Prevents 'connector not found' errors when MiniPay is not available - Fallback to injected() connector for other wallets * fix: MiniPay connector improvements and code cleanup * fix: MiniPay connector visibility and disconnect behavior * fix: MiniPay connector type compatibility and auto-connect * wip: fix autoconnect minipay * fix: remove duplicate minipay connector * feat: add MiniPay status box and simplify auto-connect * fix: resolve MiniPay provider fallback in useWeb3 hook * refactor: remove MiniPay status overlay display * Apply suggestions from code review * fix: resolve merge conflicts and remove unused code * refactor: remove unnecessary onConnect handler from minipay connector * Apply suggestions from code review * feat: hide MiniPay from wallet selection UI, enable background auto-connect --------- Co-authored-by: Peter Kompasz <kompaszbence@gmail.com> Co-authored-by: LewisB <lewis@gooddollar.org> Co-authored-by: Lewis B <lewis@ikigaistudios.eu>
1 parent 5df5128 commit bc9d1ac

File tree

102 files changed

+4695
-4299
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

102 files changed

+4695
-4299
lines changed

docs/WALLET_INTEGRATION.md

Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,175 @@
1+
# Wallet Integration with Reown AppKit
2+
3+
## Overview
4+
5+
This document describes the wallet integration implementation using Reown AppKit, replacing the legacy Web3 React hooks.
6+
7+
## Architecture
8+
9+
### Core Components
10+
11+
1. **useConnectionInfo Hook**: Centralized hook that provides wallet connection state
12+
2. **WalletErrorBoundary**: Error boundary for wallet-related errors
13+
3. **Wallet Configuration**: Centralized configuration for supported chains and wallets
14+
15+
### Supported Wallets
16+
17+
#### WalletConnect
18+
- **GoodWallet**: Primary wallet for GoodDollar ecosystem
19+
- **Valora**: Celo ecosystem wallet
20+
21+
#### Social Login
22+
- **Google**: Social authentication
23+
24+
#### Injected Wallets
25+
- **MetaMask**: Browser extension wallet
26+
- **MiniPay**: Opera browser wallet
27+
28+
### Supported Networks
29+
30+
- **Celo (42220)**: Primary network (default)
31+
- **Fuse (122)**: Secondary network
32+
- **Ethereum (1)**: Mainnet support
33+
34+
## Implementation Details
35+
36+
### useConnectionInfo Hook
37+
38+
```typescript
39+
interface ConnectionInfo {
40+
address?: string
41+
chainId: number
42+
walletInfo?: WalletInfo
43+
isConnected: boolean
44+
isSupportedChain: boolean
45+
connectionStatus: 'disconnected' | 'connecting' | 'connected' | 'error'
46+
}
47+
```
48+
49+
### Error Handling
50+
51+
The `WalletErrorBoundary` component catches and handles wallet-related errors gracefully, providing user-friendly error messages and recovery options.
52+
53+
### Security Features
54+
55+
1. **Chain Validation**: Only supported chains are allowed
56+
2. **Connection Timeout**: 30-second timeout for wallet connections
57+
3. **Error Logging**: Comprehensive error logging for debugging
58+
59+
## Testing
60+
61+
### Manual Testing Checklist
62+
63+
#### MiniPay
64+
- [ ] Connect wallet
65+
- [ ] Sign transactions
66+
- [ ] Switch networks
67+
- [ ] Disconnect wallet
68+
69+
#### GoodWallet (WalletConnect)
70+
- [ ] Deep link from mobile
71+
- [ ] QR code on desktop
72+
- [ ] Transaction signing
73+
- [ ] Network switching
74+
75+
#### Valora
76+
- [ ] Connect via WalletConnect
77+
- [ ] Transaction signing
78+
- [ ] Network switching
79+
80+
#### MetaMask
81+
- [ ] Connect via injected provider
82+
- [ ] Switch to Celo network
83+
- [ ] Transaction signing
84+
- [ ] Explorer link navigation
85+
86+
### Automated Testing
87+
88+
Run the test suite:
89+
90+
```bash
91+
yarn test useConnectionInfo
92+
```
93+
94+
## Migration Guide
95+
96+
### Replacing Legacy Hooks
97+
98+
**Before:**
99+
```typescript
100+
import { useActiveWeb3React } from '@web3-react/core'
101+
import { useActiveOnboard } from '@web3-onboard/react'
102+
103+
const { account, chainId } = useActiveWeb3React()
104+
const { wallet } = useActiveOnboard()
105+
```
106+
107+
**After:**
108+
```typescript
109+
import { useConnectionInfo } from 'hooks/useConnectionInfo'
110+
111+
const { address, chainId, walletInfo, isConnected } = useConnectionInfo()
112+
```
113+
114+
### Error Handling
115+
116+
**Before:**
117+
```typescript
118+
// Manual error handling
119+
if (!account) {
120+
// Handle disconnected state
121+
}
122+
```
123+
124+
**After:**
125+
```typescript
126+
// Automatic error handling with status
127+
if (connectionStatus === 'error') {
128+
// Error boundary handles this
129+
}
130+
```
131+
132+
## Troubleshooting
133+
134+
### Common Issues
135+
136+
1. **WalletConnect not loading on localhost**
137+
- Ensure `projectId` is set in environment variables
138+
- Add localhost to allowed origins in WalletConnect project settings
139+
140+
2. **Unsupported chain errors**
141+
- Check if chain ID is in `SUPPORTED_CHAINS` array
142+
- Verify network configuration
143+
144+
3. **Connection timeout**
145+
- Check network connectivity
146+
- Verify wallet is properly installed
147+
- Check for browser popup blockers
148+
149+
### Debug Mode
150+
151+
Enable debug logging by setting:
152+
```typescript
153+
localStorage.setItem('wallet-debug', 'true')
154+
```
155+
156+
## Performance Considerations
157+
158+
1. **Memoization**: `useConnectionInfo` uses `useMemo` to prevent unnecessary re-renders
159+
2. **Error Boundaries**: Isolate wallet errors to prevent app crashes
160+
3. **Connection Pooling**: Reuse connections where possible
161+
162+
## Security Best Practices
163+
164+
1. **Always validate chain IDs** before processing transactions
165+
2. **Use error boundaries** to handle connection failures gracefully
166+
3. **Log errors** for debugging without exposing sensitive information
167+
4. **Implement connection timeouts** to prevent hanging connections
168+
5. **Validate wallet authenticity** before processing sensitive operations
169+
170+
## Future Enhancements
171+
172+
1. **Multi-wallet support**: Allow users to connect multiple wallets
173+
2. **Wallet analytics**: Track wallet usage patterns
174+
3. **Enhanced error recovery**: Automatic retry mechanisms
175+
4. **Connection persistence**: Remember wallet preferences across sessions

src/components/AccountDetails/Transaction.tsx

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
import React from 'react'
22
import { CheckCircle, Triangle } from 'react-feather'
33
import styled from 'styled-components'
4-
import { useActiveWeb3React } from '../../hooks/useActiveWeb3React'
54
import { useAllTransactions } from '../../state/transactions/hooks'
65
import { ExternalLink } from '../../theme'
76
import { getExplorerLink } from '../../utils'
7+
import { getSafeChainId } from 'utils/chain'
88
import Loader from '../Loader'
99
import { RowFixed } from '../Row'
10+
import { useAppKitNetwork } from '@reown/appkit/react'
1011

1112
const TransactionWrapper = styled.div`
1213
a {
@@ -69,7 +70,7 @@ const IconWrapper = styled.div<{ pending: boolean; success?: boolean }>`
6970
`
7071

7172
export default function Transaction({ hash }: { hash: string }): any {
72-
const { chainId } = useActiveWeb3React()
73+
const { chainId } = useAppKitNetwork()
7374
const allTransactions = useAllTransactions()
7475

7576
const tx = allTransactions?.[hash]
@@ -81,7 +82,10 @@ export default function Transaction({ hash }: { hash: string }): any {
8182

8283
return (
8384
<TransactionWrapper>
84-
<TransactionState url={getExplorerLink(chainId, hash, 'transaction')} dataAttr="external_explorer">
85+
<TransactionState
86+
url={getExplorerLink(getSafeChainId(chainId), hash, 'transaction')}
87+
dataAttr="external_explorer"
88+
>
8589
<RowFixed className="transition">
8690
<TransactionStatusText>{summary}</TransactionStatusText>
8791
</RowFixed>

src/components/AccountDetails/index.tsx

Lines changed: 35 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,17 @@ import { useLingui } from '@lingui/react'
33
import React, { useCallback } from 'react'
44
import { useDispatch } from 'react-redux'
55
import styled from 'styled-components'
6-
import { useConnectWallet } from '@web3-onboard/react'
6+
import { useAppKit } from '@reown/appkit/react'
77
import { useRedirectNotice } from '@gooddollar/good-design'
8+
import { isMiniPay } from 'utils/minipay'
89

910
import { ReactComponent as Close } from '../../assets/images/x.svg'
10-
import { WalletLabels } from '../../hooks/useActiveOnboard'
11-
import { useActiveWeb3React } from '../../hooks/useActiveWeb3React'
1211
import { AppDispatch } from '../../state'
1312
import { clearAllTransactions } from '../../state/transactions/actions'
1413
import { ExternalLink } from 'theme'
1514
import { getExplorerLink, shortenAddress } from '../../utils'
15+
import { getSafeChainId } from 'utils/chain'
16+
import { useConnectionInfo } from 'hooks/useConnectionInfo'
1617
import { ButtonOutlined } from '../gd/Button'
1718
import Title from '../gd/Title'
1819
import { AutoRow } from '../Row'
@@ -21,6 +22,7 @@ import Transaction from './Transaction'
2122
import useSendAnalyticsData from '../../hooks/useSendAnalyticsData'
2223

2324
import { getEnv } from 'utils/env'
25+
import { useDisconnect } from 'wagmi'
2426

2527
const UpperSection = styled.div`
2628
position: relative;
@@ -209,34 +211,40 @@ export default function AccountDetails({
209211
ENSName,
210212
}: AccountDetailsProps): any {
211213
const { i18n } = useLingui()
212-
const { chainId, account } = useActiveWeb3React()
213214
const dispatch = useDispatch<AppDispatch>()
214215
const network = getEnv()
215-
//eslint-disable-next-line @typescript-eslint/no-unused-vars
216-
const [{ wallet, connecting }, connect, disconnect] = useConnectWallet()
216+
217+
const { address, chainId, walletInfo } = useConnectionInfo()
218+
219+
const { open } = useAppKit()
220+
const { disconnect } = useDisconnect()
221+
222+
// Connection management handled by AppKit modal and wagmi disconnect
217223
const sendData = useSendAnalyticsData()
218224
const { goToExternal } = useRedirectNotice()
219225

226+
// walletInfo provided by useConnectionInfo
227+
228+
const miniPay = isMiniPay()
229+
220230
function formatConnectorName() {
221-
return `${i18n._(t`Connected with`)} ${wallet?.label}`
231+
const name = miniPay ? 'MiniPay' : walletInfo?.name ?? ''
232+
return `${i18n._(t`Connected with`)} ${name}`
222233
}
223234

224235
const changeWallet = useCallback(async () => {
225236
toggleWalletModal()
226-
await connect()
227-
}, [toggleWalletModal, connect])
228-
229-
const disconnectWallet = useCallback(async () => {
230-
if (wallet) {
231-
toggleWalletModal()
232-
sendData({ event: 'account', action: 'address_disconnect_success', network: network })
233-
await disconnect({ label: wallet.label })
234-
await connect()
235-
}
236-
}, [toggleWalletModal, connect, disconnect, wallet])
237+
await open({ view: 'Connect' })
238+
}, [toggleWalletModal, open])
239+
240+
const disconnectWallet = useCallback(() => {
241+
toggleWalletModal()
242+
sendData({ event: 'account', action: 'address_disconnect_success', network: network })
243+
disconnect()
244+
}, [toggleWalletModal, disconnect, network, sendData])
237245

238246
const clearAllTransactionsCallback = useCallback(() => {
239-
if (chainId) dispatch(clearAllTransactions({ chainId }))
247+
if (chainId) dispatch(clearAllTransactions({ chainId: getSafeChainId(chainId) }))
240248
}, [dispatch, chainId])
241249

242250
const goToExplorer = (e: any, url: string) => {
@@ -250,14 +258,15 @@ export default function AccountDetails({
250258
<CloseIcon onClick={toggleWalletModal}>
251259
<CloseColor />
252260
</CloseIcon>
261+
253262
<Title className="mb-8 text-center">{i18n._(t`Account`)}</Title>
254263
<AccountSection>
255264
<YourAccount>
256265
<InfoCard>
257266
<AccountGroupingRow>
258267
{formatConnectorName()}
259268
<div className="mt-3.5 mb-3.5">
260-
{wallet?.label && WalletLabels.includes(wallet.label) && (
269+
{address && (
261270
<WalletAction
262271
width={'85px'}
263272
size="sm"
@@ -271,7 +280,7 @@ export default function AccountDetails({
271280
width={'75px'}
272281
size="sm"
273282
style={{ marginRight: '-5px' }}
274-
onClick={wallet?.label === 'MetaMask' ? disconnectWallet : changeWallet}
283+
onClick={walletInfo?.label === 'MetaMask' ? disconnectWallet : changeWallet}
275284
>
276285
{i18n._(t`Change`)}
277286
</WalletAction>
@@ -280,21 +289,21 @@ export default function AccountDetails({
280289
<AccountGroupingRow id="web3-account-identifier-row">
281290
<AccountControl>
282291
<div className="justify-center text-center">
283-
<p> {ENSName ?? shortenAddress(account ?? '')}</p>
292+
<p> {ENSName ?? shortenAddress(address ?? '')}</p>
284293
</div>
285294
</AccountControl>
286295
</AccountGroupingRow>
287296
<AccountGroupingRow className="mt-4">
288297
<AccountControl>
289298
<div>
290-
{account && (
291-
<Copy toCopy={account}>
299+
{address && (
300+
<Copy toCopy={address}>
292301
<span style={{ marginLeft: '4px' }}>{i18n._(t`Copy address`)}</span>
293302
</Copy>
294303
)}
295-
{chainId && account && (
304+
{chainId && address && (
296305
<ExternalLink
297-
url={getExplorerLink(chainId, account, 'address')}
306+
url={getExplorerLink(getSafeChainId(chainId), address, 'address')}
298307
label={i18n._(t`View on explorer`)}
299308
dataAttr="external_explorer"
300309
onPress={goToExplorer}

0 commit comments

Comments
 (0)