Merge branch 'main' into abacus-tracking

This commit is contained in:
jaredvu
2023-09-05 13:01:07 -07:00
27 changed files with 184 additions and 79 deletions
+1 -1
View File
@@ -37,7 +37,7 @@
"@cosmjs/proto-signing": "^0.31.0",
"@cosmjs/stargate": "^0.31.0",
"@cosmjs/tendermint-rpc": "^0.31.0",
"@dydxprotocol/abacus": "^0.4.1",
"@dydxprotocol/abacus": "^0.4.6",
"@dydxprotocol/v4-client-js": "^0.32.0",
"@dydxprotocol/v4-localization": "^0.0.25",
"@ethersproject/providers": "^5.7.2",
+8 -8
View File
@@ -1,5 +1,9 @@
lockfileVersion: '6.0'
settings:
autoInstallPeers: true
excludeLinksFromLockfile: false
dependencies:
'@0xsquid/sdk':
specifier: ^1.7.2
@@ -23,8 +27,8 @@ dependencies:
specifier: ^0.31.0
version: 0.31.0
'@dydxprotocol/abacus':
specifier: ^0.4.1
version: 0.4.1
specifier: ^0.4.6
version: 0.4.6
'@dydxprotocol/v4-client-js':
specifier: ^0.32.0
version: 0.32.0
@@ -1142,8 +1146,8 @@ packages:
resolution: {integrity: sha512-RpfLEtTlyIxeNPGKcokS+p3BZII/Q3bYxryFRglh5H3A3T8q9fsLYm72VYAMEOOIBLEa8o93kFLiBDUWKrwXZA==}
dev: true
/@dydxprotocol/abacus@0.4.1:
resolution: {integrity: sha512-+2uKbTYBM6h7e3L8OX6gYwbqfIPtzwWUz4Onw6UCk7oD966Znwoky/PQmVDGjIcxw0BGWJUfHmF3Qd3t973tLQ==}
/@dydxprotocol/abacus@0.4.6:
resolution: {integrity: sha512-nvF9B1JuWzsnrPtQ/mKo06XWuqFc9fy6TEFcFwlIGGbxKortod7fSDj9sEZGKGdRyIj5wvl7H/Rgh+dlywO+aQ==}
dev: false
/@dydxprotocol/dydxjs@0.3.0:
@@ -15858,7 +15862,3 @@ packages:
release-it: 15.11.0
semver: 7.5.1
dev: false
settings:
autoInstallPeers: true
excludeLinksFromLockfile: false
Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 817 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 973 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

+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',
+13 -13
View File
@@ -88,17 +88,17 @@ export type TooltipStrings = {
};
export const ORDER_ERROR_CODE_MAP: { [key: number]: string } = {
2000: '2000_FILL_OR_KILL_ORDER_COULD_NOT_BE_FULLY_FILLED',
2001: '2001_REDUCE_ONLY_WOULD_INCREASE_POSITION_SIZE',
2002: '2002_REDUCE_ONLY_WOULD_CHANGE_POSITION_SIDE',
2003: '2003_POST_ONLY_WOULD_CROSS_MAKER_ORDER',
3000: '3000_INVALID_ORDER_FLAGS',
3001: '3001_INVALID_STATEFUL_ORDER_GOOD_TIL_BLOCK_TIME',
3002: '3002_STATEFUL_ORDERS_CANNOT_REQUIRE_IMMEDIATE_EXECUTION',
3003: '3003_TIME_EXCEEDS_GOOD_TIL_BLOCK_TIME',
3004: '3004_GOOD_TIL_BLOCK_TIME_EXCEEDS_STATEFUL_ORDER_TIME_WINDOW',
3005: '3005_STATEFUL_ORDER_ALREADY_EXISTS',
3006: '3006_STATEFUL_ORDER_DOES_NOT_EXIST',
3007: '3007_STATEFUL_ORDER_COLLATERALIZATION_CHECK_FAILED',
3008: '3008_STATEFUL_ORDER_PREVIOUSLY_CANCELLED',
2000: STRING_KEYS['2000_FILL_OR_KILL_ORDER_COULD_NOT_BE_FULLY_FILLED'],
2001: STRING_KEYS['2001_REDUCE_ONLY_WOULD_INCREASE_POSITION_SIZE'],
2002: STRING_KEYS['2002_REDUCE_ONLY_WOULD_CHANGE_POSITION_SIDE'],
2003: STRING_KEYS['2003_POST_ONLY_WOULD_CROSS_MAKER_ORDER'],
3000: STRING_KEYS['3000_INVALID_ORDER_FLAGS'],
3001: STRING_KEYS['3001_INVALID_STATEFUL_ORDER_GOOD_TIL_BLOCK_TIME'],
3002: STRING_KEYS['3002_STATEFUL_ORDERS_CANNOT_REQUIRE_IMMEDIATE_EXECUTION'],
3003: STRING_KEYS['3003_TIME_EXCEEDS_GOOD_TIL_BLOCK_TIME'],
3004: STRING_KEYS['3004_GOOD_TIL_BLOCK_TIME_EXCEEDS_STATEFUL_ORDER_TIME_WINDOW'],
3005: STRING_KEYS['3005_STATEFUL_ORDER_ALREADY_EXISTS'],
3006: STRING_KEYS['3006_STATEFUL_ORDER_DOES_NOT_EXIST'],
3007: STRING_KEYS['3007_STATEFUL_ORDER_COLLATERALIZATION_CHECK_FAILED'],
3008: STRING_KEYS['3008_STATEFUL_ORDER_PREVIOUSLY_CANCELLED'],
};
+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);
}
+2 -1
View File
@@ -551,7 +551,8 @@ export const useSubaccountContext = ({ localDydxWallet }: { localDydxWallet?: Lo
} as HumanReadablePlaceOrderPayload & { isClosePosition: boolean });
onSuccess?.();
} catch (error) {
const errorStringKey = error?.code && ORDER_ERROR_CODE_MAP[error.code as number];
const errorCode: number | undefined = error?.code;
const errorStringKey = errorCode ? ORDER_ERROR_CODE_MAP[errorCode] : undefined;
onError?.({ errorStringKey });
log('useSubaccount/placeOrder', error, {
+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;