Skip to content

Commit c499432

Browse files
committed
feat(clerk-js,types): Support connecting Coinbase Wallet via <UserProfile />
1 parent 0158c77 commit c499432

File tree

7 files changed

+61
-25
lines changed

7 files changed

+61
-25
lines changed

.changeset/late-dots-greet.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
"@clerk/clerk-js": minor
3+
"@clerk/types": minor
4+
---
5+
6+
Support connecting Coinbase Wallet via <UserProfile />

packages/clerk-js/src/core/resources/User.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -392,6 +392,10 @@ export class User extends BaseResource implements UserResource {
392392
return this.externalAccounts.filter(externalAccount => externalAccount.verification?.status != 'verified');
393393
}
394394

395+
get verifiedWeb3Wallets() {
396+
return this.web3Wallets.filter(web3Wallet => web3Wallet.verification?.status == 'verified');
397+
}
398+
395399
get hasVerifiedEmailAddress() {
396400
return this.emailAddresses.filter(email => email.verification.status === 'verified').length > 0;
397401
}

packages/clerk-js/src/ui/components/UserProfile/Web3Form.tsx

Lines changed: 21 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { useUser } from '@clerk/shared/react';
2-
import type { Web3Strategy } from '@clerk/types';
2+
import type { Web3Provider, Web3Strategy } from '@clerk/types';
33

