Skip to content

Commit

Permalink
feat: Provide WalletConnect project ID for WalletModal (#1670)
Browse files Browse the repository at this point in the history
  • Loading branch information
cpcramer authored Nov 26, 2024
1 parent 2a1f583 commit 79f3e4c
Show file tree
Hide file tree
Showing 4 changed files with 105 additions and 39 deletions.
13 changes: 1 addition & 12 deletions playground/nextjs-app-router/components/OnchainProviders.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import type { ReactNode } from 'react';
import { http, createConfig } from 'wagmi';
import { WagmiProvider } from 'wagmi';
import { base, baseSepolia } from 'wagmi/chains';
import { coinbaseWallet, walletConnect } from 'wagmi/connectors';
import { coinbaseWallet } from 'wagmi/connectors';

export const config = createConfig({
chains: [base, baseSepolia],
Expand All @@ -24,17 +24,6 @@ export const config = createConfig({
appName: 'OnchainKit',
preference: 'eoaOnly',
}),
walletConnect({
projectId:
ENVIRONMENT_VARIABLES[ENVIRONMENT.WALLETCONNECT_PROJECT_ID] ?? '',
showQrModal: true,
metadata: {
name: 'OnchainKit',
description: 'build onchain',
url: 'https://onchainkit.xyz/',
icons: [],
},
}),
],
});

Expand Down
102 changes: 86 additions & 16 deletions src/wallet/components/WalletModal.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { fireEvent, render, screen } from '@testing-library/react';
import { type Mock, beforeEach, describe, expect, it, vi } from 'vitest';
import { useConnect, useConnectors } from 'wagmi';
import { useOnchainKit } from '../../useOnchainKit';
import { ONCHAINKIT_WALLETCONNECT_PROJECT_ID } from '../constants';
import { WalletModal } from './WalletModal';

