Compare commits

..
Author SHA1 Message Date
Rui 45e1b874fd Change "iOS" to "ios" for consistency 2023-11-07 10:58:17 -08:00
John Huang 8d5bf1a721 TRCL-3128 TradePlaceOrder and TradeCancelOrder are now tracked by Abacus (#115) 2023-11-07 10:34:06 -08:00
aleka 7f3d57b46a support multiple modes (#125) 2023-11-07 12:13:59 -05:00
Bill c292c84c2c Fix decimal overflow bug (#127)
* Fix decimal overflow bug

* use decimals:
2023-11-06 17:48:19 -08:00
Bill 2d37ff676b do not use TESTNET_CHAIN_ID (#126) 2023-11-06 17:39:02 -08:00
16 changed files with 67 additions and 50 deletions
+3 -2
View File
@@ -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]",
+12 -6
View File
@@ -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;
+2 -1
View File
@@ -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,
+4 -2
View File
@@ -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;
-6
View File
@@ -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 });
+2 -2
View File
@@ -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={[
+11 -10
View File
@@ -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);
-5
View File
@@ -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;
+1 -1
View File
@@ -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;
+3 -2
View File
@@ -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);
};
};
+3 -1
View File
@@ -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 -1
View File
@@ -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 },
})
);
}
+14 -5
View File
@@ -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>
);
+2 -1
View File
@@ -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(),