Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
9c50170
chore: remove onboard provider
pbkompasz Aug 4, 2025
74e45da
feat: add appkit provider
pbkompasz Aug 4, 2025
ee3abbe
chore: replace hooks
pbkompasz Aug 4, 2025
e709dd2
chore: onboard -> appkit
pbkompasz Aug 6, 2025
95c730b
feat(appkit): integrate Reown AppKit; remove Web3 Onboard; wallet pri…
vortex-hue Sep 8, 2025
e48cd04
Merge conflicts resolved and TypeScript errors fixed
vortex-hue Sep 8, 2025
d31a141
fix: yarn lingui and revert back to last commit
vortex-hue Sep 22, 2025
e4a9d54
Merge branch 'feat-appkit' of https://github.com/vortex-hue/GoodProto…
vortex-hue Sep 22, 2025
125bb80
Merge remote-tracking branch 'origin/master' into feat-appkit
vortex-hue Oct 3, 2025
35c9a1f
Address review: CELO default chain helper, explorer defaults, MiniPay…
vortex-hue Oct 3, 2025
aac96e6
Refactor: useConnectionInfo rollout (partial), clarify SwapCelo handl…
vortex-hue Oct 3, 2025
1267495
refactor(appkit): rollout useConnectionInfo across components (Wallet…
vortex-hue Oct 3, 2025
d1404cd
fix: complete AppKit integration with security improvements
vortex-hue Oct 3, 2025
0848d21
Merge origin/master into feat-appkit
vortex-hue Nov 10, 2025
e707763
Merge branch 'master' of https://github.com/GoodDollar/GoodProtocolUI…
L03TJ3 Nov 17, 2025
fef0507
chore: lingui
L03TJ3 Nov 17, 2025
fea50b2
fix: remove walletConnect connector to resolve double modal issue
vortex-hue Nov 18, 2025
6e42a92
fix: address code review comments - default chain fallbacks, enum usa…
vortex-hue Nov 23, 2025
7baf4ff
fix: align Reown networks with NetworkModal using feature flags
vortex-hue Nov 26, 2025
1cadc38
refactor: use dynamic SupportedChains check instead of hardcoded list
vortex-hue Nov 26, 2025
14f317a
fix: set all networks enabled and force CELO as first network
vortex-hue Nov 26, 2025
52f7334
Apply suggestions from code review
L03TJ3 Nov 26, 2025
ca3789c
fix: handleConnect return value and restore reserveEnabled check
vortex-hue Nov 26, 2025
5491d05
Merge branch 'master' of https://github.com/GoodDollar/GoodProtocolUI…
L03TJ3 Nov 26, 2025
20811d2
fix: use correct wallet ID hashes for featured wallets
vortex-hue Nov 26, 2025
26ab721
Merge branch 'master' of https://github.com/GoodDollar/GoodProtocolUI…
L03TJ3 Nov 26, 2025
5c4c6ae
Merge branch 'master' of https://github.com/GoodDollar/GoodProtocolUI…
L03TJ3 Nov 26, 2025
c54bcb5
Merge branch 'master' of https://github.com/GoodDollar/GoodProtocolUI…
L03TJ3 Nov 27, 2025
eb51392
trigger deployment
L03TJ3 Nov 27, 2025
333b2bb
feat: add MiniPay support via injected connector and update tunnel co…
vortex-hue Nov 27, 2025
b7d027e
feat: add custom MiniPay connector with auto-connect support
vortex-hue Nov 27, 2025
04d3b4b
fix: conditionally include MiniPay connector only when detected
vortex-hue Nov 28, 2025
5f06759
Merge remote-tracking branch 'origin/master' into feat-appkit
vortex-hue Dec 11, 2025
48613cc
fix: MiniPay connector improvements and code cleanup
vortex-hue Dec 11, 2025
795a7ce
fix: MiniPay connector visibility and disconnect behavior
vortex-hue Dec 11, 2025
382ee7d
fix: MiniPay connector type compatibility and auto-connect
vortex-hue Dec 11, 2025
236196b
wip: fix autoconnect minipay
L03TJ3 Dec 11, 2025
f151b00
fix: remove duplicate minipay connector
L03TJ3 Dec 11, 2025
f0e0934
feat: add MiniPay status box and simplify auto-connect
vortex-hue Dec 12, 2025
4f460d8
fix: resolve MiniPay provider fallback in useWeb3 hook
vortex-hue Dec 13, 2025
9c93dfe
refactor: remove MiniPay status overlay display
vortex-hue Dec 13, 2025
f2a0caa
Apply suggestions from code review
L03TJ3 Dec 15, 2025
a152f84
fix: resolve merge conflicts and remove unused code
vortex-hue Dec 15, 2025
3411c8e
refactor: remove unnecessary onConnect handler from minipay connector
vortex-hue Dec 15, 2025
8fcfe71
Apply suggestions from code review
L03TJ3 Dec 16, 2025
9f58702
feat: hide MiniPay from wallet selection UI, enable background auto-c…
vortex-hue Dec 16, 2025
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
175 changes: 175 additions & 0 deletions docs/WALLET_INTEGRATION.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
# Wallet Integration with Reown AppKit

## Overview

This document describes the wallet integration implementation using Reown AppKit, replacing the legacy Web3 React hooks.

## Architecture

### Core Components

1. **useConnectionInfo Hook**: Centralized hook that provides wallet connection state
2. **WalletErrorBoundary**: Error boundary for wallet-related errors
3. **Wallet Configuration**: Centralized configuration for supported chains and wallets

### Supported Wallets

#### WalletConnect
- **GoodWallet**: Primary wallet for GoodDollar ecosystem
- **Valora**: Celo ecosystem wallet

#### Social Login
- **Google**: Social authentication

#### Injected Wallets
- **MetaMask**: Browser extension wallet
- **MiniPay**: Opera browser wallet

### Supported Networks

- **Celo (42220)**: Primary network (default)
- **Fuse (122)**: Secondary network
- **Ethereum (1)**: Mainnet support

## Implementation Details

### useConnectionInfo Hook

```typescript
interface ConnectionInfo {
address?: string
chainId: number
walletInfo?: WalletInfo
isConnected: boolean
isSupportedChain: boolean
connectionStatus: 'disconnected' | 'connecting' | 'connected' | 'error'
}
```

### Error Handling

The `WalletErrorBoundary` component catches and handles wallet-related errors gracefully, providing user-friendly error messages and recovery options.

### Security Features

1. **Chain Validation**: Only supported chains are allowed
2. **Connection Timeout**: 30-second timeout for wallet connections
3. **Error Logging**: Comprehensive error logging for debugging

## Testing

### Manual Testing Checklist

#### MiniPay
- [ ] Connect wallet
- [ ] Sign transactions
- [ ] Switch networks
- [ ] Disconnect wallet

#### GoodWallet (WalletConnect)
- [ ] Deep link from mobile
- [ ] QR code on desktop
- [ ] Transaction signing
- [ ] Network switching

#### Valora
- [ ] Connect via WalletConnect
- [ ] Transaction signing
- [ ] Network switching

#### MetaMask
- [ ] Connect via injected provider
- [ ] Switch to Celo network
- [ ] Transaction signing
- [ ] Explorer link navigation

### Automated Testing

Run the test suite:

```bash
yarn test useConnectionInfo
```

## Migration Guide

### Replacing Legacy Hooks

**Before:**
```typescript
import { useActiveWeb3React } from '@web3-react/core'
import { useActiveOnboard } from '@web3-onboard/react'

const { account, chainId } = useActiveWeb3React()
const { wallet } = useActiveOnboard()
```

**After:**
```typescript
import { useConnectionInfo } from 'hooks/useConnectionInfo'

const { address, chainId, walletInfo, isConnected } = useConnectionInfo()
```

### Error Handling

**Before:**
```typescript
// Manual error handling
if (!account) {
// Handle disconnected state
}
```

**After:**
```typescript
// Automatic error handling with status
if (connectionStatus === 'error') {
// Error boundary handles this
}
```

## Troubleshooting

### Common Issues

1. **WalletConnect not loading on localhost**
- Ensure `projectId` is set in environment variables
- Add localhost to allowed origins in WalletConnect project settings

2. **Unsupported chain errors**
- Check if chain ID is in `SUPPORTED_CHAINS` array
- Verify network configuration

3. **Connection timeout**
- Check network connectivity
- Verify wallet is properly installed
- Check for browser popup blockers

### Debug Mode

Enable debug logging by setting:
```typescript
localStorage.setItem('wallet-debug', 'true')
```

## Performance Considerations

1. **Memoization**: `useConnectionInfo` uses `useMemo` to prevent unnecessary re-renders
2. **Error Boundaries**: Isolate wallet errors to prevent app crashes
3. **Connection Pooling**: Reuse connections where possible

## Security Best Practices

1. **Always validate chain IDs** before processing transactions
2. **Use error boundaries** to handle connection failures gracefully
3. **Log errors** for debugging without exposing sensitive information
4. **Implement connection timeouts** to prevent hanging connections
5. **Validate wallet authenticity** before processing sensitive operations

## Future Enhancements

1. **Multi-wallet support**: Allow users to connect multiple wallets
2. **Wallet analytics**: Track wallet usage patterns
3. **Enhanced error recovery**: Automatic retry mechanisms
4. **Connection persistence**: Remember wallet preferences across sessions
10 changes: 7 additions & 3 deletions src/components/AccountDetails/Transaction.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import React from 'react'
import { CheckCircle, Triangle } from 'react-feather'
import styled from 'styled-components'
import { useActiveWeb3React } from '../../hooks/useActiveWeb3React'
import { useAllTransactions } from '../../state/transactions/hooks'
import { ExternalLink } from '../../theme'
import { getExplorerLink } from '../../utils'
import { getSafeChainId } from 'utils/chain'
import Loader from '../Loader'
import { RowFixed } from '../Row'
import { useAppKitNetwork } from '@reown/appkit/react'

const TransactionWrapper = styled.div`
a {
Expand Down Expand Up @@ -69,7 +70,7 @@ const IconWrapper = styled.div<{ pending: boolean; success?: boolean }>`
`

export default function Transaction({ hash }: { hash: string }): any {
const { chainId } = useActiveWeb3React()
const { chainId } = useAppKitNetwork()
const allTransactions = useAllTransactions()

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

return (
<TransactionWrapper>
<TransactionState url={getExplorerLink(chainId, hash, 'transaction')} dataAttr="external_explorer">
<TransactionState
url={getExplorerLink(getSafeChainId(chainId), hash, 'transaction')}
dataAttr="external_explorer"
>
<RowFixed className="transition">
<TransactionStatusText>{summary} ↗</TransactionStatusText>
</RowFixed>
Expand Down
61 changes: 35 additions & 26 deletions src/components/AccountDetails/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,17 @@ import { useLingui } from '@lingui/react'
import React, { useCallback } from 'react'
import { useDispatch } from 'react-redux'
import styled from 'styled-components'
import { useConnectWallet } from '@web3-onboard/react'
import { useAppKit } from '@reown/appkit/react'
import { useRedirectNotice } from '@gooddollar/good-design'
import { isMiniPay } from 'utils/minipay'

import { ReactComponent as Close } from '../../assets/images/x.svg'
import { WalletLabels } from '../../hooks/useActiveOnboard'
import { useActiveWeb3React } from '../../hooks/useActiveWeb3React'
import { AppDispatch } from '../../state'
import { clearAllTransactions } from '../../state/transactions/actions'
import { ExternalLink } from 'theme'
import { getExplorerLink, shortenAddress } from '../../utils'
import { getSafeChainId } from 'utils/chain'
import { useConnectionInfo } from 'hooks/useConnectionInfo'
import { ButtonOutlined } from '../gd/Button'
import Title from '../gd/Title'
import { AutoRow } from '../Row'
Expand All @@ -21,6 +22,7 @@ import Transaction from './Transaction'
import useSendAnalyticsData from '../../hooks/useSendAnalyticsData'

import { getEnv } from 'utils/env'
import { useDisconnect } from 'wagmi'

const UpperSection = styled.div`
position: relative;
Expand Down Expand Up @@ -209,34 +211,40 @@ export default function AccountDetails({
ENSName,
}: AccountDetailsProps): any {
const { i18n } = useLingui()
const { chainId, account } = useActiveWeb3React()
const dispatch = useDispatch<AppDispatch>()
const network = getEnv()
//eslint-disable-next-line @typescript-eslint/no-unused-vars
const [{ wallet, connecting }, connect, disconnect] = useConnectWallet()

const { address, chainId, walletInfo } = useConnectionInfo()

const { open } = useAppKit()
const { disconnect } = useDisconnect()

// Connection management handled by AppKit modal and wagmi disconnect
const sendData = useSendAnalyticsData()
const { goToExternal } = useRedirectNotice()

// walletInfo provided by useConnectionInfo

const miniPay = isMiniPay()

function formatConnectorName() {
return `${i18n._(t`Connected with`)} ${wallet?.label}`
const name = miniPay ? 'MiniPay' : walletInfo?.name ?? ''
return `${i18n._(t`Connected with`)} ${name}`
}

const changeWallet = useCallback(async () => {
toggleWalletModal()
await connect()
}, [toggleWalletModal, connect])

const disconnectWallet = useCallback(async () => {
if (wallet) {
toggleWalletModal()
sendData({ event: 'account', action: 'address_disconnect_success', network: network })
await disconnect({ label: wallet.label })
await connect()
}
}, [toggleWalletModal, connect, disconnect, wallet])
await open({ view: 'Connect' })
}, [toggleWalletModal, open])

