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 email, sms, and metamask extension #148

Merged
merged 12 commits into from
Dec 20, 2024
Binary file modified bun.lockb
Binary file not shown.
1 change: 0 additions & 1 deletion components/bank/forms/sendForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,6 @@ export default function SendForm({
amount: [{ denom: values.selectedToken.coreDenom, amount: amountInBaseUnits }],
});

console.log('Estimating fee for address:', address);
const fee = await estimateFee(address, [msg]);

await tx([msg], {
Expand Down
2 changes: 0 additions & 2 deletions components/groups/modals/memberManagementModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -128,8 +128,6 @@ export function MemberManagementModal({
weight: member.markedForDeletion ? '0' : member.weight || '1',
}));

console.log('Member updates:', memberUpdates);

const msg = updateGroupMembers({
admin: groupAdmin,
groupId: BigInt(groupId),
Expand Down
86 changes: 77 additions & 9 deletions components/react/modal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,20 @@ import type { ChainWalletBase, WalletModalProps } from 'cosmos-kit';
import { WalletStatus } from 'cosmos-kit';
import React, { useCallback, Fragment, useState, useMemo, useEffect } from 'react';
import { Dialog, Transition, Portal } from '@headlessui/react';
import { Connected, Connecting, Error, NotExist, QRCode, WalletList, Contacts } from './views';
import {
Connected,
Connecting,
Error,
NotExist,
QRCode,
WalletList,
Contacts,
EmailInput,
SMSInput,
} from './views';
import { useRouter } from 'next/router';
import { ToastProvider } from '@/contexts/toastContext';
import { Web3AuthClient, Web3AuthWallet } from '@cosmos-kit/web3auth';

export enum ModalView {
WalletList,
Expand All @@ -15,6 +26,8 @@ export enum ModalView {
Error,
NotExist,
Contacts,
EmailInput,
SMSInput,
}

export const TailwindModal: React.FC<
Expand Down Expand Up @@ -78,17 +91,29 @@ export const TailwindModal: React.FC<

const onWalletClicked = useCallback(
(name: string) => {
const wallet = walletRepo?.getWallet(name);
if (wallet?.walletInfo.prettyName === 'Email') {
setCurrentView(ModalView.EmailInput);
return;
}
if (wallet?.walletInfo.prettyName === 'SMS') {
setCurrentView(ModalView.SMSInput);
return;
}
Comment on lines +95 to +103
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Improve error handling for wallet selection

The wallet selection logic needs better error handling for cases where the wallet is undefined.

Apply this diff to add proper error handling:

-      if (wallet?.walletInfo.prettyName === 'Email') {
+      if (!wallet) {
+        console.error('Wallet not found');
+        return;
+      }
+      if (wallet.walletInfo.prettyName === 'Email') {

Committable suggestion skipped: line range outside the PR's diff.


walletRepo?.connect(name);

// 1ms timeout prevents _render from determining the view to show first
setTimeout(() => {
const wallet = walletRepo?.getWallet(name);

if (wallet?.isWalletNotExist) {
if (
wallet?.walletInfo.name === 'cosmos-extension-metamask' &&
wallet.message?.includes("Cannot read properties of undefined (reading 'request')")
) {
setCurrentView(ModalView.NotExist);
setSelectedWallet(wallet);
}
if (wallet?.walletInfo.mode === 'wallet-connect') {
} else if (wallet?.isWalletNotExist) {
setCurrentView(ModalView.NotExist);
setSelectedWallet(wallet);
} else if (wallet?.walletInfo.mode === 'wallet-connect') {
setCurrentView(ModalView.QRCode);
setQRWallet(wallet);
}
Expand All @@ -111,6 +136,49 @@ export const TailwindModal: React.FC<
wallets={walletRepo?.wallets || []}
/>
);
case ModalView.EmailInput:
return (
<EmailInput
onClose={onCloseModal}
onReturn={() => setCurrentView(ModalView.WalletList)}
onSubmit={async email => {
try {
const emailWallet = walletRepo?.wallets.find(
w => w.walletInfo.prettyName === 'Email'
) as Web3AuthWallet | undefined;

if (emailWallet?.client instanceof Web3AuthClient) {
console.log('Setting login hint:', email);
emailWallet.client.setLoginHint(email);
await walletRepo?.connect(emailWallet.walletInfo.name);
} else {
console.error('Email wallet or client not found');
}
} catch (error) {
console.error('Email login error:', error);
// Handle the error appropriately in your UI
}
}}
/>
);

case ModalView.SMSInput:
return (
<SMSInput
onClose={onCloseModal}
onReturn={() => setCurrentView(ModalView.WalletList)}
onSubmit={phone => {
const smsWallet = walletRepo?.wallets.find(w => w.walletInfo.prettyName === 'SMS') as
| Web3AuthWallet
| undefined;

if (smsWallet?.client instanceof Web3AuthClient) {
smsWallet.client.setLoginHint(phone);
walletRepo?.connect(smsWallet.walletInfo.name);
}
}}
/>
);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Add error handling for email/SMS submission

The email and SMS submission logic needs better error handling and user feedback.

Add proper error handling and user feedback:

 onSubmit={async email => {
   try {
     const emailWallet = walletRepo?.wallets.find(
       w => w.walletInfo.prettyName === 'Email'
     ) as Web3AuthWallet | undefined;

     if (emailWallet?.client instanceof Web3AuthClient) {
-      console.log('Setting login hint:', email);
+      // Avoid logging sensitive information
       emailWallet.client.setLoginHint(email);
       await walletRepo?.connect(emailWallet.walletInfo.name);
     } else {
-      console.error('Email wallet or client not found');
+      throw new Error('Email wallet configuration not found');
     }
   } catch (error) {
-    console.error('Email login error:', error);
+    // Handle specific error types
+    if (error instanceof Error) {
+      // Show user-friendly error message
+      throw new Error(`Failed to login: ${error.message}`);
+    }
   }
 }}

Committable suggestion skipped: line range outside the PR's diff.

Comment on lines +165 to +181
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Add error handling and improve type safety in SMS login

The current implementation lacks error handling and proper async/await usage:

-            onSubmit={phone => {
+            onSubmit={async phone => {
+              try {
                 const smsWallet = walletRepo?.wallets.find(
                   w => w.walletInfo.prettyName === 'SMS'
-                ) as Web3AuthWallet | undefined;
+                );
+                
+                if (!smsWallet) {
+                  throw new Error('SMS wallet not found');
+                }
 
-              if (smsWallet?.client instanceof Web3AuthClient) {
+                if (smsWallet.client instanceof Web3AuthClient) {
                   smsWallet.client.setLoginHint(phone);
-                  walletRepo?.connect(smsWallet.walletInfo.name);
+                  await walletRepo?.connect(smsWallet.walletInfo.name);
+                } else {
+                  throw new Error('SMS wallet configuration not found');
+                }
+              } catch (error) {
+                if (error instanceof Error) {
+                  throw new Error(`SMS login failed: ${error.message}`);
+                }
+                throw new Error('An unexpected error occurred');
+              }
             }}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
case ModalView.SMSInput:
return (
<SMSInput
onClose={onCloseModal}
onReturn={() => setCurrentView(ModalView.WalletList)}
onSubmit={phone => {
const smsWallet = walletRepo?.wallets.find(w => w.walletInfo.prettyName === 'SMS') as
| Web3AuthWallet
| undefined;
if (smsWallet?.client instanceof Web3AuthClient) {
smsWallet.client.setLoginHint(phone);
walletRepo?.connect(smsWallet.walletInfo.name);
}
}}
/>
);
case ModalView.SMSInput:
return (
<SMSInput
onClose={onCloseModal}
onReturn={() => setCurrentView(ModalView.WalletList)}
onSubmit={async phone => {
try {
const smsWallet = walletRepo?.wallets.find(
w => w.walletInfo.prettyName === 'SMS'
);
if (!smsWallet) {
throw new Error('SMS wallet not found');
}
if (smsWallet.client instanceof Web3AuthClient) {
smsWallet.client.setLoginHint(phone);
await walletRepo?.connect(smsWallet.walletInfo.name);
} else {
throw new Error('SMS wallet configuration not found');
}
} catch (error) {
if (error instanceof Error) {
throw new Error(`SMS login failed: ${error.message}`);
}
throw new Error('An unexpected error occurred');
}
}}
/>
);

case ModalView.Connected:
return (
<Connected
Expand All @@ -125,11 +193,11 @@ export const TailwindModal: React.FC<
);
case ModalView.Connecting:
let subtitle: string;
if (currentWalletData!.mode === 'wallet-connect') {
if (currentWalletData!?.mode === 'wallet-connect') {
subtitle = `Approve ${currentWalletData!.prettyName} connection request on your mobile.`;
} else {
subtitle = `Open the ${
currentWalletData!.prettyName
currentWalletData!?.prettyName
Comment on lines +196 to +200
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Replace unsafe non-null assertions

The current code uses multiple non-null assertions (!), which could lead to runtime errors if currentWalletData is undefined.

Apply this safer approach using optional chaining with fallbacks:

-if (currentWalletData!?.mode === 'wallet-connect') {
-  subtitle = `Approve ${currentWalletData!.prettyName} connection request on your mobile.`;
-} else {
-  subtitle = `Open the ${currentWalletData!?.prettyName} browser extension to connect your wallet.`;
-}
+if (currentWalletData?.mode === 'wallet-connect') {
+  subtitle = `Approve ${currentWalletData.prettyName || 'wallet'} connection request on your mobile.`;
+} else {
+  subtitle = `Open the ${currentWalletData?.prettyName || 'wallet'} browser extension to connect your wallet.`;
+}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (currentWalletData!?.mode === 'wallet-connect') {
subtitle = `Approve ${currentWalletData!.prettyName} connection request on your mobile.`;
} else {
subtitle = `Open the ${
currentWalletData!.prettyName
currentWalletData!?.prettyName
if (currentWalletData?.mode === 'wallet-connect') {
subtitle = `Approve ${currentWalletData.prettyName || 'wallet'} connection request on your mobile.`;
} else {
subtitle = `Open the ${currentWalletData?.prettyName || 'wallet'} browser extension to connect your wallet.`;
}
🧰 Tools
🪛 Biome (1.9.4)

[error] 134-134: Forbidden extra non-null assertion.

Safe fix: Remove extra non-null assertion.

(lint/suspicious/noExtraNonNullAssertion)


[error] 138-138: Forbidden extra non-null assertion.

Safe fix: Remove extra non-null assertion.

(lint/suspicious/noExtraNonNullAssertion)

🪛 GitHub Check: codecov/patch

[warning] 134-134: components/react/modal.tsx#L134
Added line #L134 was not covered by tests


[warning] 138-138: components/react/modal.tsx#L138
Added line #L138 was not covered by tests

} browser extension to connect your wallet.`;
}

Expand Down
2 changes: 1 addition & 1 deletion components/react/views/Connected.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ export const Connected = ({
<Image
height={0}
width={0}
src={getRealLogo(logo)}
src={name === 'Cosmos MetaMask Extension' ? '/metamask.svg' : getRealLogo(logo)}
alt={name}
className="w-8 h-8 rounded-full mr-2"
/>
Expand Down
2 changes: 1 addition & 1 deletion components/react/views/Connecting.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ export const Connecting = ({
</div>
<div className="flex flex-col w-full h-full mt-4 sm:px-8 sm:py-6">
<img
src={getRealLogo(logo)}
src={name === 'Cosmos MetaMask Extension' ? '/metamask.svg' : getRealLogo(logo)}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codebase verification

🛠️ Refactor suggestion

Refactor wallet name comparison for maintainability

The string 'Cosmos MetaMask Extension' is used consistently across multiple view components for wallet identification and logo rendering. To improve maintainability, create a new constant in utils/constants.ts:

// utils/constants.ts
+ export const WALLET_IDENTIFIERS = {
+   METAMASK: 'Cosmos MetaMask Extension'
+ } as const;

Issues found:

  • The string 'Cosmos MetaMask Extension' is duplicated across 5 different view components (WalletList.tsx, Connecting.tsx, NotExist.tsx, Error.tsx, Connected.tsx)
  • The MetaMask logo path '/metamask.svg' is also duplicated across these components
  • No existing wallet type constants are defined in the codebase to handle these identifiers

Please consolidate these hardcoded values into constants and update all occurrences for better maintainability.

🔗 Analysis chain

Refactor wallet name comparison for maintainability

The hardcoded string comparison makes the code fragile and harder to maintain. Consider extracting wallet identifiers into constants.

+ const WALLET_TYPES = {
+   METAMASK: 'Cosmos MetaMask Extension'
+ } as const;
+
  export const Connecting = ({
    // ...
  }) => {
    return (
      // ...
          src={name === WALLET_TYPES.METAMASK ? '/metamask.svg' : getRealLogo(logo)}
      // ...
    );
  };

Additionally, please add test coverage for this new conditional logic.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check if MetaMask logo exists
if [ ! -f "public/metamask.svg" ]; then
  echo "Warning: MetaMask logo file not found at public/metamask.svg"
  exit 1
fi

# Search for similar hardcoded strings across codebase
rg -l "Cosmos MetaMask Extension"

Length of output: 254


Script:

#!/bin/bash
# Let's check how this string is used across files to understand the pattern
rg "Cosmos MetaMask Extension" -A 2 -B 2

# Also check if there are any existing constants for wallet types
rg "const.*WALLET|METAMASK" --type typescript

Length of output: 2892


Script:

#!/bin/bash
# Let's check for any existing type definitions or constants in the codebase
rg "type.*Wallet|enum.*Wallet|const.*Wallet|METAMASK" --type ts

# Also check if there's a constants file or types file
fd "constants|types" -e ts -e tsx

Length of output: 2154


Script:

#!/bin/bash
# Let's check the content of these files for any existing wallet-related constants
cat utils/constants.ts
cat components/types.tsx

Length of output: 1770

🧰 Tools
🪛 GitHub Check: codecov/patch

[warning] 46-46: components/react/views/Connecting.tsx#L46
Added line #L46 was not covered by tests

alt={name}
className="flex-shrink-0 w-20 h-20 mx-auto aspect-1"
/>
Expand Down
63 changes: 63 additions & 0 deletions components/react/views/EmailInput.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import { XMarkIcon, ArrowLeftIcon } from '@heroicons/react/24/outline';
import { Formik, Form } from 'formik';
import * as Yup from 'yup';
import { TextInput } from '../inputs/TextInput';

const validationSchema = Yup.object({
email: Yup.string().email('Invalid email address').required('Email is required'),
});

export const EmailInput = ({
onClose,
onReturn,
onSubmit,
}: {
onClose: () => void;
onReturn: () => void;
onSubmit: (email: string) => void;
}) => {
return (
<div className="p-1 relative max-w-sm mx-auto">
<div className="flex items-center justify-between mb-6">
<button
onClick={onReturn}
className="p-2 text-primary bg-neutral rounded-full hover:bg-gray-200 dark:hover:bg-gray-700"
>
<ArrowLeftIcon className="w-5 h-5" />
</button>
<h1 className="text-sm font-semibold">Enter Email</h1>
<button
onClick={onClose}
className="p-2 text-primary bg-neutral rounded-full hover:bg-gray-200 dark:hover:bg-gray-700"
>
<XMarkIcon className="w-5 h-5" />
</button>
</div>

<Formik
initialValues={{ email: '' }}
validationSchema={validationSchema}
onSubmit={values => onSubmit(values.email)}
>
{({ isValid, dirty }) => (
<Form className="space-y-4">
<TextInput
name="email"
type="email"
placeholder="[email protected]"
className="w-full p-3 rounded-lg dark:bg-[#ffffff0c] bg-[#f0f0ff5c]"
/>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Enhance accessibility for email input.

The email input field should have proper accessibility attributes.

 <TextInput
   name="email"
   type="email"
+  aria-label="Email address"
+  aria-required="true"
   placeholder="[email protected]"
   className="w-full p-3 rounded-lg dark:bg-[#ffffff0c] bg-[#f0f0ff5c]"
 />
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<TextInput
name="email"
type="email"
placeholder="[email protected]"
className="w-full p-3 rounded-lg dark:bg-[#ffffff0c] bg-[#f0f0ff5c]"
/>
<TextInput
name="email"
type="email"
aria-label="Email address"
aria-required="true"
placeholder="[email protected]"
className="w-full p-3 rounded-lg dark:bg-[#ffffff0c] bg-[#f0f0ff5c]"
/>


<button
type="submit"
disabled={!isValid || !dirty}
className="w-full p-3 rounded-lg bg-primary text-white disabled:opacity-50 transition"
>
Continue with Email
</button>
</Form>
)}
</Formik>
</div>
);
};
6 changes: 5 additions & 1 deletion components/react/views/Error.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,11 @@ export const Error = ({
<div className="flex flex-col w-full h-full py-6 mt-4 sm:px-8">
<div className="p-3 border rounded-full border-red-600 mx-auto aspect-1 flex-shrink-0">
<Image
src={getRealLogo(logo)}
src={
currentWalletName === 'cosmos-extension-metamask'
? '/metamask.svg'
: getRealLogo(logo)
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Standardize MetaMask wallet identifier

The MetaMask check uses 'cosmos-extension-metamask' while other components use 'Cosmos MetaMask Extension'. This inconsistency could lead to bugs.

- currentWalletName === 'cosmos-extension-metamask'
+ currentWalletName === WALLET_TYPES.METAMASK

Committable suggestion skipped: line range outside the PR's diff.

🧰 Tools
🪛 GitHub Check: codecov/patch

[warning] 48-52: components/react/views/Error.tsx#L48-L52
Added lines #L48 - L52 were not covered by tests

alt="Wallet type logo"
className="flex-shrink-0 w-16 h-16 aspect-1"
width={16}
Expand Down
13 changes: 8 additions & 5 deletions components/react/views/NotExist.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export const NotExist = ({
<ChevronLeftIcon className="w-5 h-5" aria-hidden="true" />
</button>
<Dialog.Title as="h3" className="text-lg font-semibold">
{name}
{name === 'Cosmos MetaMask Extension' ? 'Metamask' : name}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Refactor duplicated wallet name checks and logo logic

The condition name === 'Cosmos MetaMask Extension' is repeated multiple times, and the logo source determination logic is duplicated across components. This makes maintenance difficult and prone to errors.

Consider extracting these into shared utilities:

+ // utils/wallet.ts
+ export const WALLET_TYPES = {
+   METAMASK: 'Cosmos MetaMask Extension'
+ } as const;
+ 
+ export const getWalletDisplayName = (name: string) => {
+   return name === WALLET_TYPES.METAMASK ? 'Metamask' : name;
+ };
+ 
+ export const getWalletLogo = (name: string, defaultLogo: string) => {
+   return name === WALLET_TYPES.METAMASK ? '/metamask.svg' : getRealLogo(defaultLogo);
+ };

  // In component
- name === 'Cosmos MetaMask Extension' ? 'Metamask' : name
+ getWalletDisplayName(name)

- src={name === 'Cosmos MetaMask Extension' ? '/metamask.svg' : getRealLogo(logo)}
+ src={getWalletLogo(name, logo)}

Also applies to: 43-43, 48-48, 51-51, 59-59

🧰 Tools
🪛 GitHub Check: codecov/patch

[warning] 31-31: components/react/views/NotExist.tsx#L31
Added line #L31 was not covered by tests


💡 Codebase verification

Add test coverage for NotExist component's wallet name rendering

The verification confirms that:

  • The NotExist component handles conditional wallet name rendering for MetaMask
  • There are multiple test files in the codebase following a consistent pattern under __tests__ directories
  • Related wallet components exist (WalletList.tsx, Connected.tsx) but NotExist.tsx lacks test coverage

You should:

  • Create a new test file at components/react/views/__tests__/NotExist.test.tsx
  • Test the following scenarios:
    • Rendering with MetaMask wallet name (should display "Metamask")
    • Rendering with other wallet names (should display the original name)
    • Logo source conditional logic
    • Button click handlers (onClose, onReturn, onInstall)
🔗 Analysis chain

Add test coverage for wallet name and logo rendering logic

The new conditional logic for wallet names and logos lacks test coverage.

Would you like me to help generate test cases for the new wallet rendering logic?

Also applies to: 43-43, 48-48, 51-51, 59-59

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check current test coverage for wallet-related components
fd -e test.tsx -e spec.tsx . | xargs rg "describe.*NotExist|test.*MetaMask"

Length of output: 77


Script:

#!/bin/bash
# Let's first check if the NotExist component exists and its test files
fd NotExist

# Then let's look for any existing test files in the components directory
fd -e test.tsx -e spec.tsx -e test.ts -e spec.ts components/

# Finally, let's check the content of NotExist.tsx to understand the full context
cat components/react/views/NotExist.tsx

Length of output: 2886


Script:

#!/bin/bash
# Let's check for any existing test files in the components directory with correct path
fd -e test.tsx -e spec.tsx -e test.ts -e spec.ts . components

# Let's also check if there are any test files that might test wallet-related functionality
rg -l "wallet.*test|test.*wallet" -g "*.test.*" -g "*.spec.*"

# Let's see if there are any similar components that might have test patterns we can follow
fd -e tsx -e ts . components | rg -i "wallet|connect"

Length of output: 2177

🧰 Tools
🪛 GitHub Check: codecov/patch

[warning] 31-31: components/react/views/NotExist.tsx#L31
Added line #L31 was not covered by tests

</Dialog.Title>
<button
type="button"
Expand All @@ -40,20 +40,23 @@ export const NotExist = ({
</div>
<div className="flex flex-col w-full h-full py-6 mt-4 sm:px-8">
<img
src={getRealLogo(logo)}
src={name === 'Cosmos MetaMask Extension' ? '/metamask.svg' : getRealLogo(logo)}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codebase verification

🛠️ Refactor suggestion

Confirmed: Wallet logo logic duplication needs refactoring

The verification shows clear evidence of duplicated wallet logo logic across multiple components:

  • NotExist.tsx, Connecting.tsx, Connected.tsx all use identical condition: name === 'Cosmos MetaMask Extension' ? '/metamask.svg' : getRealLogo(logo)
  • WalletList.tsx and Error.tsx have similar but slightly different implementations
  • getRealLogo utility already exists in utils/logos.ts, showing a precedent for shared wallet utilities

The original review suggestion to extract this logic is valid and would improve code maintainability.

🔗 Analysis chain

Extract shared wallet logo logic to avoid duplication

The wallet logo rendering logic is duplicated across multiple components. Consider extracting this into a shared utility function.

+ // utils/wallet.ts
+ export const getWalletLogo = (name: string, defaultLogo: string) => {
+   return name === WALLET_TYPES.METAMASK ? '/metamask.svg' : getRealLogo(defaultLogo);
+ };

  // In component
  src={getWalletLogo(name, logo)}

Please add test coverage for the new logic.


Let me check the actual implementation of these files to verify the duplication pattern.


Let me try a different approach to verify the pattern.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Find all components using similar wallet logo logic
rg -l "metamask\.svg"

# Check for existing wallet-related utilities
fd -e ts -e tsx -p "wallet.*\.(ts|tsx)$" src utils components

Length of output: 379


Script:

#!/bin/bash
# Check the actual implementation of wallet logo logic in all relevant files
rg -A 2 "metamask\.svg" --type tsx

# Check if there's any existing wallet utility functions
ast-grep --pattern 'function $_(name: string, $_) {
  $$$
  metamask$$$
}'

Length of output: 141


Script:

#!/bin/bash
# Check the actual implementation of wallet logo logic in all relevant files
rg -A 2 "metamask\.svg"

# Look for any existing utility functions related to wallet logos
rg "getRealLogo" -A 2

# Check for any constants or types related to wallet names
rg "WALLET_TYPES|WalletType" -A 2

Length of output: 5100

🧰 Tools
🪛 GitHub Check: codecov/patch

[warning] 43-43: components/react/views/NotExist.tsx#L43
Added line #L43 was not covered by tests

alt={name}
className="flex-shrink-0 w-16 h-16 mx-auto aspect-1"
/>
<p className="mt-3 font-medium text-black dark:text-white">Install {name}</p>
<p className="mt-3 font-medium text-black dark:text-white">
Install {name === 'Cosmos MetaMask Extension' ? 'Metamask' : name}
</p>
<p className="mt-1 text-sm text-gray-500 dark:text-white/75">
To connect your {name} wallet, install the browser extension.
To connect your {name === 'Cosmos MetaMask Extension' ? 'Metamask' : name} wallet, install
the browser extension.
</p>
<button
className={`rounded-lg btn-primary btn btn-md ${name.length >= 12 ? 'w-1/2' : 'w-1/3'} mx-auto inline-flex justify-center items-center py-2.5 font-medium mt-4 text-white`}
onClick={onInstall}
>
<ArrowDownTrayIcon className="flex-shrink-0 w-5 h-5 mr-2 text-white" />
Install {name}
Install {name === 'Cosmos MetaMask Extension' ? 'Metamask' : name}
</button>
</div>
</div>
Expand Down
Loading
Loading