Update Onboarding logs and utilize helper functions (#20)

* Handle wallet signing rejection

* nits

* selectedWalletError -> string
This commit is contained in:
Jared Vu
2023-09-05 09:59:27 -07:00
committed by GitHub
parent d4c149af12
commit 2b888001aa
8 changed files with 160 additions and 56 deletions
+3 -1
View File
@@ -192,7 +192,9 @@ Styled.NotificationsToastArea = styled(NotificationsToastArea)`
`;
Styled.DialogArea = styled.aside`
position: absolute;
position: fixed;
height: 100vh;
z-index: 1;
inset: 0;
overflow: clip;
${layoutMixins.noPointerEvents}
+1
View File
@@ -67,6 +67,7 @@ export enum AnalyticsEvent {
// Onboarding
OnboardingStepChanged = 'OnboardingStepChanged',
OnboardingAccountDerived = 'OnboardingAccountDerived',
OnboardingWalletIsNonDeterministic = 'OnboardingWalletIsNonDeterministic',
// Transfers
TransferFaucet = 'TransferFaucet',
+12
View File
@@ -32,6 +32,18 @@ export enum WalletConnectionType {
WalletConnect2 = 'walletConnect2',
}
export enum WalletErrorType {
// General
ChainMismatch,
UserCanceled,
// Non-Deterministic
NonDeterministicWallet,
// Misc
Unknown,
}
type WalletConnectionTypeConfig = {
name: string;
wagmiConnectorId?: string;
+7 -4
View File
@@ -57,8 +57,8 @@ const useDydxClientContext = () => {
networkConfig?.indexerSocketUrl &&
networkConfig?.validatorUrl
) {
setCompositeClient(
await CompositeClient.connect(
try {
const initializedClient = await CompositeClient.connect(
new Network(
selectedNetwork,
new IndexerConfig(networkConfig.indexerUrl, networkConfig.indexerSocketUrl),
@@ -67,8 +67,11 @@ const useDydxClientContext = () => {
broadcastTimeoutMs: 60_000,
})
)
)
);
);
setCompositeClient(initializedClient);
} catch (error) {
log('useDydxClient/initializeCompositeClient', error);
}
} else {
setCompositeClient(undefined);
}
+13 -7
View File
@@ -11,6 +11,8 @@ import {
DYDX_CHAIN_INFO,
} from '@/constants/wallets';
import { useLocalStorage } from '@/hooks/useLocalStorage';
import {
useConnect as useConnectWagmi,
useAccount as useAccountWagmi,
@@ -26,10 +28,9 @@ import {
} from 'graz';
import { resolveWagmiConnector } from '@/lib/wagmi';
import { getWalletConnection } from '@/lib/wallet';
import { getWalletConnection, parseWalletError } from '@/lib/wallet';
import { log } from '@/lib/telemetry';
import { useLocalStorage } from '@/hooks/useLocalStorage';
import { useStringGetter } from './useStringGetter';
export const useWalletConnection = () => {
@@ -129,8 +130,6 @@ export const useWalletConnection = () => {
}
}
} catch (error) {
log('useWalletConnection/connectWallet', error);
throw Object.assign(
new Error([error.message, error.cause?.message].filter(Boolean).join('\n')),
{
@@ -158,7 +157,7 @@ export const useWalletConnection = () => {
// Wallet selection
const [selectedWalletType, setSelectedWalletType] = useState<WalletType | undefined>(walletType);
const [selectedWalletError, setSelectedWalletError] = useState<Error>();
const [selectedWalletError, setSelectedWalletError] = useState<string>();
useEffect(() => {
(async () => {
@@ -173,8 +172,15 @@ export const useWalletConnection = () => {
setWalletType(walletType);
setWalletConnectionType(walletConnectionType);
} catch (error) {
log('useWalletConnection/connectWallet', error);
setSelectedWalletError(error);
const { walletErrorType, message } = parseWalletError({
error,
stringGetter,
});
if (message) {
log('useWalletConnection/connectWallet', error, { walletErrorType });
setSelectedWalletError(message);
}
}
} else {
setWalletType(undefined);
+66
View File
@@ -1,7 +1,10 @@
import { STRING_KEYS, StringGetterFunction } from '@/constants/localization';
import {
type WalletConnection,
wallets,
WalletConnectionType,
WalletErrorType,
WalletType,
} from '@/constants/wallets';
@@ -68,3 +71,66 @@ export const getWalletConnection = ({
}
}
};
export const getWalletErrorType = ({ error }: { error: Error }) => {
const { message } = error;
const messageLower = message.toLowerCase();
// General - Cancelled
if (
messageLower.includes('connection request reset') ||
messageLower.includes('rejected') ||
messageLower.includes('reject') ||
messageLower.includes('cancelled') ||
messageLower.includes('canceled') ||
messageLower.includes('user denied')
) {
return WalletErrorType.UserCanceled;
}
if (messageLower.includes('chain mismatch')) {
return WalletErrorType.ChainMismatch;
}
// ImToken - User canceled
if (messageLower.includes('用户取消了操作')) {
return WalletErrorType.UserCanceled;
}
if (messageLower.includes('does not support deterministic signing')) {
return WalletErrorType.NonDeterministicWallet;
}
return WalletErrorType.Unknown;
};
export const parseWalletError = ({
error,
stringGetter,
}: {
error: Error;
stringGetter: StringGetterFunction;
}) => {
const walletErrorType = getWalletErrorType({ error });
let message;
switch (walletErrorType) {
case WalletErrorType.ChainMismatch:
case WalletErrorType.UserCanceled: {
break;
}
default: {
message = stringGetter({
key: STRING_KEYS.SOMETHING_WENT_WRONG_WITH_MESSAGE,
params: {
ERROR_MESSAGE: error.message || stringGetter({ key: STRING_KEYS.UNKNOWN_ERROR }),
},
});
}
}
return {
walletErrorType,
message,
};
};
@@ -32,8 +32,12 @@ export const ChooseWallet = () => {
<>
{selectedWalletType && selectedWalletError && (
<Styled.AlertMessage type={AlertType.Error}>
{<h4>Couldn't connect to {stringGetter({ key: wallets[selectedWalletType].stringKey })}.</h4>}
<code>{selectedWalletError.message}</code>
{
<h4>
Couldn't connect to {stringGetter({ key: wallets[selectedWalletType].stringKey })}.
</h4>
}
{selectedWalletError}
</Styled.AlertMessage>
)}
@@ -25,11 +25,12 @@ import { Switch } from '@/components/Switch';
import { WithReceipt } from '@/components/WithReceipt';
import { WithTooltip } from '@/components/WithTooltip';
import { getSelectedNetwork } from '@/state/appSelectors';
import { track } from '@/lib/analytics';
import { isTruthy } from '@/lib/isTruthy';
import { log } from '@/lib/telemetry';
import { getSelectedNetwork } from '@/state/appSelectors';
import { parseWalletError } from '@/lib/wallet';
type ElementProps = {
status: EvmDerivedAccountStatus;
@@ -66,8 +67,12 @@ export const GenerateKeys = ({
try {
await matchNetwork?.();
} catch (error) {
setError(error.message);
log('GenerateKeys/switchNetwork', error);
const { message, walletErrorType } = parseWalletError({ error, stringGetter });
if (message) {
log('GenerateKeys/switchNetwork', error, { walletErrorType });
setError(message);
}
}
};
@@ -124,7 +129,12 @@ export const GenerateKeys = ({
}
}
} catch (error) {
log('GenerateKeys/getSubaccounts', error);
const { message } = parseWalletError({ error, stringGetter });
if (message) {
track(AnalyticsEvent.OnboardingWalletIsNonDeterministic);
setError(message);
}
}
await setWalletFromEvmSignature(signature);
@@ -140,48 +150,48 @@ export const GenerateKeys = ({
setStatus(EvmDerivedAccountStatus.Derived);
} catch (error) {
setStatus(EvmDerivedAccountStatus.NotDerived);
setError(error?.message);
const { message, walletErrorType } = parseWalletError({ error, stringGetter });
log('GenerateKeys/deriveKeys', error);
throw error;
if (message) {
setError(message);
log('GenerateKeys/deriveKeys', error, { walletErrorType });
}
}
};
return (
<>
{isMobile && (
<Styled.MobileStatusCards>
{[
{
status: EvmDerivedAccountStatus.Deriving,
title: stringGetter({ key: STRING_KEYS.GENERATE_COSMOS_WALLET }),
description: stringGetter({ key: STRING_KEYS.GENERATE_COSMOS_WALLET }),
},
status === EvmDerivedAccountStatus.EnsuringDeterminism && {
status: EvmDerivedAccountStatus.EnsuringDeterminism,
title: stringGetter({ key: STRING_KEYS.VERIFY_WALLET_COMPATIBILITY }),
description: stringGetter({ key: STRING_KEYS.ENSURES_WALLET_SUPPORT }),
},
]
.filter(isTruthy)
.map((step) => (
<Styled.StatusCard key={step.status} active={status === step.status}>
{status < step.status ? (
<LoadingSpinner disabled />
) : status === step.status ? (
<LoadingSpinner />
) : (
<Styled.GreenCheckCircle />
)}
<div>
<h3>{step.title}</h3>
<p>{step.description}</p>
</div>
</Styled.StatusCard>
))}
</Styled.MobileStatusCards>
)}
<Styled.StatusCardsContainer>
{[
{
status: EvmDerivedAccountStatus.Deriving,
title: stringGetter({ key: STRING_KEYS.GENERATE_COSMOS_WALLET }),
description: stringGetter({ key: STRING_KEYS.GENERATE_COSMOS_WALLET }),
},
status === EvmDerivedAccountStatus.EnsuringDeterminism && {
status: EvmDerivedAccountStatus.EnsuringDeterminism,
title: stringGetter({ key: STRING_KEYS.VERIFY_WALLET_COMPATIBILITY }),
description: stringGetter({ key: STRING_KEYS.ENSURES_WALLET_SUPPORT }),
},
]
.filter(isTruthy)
.map((step) => (
<Styled.StatusCard key={step.status} active={status === step.status}>
{status < step.status ? (
<LoadingSpinner disabled />
) : status === step.status ? (
<LoadingSpinner />
) : (
<Styled.GreenCheckCircle />
)}
<div>
<h3>{step.title}</h3>
<p>{step.description}</p>
</div>
</Styled.StatusCard>
))}
</Styled.StatusCardsContainer>
<Styled.Footer>
<Styled.RememberMe htmlFor="remember-me">
<WithTooltip withIcon tooltip="remember-me">
@@ -251,7 +261,7 @@ export const GenerateKeys = ({
const Styled: Record<string, AnyStyledComponent> = {};
Styled.MobileStatusCards = styled.div`
Styled.StatusCardsContainer = styled.div`
display: grid;
margin-top: 1rem;
gap: 1rem;