Skip to content
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

feat: Add Phantom Connector in WalletModal #1770

Merged
merged 11 commits into from
Jan 6, 2025
Merged
Show file tree
Hide file tree
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
5 changes: 5 additions & 0 deletions .changeset/green-coins-add.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@coinbase/onchainkit': patch
---

- **feat**: Add Phantom Wallet connection support in `WalletModal`. By @cpcramer #1770
Binary file modified site/docs/public/assets/wallet-modal.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
26 changes: 26 additions & 0 deletions src/internal/svg/phantomSvg.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
export const phantomSvg = (
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 146 146"
width="100%"
height="100%"
role="img"
aria-label="Phantom Logo"
>
<title>Phantom Logo</title>
<g clipPath="url(#clip0_phantom)">
<rect width="146" height="146" rx="31.3" fill="#AB9FF2" />
<path
fillRule="evenodd"
clipRule="evenodd"
d="M62.92 94.85C57.19 103.66 47.58 114.75 34.79 114.75C28.76 114.75 22.95 112.28 22.95 101.45C22.95 73.97 60.51 31.37 95.38 31.37C115.19 31.37 123.11 45.13 123.11 60.77C123.11 80.81 110.11 103.74 97.15 103.74C93.05 103.74 91.06 101.45 91.06 97.91C91.06 96.98 91.21 95.98 91.52 94.85C87.11 102.41 78.57 109.41 70.6 109.41C64.75 109.41 61.83 105.85 61.83 100.63C61.83 98.77 62.22 96.82 62.92 94.85ZM110.03 60.23C110.03 64.75 107.36 67.03 104.37 67.03C101.31 67.03 98.65 64.75 98.65 60.23C98.65 55.66 101.31 53.38 104.37 53.38C107.36 53.38 110.03 55.66 110.03 60.23ZM92.96 60.23C92.96 64.75 90.29 67.03 87.3 67.03C84.24 67.03 81.58 64.75 81.58 60.23C81.58 55.66 84.24 53.38 87.3 53.38C90.29 53.38 92.96 55.66 92.96 60.23Z"
fill="#FFFDF8"
/>
</g>
<defs>
<clipPath id="clip0_phantom">
<rect width="146" height="146" fill="white" />
</clipPath>
</defs>
</svg>
);
61 changes: 61 additions & 0 deletions src/wallet/components/WalletModal.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ vi.mock('../../core-react/useOnchainKit', () => ({
vi.mock('wagmi/connectors', () => ({
coinbaseWallet: () => ({ preference: 'all' }),
metaMask: ({ dappMetadata }: MetaMaskParameters) => ({ dappMetadata }),
injected: ({ target }: { target: string }) => ({
target,
}),
}));

describe('WalletModal', () => {
Expand Down Expand Up @@ -493,4 +496,62 @@ describe('WalletModal', () => {
'Some string error',
);
});

it('connects with Phantom when clicking Phantom button', () => {
render(<WalletModal isOpen={true} onClose={mockOnClose} />);

fireEvent.click(screen.getByText('Phantom'));

expect(mockConnect).toHaveBeenCalledWith({
connector: {
target: 'phantom',
},
});
expect(mockOnClose).toHaveBeenCalled();
});

it('handles Phantom connection errors', () => {
const mockError = new Error('Phantom connection failed');
const mockOnError = vi.fn();
(useConnect as Mock).mockReturnValue({
connect: vi.fn(() => {
throw mockError;
}),
});

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

fireEvent.click(screen.getByText('Phantom'));

expect(mockOnError).toHaveBeenCalledWith(mockError);
expect(console.error).toHaveBeenCalledWith(
'Phantom connection error:',
mockError,
);
});

it('handles non-Error objects in Phantom 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('Phantom'));

expect(mockOnError).toHaveBeenCalledWith(
new Error('Failed to connect wallet'),
);
expect(console.error).toHaveBeenCalledWith(
'Phantom connection error:',
'Some string error',
);
});
});
37 changes: 36 additions & 1 deletion src/wallet/components/WalletModal.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { useCallback, useEffect, useRef, useState } from 'react';
import { useConnect } from 'wagmi';
import { coinbaseWallet, metaMask } from 'wagmi/connectors';
import { coinbaseWallet, injected, metaMask } from 'wagmi/connectors';
import { useOnchainKit } from '../../core-react/useOnchainKit';
import { closeSvg } from '../../internal/svg/closeSvg';
import { coinbaseWalletSvg } from '../../internal/svg/coinbaseWalletSvg';
import { defaultAvatarSVG } from '../../internal/svg/defaultAvatarSVG';
import { metamaskSvg } from '../../internal/svg/metamaskSvg';
import { phantomSvg } from '../../internal/svg/phantomSvg';
import {
background,
border,
Expand Down Expand Up @@ -125,6 +126,22 @@ export function WalletModal({
}
}, [connect, onClose, onError, appName, appLogo]);

const handlePhantomConnection = useCallback(() => {
try {
const phantomConnector = injected({
target: 'phantom',
});

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

const handleLinkKeyDown = (
event: React.KeyboardEvent<HTMLAnchorElement>,
url: string,
Expand Down Expand Up @@ -278,6 +295,24 @@ export function WalletModal({
{metamaskSvg}
</div>
</button>

<button
type="button"
onClick={handlePhantomConnection}
className={cn(
border.radius,
background.default,
text.body,
pressable.alternate,
color.foreground,
'flex items-center justify-between px-4 py-3 text-left',
)}
>
Phantom
<div className="-mr-0.5 flex h-4 w-4 items-center justify-center">
{phantomSvg}
</div>
</button>
</div>

<div
Expand Down
Loading