const disconnectWallet = useCallback(() => {
toggleWalletModal()
sendData({ event: 'account', action: 'address_disconnect_success', network: network })
disconnect()
}, [toggleWalletModal, disconnect, network, sendData])

const clearAllTransactionsCallback = useCallback(() => {
if (chainId) dispatch(clearAllTransactions({ chainId }))
if (chainId) dispatch(clearAllTransactions({ chainId: getSafeChainId(chainId) }))
}, [dispatch, chainId])

const goToExplorer = (e: any, url: string) => {
Expand All @@ -250,14 +258,15 @@ export default function AccountDetails({
<CloseIcon onClick={toggleWalletModal}>
<CloseColor />
</CloseIcon>

<Title className="mb-8 text-center">{i18n._(t`Account`)}</Title>
<AccountSection>
<YourAccount>
<InfoCard>
<AccountGroupingRow>
{formatConnectorName()}
<div className="mt-3.5 mb-3.5">
{wallet?.label && WalletLabels.includes(wallet.label) && (
{address && (
<WalletAction
width={'85px'}
size="sm"
Expand All @@ -271,7 +280,7 @@ export default function AccountDetails({
width={'75px'}
size="sm"
style={{ marginRight: '-5px' }}
onClick={wallet?.label === 'MetaMask' ? disconnectWallet : changeWallet}
onClick={walletInfo?.label === 'MetaMask' ? disconnectWallet : changeWallet}
>
{i18n._(t`Change`)}
</WalletAction>
Expand All @@ -280,21 +289,21 @@ export default function AccountDetails({
<AccountGroupingRow id="web3-account-identifier-row">
<AccountControl>
<div className="justify-center text-center">
<p> {ENSName ?? shortenAddress(account ?? '')}</p>
<p> {ENSName ?? shortenAddress(address ?? '')}</p>
</div>
</AccountControl>
</AccountGroupingRow>
<AccountGroupingRow className="mt-4">
<AccountControl>
<div>
{account && (
<Copy toCopy={account}>
{address && (
<Copy toCopy={address}>
<span style={{ marginLeft: '4px' }}>{i18n._(t`Copy address`)}</span>
</Copy>
)}
{chainId && account && (
{chainId && address && (
<ExternalLink
url={getExplorerLink(chainId, account, 'address')}
url={getExplorerLink(getSafeChainId(chainId), address, 'address')}
label={i18n._(t`View on explorer`)}
dataAttr="external_explorer"
onPress={goToExplorer}
Expand Down
Loading
Loading