4-
import { generateSignatureWithMetamask, getMetamaskIdentifier } from '../../../utils/web3';
4+
import { generateWeb3Signature, getWeb3Identifier } from '../../../utils/web3';
55
import { descriptors, Image, localizationKeys } from '../../customizables';
66
import { ProfileSection, useCardState, withCardStateProvider } from '../../elements';
77
import { useEnabledThirdPartyProviders } from '../../hooks';
@@ -10,33 +10,33 @@ import { getFieldError, handleError } from '../../utils';
1010
export const AddWeb3WalletActionMenu = withCardStateProvider(() => {
1111
const card = useCardState();
1212
const { user } = useUser();
13-
const { strategyToDisplayData } = useEnabledThirdPartyProviders();
13+
const { strategies, strategyToDisplayData } = useEnabledThirdPartyProviders();
14+
15+
const enabledStrategies = strategies.filter(s => s.startsWith('web3')) as Web3Strategy[];
16+
const connectedStrategies = user?.verifiedWeb3Wallets.map(w => w.verification.strategy) as Web3Strategy[];
17+
const unconnectedStrategies = enabledStrategies.filter(strategy => {
18+
return !connectedStrategies.includes(strategy);
19+
});
1420

15-
// TODO: This logic is very similar to AddConnectedAccount but only metamask is supported right now
16-
// const enabledStrategies = strategies.filter(s => s.startsWith('web3')) as Web3Strategy[];
17-
// const connectedStrategies = user.web3Wallets.map(w => w.web3Wallet) as OAuthStrategy[];
18-
const unconnectedStrategies: Web3Strategy[] =
19-
user?.web3Wallets.filter(w => w.verification?.status === 'verified').length === 0
20-
? ['web3_metamask_signature']
21-
: [];
2221
const connect = async (strategy: Web3Strategy) => {
22+
const provider = strategy.replace('web3_', '').replace('_signature', '') as Web3Provider;
23+
2324
try {
2425
card.setLoading(strategy);
25-
const identifier = await getMetamaskIdentifier();
26+
const identifier = await getWeb3Identifier({ provider });
2627

2728
if (!user) {
2829
throw new Error('user is not defined');
2930
}
3031

3132
let web3Wallet = await user.createWeb3Wallet({ web3Wallet: identifier });
32-
web3Wallet = await web3Wallet.prepareVerification({ strategy: 'web3_metamask_signature' });
33+
web3Wallet = await web3Wallet.prepareVerification({ strategy });
3334
const nonce = web3Wallet.verification.nonce as string;
34-
const signature = await generateSignatureWithMetamask({ identifier, nonce });
35+
const signature = await generateWeb3Signature({ identifier, nonce, provider });
3536
await web3Wallet.attemptVerification({ signature });
3637
card.setIdle();
3738
} catch (err) {
3839
card.setIdle();
39-
console.log(err);
4040
const fieldError = getFieldError(err);
4141
if (fieldError) {
4242
card.setError(fieldError.longMessage);
@@ -62,7 +62,13 @@ export const AddWeb3WalletActionMenu = withCardStateProvider(() => {
6262
onClick={() => connect(strategy)}
6363
isLoading={card.loadingMetadata === strategy}
6464
isDisabled={card.isLoading}
65-
localizationKey={`Connect ${strategyToDisplayData[strategy].name} wallet`}
65+
localizationKey={localizationKeys('userProfile.web3WalletPage.web3WalletButtonsBlockButton', {
66+
provider: strategyToDisplayData[strategy].name,
67+
})}
68+
sx={t => ({
69+
justifyContent: 'start',
70+
gap: t.space.$2,
71+
})}
6672
leftIcon={
6773
<Image
6874
elementDescriptor={descriptors.providerIcon}
Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,15 @@
1+
import type { Web3Provider } from '@clerk/types';
2+
13
import { toHex } from './hex';
24

3-
export async function getMetamaskIdentifier(): Promise<string> {
5+
type GetWeb3IdentifierParams = {
6+
provider: Web3Provider;
7+
};
8+
9+
export async function getWeb3Identifier(_: GetWeb3IdentifierParams): Promise<string> {
410
// @ts-ignore
511
if (!global.ethereum) {
6-
// Do nothing when ethereum doesn't exist. We might revise this in the future
7-
// to offer an Install Metamask prompt to our users.
12+
// Do nothing when ethereum doesn't exist.
813
return '';
914
}
1015

@@ -16,24 +21,35 @@ export async function getMetamaskIdentifier(): Promise<string> {
1621
return (identifiers && identifiers[0]) || '';
1722
}
1823

19-
export type GenerateSignatureParams = {
24+
type GenerateWeb3SignatureParams = {
2025
identifier: string;
2126
nonce: string;
27+
provider: Web3Provider;
2228
};
2329

24-
export async function generateSignatureWithMetamask({ identifier, nonce }: GenerateSignatureParams): Promise<string> {
30+
export async function generateWeb3Signature({ identifier, nonce }: GenerateWeb3SignatureParams): Promise<string> {
2531
// @ts-ignore
2632
if (!global.ethereum) {
27-
// Do nothing when ethereum doesn't exist. We might revise this in the future
28-
// to offer an Install Metamask prompt to our users.
33+
// Do nothing when ethereum doesn't exist.
2934
return '';
3035
}
3136

3237
// @ts-ignore
33-
const signature: string = await global.ethereum.request({
38+
return await global.ethereum.request({
3439
method: 'personal_sign',
3540
params: [`0x${toHex(nonce)}`, identifier],
3641
});
42+
}
43+
44+
export async function getMetamaskIdentifier(): Promise<string> {
45+
return await getWeb3Identifier({ provider: 'metamask' });
46+
}
3747

38-
return signature;
48+
type GenerateSignatureParams = {
49+
identifier: string;
50+
nonce: string;
51+
};
52+
53+
export async function generateSignatureWithMetamask({ identifier, nonce }: GenerateSignatureParams): Promise<string> {
54+
return await generateWeb3Signature({ identifier, nonce, provider: 'metamask' });
3955
}

packages/localizations/src/en-US.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -792,7 +792,7 @@ export const enUS: LocalizationResource = {
792792
},
793793
web3WalletsSection: {
794794
destructiveAction: 'Remove wallet',
795-
primaryButton: 'Web3 wallets',
795+
primaryButton: 'Connect wallet',
796796
title: 'Web3 wallets',
797797
},
798798
},
@@ -810,6 +810,7 @@ export const enUS: LocalizationResource = {
810810
},
811811
subtitle__availableWallets: 'Select a web3 wallet to connect to your account.',
812812
subtitle__unavailableWallets: 'There are no available web3 wallets.',
813+
web3WalletButtonsBlockButton: '{{provider|titleize}}',
813814
successMessage: 'The wallet has been added to your account.',
814815
title: 'Add web3 wallet',
815816
},

packages/types/src/localization.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -461,6 +461,7 @@ type _LocalizationResource = {
461461
title: LocalizationValue;
462462
subtitle__availableWallets: LocalizationValue;
463463
subtitle__unavailableWallets: LocalizationValue;
464+
web3WalletButtonsBlockButton: LocalizationValue;
464465
successMessage: LocalizationValue;
465466
removeResource: {
466467
title: LocalizationValue;

packages/types/src/user.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,8 @@ export interface UserResource extends ClerkResource {
144144

145145
get unverifiedExternalAccounts(): ExternalAccountResource[];
146146

147+
get verifiedWeb3Wallets(): Web3WalletResource[];
148+
147149
get hasVerifiedEmailAddress(): boolean;
148150

149151
get hasVerifiedPhoneNumber(): boolean;

0 commit comments

Comments
 (0)