Compare commits
3
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1938feb66b | ||
|
|
2b105fb522 | ||
|
|
ea81d7a150 |
+2
-2
@@ -38,8 +38,8 @@
|
|||||||
"@cosmjs/stargate": "^0.31.0",
|
"@cosmjs/stargate": "^0.31.0",
|
||||||
"@cosmjs/tendermint-rpc": "^0.31.0",
|
"@cosmjs/tendermint-rpc": "^0.31.0",
|
||||||
"@dydxprotocol/v4-abacus": "^0.4.28",
|
"@dydxprotocol/v4-abacus": "^0.4.28",
|
||||||
"@dydxprotocol/v4-client-js": "^0.35.0",
|
"@dydxprotocol/v4-client-js": "^0.36.1",
|
||||||
"@dydxprotocol/v4-localization": "^0.1.5",
|
"@dydxprotocol/v4-localization": "^0.1.8",
|
||||||
"@ethersproject/providers": "^5.7.2",
|
"@ethersproject/providers": "^5.7.2",
|
||||||
"@js-joda/core": "^5.5.3",
|
"@js-joda/core": "^5.5.3",
|
||||||
"@radix-ui/react-collapsible": "^1.0.3",
|
"@radix-ui/react-collapsible": "^1.0.3",
|
||||||
|
|||||||
Generated
+8
-8
@@ -30,11 +30,11 @@ dependencies:
|
|||||||
specifier: ^0.4.28
|
specifier: ^0.4.28
|
||||||
version: 0.4.28
|
version: 0.4.28
|
||||||
'@dydxprotocol/v4-client-js':
|
'@dydxprotocol/v4-client-js':
|
||||||
specifier: ^0.35.0
|
specifier: ^0.36.1
|
||||||
version: 0.35.0
|
version: 0.36.1
|
||||||
'@dydxprotocol/v4-localization':
|
'@dydxprotocol/v4-localization':
|
||||||
specifier: ^0.1.5
|
specifier: ^0.1.8
|
||||||
version: 0.1.5
|
version: 0.1.8
|
||||||
'@ethersproject/providers':
|
'@ethersproject/providers':
|
||||||
specifier: ^5.7.2
|
specifier: ^5.7.2
|
||||||
version: 5.7.2
|
version: 5.7.2
|
||||||
@@ -983,8 +983,8 @@ packages:
|
|||||||
resolution: {integrity: sha512-RQGTXI7q4HAXDmlUpDhpJDLN8C0dFMgKHzFITK1Sz3KnLb3mkkpqEU1D8VIn/hB7ngt+equMsLFSkUwzXCzgdA==}
|
resolution: {integrity: sha512-RQGTXI7q4HAXDmlUpDhpJDLN8C0dFMgKHzFITK1Sz3KnLb3mkkpqEU1D8VIn/hB7ngt+equMsLFSkUwzXCzgdA==}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/@dydxprotocol/v4-client-js@0.35.0:
|
/@dydxprotocol/v4-client-js@0.36.1:
|
||||||
resolution: {integrity: sha512-H+0/tOBVqyWx2JQ4jUFdJOlFof0NqN1u9vzKJ2h3Nv5KNteSPd59eiywoz+3J0jlmkREw0Jzg9CS0bLwzYVLvA==}
|
resolution: {integrity: sha512-KJ3MtWI61wmm+xZtXQd7/hYKIoVFG32TRdyyVaXXO8vpW9Oqd0JD8QSM/wuegkciAh5YmP/BrDzYuu77zHO6yg==}
|
||||||
dependencies:
|
dependencies:
|
||||||
'@cosmjs/amino': 0.30.1
|
'@cosmjs/amino': 0.30.1
|
||||||
'@cosmjs/encoding': 0.31.1
|
'@cosmjs/encoding': 0.31.1
|
||||||
@@ -1010,8 +1010,8 @@ packages:
|
|||||||
- utf-8-validate
|
- utf-8-validate
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/@dydxprotocol/v4-localization@0.1.5:
|
/@dydxprotocol/v4-localization@0.1.8:
|
||||||
resolution: {integrity: sha512-fiSHWrG8E2HuXkCzWsqyekntlI13hBRACrP0vaYudeSulw+ScGeAqZ5xp9/cANF6PP+H3z1yciNCZOH3OwSDwA==}
|
resolution: {integrity: sha512-ZuM/V2tLVSWyi9pDZLOu8h6HScrzKlFftQ/1iBPNIOU4bBMx83vYgokm0X9hzueWzz0PJ2pzT+EoN81sPlN2bg==}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/@dydxprotocol/v4-proto@0.2.1:
|
/@dydxprotocol/v4-proto@0.2.1:
|
||||||
|
|||||||
@@ -339,12 +339,12 @@ export type EvmAddress = `0x${string}`;
|
|||||||
export type DydxAddress = `dydx${string}`;
|
export type DydxAddress = `dydx${string}`;
|
||||||
|
|
||||||
export const DYDX_CHAIN_INFO: Parameters<typeof suggestChain>[0] = {
|
export const DYDX_CHAIN_INFO: Parameters<typeof suggestChain>[0] = {
|
||||||
rpc: '13.59.4.93:26657',
|
rpc: 'https://dydx-testnet-archive.allthatnode.com:26657',
|
||||||
rest: '13.59.4.93:1317',
|
rest: 'https://dydx-testnet-archive.allthatnode.com:1317',
|
||||||
chainId: 'dydx-testnet-2',
|
chainId: 'dydx-testnet-3',
|
||||||
chainName: 'dYdX Public Testnet',
|
chainName: 'dYdX Public Testnet',
|
||||||
chainSymbolImageUrl:
|
chainSymbolImageUrl:
|
||||||
'https://raw.githubusercontent.com/chainapsis/keplr-chain-registry/main/images/dydx-testnet-2/chain.png',
|
'https://raw.githubusercontent.com/chainapsis/keplr-chain-registry/main/images/dydx-testnet-3/chain.png',
|
||||||
bech32Config: {
|
bech32Config: {
|
||||||
bech32PrefixAccPub: 'dydxpub',
|
bech32PrefixAccPub: 'dydxpub',
|
||||||
bech32PrefixValPub: 'dydxvaloperpub',
|
bech32PrefixValPub: 'dydxvaloperpub',
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import { LocalStorageKey } from '@/constants/localStorage';
|
|||||||
import { type TransferNotifcation } from '@/constants/notifications';
|
import { type TransferNotifcation } from '@/constants/notifications';
|
||||||
|
|
||||||
import { useAccounts } from '@/hooks/useAccounts';
|
import { useAccounts } from '@/hooks/useAccounts';
|
||||||
import { useSquid } from '@/hooks/useSquid';
|
import { SQUID_ERROR_TYPES, useSquid } from '@/hooks/useSquid';
|
||||||
import { useLocalStorage } from './useLocalStorage';
|
import { useLocalStorage } from './useLocalStorage';
|
||||||
|
|
||||||
const LocalNotificationsContext = createContext<
|
const LocalNotificationsContext = createContext<
|
||||||
@@ -70,7 +70,10 @@ const useLocalNotificationsContext = () => {
|
|||||||
const status = await squid?.getStatus({ transactionId: txHash, toChainId, fromChainId });
|
const status = await squid?.getStatus({ transactionId: txHash, toChainId, fromChainId });
|
||||||
if (status) statuses[txHash] = status;
|
if (status) statuses[txHash] = status;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error);
|
// ignore not found errors since the route might not be available yet
|
||||||
|
if (error?.errors?.length && error.errors[0].errorType !== SQUID_ERROR_TYPES.NotFoundError) {
|
||||||
|
statuses[txHash] = error;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return statuses;
|
return statuses;
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
import { useCallback, useEffect, useMemo } from 'react';
|
import { useCallback, useEffect, useMemo } from 'react';
|
||||||
|
import styled, { type AnyStyledComponent } from 'styled-components';
|
||||||
import { useSelector, shallowEqual, useDispatch } from 'react-redux';
|
import { useSelector, shallowEqual, useDispatch } from 'react-redux';
|
||||||
import { groupBy } from 'lodash';
|
import { groupBy } from 'lodash';
|
||||||
|
|
||||||
|
import { AlertType } from '@/constants/alerts';
|
||||||
import { AbacusOrderStatus, ORDER_SIDES, ORDER_STATUS_STRINGS } from '@/constants/abacus';
|
import { AbacusOrderStatus, ORDER_SIDES, ORDER_STATUS_STRINGS } from '@/constants/abacus';
|
||||||
import { DialogTypes } from '@/constants/dialogs';
|
import { DialogTypes } from '@/constants/dialogs';
|
||||||
import { STRING_KEYS } from '@/constants/localization';
|
import { STRING_KEYS } from '@/constants/localization';
|
||||||
@@ -10,6 +12,7 @@ import { ORDER_SIDE_STRINGS, TRADE_TYPE_STRINGS, TradeTypes } from '@/constants/
|
|||||||
|
|
||||||
import { useLocalNotifications } from '@/hooks/useLocalNotifications';
|
import { useLocalNotifications } from '@/hooks/useLocalNotifications';
|
||||||
|
|
||||||
|
import { AlertMessage } from '@/components/AlertMessage';
|
||||||
import { Icon, IconName } from '@/components/Icon';
|
import { Icon, IconName } from '@/components/Icon';
|
||||||
import { Output, OutputType } from '@/components/Output';
|
import { Output, OutputType } from '@/components/Output';
|
||||||
import { TransferStatusToast } from '@/views/TransferStatus';
|
import { TransferStatusToast } from '@/views/TransferStatus';
|
||||||
@@ -119,19 +122,36 @@ export const notificationTypes = [
|
|||||||
const { toChainId, status, txHash, toAmount } = transfer;
|
const { toChainId, status, txHash, toAmount } = transfer;
|
||||||
const finished = Boolean(status) && status?.squidTransactionStatus !== 'ongoing';
|
const finished = Boolean(status) && status?.squidTransactionStatus !== 'ongoing';
|
||||||
const type = toChainId === TESTNET_CHAIN_ID ? 'deposit' : 'withdraw';
|
const type = toChainId === TESTNET_CHAIN_ID ? 'deposit' : 'withdraw';
|
||||||
|
// @ts-ignore status.errors is not in the type definition but can be returned
|
||||||
|
const error = status?.errors?.length ? status?.errors[0] : status?.error;
|
||||||
|
|
||||||
|
// TODO: confirm with design what the description should be
|
||||||
|
const description = (
|
||||||
|
<div>
|
||||||
|
<Styled.TransferText>
|
||||||
|
{type === 'deposit' ? 'Deposit of ' : 'Withdraw of '}
|
||||||
|
<Output type={OutputType.Fiat} value={toAmount} />
|
||||||
|
</Styled.TransferText>
|
||||||
|
|
||||||
|
{error && (
|
||||||
|
<Styled.ErrorMessage type={AlertType.Error}>
|
||||||
|
{stringGetter({
|
||||||
|
key: STRING_KEYS.SOMETHING_WENT_WRONG_WITH_MESSAGE,
|
||||||
|
params: {
|
||||||
|
ERROR_MESSAGE: error.message || stringGetter({ key: STRING_KEYS.UNKNOWN_ERROR }),
|
||||||
|
},
|
||||||
|
})}
|
||||||
|
</Styled.ErrorMessage>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
trigger(
|
trigger(
|
||||||
txHash,
|
txHash,
|
||||||
{
|
{
|
||||||
icon: <Icon iconName={finished ? IconName.Transfer : IconName.Clock} />,
|
icon: <Icon iconName={finished ? IconName.Transfer : IconName.Clock} />,
|
||||||
title: stringGetter({ key: getTitleStringKey(type, finished) }),
|
title: stringGetter({ key: getTitleStringKey(type, finished) }),
|
||||||
// TODO: confirm with design what the description should be
|
description: description,
|
||||||
description: (
|
|
||||||
<>
|
|
||||||
<span>{type === 'deposit' ? 'Deposit of ' : 'Withdraw of'}</span>
|
|
||||||
<Output type={OutputType.Fiat} value={toAmount} />
|
|
||||||
</>
|
|
||||||
),
|
|
||||||
customContent: (
|
customContent: (
|
||||||
<TransferStatusToast
|
<TransferStatusToast
|
||||||
toAmount={transfer.toAmount}
|
toAmount={transfer.toAmount}
|
||||||
@@ -139,7 +159,12 @@ export const notificationTypes = [
|
|||||||
status={transfer.status}
|
status={transfer.status}
|
||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
customMenuContent: !finished && <TransferStatusSteps status={transfer.status} />,
|
customMenuContent: !finished && (
|
||||||
|
<div>
|
||||||
|
{description}
|
||||||
|
<TransferStatusSteps status={transfer.status} />
|
||||||
|
</div>
|
||||||
|
),
|
||||||
toastSensitivity: 'foreground',
|
toastSensitivity: 'foreground',
|
||||||
},
|
},
|
||||||
[]
|
[]
|
||||||
@@ -149,3 +174,15 @@ export const notificationTypes = [
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
] satisfies NotificationTypeConfig[];
|
] satisfies NotificationTypeConfig[];
|
||||||
|
|
||||||
|
const Styled: Record<string, AnyStyledComponent> = {};
|
||||||
|
|
||||||
|
Styled.TransferText = styled.span`
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.5ch;
|
||||||
|
`
|
||||||
|
|
||||||
|
Styled.ErrorMessage = styled.div`
|
||||||
|
max-width: 13rem;
|
||||||
|
`;
|
||||||
@@ -1,14 +1,17 @@
|
|||||||
import { createContext, useContext, useEffect, useMemo, useState } from 'react';
|
import { createContext, useContext, useEffect, useMemo, useState } from 'react';
|
||||||
import { useSelector } from 'react-redux';
|
import { useSelector } from 'react-redux';
|
||||||
import { TESTNET_CHAIN_ID } from '@dydxprotocol/v4-client-js';
|
|
||||||
import { Squid } from '@0xsquid/sdk';
|
import { Squid } from '@0xsquid/sdk';
|
||||||
|
|
||||||
import { CLIENT_NETWORK_CONFIGS, DydxV4Network, isDydxV4Network } from '@/constants/networks';
|
import { CLIENT_NETWORK_CONFIGS, isDydxV4Network } from '@/constants/networks';
|
||||||
|
|
||||||
import { getSelectedNetwork } from '@/state/appSelectors';
|
import { getSelectedNetwork } from '@/state/appSelectors';
|
||||||
|
|
||||||
export const NATIVE_TOKEN_ADDRESS = "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE";
|
export const NATIVE_TOKEN_ADDRESS = "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE";
|
||||||
|
|
||||||
|
export enum SQUID_ERROR_TYPES {
|
||||||
|
NotFoundError = 'NotFoundError',
|
||||||
|
}
|
||||||
|
|
||||||
const useSquidContext = () => {
|
const useSquidContext = () => {
|
||||||
const selectedNetwork = useSelector(getSelectedNetwork);
|
const selectedNetwork = useSelector(getSelectedNetwork);
|
||||||
const [_, setInitialized] = useState(false);
|
const [_, setInitialized] = useState(false);
|
||||||
|
|||||||
@@ -7,9 +7,11 @@ import { StatusResponse } from '@0xsquid/sdk';
|
|||||||
import { useInterval, useStringGetter } from '@/hooks';
|
import { useInterval, useStringGetter } from '@/hooks';
|
||||||
|
|
||||||
import { STRING_KEYS } from '@/constants/localization';
|
import { STRING_KEYS } from '@/constants/localization';
|
||||||
|
import { AlertType } from '@/constants/alerts';
|
||||||
|
|
||||||
import { formatSeconds } from '@/lib/timeUtils';
|
import { formatSeconds } from '@/lib/timeUtils';
|
||||||
|
|
||||||
|
import { AlertMessage } from '@/components/AlertMessage';
|
||||||
import { Output, OutputType } from '@/components/Output';
|
import { Output, OutputType } from '@/components/Output';
|
||||||
import { WithReceipt } from '@/components/WithReceipt';
|
import { WithReceipt } from '@/components/WithReceipt';
|
||||||
import { Icon, IconName } from '@/components/Icon';
|
import { Icon, IconName } from '@/components/Icon';
|
||||||
@@ -33,6 +35,9 @@ export const TransferStatusToast = ({
|
|||||||
const [open, setOpen] = useState<boolean>(false);
|
const [open, setOpen] = useState<boolean>(false);
|
||||||
const [secondsLeft, setSecondsLeft] = useState<number | undefined>();
|
const [secondsLeft, setSecondsLeft] = useState<number | undefined>();
|
||||||
|
|
||||||
|
// @ts-ignore status.errors is not in the type definition but can be returned
|
||||||
|
const error = status?.errors?.length ? status?.errors[0] : status?.error;
|
||||||
|
|
||||||
const type = useMemo(
|
const type = useMemo(
|
||||||
() => (status?.toChain?.chainData?.chainId === TESTNET_CHAIN_ID ? 'deposit' : 'withdrawal'),
|
() => (status?.toChain?.chainData?.chainId === TESTNET_CHAIN_ID ? 'deposit' : 'withdrawal'),
|
||||||
[status]
|
[status]
|
||||||
@@ -74,6 +79,16 @@ export const TransferStatusToast = ({
|
|||||||
},
|
},
|
||||||
})}
|
})}
|
||||||
</Styled.Status>
|
</Styled.Status>
|
||||||
|
{error && (
|
||||||
|
<AlertMessage type={AlertType.Error}>
|
||||||
|
{stringGetter({
|
||||||
|
key: STRING_KEYS.SOMETHING_WENT_WRONG_WITH_MESSAGE,
|
||||||
|
params: {
|
||||||
|
ERROR_MESSAGE: error.message || stringGetter({ key: STRING_KEYS.UNKNOWN_ERROR }),
|
||||||
|
},
|
||||||
|
})}
|
||||||
|
</AlertMessage>
|
||||||
|
)}
|
||||||
<Styled.Trigger>
|
<Styled.Trigger>
|
||||||
<Styled.TriggerIcon>
|
<Styled.TriggerIcon>
|
||||||
<Icon iconName={IconName.Caret} />
|
<Icon iconName={IconName.Caret} />
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ export const TransferStatusSteps = ({ status }: ElementProps) => {
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
const currentStatus = routeStatus[routeStatus?.length - 1];
|
const currentStatus = routeStatus?.[routeStatus?.length - 1];
|
||||||
|
|
||||||
let currentStep = TransferStatusStep.Bridge;
|
let currentStep = TransferStatusStep.Bridge;
|
||||||
|
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ import { getTransferInputs } from '@/state/inputsSelectors';
|
|||||||
import abacusStateManager from '@/lib/abacus';
|
import abacusStateManager from '@/lib/abacus';
|
||||||
import { MustBigNumber } from '@/lib/numbers';
|
import { MustBigNumber } from '@/lib/numbers';
|
||||||
import { log } from '@/lib/telemetry';
|
import { log } from '@/lib/telemetry';
|
||||||
|
import { parseWalletError } from '@/lib/wallet';
|
||||||
|
|
||||||
import { ChainSelectMenu } from './ChainSelectMenu';
|
import { ChainSelectMenu } from './ChainSelectMenu';
|
||||||
import { TokenSelectMenu } from './TokenSelectMenu';
|
import { TokenSelectMenu } from './TokenSelectMenu';
|
||||||
@@ -286,12 +287,7 @@ export const DepositForm = ({ onDeposit, onError }: DepositFormProps) => {
|
|||||||
|
|
||||||
const errorMessage = useMemo(() => {
|
const errorMessage = useMemo(() => {
|
||||||
if (error) {
|
if (error) {
|
||||||
return error?.message
|
return parseWalletError({ error, stringGetter }).message;
|
||||||
? stringGetter({
|
|
||||||
key: STRING_KEYS.SOMETHING_WENT_WRONG_WITH_MESSAGE,
|
|
||||||
params: { ERROR_MESSAGE: error.message },
|
|
||||||
})
|
|
||||||
: stringGetter({ key: STRING_KEYS.SOMETHING_WENT_WRONG });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fromAmount) {
|
if (fromAmount) {
|
||||||
|
|||||||
Reference in New Issue
Block a user