Compare commits
5
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
45e1b874fd | ||
|
|
8d5bf1a721 | ||
|
|
7f3d57b46a | ||
|
|
c292c84c2c | ||
|
|
2d37ff676b |
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"apps": {
|
||||
"iOS": {
|
||||
"ios": {
|
||||
"scheme": "dydxv4"
|
||||
}
|
||||
},
|
||||
@@ -893,6 +893,7 @@
|
||||
"privacy": "https://dydx.exchange/privacy",
|
||||
"statusPage": "https://status.v4testnet.dydx.exchange/",
|
||||
"mintscan": "https://testnet.mintscan.io/dydx-testnet/txs/{tx_hash}",
|
||||
"mintscanBase": "https://testnet.mintscan.io/dydx-testnet",
|
||||
"documentation": "https://docs.dydx.exchange/",
|
||||
"community": "https://discord.com/invite/dydx",
|
||||
"feedback": "https://docs.google.com/forms/d/e/1FAIpQLSezLsWCKvAYDEb7L-2O4wOON1T56xxro9A2Azvl6IxXHP_15Q/viewform",
|
||||
@@ -1033,7 +1034,7 @@
|
||||
"tos": "[HTTP link to TOS]",
|
||||
"privacy": "[HTTP link to Privacy Policy]",
|
||||
"mintscan": "[HTTP link to Mintscan, with {tx_hash} placeholder]",
|
||||
"mintscanBase": "[HTTP link to TOS mintsacn base url]",
|
||||
"mintscanBase": "[HTTP link to TOS mintscan base url]",
|
||||
"feedback": "[HTTP link to feedback form, can be null]",
|
||||
"blogs": "[HTTP link to blogs, can be null]",
|
||||
"foundation": "[HTTP link to foundation, can be null]",
|
||||
|
||||
@@ -1,12 +1,18 @@
|
||||
import environments from '../../public/configs/env.json';
|
||||
|
||||
// TODO: Update for Mainnet deployment
|
||||
export const AVAILABLE_ENVIRONMENTS =
|
||||
import.meta.env.MODE === 'production'
|
||||
? environments.deployments.TESTNET
|
||||
: environments.deployments.DEV;
|
||||
const CURRENT_MODE = ({
|
||||
production: 'MAINNET',
|
||||
testnet: 'TESTNET',
|
||||
staging: 'DEV',
|
||||
development: 'DEV',
|
||||
}[import.meta.env.MODE] ?? 'MAINNET') as 'MAINNET' | 'TESTNET' | 'DEV';
|
||||
|
||||
export const CURRENT_ABACUS_DEPLOYMENT = import.meta.env.MODE === 'production' ? 'TESTNET' : 'DEV';
|
||||
export const isMainnet = CURRENT_MODE === 'MAINNET';
|
||||
export const isTestnet = CURRENT_MODE === 'TESTNET';
|
||||
export const isDev = CURRENT_MODE === 'DEV';
|
||||
|
||||
export const AVAILABLE_ENVIRONMENTS = environments.deployments[CURRENT_MODE];
|
||||
export const CURRENT_ABACUS_DEPLOYMENT = CURRENT_MODE;
|
||||
export const ENVIRONMENT_CONFIG_MAP = environments.environments;
|
||||
export type DydxNetwork = keyof typeof ENVIRONMENT_CONFIG_MAP;
|
||||
export const DEFAULT_APP_ENVIRONMENT = AVAILABLE_ENVIRONMENTS.default as DydxNetwork;
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { isDev } from '@/constants/networks';
|
||||
import { WalletType } from '@/constants/wallets';
|
||||
|
||||
import { isTruthy } from '@/lib/isTruthy';
|
||||
@@ -6,7 +7,7 @@ export const useDisplayedWallets = () => {
|
||||
return [
|
||||
WalletType.MetaMask,
|
||||
|
||||
import.meta.env.MODE !== 'production' && WalletType.Keplr,
|
||||
isDev && WalletType.Keplr,
|
||||
|
||||
WalletType.WalletConnect2,
|
||||
|
||||
|
||||
@@ -7,9 +7,11 @@ import { AlertType } from '@/constants/alerts';
|
||||
import { AbacusOrderStatus, ORDER_SIDES } from '@/constants/abacus';
|
||||
import { DialogTypes } from '@/constants/dialogs';
|
||||
import { STRING_KEYS, StringKey } from '@/constants/localization';
|
||||
import { ENVIRONMENT_CONFIG_MAP } from '@/constants/networks';
|
||||
import { type NotificationTypeConfig, NotificationType } from '@/constants/notifications';
|
||||
import { ORDER_SIDE_STRINGS } from '@/constants/trade';
|
||||
|
||||
import { useSelectedNetwork } from '@/hooks';
|
||||
import { useLocalNotifications } from '@/hooks/useLocalNotifications';
|
||||
|
||||
import { Icon, IconName } from '@/components/Icon';
|
||||
@@ -23,7 +25,6 @@ import { OrderStatusIcon } from '@/views/OrderStatusIcon';
|
||||
|
||||
import { useStringGetter } from './useStringGetter';
|
||||
import { TransferStatusSteps } from '@/views/TransferStatusSteps';
|
||||
import { TESTNET_CHAIN_ID } from '@dydxprotocol/v4-client-js';
|
||||
|
||||
export const notificationTypes = [
|
||||
{
|
||||
@@ -124,6 +125,7 @@ export const notificationTypes = [
|
||||
useTrigger: ({ trigger }) => {
|
||||
const stringGetter = useStringGetter();
|
||||
const { transferNotifications } = useLocalNotifications();
|
||||
const { selectedNetwork } = useSelectedNetwork();
|
||||
|
||||
const getTitleStringKey = useCallback((type: 'deposit' | 'withdrawal', finished: boolean) => {
|
||||
if (type === 'deposit' && !finished) return STRING_KEYS.DEPOSIT_IN_PROGRESS;
|
||||
@@ -136,7 +138,7 @@ export const notificationTypes = [
|
||||
for (const transfer of transferNotifications) {
|
||||
const { fromChainId, status, txHash, toAmount } = transfer;
|
||||
const finished = Boolean(status) && status?.squidTransactionStatus !== 'ongoing';
|
||||
const type = fromChainId === TESTNET_CHAIN_ID ? 'withdrawal' : 'deposit';
|
||||
const type = fromChainId === ENVIRONMENT_CONFIG_MAP[selectedNetwork].dydxChainId ? 'withdrawal' : 'deposit';
|
||||
// @ts-ignore status.errors is not in the type definition but can be returned
|
||||
const error = status?.errors?.length ? status?.errors[0] : status?.error;
|
||||
|
||||
|
||||
@@ -350,11 +350,6 @@ export const useSubaccountContext = ({ localDydxWallet }: { localDydxWallet?: Lo
|
||||
placeOrderParams = abacusStateManager.placeOrder(callback);
|
||||
}
|
||||
|
||||
track(AnalyticsEvent.TradePlaceOrder, {
|
||||
...placeOrderParams,
|
||||
isClosePosition,
|
||||
} as HumanReadablePlaceOrderPayload & { isClosePosition: boolean });
|
||||
|
||||
return placeOrderParams;
|
||||
},
|
||||
[subaccountClient]
|
||||
@@ -383,7 +378,6 @@ export const useSubaccountContext = ({ localDydxWallet }: { localDydxWallet?: Lo
|
||||
}) => {
|
||||
const callback = (success: boolean, parsingError?: Nullable<ParsingError>) => {
|
||||
if (success) {
|
||||
track(AnalyticsEvent.TradeCancelOrder);
|
||||
onSuccess?.();
|
||||
} else {
|
||||
onError?.({ errorStringKey: parsingError?.stringKey });
|
||||
|
||||
@@ -3,7 +3,7 @@ import styled, { type AnyStyledComponent, css } from 'styled-components';
|
||||
import { AbacusApiStatus } from '@/constants/abacus';
|
||||
import { ButtonSize } from '@/constants/buttons';
|
||||
import { STRING_KEYS } from '@/constants/localization';
|
||||
import { ENVIRONMENT_CONFIG_MAP } from '@/constants/networks';
|
||||
import { ENVIRONMENT_CONFIG_MAP, isDev } from '@/constants/networks';
|
||||
|
||||
import { useApiState, useSelectedNetwork, useStringGetter } from '@/hooks';
|
||||
import { ChatIcon, LinkOutIcon } from '@/icons';
|
||||
@@ -75,7 +75,7 @@ export const FooterDesktop = () => {
|
||||
)}
|
||||
</Styled.Row>
|
||||
|
||||
{import.meta.env.MODE !== 'production' && (
|
||||
{isDev && (
|
||||
<Styled.Details
|
||||
withSeparators
|
||||
items={[
|
||||
|
||||
@@ -30,7 +30,7 @@ import {
|
||||
|
||||
import { DialogTypes } from '@/constants/dialogs';
|
||||
import { UNCOMMITTED_ORDER_TIMEOUT_MS } from '@/constants/trade';
|
||||
import { QUANTUM_MULTIPLIER } from '@/constants/numbers';
|
||||
import { ENVIRONMENT_CONFIG_MAP, DydxNetwork, isTestnet } from '@/constants/networks';
|
||||
|
||||
import { RootStore } from '@/state/_store';
|
||||
import { addUncommittedOrderClientId, removeUncommittedOrderClientId } from '@/state/account';
|
||||
@@ -198,8 +198,13 @@ class DydxChainTransactions implements AbacusDYDXChainTransactionsProtocol {
|
||||
const parsedTx = this.parseToPrimitives(tx);
|
||||
const hash = parsedTx?.hash;
|
||||
|
||||
if (import.meta.env.MODE === 'production') {
|
||||
console.log(`https://testnet.mintscan.io/dydx-testnet/txs/${hash}`);
|
||||
if (isTestnet) {
|
||||
console.log(
|
||||
`${
|
||||
ENVIRONMENT_CONFIG_MAP[this.compositeClient.network.getString() as DydxNetwork]?.links
|
||||
?.mintscanBase
|
||||
}/txs/${hash}`
|
||||
);
|
||||
} else console.log(`txHash: ${hash}`);
|
||||
|
||||
return JSON.stringify(parsedTx);
|
||||
@@ -229,7 +234,7 @@ class DydxChainTransactions implements AbacusDYDXChainTransactionsProtocol {
|
||||
orderFlags,
|
||||
clobPairId,
|
||||
goodTilBlock || undefined,
|
||||
goodTilBlockTime || undefined,
|
||||
goodTilBlockTime || undefined
|
||||
);
|
||||
|
||||
const parsedTx = this.parseToPrimitives(tx);
|
||||
@@ -295,15 +300,11 @@ class DydxChainTransactions implements AbacusDYDXChainTransactionsProtocol {
|
||||
if (!this.localWallet) {
|
||||
throw new Error('Missing compositeClient or localWallet');
|
||||
}
|
||||
const msg = compositeClient?.sendTokenMessage(
|
||||
this.localWallet,
|
||||
amount,
|
||||
recipient,
|
||||
);
|
||||
const msg = compositeClient?.sendTokenMessage(this.localWallet, amount, recipient);
|
||||
|
||||
resolve([msg]);
|
||||
}),
|
||||
this.compositeClient?.validatorClient?.post.defaultDydxGasPrice,
|
||||
this.compositeClient?.validatorClient?.post.defaultDydxGasPrice
|
||||
);
|
||||
|
||||
const parsedTx = this.parseToPrimitives(tx);
|
||||
|
||||
@@ -1,10 +1,5 @@
|
||||
import type { AbacusFileSystemProtocol, FileLocation, Nullable } from '@/constants/abacus';
|
||||
|
||||
export const ENDPOINTS_PATH =
|
||||
import.meta.env.MODE === 'production'
|
||||
? 'config/prod/endpoints.json'
|
||||
: 'config/staging/dev_endpoints.json';
|
||||
|
||||
class AbacusFileSystem implements AbacusFileSystemProtocol {
|
||||
readTextFile(location: FileLocation, path: string): Nullable<string> {
|
||||
return null;
|
||||
|
||||
@@ -41,7 +41,7 @@ import AbacusStateNotifier from './stateNotification';
|
||||
import AbacusLocalizer from './localizer';
|
||||
import AbacusFormatter from './formatter';
|
||||
import AbacusThreading from './threading';
|
||||
import AbacusFileSystem, { ENDPOINTS_PATH } from './filesystem';
|
||||
import AbacusFileSystem from './filesystem';
|
||||
import { LocaleSeparators } from '../numbers';
|
||||
class AbacusStateManager {
|
||||
private store: RootStore | undefined;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import type { AbacusWebsocketProtocol } from '@/constants/abacus';
|
||||
import type { TradingViewBar } from '@/constants/candles';
|
||||
import { isDev } from '@/constants/networks';
|
||||
|
||||
import {
|
||||
PING_INTERVAL_MS,
|
||||
@@ -161,13 +162,13 @@ class AbacusWebsocket implements Omit<AbacusWebsocketProtocol, '__doNotUseOrImpl
|
||||
|
||||
this.socket.onclose = (e) => {
|
||||
this.connectedCallback?.(false);
|
||||
if (import.meta.env.MODE === 'production') return;
|
||||
if (!isDev) return;
|
||||
console.warn('AbacusStateManager > WS > close > ', e);
|
||||
};
|
||||
|
||||
this.socket.onerror = (e) => {
|
||||
this.connectedCallback?.(false);
|
||||
if (import.meta.env.MODE === 'production') return;
|
||||
if (!isDev) return;
|
||||
console.error('AbacusStateManager > WS > error > ', e);
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import { isDev } from "@/constants/networks";
|
||||
|
||||
export const log = (location: string, error: Error, metadata?: any) => {
|
||||
if (import.meta.env.MODE !== 'production') {
|
||||
if (isDev) {
|
||||
console.warn('telemetry/log:', { location, error, metadata });
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ import type { PayloadAction } from '@reduxjs/toolkit';
|
||||
|
||||
import { AbacusApiStatus } from '@/constants/abacus';
|
||||
import { DialogTypes } from '@/constants/dialogs';
|
||||
import { isDev } from '@/constants/networks';
|
||||
|
||||
import { setApiState, setSelectedNetwork } from '@/state/app';
|
||||
import { resetPerpetualsState } from '@/state/perpetuals';
|
||||
@@ -30,7 +31,7 @@ export default (store: any) => (next: any) => async (action: PayloadAction<any>)
|
||||
store.dispatch(
|
||||
openDialog({
|
||||
type: DialogTypes.ExchangeOffline,
|
||||
dialogProps: { preventClose: import.meta.env.MODE === 'production' },
|
||||
dialogProps: { preventClose: !isDev },
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { useState } from 'react';
|
||||
import styled, { type AnyStyledComponent } from 'styled-components';
|
||||
|
||||
import { isMainnet } from '@/constants/networks';
|
||||
import { STRING_KEYS } from '@/constants/localization';
|
||||
import { useBreakpoints, useStringGetter } from '@/hooks';
|
||||
|
||||
@@ -27,14 +28,22 @@ export const DepositDialog = ({ setIsOpen }: ElementProps) => {
|
||||
isOpen
|
||||
setIsOpen={setIsOpen}
|
||||
title={stringGetter({ key: STRING_KEYS.DEPOSIT })}
|
||||
description={showTestDeposit && 'Test funds will be sent directly to your dYdX account.'}
|
||||
description={
|
||||
!isMainnet && showTestDeposit && 'Test funds will be sent directly to your dYdX account.'
|
||||
}
|
||||
placement={isMobile ? DialogPlacement.FullScreen : DialogPlacement.Default}
|
||||
>
|
||||
<Styled.Content>
|
||||
{showTestDeposit ? <TestnetDepositForm onDeposit={closeDialog} /> : <DepositForm />}
|
||||
<Styled.TextToggle onClick={() => setShowTestDeposit(!showTestDeposit)}>
|
||||
{showTestDeposit ? 'Show deposit form (Under Construction)' : 'Show test faucet'}
|
||||
</Styled.TextToggle>
|
||||
{!isMainnet && showTestDeposit ? (
|
||||
<TestnetDepositForm onDeposit={closeDialog} />
|
||||
) : (
|
||||
<DepositForm />
|
||||
)}
|
||||
{!isMainnet && (
|
||||
<Styled.TextToggle onClick={() => setShowTestDeposit(!showTestDeposit)}>
|
||||
{showTestDeposit ? 'Show deposit form (Under Construction)' : 'Show test faucet'}
|
||||
</Styled.TextToggle>
|
||||
)}
|
||||
</Styled.Content>
|
||||
</Dialog>
|
||||
);
|
||||
|
||||
@@ -5,6 +5,7 @@ import { shallowEqual, useDispatch, useSelector } from 'react-redux';
|
||||
import { AbacusApiStatus } from '@/constants/abacus';
|
||||
import { DialogTypes } from '@/constants/dialogs';
|
||||
import { STRING_KEYS } from '@/constants/localization';
|
||||
import { isDev } from '@/constants/networks';
|
||||
|
||||
import { useApiState, useStringGetter } from '@/hooks';
|
||||
import { layoutMixins } from '@/styles/layoutMixins';
|
||||
@@ -45,7 +46,7 @@ export const ExchangeOfflineDialog = ({ preventClose, setIsOpen }: ElementProps)
|
||||
>
|
||||
<Styled.Content>
|
||||
<p>{statusErrorMessage}</p>
|
||||
{import.meta.env.MODE !== 'production' && <NetworkSelectMenu />}
|
||||
{isDev && <NetworkSelectMenu />}
|
||||
</Styled.Content>
|
||||
</Dialog>
|
||||
);
|
||||
|
||||
@@ -2,7 +2,6 @@ import { type FormEvent, useCallback, useEffect, useMemo, useState } from 'react
|
||||
import styled, { type AnyStyledComponent } from 'styled-components';
|
||||
import { type NumberFormatValues } from 'react-number-format';
|
||||
import { shallowEqual, useSelector } from 'react-redux';
|
||||
import { TESTNET_CHAIN_ID } from '@dydxprotocol/v4-client-js';
|
||||
import { parseUnits } from 'viem'
|
||||
|
||||
import erc20 from '@/abi/erc20.json';
|
||||
@@ -10,10 +9,11 @@ import { TransferInputField, TransferInputTokenResource, TransferType } from '@/
|
||||
import { AlertType } from '@/constants/alerts';
|
||||
import { ButtonSize } from '@/constants/buttons';
|
||||
import { STRING_KEYS } from '@/constants/localization';
|
||||
import { ENVIRONMENT_CONFIG_MAP } from '@/constants/networks';
|
||||
import { NumberSign } from '@/constants/numbers';
|
||||
import type { EvmAddress } from '@/constants/wallets';
|
||||
|
||||
import { useAccounts, useDebounce, useStringGetter } from '@/hooks';
|
||||
import { useAccounts, useDebounce, useStringGetter, useSelectedNetwork } from '@/hooks';
|
||||
import { useAccountBalance, CHAIN_DEFAULT_TOKEN_ADDRESS } from '@/hooks/useAccountBalance';
|
||||
import { useLocalNotifications } from '@/hooks/useLocalNotifications';
|
||||
import { NATIVE_TOKEN_ADDRESS, useSquid } from '@/hooks/useSquid';
|
||||
@@ -54,6 +54,7 @@ export const DepositForm = ({ onDeposit, onError }: DepositFormProps) => {
|
||||
const stringGetter = useStringGetter();
|
||||
const [error, setError] = useState<Error | null>(null);
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const { selectedNetwork } = useSelectedNetwork();
|
||||
|
||||
const { evmAddress, signerWagmi } = useAccounts();
|
||||
const { publicClientWagmi } = useWalletConnection();
|
||||
@@ -239,7 +240,7 @@ export const DepositForm = ({ onDeposit, onError }: DepositFormProps) => {
|
||||
if (txHash) {
|
||||
addTransferNotification({
|
||||
txHash: txHash,
|
||||
toChainId: TESTNET_CHAIN_ID,
|
||||
toChainId: ENVIRONMENT_CONFIG_MAP[selectedNetwork].dydxChainId,
|
||||
fromChainId: chainIdStr || undefined,
|
||||
toAmount: summary?.usdcSize || undefined,
|
||||
triggeredAt: Date.now(),
|
||||
|
||||
@@ -3,13 +3,13 @@ import type { ChangeEvent, FormEvent } from 'react';
|
||||
import styled, { type AnyStyledComponent } from 'styled-components';
|
||||
import type { NumberFormatValues } from 'react-number-format';
|
||||
import { shallowEqual, useSelector } from 'react-redux';
|
||||
import { TESTNET_CHAIN_ID } from '@dydxprotocol/v4-client-js';
|
||||
import { isAddress } from 'viem';
|
||||
|
||||
import { TransferInputField, TransferInputTokenResource, TransferType } from '@/constants/abacus';
|
||||
import { AlertType } from '@/constants/alerts';
|
||||
import { ButtonSize } from '@/constants/buttons';
|
||||
import { STRING_KEYS } from '@/constants/localization';
|
||||
import { ENVIRONMENT_CONFIG_MAP } from '@/constants/networks';
|
||||
import { NumberSign } from '@/constants/numbers';
|
||||
|
||||
import {
|
||||
@@ -17,6 +17,7 @@ import {
|
||||
useDebounce,
|
||||
useDydxClient,
|
||||
useRestrictions,
|
||||
useSelectedNetwork,
|
||||
useStringGetter,
|
||||
useSubaccount,
|
||||
} from '@/hooks';
|
||||
@@ -52,6 +53,7 @@ export const WithdrawForm = () => {
|
||||
const stringGetter = useStringGetter();
|
||||
const [error, setError] = useState<string>();
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const { selectedNetwork } = useSelectedNetwork();
|
||||
|
||||
const { sendSquidWithdraw } = useSubaccount();
|
||||
const { freeCollateral } = useSelector(getSubaccount, shallowEqual) || {};
|
||||
@@ -164,7 +166,7 @@ export const WithdrawForm = () => {
|
||||
const hash = `0x${Buffer.from(txHash.hash).toString('hex')}`;
|
||||
addTransferNotification({
|
||||
txHash: hash,
|
||||
fromChainId: TESTNET_CHAIN_ID,
|
||||
fromChainId: ENVIRONMENT_CONFIG_MAP[selectedNetwork].dydxChainId,
|
||||
toChainId: chainIdStr || undefined,
|
||||
toAmount: debouncedAmountBN.toNumber(),
|
||||
triggeredAt: Date.now(),
|
||||
|
||||
Reference in New Issue
Block a user