vi.mock('wagmi', () => ({
Expand All @@ -15,6 +16,14 @@ vi.mock('../../useOnchainKit', () => ({

vi.mock('wagmi/connectors', () => ({
coinbaseWallet: () => ({ preference: 'all' }),
walletConnect: () => ({
projectId: ONCHAINKIT_WALLETCONNECT_PROJECT_ID,
showQrModal: true,
}),
}));

vi.mock('../../constants', () => ({
ONCHAINKIT_WALLETCONNECT_PROJECT_ID: 'test-project-id',
}));

describe('WalletModal', () => {
Expand Down Expand Up @@ -104,7 +113,10 @@ describe('WalletModal', () => {
fireEvent.click(screen.getByText('Other wallets'));

expect(mockConnect).toHaveBeenCalledWith({
connector: mockConnectors.find((c) => c.type === 'walletConnect'),
connector: expect.objectContaining({
projectId: ONCHAINKIT_WALLETCONNECT_PROJECT_ID,
showQrModal: true,
}),
});
expect(mockOnClose).toHaveBeenCalled();
});
Expand Down Expand Up @@ -157,21 +169,6 @@ describe('WalletModal', () => {
expect(overlay).toHaveClass('custom-class');
});

it('handles case when WalletConnect connector is not found', () => {
const mockConnectorsWithoutWC = [
{ id: 'smartWallet', name: 'Smart Wallet' },
{ id: 'coinbaseWallet', name: 'Coinbase Wallet' },
{ id: 'other', name: 'Other' },
];
(useConnectors as Mock).mockReturnValue(mockConnectorsWithoutWC);

render(<WalletModal isOpen={true} onClose={mockOnClose} />);

fireEvent.click(screen.getByText('Other wallets'));

expect(mockConnect).not.toHaveBeenCalled();
});

it('applies correct transition classes based on isOpen state', () => {
const { rerender } = render(
<WalletModal isOpen={true} onClose={mockOnClose} />,
Expand Down Expand Up @@ -368,4 +365,77 @@ describe('WalletModal', () => {

expect(mockOnClose).toHaveBeenCalled();
});

it('does not render when shouldRender is false', () => {
const { container } = render(
<WalletModal isOpen={false} onClose={mockOnClose} />,
);

expect(container.firstChild).toBeNull();
});

it('opens terms and privacy links on Enter key press', () => {
(useOnchainKit as Mock).mockReturnValue({
config: {
appearance: {},
wallet: {
termsUrl: 'https://terms.test',
privacyUrl: 'https://privacy.test',
},
},
});

render(<WalletModal isOpen={true} onClose={mockOnClose} />);

const termsLink = screen.getByText('Terms of Service');
const privacyLink = screen.getByText('Privacy Policy');

fireEvent.keyDown(termsLink, { key: 'Enter' });
fireEvent.keyDown(privacyLink, { key: 'Enter' });

expect(window.open).toHaveBeenCalledWith(
'https://terms.test',
'_blank',
'noopener,noreferrer',
);
expect(window.open).toHaveBeenCalledWith(
'https://privacy.test',
'_blank',
'noopener,noreferrer',
);
});

it('resets body overflow style on modal close', () => {
const { rerender } = render(
<WalletModal isOpen={true} onClose={mockOnClose} />,
);

expect(document.body.style.overflow).toBe('hidden');

rerender(<WalletModal isOpen={false} onClose={mockOnClose} />);
expect(document.body.style.overflow).toBe('');
});

it('handles non-Error objects in WalletConnect connection errors', () => {
const mockOnError = vi.fn();
(useConnect as Mock).mockReturnValue({
connect: vi.fn(() => {
throw 'Some string error';
}),
});

render(
<WalletModal isOpen={true} onClose={mockOnClose} onError={mockOnError} />,
);

fireEvent.click(screen.getByText('Other wallets'));

expect(mockOnError).toHaveBeenCalledWith(
new Error('Failed to connect wallet'),
);
expect(console.error).toHaveBeenCalledWith(
'WalletConnect connection error:',
'Some string error',
);
});
});
27 changes: 16 additions & 11 deletions src/wallet/components/WalletModal.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { useCallback, useEffect, useRef, useState } from 'react';
import { useConnect, useConnectors } from 'wagmi';
import { coinbaseWallet } from 'wagmi/connectors';
import { useConnect } from 'wagmi';
import { coinbaseWallet, walletConnect } from 'wagmi/connectors';
import { closeSvg } from '../../internal/svg/closeSvg';
import { coinbaseWalletSvg } from '../../internal/svg/coinbaseWalletSvg';
import { defaultAvatarSVG } from '../../internal/svg/defaultAvatarSVG';
Expand All @@ -15,6 +15,7 @@ import {
text,
} from '../../styles/theme';
import { useOnchainKit } from '../../useOnchainKit';
import { ONCHAINKIT_WALLETCONNECT_PROJECT_ID } from '../constants';

type WalletModalProps = {
isOpen: boolean;
Expand All @@ -33,7 +34,6 @@ export function WalletModal({
const modalRef = useRef<HTMLDivElement>(null);
const [shouldRender, setShouldRender] = useState(isOpen);
const { connect } = useConnect();
const connectors = useConnectors();
const { config } = useOnchainKit();

useEffect(() => {
Expand Down Expand Up @@ -109,19 +109,24 @@ export function WalletModal({

const handleWalletConnectConnector = useCallback(() => {
try {
const walletConnectConnector = connectors.find(
(c) => c.type === 'walletConnect',
);
if (!walletConnectConnector) {
console.error('WalletConnect connector not configured');
return;
}
const walletConnectConnector = walletConnect({
projectId: ONCHAINKIT_WALLETCONNECT_PROJECT_ID,
showQrModal: true,
});

connect({ connector: walletConnectConnector });
onClose();
} catch (error) {
console.error('WalletConnect connection error:', error);
if (onError) {
onError(
error instanceof Error
? error
: new Error('Failed to connect wallet'),
);
}
}
}, [connect, connectors, onClose]);
}, [connect, onClose, onError]);

const handleLinkKeyDown = (
event: React.KeyboardEvent<HTMLAnchorElement>,
Expand Down
2 changes: 2 additions & 0 deletions src/wallet/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,5 @@ export const ERC_1967_PROXY_IMPLEMENTATION_SLOT =
// The Coinbase Smart Wallet factory address.
export const CB_SW_FACTORY_ADDRESS =
'0x0BA5ED0c6AA8c49038F819E587E2633c4A9F428a';
export const ONCHAINKIT_WALLETCONNECT_PROJECT_ID =
'c652d0148879353d7e965d7f6f361e59';

0 comments on commit 79f3e4c

Please sign in to comment.