Update Onboarding logs and utilize helper functions (#20)
* Handle wallet signing rejection * nits * selectedWalletError -> string
This commit is contained in:
+3
-1
@@ -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}
|
||||
|
||||
@@ -67,6 +67,7 @@ export enum AnalyticsEvent {
|
||||
// Onboarding
|
||||
OnboardingStepChanged = 'OnboardingStepChanged',
|
||||
OnboardingAccountDerived = 'OnboardingAccountDerived',
|
||||
OnboardingWalletIsNonDeterministic = 'OnboardingWalletIsNonDeterministic',
|
||||
|
||||
// Transfers
|
||||
TransferFaucet = 'TransferFaucet',
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user