Compare commits
18
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
606c82d940 | ||
|
|
76100c9857 | ||
|
|
9bbd8d30ed | ||
|
|
7a24e2acfd | ||
|
|
90d2ede5c6 | ||
|
|
e635778438 | ||
|
|
4ca6df3d31 | ||
|
|
7a456b33d4 | ||
|
|
271c98c9bb | ||
|
|
c397c0dec9 | ||
|
|
cc53ac59d6 | ||
|
|
80be9b357f | ||
|
|
cda3e2bb6e | ||
|
|
cc6d61344b | ||
|
|
7df6e39e87 | ||
|
|
6d25a072bd | ||
|
|
9d3413b04d | ||
|
|
628041e537 |
@@ -4,6 +4,8 @@
|
|||||||
|
|
||||||
- Node.js version 18 and `pnpm` installed on your system
|
- Node.js version 18 and `pnpm` installed on your system
|
||||||
|
|
||||||
|
For deploying with Vercel, create an account with [Vercel](https://vercel.com/signup) if you don't have one already.
|
||||||
|
|
||||||
For deploying to IPFS, choose one of the following:
|
For deploying to IPFS, choose one of the following:
|
||||||
|
|
||||||
- **Option 1:** A free [web3.storage](https://web3.storage/) account
|
- **Option 1:** A free [web3.storage](https://web3.storage/) account
|
||||||
@@ -51,7 +53,24 @@ pnpm ladle
|
|||||||
|
|
||||||
This will automatically open your default browser at `http://localhost:61000`.
|
This will automatically open your default browser at `http://localhost:61000`.
|
||||||
|
|
||||||
## Part 3: Deploying to IPFS
|
## Part 3: Deploying with Vercel
|
||||||
|
|
||||||
|
### Step 1: Connect your repository to Vercel
|
||||||
|
|
||||||
|
Select "Import Git Repository" from your dashboard, and provide the URL of this repository or your forked repository.
|
||||||
|
|
||||||
|
### Step 2: Configure your project
|
||||||
|
|
||||||
|
For the "Build & Development Settings", we recommend the following:
|
||||||
|
- Framework Preset: `Vite`
|
||||||
|
- Build Command (override): `pnpm run build`
|
||||||
|
|
||||||
|
If you wish to incorporate analytics via Amplitude and Bugsnag, you can use our scripts:
|
||||||
|
`pnpm run build:inject-amplitude` and `pnpm run build:inject-bugsnag`. You will need to provide your own API keys for these services. In the Environment Variables section, name the variables as `AMPLITUDE_API_KEY` and `BUGSNAG_API_KEY` and provide the respective keys as their values.
|
||||||
|
|
||||||
|
For more details, check out Vercel's [official documentation](https://vercel.com/docs).
|
||||||
|
|
||||||
|
## Part 4: Deploying to IPFS
|
||||||
|
|
||||||
### web3.storage: deploy to IPFS via web3.storage using the provided script
|
### web3.storage: deploy to IPFS via web3.storage using the provided script
|
||||||
|
|
||||||
@@ -74,7 +93,7 @@ ipfs add -r dist
|
|||||||
|
|
||||||
Save the CID provided in the output.
|
Save the CID provided in the output.
|
||||||
|
|
||||||
## Part 4: Accessing your content on IPFS
|
### Accessing your content on IPFS
|
||||||
|
|
||||||
To access your content on IPFS:
|
To access your content on IPFS:
|
||||||
|
|
||||||
@@ -82,4 +101,4 @@ To access your content on IPFS:
|
|||||||
|
|
||||||
2. **Public IPFS gateway:** Access your content via a public IPFS gateway, such as [https://dweb.link](https://dweb.link/) or [https://w3s.link/](https://w3s.link/). Use the gateway URL with your CID appended, like `https://dweb.link/ipfs/your_cid`.
|
2. **Public IPFS gateway:** Access your content via a public IPFS gateway, such as [https://dweb.link](https://dweb.link/) or [https://w3s.link/](https://w3s.link/). Use the gateway URL with your CID appended, like `https://dweb.link/ipfs/your_cid`.
|
||||||
|
|
||||||
Replace `your_cid` with the actual CID.
|
Replace `your_cid` with the actual CID.
|
||||||
|
|||||||
+4
-3
@@ -29,15 +29,16 @@
|
|||||||
},
|
},
|
||||||
"packageManager": "pnpm@8.6.6",
|
"packageManager": "pnpm@8.6.6",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@0xsquid/sdk": "^1.10.0",
|
"@0xsquid/sdk": "^1.7.2",
|
||||||
"@cosmjs/amino": "^0.31.0",
|
"@cosmjs/amino": "^0.31.0",
|
||||||
"@cosmjs/crypto": "^0.31.0",
|
"@cosmjs/crypto": "^0.31.0",
|
||||||
"@cosmjs/encoding": "^0.31.0",
|
"@cosmjs/encoding": "^0.31.0",
|
||||||
"@cosmjs/proto-signing": "^0.31.0",
|
"@cosmjs/proto-signing": "^0.31.0",
|
||||||
"@cosmjs/stargate": "^0.31.0",
|
"@cosmjs/stargate": "^0.31.0",
|
||||||
"@dydxprotocol/abacus": "^0.2.37",
|
|
||||||
"@cosmjs/tendermint-rpc": "^0.31.0",
|
"@cosmjs/tendermint-rpc": "^0.31.0",
|
||||||
"@dydxprotocol/v4-client": "^0.29.0",
|
"@dydxprotocol/abacus": "^0.3.10",
|
||||||
|
"@dydxprotocol/v4-client-js": "^0.30.3",
|
||||||
|
"@dydxprotocol/v4-localization": "^0.0.16",
|
||||||
"@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
+1772
-202
File diff suppressed because it is too large
Load Diff
+24
-27
@@ -13,9 +13,8 @@ import { AccountsProvider } from '@/hooks/useAccounts';
|
|||||||
import { DialogAreaProvider, useDialogArea } from './hooks/useDialogArea';
|
import { DialogAreaProvider, useDialogArea } from './hooks/useDialogArea';
|
||||||
import { LocaleProvider } from './hooks/useLocaleSeparators';
|
import { LocaleProvider } from './hooks/useLocaleSeparators';
|
||||||
import { NotificationsProvider } from './hooks/useNotifications';
|
import { NotificationsProvider } from './hooks/useNotifications';
|
||||||
import { LocalNotificationsProvider } from './hooks/useLocalNotifications';
|
|
||||||
import { SubaccountProvider } from './hooks/useSubaccount';
|
import { SubaccountProvider } from './hooks/useSubaccount';
|
||||||
import { SquidProvider } from '@/hooks/useSquid';
|
import { SquidProvider } from '@/hooks/useSquidRouter';
|
||||||
|
|
||||||
import { GuardedMobileRoute } from '@/components/GuardedMobileRoute';
|
import { GuardedMobileRoute } from '@/components/GuardedMobileRoute';
|
||||||
|
|
||||||
@@ -99,31 +98,29 @@ const Content = () => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const wrapProvider = (Component: React.ComponentType<any>, props?: any) => {
|
const App = () => (
|
||||||
return ({ children }: { children: React.ReactNode }) => (
|
<QueryClientProvider client={queryClient}>
|
||||||
<Component {...props}>{children}</Component>
|
<GrazProvider>
|
||||||
);
|
<WagmiConfig config={config}>
|
||||||
};
|
<LocaleProvider>
|
||||||
|
<DydxProvider>
|
||||||
const providers = [
|
<AccountsProvider>
|
||||||
wrapProvider(QueryClientProvider, { client: queryClient }),
|
<SubaccountProvider>
|
||||||
wrapProvider(GrazProvider),
|
<NotificationsProvider>
|
||||||
wrapProvider(WagmiConfig, { config }),
|
<DialogAreaProvider>
|
||||||
wrapProvider(LocaleProvider),
|
<SquidProvider>
|
||||||
wrapProvider(DydxProvider),
|
<Content />
|
||||||
wrapProvider(AccountsProvider),
|
</SquidProvider>
|
||||||
wrapProvider(SubaccountProvider),
|
</DialogAreaProvider>
|
||||||
wrapProvider(SquidProvider),
|
</NotificationsProvider>
|
||||||
wrapProvider(LocalNotificationsProvider),
|
</SubaccountProvider>
|
||||||
wrapProvider(NotificationsProvider),
|
</AccountsProvider>
|
||||||
wrapProvider(DialogAreaProvider),
|
</DydxProvider>
|
||||||
];
|
</LocaleProvider>
|
||||||
|
</WagmiConfig>
|
||||||
const App = () => {
|
</GrazProvider>
|
||||||
return [...providers].reverse().reduce((children, Provider) => {
|
</QueryClientProvider>
|
||||||
return <Provider>{children}</Provider>;
|
);
|
||||||
}, <Content />);
|
|
||||||
};
|
|
||||||
|
|
||||||
const Styled: Record<string, AnyStyledComponent> = {};
|
const Styled: Record<string, AnyStyledComponent> = {};
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import type { Story } from '@ladle/react';
|
import type { Story } from '@ladle/react';
|
||||||
import { OrderSide } from '@dydxprotocol/v4-client';
|
import { OrderSide } from '@dydxprotocol/v4-client-js';
|
||||||
|
|
||||||
import { OrderSideTag } from '@/components/OrderSideTag';
|
import { OrderSideTag } from '@/components/OrderSideTag';
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { OrderSide } from '@dydxprotocol/v4-client';
|
import { OrderSide } from '@dydxprotocol/v4-client-js';
|
||||||
|
|
||||||
import { STRING_KEYS } from '@/constants/localization';
|
import { STRING_KEYS } from '@/constants/localization';
|
||||||
import { useStringGetter } from '@/hooks';
|
import { useStringGetter } from '@/hooks';
|
||||||
|
|||||||
+10
-12
@@ -17,7 +17,6 @@ type ElementProps = {
|
|||||||
slotIcon?: React.ReactNode;
|
slotIcon?: React.ReactNode;
|
||||||
slotTitle?: React.ReactNode;
|
slotTitle?: React.ReactNode;
|
||||||
slotDescription?: React.ReactNode;
|
slotDescription?: React.ReactNode;
|
||||||
slotCustomContent?: React.ReactNode;
|
|
||||||
slotAction?: React.ReactNode;
|
slotAction?: React.ReactNode;
|
||||||
actionDescription?: string;
|
actionDescription?: string;
|
||||||
actionAltText?: string;
|
actionAltText?: string;
|
||||||
@@ -34,7 +33,6 @@ export const Toast = ({
|
|||||||
slotIcon,
|
slotIcon,
|
||||||
slotTitle,
|
slotTitle,
|
||||||
slotDescription,
|
slotDescription,
|
||||||
slotCustomContent,
|
|
||||||
slotAction,
|
slotAction,
|
||||||
actionDescription = '',
|
actionDescription = '',
|
||||||
actionAltText = actionDescription,
|
actionAltText = actionDescription,
|
||||||
@@ -80,13 +78,12 @@ export const Toast = ({
|
|||||||
|
|
||||||
<$Title>{slotTitle}</$Title>
|
<$Title>{slotTitle}</$Title>
|
||||||
</$Header>
|
</$Header>
|
||||||
{!slotCustomContent && <$Description>{slotDescription}</$Description>}
|
|
||||||
{slotCustomContent}
|
<$Description>{slotDescription}</$Description>
|
||||||
{actionDescription && (
|
|
||||||
<$Action asChild altText={actionAltText}>
|
<$Action asChild altText={actionAltText}>
|
||||||
{slotAction}
|
{slotAction}
|
||||||
</$Action>
|
</$Action>
|
||||||
)}
|
|
||||||
</$Container>
|
</$Container>
|
||||||
</div>
|
</div>
|
||||||
</$Root>
|
</$Root>
|
||||||
@@ -121,7 +118,8 @@ const $Root = styled(Root)`
|
|||||||
align-items: end;
|
align-items: end;
|
||||||
transform-origin: left bottom;
|
transform-origin: left bottom;
|
||||||
|
|
||||||
animation: ${keyframes`
|
animation:
|
||||||
|
${keyframes`
|
||||||
from {
|
from {
|
||||||
/* scale: 0; */
|
/* scale: 0; */
|
||||||
grid-template-rows: 0fr; // height transition
|
grid-template-rows: 0fr; // height transition
|
||||||
@@ -205,8 +203,8 @@ const $Container = styled.div`
|
|||||||
// Rules
|
// Rules
|
||||||
${popoverMixins.popover}
|
${popoverMixins.popover}
|
||||||
padding: 1rem;
|
padding: 1rem;
|
||||||
box-shadow: 0 0 0 var(--border-width) var(--color-border),
|
box-shadow:
|
||||||
// border
|
0 0 0 var(--border-width) var(--color-border), // border
|
||||||
0 0 0.5rem 0.1rem var(--color-layer-2); // shadow
|
0 0 0.5rem 0.1rem var(--color-layer-2); // shadow
|
||||||
|
|
||||||
${$Root}:focus:not([data-swipe='end']) & {
|
${$Root}:focus:not([data-swipe='end']) & {
|
||||||
|
|||||||
+10
-1
@@ -1,5 +1,5 @@
|
|||||||
import Abacus, { kollections } from '@dydxprotocol/abacus';
|
import Abacus, { kollections } from '@dydxprotocol/abacus';
|
||||||
import { OrderSide } from '@dydxprotocol/v4-client';
|
import { OrderSide } from '@dydxprotocol/v4-client-js';
|
||||||
import { PositionSide, TradeTypes } from './trade';
|
import { PositionSide, TradeTypes } from './trade';
|
||||||
import { STRING_KEYS } from './localization';
|
import { STRING_KEYS } from './localization';
|
||||||
|
|
||||||
@@ -36,6 +36,12 @@ export type AbacusThreadingProtocol = Omit<
|
|||||||
Abacus.exchange.dydx.abacus.protocols.ThreadingProtocol,
|
Abacus.exchange.dydx.abacus.protocols.ThreadingProtocol,
|
||||||
'__doNotUseOrImplementIt'
|
'__doNotUseOrImplementIt'
|
||||||
>;
|
>;
|
||||||
|
export type AbacusFileSystemProtocol = Omit<
|
||||||
|
Abacus.exchange.dydx.abacus.protocols.FileSystemProtocol,
|
||||||
|
'__doNotUseOrImplementIt'
|
||||||
|
>;
|
||||||
|
|
||||||
|
export type FileLocation = Abacus.exchange.dydx.abacus.protocols.FileLocation;
|
||||||
export type ThreadingType = Abacus.exchange.dydx.abacus.protocols.ThreadingType;
|
export type ThreadingType = Abacus.exchange.dydx.abacus.protocols.ThreadingType;
|
||||||
export const CoroutineTimer = Abacus.exchange.dydx.abacus.utils.CoroutineTimer;
|
export const CoroutineTimer = Abacus.exchange.dydx.abacus.utils.CoroutineTimer;
|
||||||
|
|
||||||
@@ -180,6 +186,9 @@ export const RiskLevel = Abacus.exchange.dydx.abacus.utils.RiskLevel;
|
|||||||
const riskLevels = [...RiskLevel.values()] as const;
|
const riskLevels = [...RiskLevel.values()] as const;
|
||||||
export type RiskLevels = (typeof riskLevels)[number];
|
export type RiskLevels = (typeof riskLevels)[number];
|
||||||
|
|
||||||
|
// ------ Notifications ------ //
|
||||||
|
export type AbacusNotification = Abacus.exchange.dydx.abacus.output.Notification;
|
||||||
|
|
||||||
// ------ Enum Conversions ------ //
|
// ------ Enum Conversions ------ //
|
||||||
type IfEquals<X, Y, A, B> = (<T>() => T extends X ? 1 : 2) extends <T>() => T extends Y ? 1 : 2
|
type IfEquals<X, Y, A, B> = (<T>() => T extends X ? 1 : 2) extends <T>() => T extends Y ? 1 : 2
|
||||||
? A
|
? A
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ export enum LocalStorageKey {
|
|||||||
NotificationsLastUpdated = 'dydx.NotificationsLastUpdated',
|
NotificationsLastUpdated = 'dydx.NotificationsLastUpdated',
|
||||||
PushNotificationsEnabled = 'dydx.PushNotificationsEnabled',
|
PushNotificationsEnabled = 'dydx.PushNotificationsEnabled',
|
||||||
PushNotificationsLastUpdated = 'dydx.PushNotificationsLastUpdated',
|
PushNotificationsLastUpdated = 'dydx.PushNotificationsLastUpdated',
|
||||||
TransferNotifications = 'dydx.TransferNotifications',
|
|
||||||
|
|
||||||
// UI State
|
// UI State
|
||||||
LastViewedMarket = 'dydx.LastViewedMarket',
|
LastViewedMarket = 'dydx.LastViewedMarket',
|
||||||
|
|||||||
@@ -109,7 +109,6 @@ export const APP_STRING_KEYS = {
|
|||||||
HEDGIES: 'GENERAL.HEDGIES',
|
HEDGIES: 'GENERAL.HEDGIES',
|
||||||
HIDE_SECTION: 'GENERAL.HIDE_SECTION',
|
HIDE_SECTION: 'GENERAL.HIDE_SECTION',
|
||||||
HIDE: 'GENERAL.HIDE',
|
HIDE: 'GENERAL.HIDE',
|
||||||
HIDE_DETAILS: 'GENERAL.HIDE_DETAILS',
|
|
||||||
HISTORY: 'GENERAL.HISTORY',
|
HISTORY: 'GENERAL.HISTORY',
|
||||||
INCREASED: 'GENERAL.INCREASED',
|
INCREASED: 'GENERAL.INCREASED',
|
||||||
INCREASING: 'GENERAL.INCREASING',
|
INCREASING: 'GENERAL.INCREASING',
|
||||||
@@ -384,7 +383,6 @@ export const APP_STRING_KEYS = {
|
|||||||
CONNECTING_SUBTITLE: 'ONBOARDING.CONNECTING_SUBTITLE',
|
CONNECTING_SUBTITLE: 'ONBOARDING.CONNECTING_SUBTITLE',
|
||||||
COULD_NOT_FIND_AFFILIATE: 'ONBOARDING.COULD_NOT_FIND_AFFILIATE',
|
COULD_NOT_FIND_AFFILIATE: 'ONBOARDING.COULD_NOT_FIND_AFFILIATE',
|
||||||
CREATE_OR_VERIFY_COSMOS_ADDRESS: 'ONBOARDING.CREATE_OR_VERIFY_COSMOS_ADDRESS',
|
CREATE_OR_VERIFY_COSMOS_ADDRESS: 'ONBOARDING.CREATE_OR_VERIFY_COSMOS_ADDRESS',
|
||||||
DEPOSIT_STATUS: 'ONBOARDING.DEPOSIT_STATUS',
|
|
||||||
DONT_MISS: 'ONBOARDING.DONT_MISS',
|
DONT_MISS: 'ONBOARDING.DONT_MISS',
|
||||||
ENABLE_API: 'ONBOARDING.ENABLE_API',
|
ENABLE_API: 'ONBOARDING.ENABLE_API',
|
||||||
ENABLE_TRADING: 'ONBOARDING.ENABLE_TRADING',
|
ENABLE_TRADING: 'ONBOARDING.ENABLE_TRADING',
|
||||||
@@ -447,7 +445,6 @@ export const APP_STRING_KEYS = {
|
|||||||
VERIFY_WALLET_COMPATIBILITY: 'ONBOARDING.VERIFY_WALLET_COMPATIBILITY',
|
VERIFY_WALLET_COMPATIBILITY: 'ONBOARDING.VERIFY_WALLET_COMPATIBILITY',
|
||||||
WELCOME: 'ONBOARDING.WELCOME',
|
WELCOME: 'ONBOARDING.WELCOME',
|
||||||
WELCOME_DYDX: 'ONBOARDING.WELCOME_DYDX',
|
WELCOME_DYDX: 'ONBOARDING.WELCOME_DYDX',
|
||||||
WITHDRAW_STATUS: 'ONBOARDING.WITHDRAW_STATUS',
|
|
||||||
WRONG_NETWORK_EXPLANATION_PRODUCTION: 'ONBOARDING.WRONG_NETWORK_EXPLANATION_PRODUCTION',
|
WRONG_NETWORK_EXPLANATION_PRODUCTION: 'ONBOARDING.WRONG_NETWORK_EXPLANATION_PRODUCTION',
|
||||||
WRONG_NETWORK_EXPLANATION_STAGING: 'ONBOARDING.WRONG_NETWORK_EXPLANATION_STAGING',
|
WRONG_NETWORK_EXPLANATION_STAGING: 'ONBOARDING.WRONG_NETWORK_EXPLANATION_STAGING',
|
||||||
WRONG_NETWORK: 'ONBOARDING.WRONG_NETWORK',
|
WRONG_NETWORK: 'ONBOARDING.WRONG_NETWORK',
|
||||||
@@ -903,7 +900,6 @@ export const APP_STRING_KEYS = {
|
|||||||
'66_REDUCTION': 'NOTIFICATIONS.66_REDUCTION',
|
'66_REDUCTION': 'NOTIFICATIONS.66_REDUCTION',
|
||||||
ADJUSTED_IMR: 'NOTIFICATIONS.ADJUSTED_IMR',
|
ADJUSTED_IMR: 'NOTIFICATIONS.ADJUSTED_IMR',
|
||||||
ADJUSTED_IMR_BODY: 'NOTIFICATIONS.ADJUSTED_IMR_BODY',
|
ADJUSTED_IMR_BODY: 'NOTIFICATIONS.ADJUSTED_IMR_BODY',
|
||||||
BRIDGING_TOKENS: "NOTIFICATIONS.BRIDGING_TOKENS",
|
|
||||||
CLOSE_MARKET_POSITIONS: 'NOTIFICATIONS.CLOSE_MARKET_POSITIONS',
|
CLOSE_MARKET_POSITIONS: 'NOTIFICATIONS.CLOSE_MARKET_POSITIONS',
|
||||||
CLOSE_MARKET_POSITIONS_BODY: 'NOTIFICATIONS.CLOSE_MARKET_POSITIONS_BODY',
|
CLOSE_MARKET_POSITIONS_BODY: 'NOTIFICATIONS.CLOSE_MARKET_POSITIONS_BODY',
|
||||||
COMPLIANCE_ALERT: 'NOTIFICATIONS.COMPLIANCE_ALERT',
|
COMPLIANCE_ALERT: 'NOTIFICATIONS.COMPLIANCE_ALERT',
|
||||||
@@ -911,7 +907,6 @@ export const APP_STRING_KEYS = {
|
|||||||
DEPOSIT_IN_PROGRESS: 'NOTIFICATIONS.DEPOSIT_IN_PROGRESS',
|
DEPOSIT_IN_PROGRESS: 'NOTIFICATIONS.DEPOSIT_IN_PROGRESS',
|
||||||
DEPOSIT_SUCCESS_DESCRIPTION: 'NOTIFICATIONS.DEPOSIT_SUCCESS_DESCRIPTION',
|
DEPOSIT_SUCCESS_DESCRIPTION: 'NOTIFICATIONS.DEPOSIT_SUCCESS_DESCRIPTION',
|
||||||
DEPOSIT_SUCCESS: 'NOTIFICATIONS.DEPOSIT_SUCCESS',
|
DEPOSIT_SUCCESS: 'NOTIFICATIONS.DEPOSIT_SUCCESS',
|
||||||
DEPOSIT_TO_CHAIN: "NOTIFICATIONS.DEPOSIT_TO_CHAIN",
|
|
||||||
DIRECT_TRANSFER_SUCCESS: 'NOTIFICATIONS.DIRECT_TRANSFER_SUCCESS',
|
DIRECT_TRANSFER_SUCCESS: 'NOTIFICATIONS.DIRECT_TRANSFER_SUCCESS',
|
||||||
DIRECT_TRANSFER_SUCCESS_DESCRIPTION: 'NOTIFICATIONS.DIRECT_TRANSFER_SUCCESS_DESCRIPTION',
|
DIRECT_TRANSFER_SUCCESS_DESCRIPTION: 'NOTIFICATIONS.DIRECT_TRANSFER_SUCCESS_DESCRIPTION',
|
||||||
EPOCH_REWARDS: 'NOTIFICATIONS.EPOCH_REWARDS',
|
EPOCH_REWARDS: 'NOTIFICATIONS.EPOCH_REWARDS',
|
||||||
@@ -920,8 +915,6 @@ export const APP_STRING_KEYS = {
|
|||||||
FAST_WITHDRAW_PENDING: 'NOTIFICATIONS.FAST_WITHDRAW_PENDING',
|
FAST_WITHDRAW_PENDING: 'NOTIFICATIONS.FAST_WITHDRAW_PENDING',
|
||||||
FAST_WITHDRAW_SUCCESS_DESCRIPTION: 'NOTIFICATIONS.FAST_WITHDRAW_SUCCESS_DESCRIPTION',
|
FAST_WITHDRAW_SUCCESS_DESCRIPTION: 'NOTIFICATIONS.FAST_WITHDRAW_SUCCESS_DESCRIPTION',
|
||||||
FAST_WITHDRAW_SUCCESS: 'NOTIFICATIONS.FAST_WITHDRAW_SUCCESS',
|
FAST_WITHDRAW_SUCCESS: 'NOTIFICATIONS.FAST_WITHDRAW_SUCCESS',
|
||||||
INITIATED_DEPOSIT: "NOTIFICATIONS.INITIATED_DEPOSIT",
|
|
||||||
INITIATED_WITHDRAWAL: "NOTIFICATIONS.INITIATED_WITHDRAWAL",
|
|
||||||
LEGAL_UPDATES: 'NOTIFICATIONS.LEGAL_UPDATES',
|
LEGAL_UPDATES: 'NOTIFICATIONS.LEGAL_UPDATES',
|
||||||
LEGAL_UPDATES_DESCRIPTION: 'NOTIFICATIONS.LEGAL_UPDATES_DESCRIPTION',
|
LEGAL_UPDATES_DESCRIPTION: 'NOTIFICATIONS.LEGAL_UPDATES_DESCRIPTION',
|
||||||
MAINTENANCE_MARGIN_ADJUSTMENTS: 'NOTIFICATIONS.MAINTENANCE_MARGIN_ADJUSTMENTS',
|
MAINTENANCE_MARGIN_ADJUSTMENTS: 'NOTIFICATIONS.MAINTENANCE_MARGIN_ADJUSTMENTS',
|
||||||
@@ -939,7 +932,6 @@ export const APP_STRING_KEYS = {
|
|||||||
SUSPICIOUS_TRADE: 'NOTIFICATIONS.SUSPICIOUS_TRADE',
|
SUSPICIOUS_TRADE: 'NOTIFICATIONS.SUSPICIOUS_TRADE',
|
||||||
SUSPICIOUS_TRADE_BODY: 'NOTIFICATIONS.SUSPICIOUS_TRADE_BODY',
|
SUSPICIOUS_TRADE_BODY: 'NOTIFICATIONS.SUSPICIOUS_TRADE_BODY',
|
||||||
WITHDRAW_IN_PROGRESS: 'NOTIFICATIONS.WITHDRAW_IN_PROGRESS',
|
WITHDRAW_IN_PROGRESS: 'NOTIFICATIONS.WITHDRAW_IN_PROGRESS',
|
||||||
WITHDRAW_TO_CHAIN: "NOTIFICATIONS.WITHDRAW_TO_CHAIN",
|
|
||||||
|
|
||||||
// Email Notifications
|
// Email Notifications
|
||||||
ACCOUNT_DESCRIPTION: 'EMAIL_NOTIFICATIONS.ACCOUNT_DESCRIPTION',
|
ACCOUNT_DESCRIPTION: 'EMAIL_NOTIFICATIONS.ACCOUNT_DESCRIPTION',
|
||||||
|
|||||||
+18
-62
@@ -1,73 +1,29 @@
|
|||||||
|
import { ENDPOINTS, DEV_ENDPOINTS } from '@dydxprotocol/v4-localization';
|
||||||
|
|
||||||
|
export const NETWORK_ENDPOINTS = import.meta.env.MODE === 'production' ? ENDPOINTS : DEV_ENDPOINTS;
|
||||||
|
|
||||||
|
export const CLIENT_NETWORK_CONFIGS: Record<
|
||||||
|
string,
|
||||||
|
(typeof NETWORK_ENDPOINTS.environments)[number]
|
||||||
|
> = Object.fromEntries(
|
||||||
|
NETWORK_ENDPOINTS.environments.map((environment) => [environment.environment, environment])
|
||||||
|
);
|
||||||
|
|
||||||
|
export const DEFAULT_APP_ENVIRONMENT = NETWORK_ENDPOINTS.defaultEnvironment;
|
||||||
|
|
||||||
export enum DydxV4Network {
|
export enum DydxV4Network {
|
||||||
V4Mainnet = 'dydxprotocol-mainnet',
|
V4Mainnet = 'dydxprotocol-mainnet',
|
||||||
V4Staging = 'dydxprotocol-staging',
|
V4Staging = 'dydxprotocol-staging',
|
||||||
V4Testnet2 = 'dydxprotocol-testnet-2',
|
V4Testnet2 = 'dydxprotocol-testnet',
|
||||||
V4Local = 'dydxprotocol-dev',
|
V4Local = 'dydxprotocol-dev',
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum DydxV3Network {
|
export type DydxNetwork = keyof typeof CLIENT_NETWORK_CONFIGS;
|
||||||
V3Mainnet = '1',
|
|
||||||
V3Testnet = '5',
|
|
||||||
}
|
|
||||||
|
|
||||||
export function isDydxV4Network(network: any): network is DydxV4Network {
|
export function isDydxV4Network(network: any): boolean {
|
||||||
return Object.values(DydxV4Network).includes(network);
|
return CLIENT_NETWORK_CONFIGS[network]?.version === 'v4';
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isValidDydxNetwork(network: any): boolean {
|
export function isValidDydxNetwork(network: any): boolean {
|
||||||
return isDydxV4Network(network) || Object.values(DydxV3Network).includes(network);
|
return Object.keys(CLIENT_NETWORK_CONFIGS).includes(network);
|
||||||
}
|
}
|
||||||
|
|
||||||
export type DydxNetwork = DydxV4Network | DydxV3Network;
|
|
||||||
|
|
||||||
export const CHAIN_IDS = {
|
|
||||||
[DydxV4Network.V4Mainnet]: '',
|
|
||||||
[DydxV4Network.V4Staging]: 'dydxprotocol-testnet',
|
|
||||||
[DydxV4Network.V4Testnet2]: 'dydx-testnet-2',
|
|
||||||
[DydxV4Network.V4Local]: 'dydxprotocol-testnet',
|
|
||||||
[DydxV3Network.V3Mainnet]: '1',
|
|
||||||
[DydxV3Network.V3Testnet]: '5',
|
|
||||||
};
|
|
||||||
|
|
||||||
export const DEFAULT_APP_ENVIRONMENT =
|
|
||||||
import.meta.env.MODE === 'production' ? DydxV4Network.V4Testnet2 : DydxV4Network.V4Staging;
|
|
||||||
|
|
||||||
export const CLIENT_NETWORK_CONFIGS: Record<
|
|
||||||
DydxV4Network,
|
|
||||||
{
|
|
||||||
chainId: string;
|
|
||||||
validatorUrl: string;
|
|
||||||
faucetUrl: string;
|
|
||||||
indexerUrl: string;
|
|
||||||
ethereumChainId: number;
|
|
||||||
}
|
|
||||||
> = {
|
|
||||||
[DydxV4Network.V4Mainnet]: {
|
|
||||||
chainId: CHAIN_IDS[DydxV4Network.V4Mainnet],
|
|
||||||
validatorUrl: import.meta.env.VITE_VALIDATOR_URL_STAGE,
|
|
||||||
faucetUrl: import.meta.env.VITE_FAUCET_URL_STAGE,
|
|
||||||
indexerUrl: import.meta.env.VITE_INDEXER_URL_STAGE,
|
|
||||||
ethereumChainId: 1,
|
|
||||||
},
|
|
||||||
[DydxV4Network.V4Local]: {
|
|
||||||
chainId: CHAIN_IDS[DydxV4Network.V4Local],
|
|
||||||
validatorUrl: import.meta.env.VITE_VALIDATOR_URL_DEV,
|
|
||||||
faucetUrl: import.meta.env.VITE_FAUCET_URL_DEV,
|
|
||||||
indexerUrl: import.meta.env.VITE_INDEXER_URL_DEV,
|
|
||||||
ethereumChainId: 5,
|
|
||||||
},
|
|
||||||
[DydxV4Network.V4Staging]: {
|
|
||||||
chainId: CHAIN_IDS[DydxV4Network.V4Staging],
|
|
||||||
validatorUrl: import.meta.env.VITE_VALIDATOR_URL_STAGE,
|
|
||||||
faucetUrl: import.meta.env.VITE_FAUCET_URL_STAGE,
|
|
||||||
indexerUrl: import.meta.env.VITE_INDEXER_URL_STAGE,
|
|
||||||
ethereumChainId: 5,
|
|
||||||
},
|
|
||||||
[DydxV4Network.V4Testnet2]: {
|
|
||||||
chainId: CHAIN_IDS[DydxV4Network.V4Testnet2],
|
|
||||||
validatorUrl: import.meta.env.VITE_VALIDATOR_URL_TESTNET2,
|
|
||||||
faucetUrl: import.meta.env.VITE_FAUCET_URL_TESTNET2,
|
|
||||||
indexerUrl: import.meta.env.VITE_INDEXER_URL_TESTNET2,
|
|
||||||
ethereumChainId: 5,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|||||||
@@ -1,22 +1,16 @@
|
|||||||
import { StatusResponse } from "@0xsquid/sdk";
|
|
||||||
|
|
||||||
/** implemented in useNotificationTypes */
|
/** implemented in useNotificationTypes */
|
||||||
export enum NotificationType {
|
export enum NotificationType {
|
||||||
OrderStatusChanged = 'OrderStatusChanged',
|
OrderStatusChanged = 'OrderStatusChanged',
|
||||||
SquidTransfer = 'SquidTransfer',
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum NotificationComponentType {}
|
export enum NotificationComponentType {}
|
||||||
|
|
||||||
export type NotificationId = string | number;
|
export type NotificationId = string | number
|
||||||
|
|
||||||
export type NotificationTypeConfig<
|
export type NotificationTypeConfig<_NotificationId extends NotificationId = string, NotificationUpdateKey = any> = {
|
||||||
_NotificationId extends NotificationId = string,
|
|
||||||
NotificationUpdateKey = any
|
|
||||||
> = {
|
|
||||||
type: NotificationType;
|
type: NotificationType;
|
||||||
|
|
||||||
/** React hook to trigger notifications based on app state */
|
/** React hook to trigger notifications based on app state */
|
||||||
useTrigger: (_: {
|
useTrigger: (_: {
|
||||||
trigger: (
|
trigger: (
|
||||||
/** Unique ID for the triggered notification */
|
/** Unique ID for the triggered notification */
|
||||||
@@ -36,7 +30,7 @@ export type NotificationTypeConfig<
|
|||||||
* @param true (default): Notification initialized with status NotificationStatus.Triggered
|
* @param true (default): Notification initialized with status NotificationStatus.Triggered
|
||||||
* @param false: Notification initialized with status NotificationStatus.Cleared
|
* @param false: Notification initialized with status NotificationStatus.Cleared
|
||||||
*/
|
*/
|
||||||
isNew?: boolean
|
isNew?: boolean,
|
||||||
) => void;
|
) => void;
|
||||||
|
|
||||||
lastUpdated: number;
|
lastUpdated: number;
|
||||||
@@ -64,10 +58,7 @@ export enum NotificationStatus {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Notification state. Serialized and cached into localStorage. */
|
/** Notification state. Serialized and cached into localStorage. */
|
||||||
export type Notification<
|
export type Notification<_NotificationId extends NotificationId = string, NotificationUpdateKey = any> = {
|
||||||
_NotificationId extends NotificationId = string,
|
|
||||||
NotificationUpdateKey = any
|
|
||||||
> = {
|
|
||||||
id: _NotificationId;
|
id: _NotificationId;
|
||||||
type: NotificationType;
|
type: NotificationType;
|
||||||
status: NotificationStatus;
|
status: NotificationStatus;
|
||||||
@@ -83,11 +74,7 @@ export type NotificationDisplayData = {
|
|||||||
|
|
||||||
title?: string;
|
title?: string;
|
||||||
|
|
||||||
description?: React.ReactNode;
|
description?: string;
|
||||||
|
|
||||||
customContent?: React.ReactNode;
|
|
||||||
|
|
||||||
customMenuContent?: React.ReactNode;
|
|
||||||
|
|
||||||
actionDescription?: string;
|
actionDescription?: string;
|
||||||
|
|
||||||
@@ -114,13 +101,3 @@ export type NotificationDisplayData = {
|
|||||||
*/
|
*/
|
||||||
toastDuration?: number;
|
toastDuration?: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Notification types
|
|
||||||
export type TransferNotifcation = {
|
|
||||||
txHash: string;
|
|
||||||
toChainId?: string;
|
|
||||||
fromChainId?: string;
|
|
||||||
toAmount?: number;
|
|
||||||
triggeredAt?: number;
|
|
||||||
status?: StatusResponse;
|
|
||||||
};
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { OrderSide } from '@dydxprotocol/v4-client';
|
import { OrderSide } from '@dydxprotocol/v4-client-js';
|
||||||
|
|
||||||
import { AlertType } from '@/constants/alerts';
|
import { AlertType } from '@/constants/alerts';
|
||||||
import { STRING_KEYS } from '@/constants/localization';
|
import { STRING_KEYS } from '@/constants/localization';
|
||||||
|
|||||||
@@ -302,7 +302,7 @@ export type WalletConnection = {
|
|||||||
|
|
||||||
// dYdX Chain wallets
|
// dYdX Chain wallets
|
||||||
|
|
||||||
import { USDC_DENOM, type Onboarding, DYDX_DENOM } from '@dydxprotocol/v4-client';
|
import { USDC_DENOM, type Onboarding, DYDX_DENOM } from '@dydxprotocol/v4-client-js';
|
||||||
import type { suggestChain } from 'graz';
|
import type { suggestChain } from 'graz';
|
||||||
|
|
||||||
export const COSMOS_DERIVATION_PATH = "m/44'/118'/0'/0/0";
|
export const COSMOS_DERIVATION_PATH = "m/44'/118'/0'/0/0";
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import { useEffect } from 'react';
|
import { useEffect } from 'react';
|
||||||
import { shallowEqual, useSelector } from 'react-redux';
|
import { shallowEqual, useSelector } from 'react-redux';
|
||||||
import { useLocation } from 'react-router-dom';
|
|
||||||
import isEmpty from 'lodash/isEmpty';
|
import isEmpty from 'lodash/isEmpty';
|
||||||
|
|
||||||
import { LanguageCode, ResolutionString, widget } from 'public/tradingview/charting_library';
|
import { LanguageCode, ResolutionString, widget } from 'public/tradingview/charting_library';
|
||||||
@@ -14,9 +13,8 @@ import { store } from '@/state/_store';
|
|||||||
import { getSelectedNetwork } from '@/state/appSelectors';
|
import { getSelectedNetwork } from '@/state/appSelectors';
|
||||||
import { getAppTheme } from '@/state/configsSelectors';
|
import { getAppTheme } from '@/state/configsSelectors';
|
||||||
import { getSelectedLocale } from '@/state/localizationSelectors';
|
import { getSelectedLocale } from '@/state/localizationSelectors';
|
||||||
import { getMarketIds } from '@/state/perpetualsSelectors';
|
import { getCurrentMarketId, getMarketIds } from '@/state/perpetualsSelectors';
|
||||||
|
|
||||||
import { getMarketIdFromLocation } from '@/lib/tradeData';
|
|
||||||
import { getDydxDatafeed } from '@/lib/tradingView/dydxfeed';
|
import { getDydxDatafeed } from '@/lib/tradingView/dydxfeed';
|
||||||
import { getSavedResolution, getWidgetOptions, getWidgetOverrides } from '@/lib/tradingView/utils';
|
import { getSavedResolution, getWidgetOptions, getWidgetOverrides } from '@/lib/tradingView/utils';
|
||||||
|
|
||||||
@@ -30,8 +28,7 @@ export const useTradingView = ({
|
|||||||
tvWidgetRef: React.MutableRefObject<any>;
|
tvWidgetRef: React.MutableRefObject<any>;
|
||||||
setIsChartReady: React.Dispatch<React.SetStateAction<boolean>>;
|
setIsChartReady: React.Dispatch<React.SetStateAction<boolean>>;
|
||||||
}) => {
|
}) => {
|
||||||
const location = useLocation();
|
const marketId = useSelector(getCurrentMarketId);
|
||||||
const marketId = getMarketIdFromLocation(location);
|
|
||||||
const appTheme = useSelector(getAppTheme);
|
const appTheme = useSelector(getAppTheme);
|
||||||
const marketIds = useSelector(getMarketIds, shallowEqual);
|
const marketIds = useSelector(getMarketIds, shallowEqual);
|
||||||
const selectedLocale = useSelector(getSelectedLocale);
|
const selectedLocale = useSelector(getSelectedLocale);
|
||||||
@@ -50,7 +47,6 @@ export const useTradingView = ({
|
|||||||
if (hasMarkets) {
|
if (hasMarkets) {
|
||||||
const widgetOptions = getWidgetOptions();
|
const widgetOptions = getWidgetOptions();
|
||||||
const widgetOverrides = getWidgetOverrides(appTheme);
|
const widgetOverrides = getWidgetOverrides(appTheme);
|
||||||
|
|
||||||
const options = {
|
const options = {
|
||||||
// debug: true,
|
// debug: true,
|
||||||
...widgetOptions,
|
...widgetOptions,
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import { StargateClient } from '@cosmjs/stargate';
|
|||||||
import { useQuery } from 'react-query';
|
import { useQuery } from 'react-query';
|
||||||
import { formatUnits } from 'viem';
|
import { formatUnits } from 'viem';
|
||||||
|
|
||||||
import { CLIENT_NETWORK_CONFIGS, type DydxV4Network } from '@/constants/networks';
|
import { CLIENT_NETWORK_CONFIGS } from '@/constants/networks';
|
||||||
import { QUANTUM_MULTIPLIER } from '@/constants/numbers';
|
import { QUANTUM_MULTIPLIER } from '@/constants/numbers';
|
||||||
import { EthereumAddress } from '@/constants/wallets';
|
import { EthereumAddress } from '@/constants/wallets';
|
||||||
|
|
||||||
@@ -15,7 +15,6 @@ import { MustBigNumber } from '@/lib/numbers';
|
|||||||
import { getSelectedNetwork } from '@/state/appSelectors';
|
import { getSelectedNetwork } from '@/state/appSelectors';
|
||||||
|
|
||||||
import { useAccounts } from './useAccounts';
|
import { useAccounts } from './useAccounts';
|
||||||
// import { useDydxClient } from './useDydxClient';
|
|
||||||
import { usePollNativeTokenBalance } from './usePollNativeTokenBalance';
|
import { usePollNativeTokenBalance } from './usePollNativeTokenBalance';
|
||||||
|
|
||||||
type UseAccountBalanceProps = {
|
type UseAccountBalanceProps = {
|
||||||
@@ -49,10 +48,8 @@ export const useAccountBalance = ({
|
|||||||
}: UseAccountBalanceProps = {}) => {
|
}: UseAccountBalanceProps = {}) => {
|
||||||
const { evmAddress, dydxAddress } = useAccounts();
|
const { evmAddress, dydxAddress } = useAccounts();
|
||||||
|
|
||||||
// TODO: let Abacus / useDydxClient handle EVM chain IDs
|
|
||||||
// const { networkConfig } = useDydxClient();
|
|
||||||
const selectedNetwork = useSelector(getSelectedNetwork);
|
const selectedNetwork = useSelector(getSelectedNetwork);
|
||||||
const evmChainId = Number(CLIENT_NETWORK_CONFIGS[selectedNetwork as DydxV4Network].ethereumChainId);
|
const evmChainId = Number(CLIENT_NETWORK_CONFIGS[selectedNetwork].ethereumChainId);
|
||||||
|
|
||||||
const evmQuery = useBalance({
|
const evmQuery = useBalance({
|
||||||
enabled: Boolean(!isCosmosChain && addressOrDenom?.startsWith('0x')),
|
enabled: Boolean(!isCosmosChain && addressOrDenom?.startsWith('0x')),
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { useCallback, useContext, createContext, useEffect, useState, useMemo }
|
|||||||
|
|
||||||
import { useDispatch } from 'react-redux';
|
import { useDispatch } from 'react-redux';
|
||||||
import { AES, enc } from 'crypto-js';
|
import { AES, enc } from 'crypto-js';
|
||||||
import { LocalWallet, USDC_DENOM, type Subaccount } from '@dydxprotocol/v4-client';
|
import { LocalWallet, USDC_DENOM, type Subaccount } from '@dydxprotocol/v4-client-js';
|
||||||
|
|
||||||
import { OnboardingGuard, OnboardingState, type EvmDerivedAddresses } from '@/constants/account';
|
import { OnboardingGuard, OnboardingState, type EvmDerivedAddresses } from '@/constants/account';
|
||||||
import { LocalStorageKey, LOCAL_STORAGE_VERSIONS } from '@/constants/localStorage';
|
import { LocalStorageKey, LOCAL_STORAGE_VERSIONS } from '@/constants/localStorage';
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ export const useCurrentMarketId = () => {
|
|||||||
|
|
||||||
const validId = useMemo(() => {
|
const validId = useMemo(() => {
|
||||||
if (marketIds.length === 0) return marketId ?? lastViewedMarket;
|
if (marketIds.length === 0) return marketId ?? lastViewedMarket;
|
||||||
if (!marketIds.includes(marketId)) return DEFAULT_MARKETID;
|
if (!marketIds.includes(marketId ?? lastViewedMarket)) return DEFAULT_MARKETID;
|
||||||
return marketId ?? lastViewedMarket;
|
return marketId ?? lastViewedMarket;
|
||||||
}, [marketIds, marketId]);
|
}, [marketIds, marketId]);
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { DydxV4Network } from '@/constants/networks';
|
import { isDydxV4Network } from '@/constants/networks';
|
||||||
import { WalletType } from '@/constants/wallets';
|
import { WalletType } from '@/constants/wallets';
|
||||||
|
|
||||||
import { isTruthy } from '@/lib/isTruthy';
|
import { isTruthy } from '@/lib/isTruthy';
|
||||||
@@ -11,9 +11,7 @@ export const useDisplayedWallets = () => {
|
|||||||
return [
|
return [
|
||||||
WalletType.MetaMask,
|
WalletType.MetaMask,
|
||||||
|
|
||||||
import.meta.env.MODE !== 'production' &&
|
import.meta.env.MODE !== 'production' && isDydxV4Network(selectedNetwork) && WalletType.Keplr,
|
||||||
[DydxV4Network.V4Testnet2, DydxV4Network.V4Staging].includes(selectedNetwork) &&
|
|
||||||
WalletType.Keplr,
|
|
||||||
|
|
||||||
WalletType.WalletConnect2,
|
WalletType.WalletConnect2,
|
||||||
WalletType.WalletConnect,
|
WalletType.WalletConnect,
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import {
|
|||||||
onboarding,
|
onboarding,
|
||||||
Network,
|
Network,
|
||||||
ValidatorConfig,
|
ValidatorConfig,
|
||||||
} from '@dydxprotocol/v4-client';
|
} from '@dydxprotocol/v4-client-js';
|
||||||
|
|
||||||
import type { ResolutionString } from 'public/tradingview/charting_library';
|
import type { ResolutionString } from 'public/tradingview/charting_library';
|
||||||
|
|
||||||
|
|||||||
@@ -3,11 +3,7 @@ import { useDispatch } from 'react-redux';
|
|||||||
|
|
||||||
import { LocalStorageKey } from '@/constants/localStorage';
|
import { LocalStorageKey } from '@/constants/localStorage';
|
||||||
|
|
||||||
import {
|
import { DEFAULT_APP_ENVIRONMENT, DydxNetwork, isValidDydxNetwork } from '@/constants/networks';
|
||||||
DEFAULT_APP_ENVIRONMENT,
|
|
||||||
DydxNetwork,
|
|
||||||
isValidDydxNetwork,
|
|
||||||
} from '@/constants/networks';
|
|
||||||
|
|
||||||
import { useLocalStorage } from '@/hooks';
|
import { useLocalStorage } from '@/hooks';
|
||||||
|
|
||||||
|
|||||||
@@ -1,95 +0,0 @@
|
|||||||
import { createContext, useContext, useCallback, useEffect, useMemo } from 'react';
|
|
||||||
import { useQuery } from 'react-query';
|
|
||||||
|
|
||||||
import { LocalStorageKey } from '@/constants/localStorage';
|
|
||||||
import { type TransferNotifcation } from '@/constants/notifications';
|
|
||||||
|
|
||||||
import { useAccounts } from '@/hooks/useAccounts';
|
|
||||||
import { useSquid } from '@/hooks/useSquid';
|
|
||||||
import { useLocalStorage } from './useLocalStorage';
|
|
||||||
|
|
||||||
import { StatusResponse } from '@0xsquid/sdk';
|
|
||||||
|
|
||||||
const LocalNotificationsContext = createContext<
|
|
||||||
ReturnType<typeof useLocalNotificationsContext> | undefined
|
|
||||||
>(undefined);
|
|
||||||
|
|
||||||
LocalNotificationsContext.displayName = 'LocalNotifications';
|
|
||||||
|
|
||||||
export const LocalNotificationsProvider = ({ ...props }) => (
|
|
||||||
<LocalNotificationsContext.Provider value={useLocalNotificationsContext()} {...props} />
|
|
||||||
);
|
|
||||||
|
|
||||||
export const useLocalNotifications = () => useContext(LocalNotificationsContext)!;
|
|
||||||
|
|
||||||
const TRANSFER_STATUS_FETCH_INTERVAL = 10_000;
|
|
||||||
|
|
||||||
const useLocalNotificationsContext = () => {
|
|
||||||
// transfer notifications
|
|
||||||
const [allTransferNotifications, setAllTransferNotifications] = useLocalStorage<{
|
|
||||||
[key: `dydx${string}`]: TransferNotifcation[];
|
|
||||||
}>({
|
|
||||||
key: LocalStorageKey.TransferNotifications,
|
|
||||||
defaultValue: {},
|
|
||||||
});
|
|
||||||
|
|
||||||
const { dydxAddress } = useAccounts();
|
|
||||||
|
|
||||||
const transferNotifications = dydxAddress ? allTransferNotifications[dydxAddress] || [] : [];
|
|
||||||
|
|
||||||
const setTransferNotifications = useCallback(
|
|
||||||
(notifications: TransferNotifcation[]) => {
|
|
||||||
if (!dydxAddress) return;
|
|
||||||
const updatedNotifications = { ...allTransferNotifications };
|
|
||||||
updatedNotifications[dydxAddress] = notifications;
|
|
||||||
setAllTransferNotifications(updatedNotifications);
|
|
||||||
},
|
|
||||||
[setAllTransferNotifications, dydxAddress]
|
|
||||||
);
|
|
||||||
|
|
||||||
const addTransferNotification = useCallback(
|
|
||||||
(notification: TransferNotifcation) =>
|
|
||||||
setTransferNotifications([...transferNotifications, notification]),
|
|
||||||
[transferNotifications]
|
|
||||||
);
|
|
||||||
|
|
||||||
const squid = useSquid();
|
|
||||||
|
|
||||||
const { data: transferStatuses } = useQuery({
|
|
||||||
queryKey: ['getTransactionStatus', transferNotifications],
|
|
||||||
queryFn: async () => {
|
|
||||||
const statuses: { [key: string]: StatusResponse } = {};
|
|
||||||
for (const {
|
|
||||||
txHash,
|
|
||||||
toChainId,
|
|
||||||
fromChainId,
|
|
||||||
status: currentStatus,
|
|
||||||
} of transferNotifications) {
|
|
||||||
if (currentStatus && currentStatus?.squidTransactionStatus !== 'ongoing') continue;
|
|
||||||
|
|
||||||
const status = await squid?.getStatus({ transactionId: txHash, toChainId, fromChainId });
|
|
||||||
if (status) statuses[txHash] = status;
|
|
||||||
}
|
|
||||||
return statuses;
|
|
||||||
},
|
|
||||||
refetchInterval: TRANSFER_STATUS_FETCH_INTERVAL,
|
|
||||||
});
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (!transferStatuses) return;
|
|
||||||
const newTransferNotifications = transferNotifications.map((notification) => {
|
|
||||||
const status = transferStatuses[notification.txHash];
|
|
||||||
if (!status) return notification;
|
|
||||||
return {
|
|
||||||
...notification,
|
|
||||||
status,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
setTransferNotifications(newTransferNotifications);
|
|
||||||
}, [transferStatuses]);
|
|
||||||
|
|
||||||
return {
|
|
||||||
transferNotifications,
|
|
||||||
addTransferNotification,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import { useCallback, useEffect, useMemo } from 'react';
|
import { useEffect, useMemo } from 'react';
|
||||||
import { useSelector, shallowEqual, useDispatch } from 'react-redux';
|
import { useSelector, shallowEqual, useDispatch } from 'react-redux';
|
||||||
import { groupBy } from 'lodash';
|
import { groupBy } from 'lodash';
|
||||||
|
|
||||||
@@ -8,20 +8,12 @@ import { STRING_KEYS } from '@/constants/localization';
|
|||||||
import { type NotificationTypeConfig, NotificationType } from '@/constants/notifications';
|
import { type NotificationTypeConfig, NotificationType } from '@/constants/notifications';
|
||||||
import { ORDER_SIDE_STRINGS, TRADE_TYPE_STRINGS, TradeTypes } from '@/constants/trade';
|
import { ORDER_SIDE_STRINGS, TRADE_TYPE_STRINGS, TradeTypes } from '@/constants/trade';
|
||||||
|
|
||||||
import { useLocalNotifications } from '@/hooks/useLocalNotifications';
|
|
||||||
|
|
||||||
import { Icon, IconName } from '@/components/Icon';
|
|
||||||
import { Output, OutputType } from '@/components/Output';
|
|
||||||
import { TransferStatusToast } from '@/views/TransferStatus';
|
|
||||||
|
|
||||||
import { getSubaccountFills, getSubaccountOrders } from '@/state/accountSelectors';
|
import { getSubaccountFills, getSubaccountOrders } from '@/state/accountSelectors';
|
||||||
import { openDialog } from '@/state/dialogs';
|
import { openDialog } from '@/state/dialogs';
|
||||||
|
|
||||||
import { OrderStatusIcon } from '@/views/OrderStatusIcon';
|
import { OrderStatusIcon } from '@/views/OrderStatusIcon';
|
||||||
|
|
||||||
import { useStringGetter } from './useStringGetter';
|
import { useStringGetter } from './useStringGetter';
|
||||||
import { TransferStatusSteps } from '@/views/TransferStatusSteps';
|
|
||||||
import { TESTNET_CHAIN_ID } from '@dydxprotocol/v4-client';
|
|
||||||
|
|
||||||
export const notificationTypes = [
|
export const notificationTypes = [
|
||||||
{
|
{
|
||||||
@@ -101,51 +93,4 @@ export const notificationTypes = [
|
|||||||
};
|
};
|
||||||
},
|
},
|
||||||
} as NotificationTypeConfig<string, [string, number]>,
|
} as NotificationTypeConfig<string, [string, number]>,
|
||||||
{
|
|
||||||
type: NotificationType.SquidTransfer,
|
|
||||||
useTrigger: ({ trigger }) => {
|
|
||||||
const stringGetter = useStringGetter();
|
|
||||||
const { transferNotifications } = useLocalNotifications();
|
|
||||||
|
|
||||||
const getTitleStringKey = useCallback((type: 'deposit' | 'withdraw', finished: boolean) => {
|
|
||||||
if (type === 'deposit' && !finished) return STRING_KEYS.DEPOSIT_IN_PROGRESS;
|
|
||||||
if (type === 'deposit' && finished) return STRING_KEYS.DEPOSIT;
|
|
||||||
if (type === 'withdraw' && !finished) return STRING_KEYS.WITHDRAW_IN_PROGRESS;
|
|
||||||
return STRING_KEYS.WITHDRAW;
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
for (const transfer of transferNotifications) {
|
|
||||||
const { toChainId, status, txHash, toAmount } = transfer;
|
|
||||||
const finished = Boolean(status) && status?.squidTransactionStatus !== 'ongoing';
|
|
||||||
const type = toChainId === TESTNET_CHAIN_ID ? 'deposit' : 'withdraw';
|
|
||||||
|
|
||||||
trigger(
|
|
||||||
txHash,
|
|
||||||
{
|
|
||||||
icon: <Icon iconName={finished ? IconName.Transfer : IconName.Clock} />,
|
|
||||||
title: stringGetter({ key: getTitleStringKey(type, finished) }),
|
|
||||||
// TODO: confirm with design what the description should be
|
|
||||||
description: (
|
|
||||||
<>
|
|
||||||
<span>{type === 'deposit' ? 'Deposit of ' : 'Withdraw of'}</span>
|
|
||||||
<Output type={OutputType.Fiat} value={toAmount} />
|
|
||||||
</>
|
|
||||||
),
|
|
||||||
customContent: (
|
|
||||||
<TransferStatusToast
|
|
||||||
toAmount={transfer.toAmount}
|
|
||||||
triggeredAt={transfer.triggeredAt}
|
|
||||||
status={transfer.status}
|
|
||||||
/>
|
|
||||||
),
|
|
||||||
customMenuContent: !finished && <TransferStatusSteps status={transfer.status} />,
|
|
||||||
toastSensitivity: 'foreground',
|
|
||||||
},
|
|
||||||
[]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}, [transferNotifications]);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
] satisfies NotificationTypeConfig[];
|
] satisfies NotificationTypeConfig[];
|
||||||
|
|||||||
@@ -106,10 +106,7 @@ const useNotificationsContext = () => {
|
|||||||
updateKey,
|
updateKey,
|
||||||
} as Notification);
|
} as Notification);
|
||||||
|
|
||||||
updateStatus(
|
updateStatus(notification, isNew ? NotificationStatus.Triggered : NotificationStatus.Cleared);
|
||||||
notification,
|
|
||||||
isNew ? NotificationStatus.Triggered : NotificationStatus.Cleared
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// updateKey changed - update existing notification
|
// updateKey changed - update existing notification
|
||||||
@@ -144,9 +141,7 @@ const useNotificationsContext = () => {
|
|||||||
// Push notifications
|
// Push notifications
|
||||||
const [hasEnabledPush, setHasEnabledPush] = useLocalStorage({
|
const [hasEnabledPush, setHasEnabledPush] = useLocalStorage({
|
||||||
key: LocalStorageKey.PushNotificationsEnabled,
|
key: LocalStorageKey.PushNotificationsEnabled,
|
||||||
defaultValue: Boolean(
|
defaultValue: Boolean(globalThis.Notification && globalThis.Notification.permission === 'granted'),
|
||||||
globalThis.Notification && globalThis.Notification.permission === 'granted'
|
|
||||||
),
|
|
||||||
});
|
});
|
||||||
const [isEnablingPush, setIsEnablingPush] = useState(false);
|
const [isEnablingPush, setIsEnablingPush] = useState(false);
|
||||||
|
|
||||||
@@ -241,3 +236,4 @@ const useNotificationsContext = () => {
|
|||||||
setIsMenuOpen,
|
setIsMenuOpen,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
// }
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { useQuery } from 'react-query';
|
|||||||
import { useAccounts } from '@/hooks';
|
import { useAccounts } from '@/hooks';
|
||||||
|
|
||||||
import { DydxAddress } from '@/constants/wallets';
|
import { DydxAddress } from '@/constants/wallets';
|
||||||
import { DYDX_DENOM } from '@dydxprotocol/v4-client';
|
import { DYDX_DENOM } from '@dydxprotocol/v4-client-js';
|
||||||
|
|
||||||
const ACCOUNT_BALANCE_POLLING_INTERVAL = 60_000;
|
const ACCOUNT_BALANCE_POLLING_INTERVAL = 60_000;
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import { useCallback, useEffect } from 'react';
|
import { useCallback } from 'react';
|
||||||
import { useDispatch, useSelector } from 'react-redux';
|
import { useDispatch, useSelector } from 'react-redux';
|
||||||
|
|
||||||
import { LocalStorageKey } from '@/constants/localStorage';
|
import { LocalStorageKey } from '@/constants/localStorage';
|
||||||
import { DEFAULT_APP_ENVIRONMENT, DydxNetwork, DydxV4Network } from '@/constants/networks';
|
import { DEFAULT_APP_ENVIRONMENT, DydxNetwork } from '@/constants/networks';
|
||||||
|
|
||||||
import { useAccounts, useLocalStorage } from '@/hooks';
|
import { useAccounts, useLocalStorage } from '@/hooks';
|
||||||
|
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ import {
|
|||||||
DYDX_DENOM,
|
DYDX_DENOM,
|
||||||
USDC_DENOM,
|
USDC_DENOM,
|
||||||
GAS_PRICE_DYDX_DENOM,
|
GAS_PRICE_DYDX_DENOM,
|
||||||
} from '@dydxprotocol/v4-client';
|
} from '@dydxprotocol/v4-client-js';
|
||||||
|
|
||||||
import type {
|
import type {
|
||||||
HumanReadableCancelOrderPayload,
|
HumanReadableCancelOrderPayload,
|
||||||
|
|||||||
@@ -41,7 +41,6 @@ export const NotificationsToastArea = ({ className }: StyleProps) => {
|
|||||||
slotIcon={displayData.icon}
|
slotIcon={displayData.icon}
|
||||||
slotTitle={displayData.title}
|
slotTitle={displayData.title}
|
||||||
slotDescription={displayData.description}
|
slotDescription={displayData.description}
|
||||||
slotCustomContent={displayData.customContent}
|
|
||||||
slotAction={
|
slotAction={
|
||||||
<Button size={ButtonSize.Small} onClick={() => onNotificationAction(notification)}>
|
<Button size={ButtonSize.Small} onClick={() => onNotificationAction(notification)}>
|
||||||
{displayData.actionDescription}
|
{displayData.actionDescription}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { OrderSide } from '@dydxprotocol/v4-client';
|
import { OrderSide } from '@dydxprotocol/v4-client-js';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
AbacusOrderSide,
|
AbacusOrderSide,
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import {
|
|||||||
Network,
|
Network,
|
||||||
NetworkOptimizer,
|
NetworkOptimizer,
|
||||||
ValidatorConfig,
|
ValidatorConfig,
|
||||||
} from '@dydxprotocol/v4-client';
|
} from '@dydxprotocol/v4-client-js';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
type AbacusDydxChainQueriesProtocol,
|
type AbacusDydxChainQueriesProtocol,
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
import type { AbacusFileSystemProtocol, FileLocation, Nullable } from '@/constants/abacus';
|
||||||
|
import { NETWORK_ENDPOINTS } from '@/constants/networks';
|
||||||
|
|
||||||
|
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> {
|
||||||
|
if (path === ENDPOINTS_PATH) {
|
||||||
|
return JSON.stringify(NETWORK_ENDPOINTS);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
writeTextFile(path: string, text: string): boolean {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default AbacusFileSystem;
|
||||||
@@ -36,8 +36,8 @@ import AbacusStateNotifier from './stateNotification';
|
|||||||
import AbacusLocalizer from './localizer';
|
import AbacusLocalizer from './localizer';
|
||||||
import AbacusFormatter from './formatter';
|
import AbacusFormatter from './formatter';
|
||||||
import AbacusThreading from './threading';
|
import AbacusThreading from './threading';
|
||||||
|
import AbacusFileSystem, { ENDPOINTS_PATH } from './filesystem';
|
||||||
import { LocaleSeparators } from '../numbers';
|
import { LocaleSeparators } from '../numbers';
|
||||||
|
|
||||||
class AbacusStateManager {
|
class AbacusStateManager {
|
||||||
private store: RootStore | undefined;
|
private store: RootStore | undefined;
|
||||||
private currentMarket: string | undefined;
|
private currentMarket: string | undefined;
|
||||||
@@ -62,7 +62,7 @@ class AbacusStateManager {
|
|||||||
null,
|
null,
|
||||||
new AbacusThreading(),
|
new AbacusThreading(),
|
||||||
new CoroutineTimer(),
|
new CoroutineTimer(),
|
||||||
null
|
new AbacusFileSystem()
|
||||||
);
|
);
|
||||||
|
|
||||||
const uiImplementations = new UIImplementations(
|
const uiImplementations = new UIImplementations(
|
||||||
@@ -72,6 +72,8 @@ class AbacusStateManager {
|
|||||||
);
|
);
|
||||||
|
|
||||||
this.stateManager = new AsyncAbacusStateManager(
|
this.stateManager = new AsyncAbacusStateManager(
|
||||||
|
import.meta.env.SHARED_RESOURCES_URI,
|
||||||
|
ENDPOINTS_PATH,
|
||||||
ioImplementations,
|
ioImplementations,
|
||||||
uiImplementations,
|
uiImplementations,
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
|
import { kollections } from '@dydxprotocol/abacus';
|
||||||
|
|
||||||
import type {
|
import type {
|
||||||
AbacusApiState,
|
AbacusApiState,
|
||||||
|
AbacusNotification,
|
||||||
AbacusStateNotificationProtocol,
|
AbacusStateNotificationProtocol,
|
||||||
Asset,
|
Asset,
|
||||||
Nullable,
|
Nullable,
|
||||||
@@ -36,6 +39,14 @@ class AbacusStateNotifier implements AbacusStateNotificationProtocol {
|
|||||||
this.store = undefined;
|
this.store = undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
environmentsChanged(): void {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
notificationsChanged(notifications: kollections.List<AbacusNotification>): void {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
stateChanged(
|
stateChanged(
|
||||||
updatedState: Nullable<PerpetualState>,
|
updatedState: Nullable<PerpetualState>,
|
||||||
incomingChanges: Nullable<PerpetualStateChanges>
|
incomingChanges: Nullable<PerpetualStateChanges>
|
||||||
|
|||||||
@@ -72,9 +72,3 @@ export const getTimeTillNextUnit = (unit: 'minute' | 'hour' | 'day') => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const getTimeString = (time: number) => time.toString().padStart(2, '0');
|
export const getTimeString = (time: number) => time.toString().padStart(2, '0');
|
||||||
|
|
||||||
export const formatSeconds = (seconds: number) => {
|
|
||||||
const minutes = Math.floor(seconds / 60);
|
|
||||||
const remainingSeconds = seconds % 60;
|
|
||||||
return `${getTimeString(minutes)}:${getTimeString(remainingSeconds)}`;
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { type Location, matchPath } from 'react-router-dom';
|
import { type Location, matchPath } from 'react-router-dom';
|
||||||
import { OrderSide } from '@dydxprotocol/v4-client';
|
import { OrderSide } from '@dydxprotocol/v4-client-js';
|
||||||
|
|
||||||
import { StringGetterFunction } from '@/constants/localization';
|
import { StringGetterFunction } from '@/constants/localization';
|
||||||
|
|
||||||
|
|||||||
@@ -113,7 +113,6 @@
|
|||||||
"HEDGIES": "Hedgies",
|
"HEDGIES": "Hedgies",
|
||||||
"HIDE_SECTION": "Hide section",
|
"HIDE_SECTION": "Hide section",
|
||||||
"HIDE": "Hide",
|
"HIDE": "Hide",
|
||||||
"HIDE_DETAILS": "Hide details",
|
|
||||||
"HISTORY": "History",
|
"HISTORY": "History",
|
||||||
"INCREASED": "increased",
|
"INCREASED": "increased",
|
||||||
"INCREASING": "Increasing",
|
"INCREASING": "Increasing",
|
||||||
@@ -389,7 +388,6 @@
|
|||||||
"CONNECTING_SUBTITLE": "Check your wallet for a connection request. Connecting to dYdX is free and does not affect your funds.",
|
"CONNECTING_SUBTITLE": "Check your wallet for a connection request. Connecting to dYdX is free and does not affect your funds.",
|
||||||
"COULD_NOT_FIND_AFFILIATE": "We couldn't find this affiliate, please check the link.",
|
"COULD_NOT_FIND_AFFILIATE": "We couldn't find this affiliate, please check the link.",
|
||||||
"CREATE_OR_VERIFY_COSMOS_ADDRESS": "Create or verify Cosmos address.",
|
"CREATE_OR_VERIFY_COSMOS_ADDRESS": "Create or verify Cosmos address.",
|
||||||
"DEPOSIT_STATUS": "Your deposit of {AMOUNT_USD} will be available in approximately {ESTIMATED_DURATION}.",
|
|
||||||
"DONT_MISS": "Don't miss your chance to get a {DISCOUNT} on trading fees!",
|
"DONT_MISS": "Don't miss your chance to get a {DISCOUNT} on trading fees!",
|
||||||
"ENABLE_API": "Enable secure access to our API for lightning quick trading",
|
"ENABLE_API": "Enable secure access to our API for lightning quick trading",
|
||||||
"ENABLE_TRADING": "Enable trading",
|
"ENABLE_TRADING": "Enable trading",
|
||||||
@@ -452,7 +450,6 @@
|
|||||||
"VERIFY_WALLET_COMPATIBILITY": "Verify wallet compatibility",
|
"VERIFY_WALLET_COMPATIBILITY": "Verify wallet compatibility",
|
||||||
"WELCOME_DYDX": "Welcome to dYdX",
|
"WELCOME_DYDX": "Welcome to dYdX",
|
||||||
"WELCOME": "Welcome",
|
"WELCOME": "Welcome",
|
||||||
"WITHDRAW_STATUS": "Your withdrawal of {AMOUNT_USD} will be available in approximately {ESTIMATED_DURATION}.",
|
|
||||||
"WRONG_NETWORK_EXPLANATION_PRODUCTION": "To complete dYdX onboarding, set your wallet network to 'Ethereum Mainnet'.",
|
"WRONG_NETWORK_EXPLANATION_PRODUCTION": "To complete dYdX onboarding, set your wallet network to 'Ethereum Mainnet'.",
|
||||||
"WRONG_NETWORK_EXPLANATION_STAGING": "To complete dYdX onboarding, set your wallet network to 'Goerli Test Network'.",
|
"WRONG_NETWORK_EXPLANATION_STAGING": "To complete dYdX onboarding, set your wallet network to 'Goerli Test Network'.",
|
||||||
"WRONG_NETWORK": "Wrong network",
|
"WRONG_NETWORK": "Wrong network",
|
||||||
@@ -918,15 +915,13 @@
|
|||||||
"66_REDUCTION": "66% reduction",
|
"66_REDUCTION": "66% reduction",
|
||||||
"ADJUSTED_IMR": "Adjusted Margin",
|
"ADJUSTED_IMR": "Adjusted Margin",
|
||||||
"ADJUSTED_IMR_BODY": "We have temporarily {ACTION} the Initial Margin Requirements on {MARKET} to {PERCENT} due to volatility. {ADDITIONAL_NOTE}",
|
"ADJUSTED_IMR_BODY": "We have temporarily {ACTION} the Initial Margin Requirements on {MARKET} to {PERCENT} due to volatility. {ADDITIONAL_NOTE}",
|
||||||
"BRIDGING_TOKENS": "Bridging tokens",
|
|
||||||
"CLOSE_MARKET_POSITIONS": "Close your {MARKET} position",
|
"CLOSE_MARKET_POSITIONS": "Close your {MARKET} position",
|
||||||
"CLOSE_MARKET_POSITIONS_BODY": "{MARKET} is set to close only mode and the close price of {MARKET} is now fixed. Please close your open {MARKET} position as soon as you are able. We're here to help via the help chat if you run into issues.",
|
"CLOSE_MARKET_POSITIONS_BODY": "{MARKET} is set to close only mode and the close price of {MARKET} is now fixed. Please close your open {MARKET} position as soon as you are able. We're here to help via the help chat if you run into issues.",
|
||||||
"COMPLIANCE_ALERT": "Compliance alert",
|
"COMPLIANCE_ALERT": "Compliance alert",
|
||||||
"DEPOSIT_IN_PROGRESS_DESCRIPTION": "Your deposit of {AMOUNT_ELEMENT} will be available after 14 confirmations.",
|
"DEPOSIT_IN_PROGRESS_DESCRIPTION": "Your deposit of {AMOUNT_ELEMENT} will be available after 14 confirmations.",
|
||||||
"DEPOSIT_IN_PROGRESS": "Deposit in progress...",
|
"DEPOSIT_IN_PROGRESS": "Deposit in progress",
|
||||||
"DEPOSIT_SUCCESS_DESCRIPTION": "Your deposit of {AMOUNT_ELEMENT} has been confirmed and is now available for trading.",
|
"DEPOSIT_SUCCESS_DESCRIPTION": "Your deposit of {AMOUNT_ELEMENT} has been confirmed and is now available for trading.",
|
||||||
"DEPOSIT_SUCCESS": "Deposit success!",
|
"DEPOSIT_SUCCESS": "Deposit success!",
|
||||||
"DEPOSIT_TO_CHAIN": "Deposit to {CHAIN}",
|
|
||||||
"DIRECT_TRANSFER_SUCCESS": "Direct transfer success!",
|
"DIRECT_TRANSFER_SUCCESS": "Direct transfer success!",
|
||||||
"DIRECT_TRANSFER_SUCCESS_DESCRIPTION": "Your direct transfer of {AMOUNT_ELEMENT} has been confirmed.",
|
"DIRECT_TRANSFER_SUCCESS_DESCRIPTION": "Your direct transfer of {AMOUNT_ELEMENT} has been confirmed.",
|
||||||
"EPOCH_REWARDS": "Epoch {EPOCH_NUMBER} Rewards",
|
"EPOCH_REWARDS": "Epoch {EPOCH_NUMBER} Rewards",
|
||||||
@@ -935,8 +930,6 @@
|
|||||||
"FAST_WITHDRAW_PENDING": "Fast withdraw pending",
|
"FAST_WITHDRAW_PENDING": "Fast withdraw pending",
|
||||||
"FAST_WITHDRAW_SUCCESS_DESCRIPTION": "Your fast withdraw of {AMOUNT_ELEMENT} has been confirmed.",
|
"FAST_WITHDRAW_SUCCESS_DESCRIPTION": "Your fast withdraw of {AMOUNT_ELEMENT} has been confirmed.",
|
||||||
"FAST_WITHDRAW_SUCCESS": "Fast withdraw success!",
|
"FAST_WITHDRAW_SUCCESS": "Fast withdraw success!",
|
||||||
"INITIATED_DEPOSIT": "Initiated deposit",
|
|
||||||
"INITIATED_WITHDRAWAL": "Initiated withdrawal",
|
|
||||||
"LEGAL_UPDATES": "Legal updates",
|
"LEGAL_UPDATES": "Legal updates",
|
||||||
"LEGAL_UPDATES_DESCRIPTION": "Please check out our updated {TOU} and {PRIVACY_POLICY}.",
|
"LEGAL_UPDATES_DESCRIPTION": "Please check out our updated {TOU} and {PRIVACY_POLICY}.",
|
||||||
"MAINTENANCE_MARGIN_ADJUSTMENTS": "Maintenance margin requirements {ACTION} at {PERCENT}%.",
|
"MAINTENANCE_MARGIN_ADJUSTMENTS": "Maintenance margin requirements {ACTION} at {PERCENT}%.",
|
||||||
@@ -953,8 +946,7 @@
|
|||||||
"SLOW_WITHDRAW_PENDING": "Slow withdraw(s) pending",
|
"SLOW_WITHDRAW_PENDING": "Slow withdraw(s) pending",
|
||||||
"SUSPICIOUS_TRADE": "Suspicious activity",
|
"SUSPICIOUS_TRADE": "Suspicious activity",
|
||||||
"SUSPICIOUS_TRADE_BODY": "We have noticed suspicious trading activity related to your account on dYdX, including potential wash trading activity. We will be reviewing your activity on an ongoing basis. If we notice similar activity in the future, then you will be permanently blocked from performing transfers within the protocol and from placing orders other than market orders that reduce your positions.",
|
"SUSPICIOUS_TRADE_BODY": "We have noticed suspicious trading activity related to your account on dYdX, including potential wash trading activity. We will be reviewing your activity on an ongoing basis. If we notice similar activity in the future, then you will be permanently blocked from performing transfers within the protocol and from placing orders other than market orders that reduce your positions.",
|
||||||
"WITHDRAW_IN_PROGRESS": "Withdrawal(s) in progress...",
|
"WITHDRAW_IN_PROGRESS": "Withdrawal(s) in progress"
|
||||||
"WITHDRAW_TO_CHAIN": "Withdraw to {CHAIN}"
|
|
||||||
},
|
},
|
||||||
"EMAIL_NOTIFICATIONS": {
|
"EMAIL_NOTIFICATIONS": {
|
||||||
"ACCOUNT_DESCRIPTION": "Deposits, Withdrawals, Account Updates",
|
"ACCOUNT_DESCRIPTION": "Deposits, Withdrawals, Account Updates",
|
||||||
@@ -1217,5 +1209,20 @@
|
|||||||
"NODE_DOWN": "Node cannot be reached.",
|
"NODE_DOWN": "Node cannot be reached.",
|
||||||
"NODE_HALTED": "Node has halted on block {BLOCK_NUMBER}.",
|
"NODE_HALTED": "Node has halted on block {BLOCK_NUMBER}.",
|
||||||
"UNKNOWN_API_ERROR": "Unknown API error"
|
"UNKNOWN_API_ERROR": "Unknown API error"
|
||||||
|
},
|
||||||
|
"CHAIN": {
|
||||||
|
"V3_MAINNET": "V3 Mainnet",
|
||||||
|
"V3_GOERLI": "V3 Staging",
|
||||||
|
"V4_DEVNET": "V4 Dev 1",
|
||||||
|
"V4_DEVNET_2": "V4 Dev 2",
|
||||||
|
"V4_DEVNET_3": "V4 Dev 3",
|
||||||
|
"V4_DEVNET_4": "V4 Dev 4",
|
||||||
|
"V4_DEVNET_5": "V4 Dev 5",
|
||||||
|
"V4_STAGING": "V4 Staging",
|
||||||
|
"V4_TESTNET2": "V4 Testnet",
|
||||||
|
"V4_TESTNET2_DSRV": "V4 Testnet (DSRV)",
|
||||||
|
"V4_TESTNET2_DYDX": "V4 Testnet (dYdX)",
|
||||||
|
"V4_TESTNET2_NODEFLEET": "V4 Testnet (nodefleet)",
|
||||||
|
"V4_TESTNET2_IMPERATOR": "V4 Testnet (Imperator)"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { createSelector } from 'reselect';
|
import { createSelector } from 'reselect';
|
||||||
|
|
||||||
import { SubaccountPosition } from '@/constants/abacus';
|
import { SubaccountPosition } from '@/constants/abacus';
|
||||||
import { OnboardingGuard, OnboardingState, OnboardingSteps } from '@/constants/account';
|
import { OnboardingState, OnboardingSteps } from '@/constants/account';
|
||||||
import { isDydxV4Network } from '@/constants/networks';
|
import { isDydxV4Network } from '@/constants/networks';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { OrderSide } from '@dydxprotocol/v4-client';
|
import { OrderSide } from '@dydxprotocol/v4-client-js';
|
||||||
import { createSelector } from 'reselect';
|
import { createSelector } from 'reselect';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { useState, useCallback } from 'react';
|
import { useState, useCallback } from 'react';
|
||||||
import { useInterval } from '@/hooks';
|
import { useInterval } from '@/hooks';
|
||||||
|
|
||||||
import { getTimeTillNextUnit, formatSeconds } from '@/lib/timeUtils';
|
import { getTimeTillNextUnit, getTimeString } from '@/lib/timeUtils';
|
||||||
import { Output, OutputType } from '@/components/Output';
|
import { Output, OutputType } from '@/components/Output';
|
||||||
|
|
||||||
export const NextFundingTimer = () => {
|
export const NextFundingTimer = () => {
|
||||||
@@ -18,7 +18,7 @@ export const NextFundingTimer = () => {
|
|||||||
type={OutputType.Text}
|
type={OutputType.Text}
|
||||||
value={
|
value={
|
||||||
secondsLeft !== undefined
|
secondsLeft !== undefined
|
||||||
? formatSeconds(secondsLeft)
|
? `${getTimeString(Math.floor(secondsLeft / 60))}:${getTimeString(secondsLeft % 60)}`
|
||||||
: undefined
|
: undefined
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -1,156 +0,0 @@
|
|||||||
import { useCallback, useState, useMemo } from 'react';
|
|
||||||
import styled, { type AnyStyledComponent } from 'styled-components';
|
|
||||||
import { TESTNET_CHAIN_ID } from '@dydxprotocol/v4-client';
|
|
||||||
import { Root, Trigger, Content } from '@radix-ui/react-collapsible';
|
|
||||||
import { StatusResponse } from '@0xsquid/sdk';
|
|
||||||
|
|
||||||
import { useInterval, useStringGetter } from '@/hooks';
|
|
||||||
|
|
||||||
import { STRING_KEYS } from '@/constants/localization';
|
|
||||||
|
|
||||||
import { formatSeconds } from '@/lib/timeUtils';
|
|
||||||
|
|
||||||
import { Output, OutputType } from '@/components/Output';
|
|
||||||
import { WithReceipt } from '@/components/WithReceipt';
|
|
||||||
import { Icon, IconName } from '@/components/Icon';
|
|
||||||
import { TransferStatusSteps } from '@/views/TransferStatusSteps';
|
|
||||||
import { LoadingDots } from '@/components/Loading/LoadingDots';
|
|
||||||
|
|
||||||
import { layoutMixins } from '@/styles/layoutMixins';
|
|
||||||
|
|
||||||
type ElementProps = {
|
|
||||||
toAmount?: number;
|
|
||||||
triggeredAt?: number;
|
|
||||||
status?: StatusResponse;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const TransferStatusToast = ({
|
|
||||||
toAmount,
|
|
||||||
triggeredAt = Date.now(),
|
|
||||||
status,
|
|
||||||
}: ElementProps) => {
|
|
||||||
const stringGetter = useStringGetter();
|
|
||||||
const [open, setOpen] = useState<boolean>(false);
|
|
||||||
const [secondsLeft, setSecondsLeft] = useState<number | undefined>();
|
|
||||||
|
|
||||||
const type = useMemo(
|
|
||||||
() => (status?.toChain?.chainData.chainId === TESTNET_CHAIN_ID ? 'deposit' : 'withdrawal'),
|
|
||||||
[status]
|
|
||||||
);
|
|
||||||
|
|
||||||
const updateSecondsLeft = useCallback(() => {
|
|
||||||
const fromChainEta = (status?.fromChain?.chainData?.estimatedRouteDuration || 0) * 1000;
|
|
||||||
const toChainEta = (status?.toChain?.chainData?.estimatedRouteDuration || 0) * 1000;
|
|
||||||
setSecondsLeft(Math.floor((triggeredAt + fromChainEta + toChainEta - Date.now()) / 1000));
|
|
||||||
}, [status]);
|
|
||||||
|
|
||||||
useInterval({ callback: updateSecondsLeft });
|
|
||||||
|
|
||||||
if (!status) return <LoadingDots size={3} />;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Styled.Root open={open} onOpenChange={setOpen}>
|
|
||||||
<WithReceipt
|
|
||||||
hideReceipt={!open}
|
|
||||||
side="bottom"
|
|
||||||
slotReceipt={
|
|
||||||
<Styled.Receipt>
|
|
||||||
<TransferStatusSteps status={status} />
|
|
||||||
</Styled.Receipt>
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<Styled.BridgingStatus>
|
|
||||||
<Styled.Status>
|
|
||||||
{stringGetter({
|
|
||||||
key: type === 'deposit' ? STRING_KEYS.DEPOSIT_STATUS : STRING_KEYS.WITHDRAW_STATUS,
|
|
||||||
params: {
|
|
||||||
AMOUNT_USD: <Styled.InlineOutput type={OutputType.Fiat} value={toAmount} />,
|
|
||||||
ESTIMATED_DURATION: (
|
|
||||||
<Styled.InlineOutput
|
|
||||||
type={OutputType.Text}
|
|
||||||
value={formatSeconds(Math.max(secondsLeft || 0, 0))}
|
|
||||||
/>
|
|
||||||
),
|
|
||||||
},
|
|
||||||
})}
|
|
||||||
</Styled.Status>
|
|
||||||
<Styled.Trigger>
|
|
||||||
<Styled.TriggerIcon>
|
|
||||||
<Icon iconName={IconName.Caret} />
|
|
||||||
</Styled.TriggerIcon>
|
|
||||||
{stringGetter({ key: open ? STRING_KEYS.HIDE_DETAILS : STRING_KEYS.VIEW_DETAILS })}
|
|
||||||
</Styled.Trigger>
|
|
||||||
</Styled.BridgingStatus>
|
|
||||||
</WithReceipt>
|
|
||||||
</Styled.Root>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const Styled: Record<string, AnyStyledComponent> = {};
|
|
||||||
|
|
||||||
Styled.Root = styled(Root)`
|
|
||||||
margin: 0.5rem -1rem -1rem -1rem;
|
|
||||||
color: var(--color-text-0);
|
|
||||||
font: var(--font-small-book);
|
|
||||||
`;
|
|
||||||
|
|
||||||
Styled.Receipt = styled.div`
|
|
||||||
padding: 0 1rem;
|
|
||||||
`;
|
|
||||||
|
|
||||||
Styled.BridgingStatus = styled.div`
|
|
||||||
${layoutMixins.flexColumn};
|
|
||||||
background-color: var(--color-layer-3);
|
|
||||||
|
|
||||||
gap: 0.5rem;
|
|
||||||
padding: 0 1rem 1rem 1rem;
|
|
||||||
border-radius: 0.5rem;
|
|
||||||
`;
|
|
||||||
|
|
||||||
Styled.Status = styled.div`
|
|
||||||
color: var(--color-text-0);
|
|
||||||
|
|
||||||
font-size: 0.875rem;
|
|
||||||
`;
|
|
||||||
|
|
||||||
Styled.InlineOutput = styled(Output)`
|
|
||||||
display: inline-block;
|
|
||||||
|
|
||||||
color: var(--color-text-1);
|
|
||||||
`;
|
|
||||||
|
|
||||||
Styled.Content = styled(Content)`
|
|
||||||
${layoutMixins.flexColumn};
|
|
||||||
|
|
||||||
gap: 0.5rem;
|
|
||||||
padding: 1rem;
|
|
||||||
`;
|
|
||||||
|
|
||||||
Styled.Step = styled.div`
|
|
||||||
${layoutMixins.row};
|
|
||||||
|
|
||||||
gap: 0.5rem;
|
|
||||||
`;
|
|
||||||
|
|
||||||
Styled.Trigger = styled(Trigger)`
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 0.5em;
|
|
||||||
|
|
||||||
color: var(--color-accent);
|
|
||||||
user-select: none;
|
|
||||||
&:focus {
|
|
||||||
outline: none;
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
Styled.TriggerIcon = styled.span`
|
|
||||||
width: 0.75em;
|
|
||||||
|
|
||||||
display: inline-flex;
|
|
||||||
transition: transform 0.3s var(--ease-out-expo);
|
|
||||||
|
|
||||||
${Styled.Trigger}[data-state='open'] & {
|
|
||||||
rotate: -0.5turn;
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
@@ -1,178 +0,0 @@
|
|||||||
import { useMemo } from 'react';
|
|
||||||
import styled, { css, keyframes, type AnyStyledComponent } from 'styled-components';
|
|
||||||
import { StatusResponse } from '@0xsquid/sdk';
|
|
||||||
import { TESTNET_CHAIN_ID } from '@dydxprotocol/v4-client';
|
|
||||||
|
|
||||||
import { useStringGetter } from '@/hooks';
|
|
||||||
|
|
||||||
import { Link } from '@/components/Link';
|
|
||||||
import { Icon, IconName } from '@/components/Icon';
|
|
||||||
import { LoadingDots } from '@/components/Loading/LoadingDots';
|
|
||||||
import { LoadingSpinner } from '@/components/Loading/LoadingSpinner';
|
|
||||||
|
|
||||||
import { layoutMixins } from '@/styles/layoutMixins';
|
|
||||||
import { STRING_KEYS } from '@/constants/localization';
|
|
||||||
|
|
||||||
type ElementProps = {
|
|
||||||
status?: StatusResponse;
|
|
||||||
};
|
|
||||||
|
|
||||||
enum TransferStatusStep {
|
|
||||||
FromChain,
|
|
||||||
Bridge,
|
|
||||||
ToChain,
|
|
||||||
Complete,
|
|
||||||
}
|
|
||||||
|
|
||||||
export const TransferStatusSteps = ({ status }: ElementProps) => {
|
|
||||||
const stringGetter = useStringGetter();
|
|
||||||
|
|
||||||
const type = useMemo(
|
|
||||||
() => (status?.toChain?.chainData.chainId === TESTNET_CHAIN_ID ? 'deposit' : 'withdrawal'),
|
|
||||||
[status]
|
|
||||||
);
|
|
||||||
|
|
||||||
const currentStep = useMemo(() => {
|
|
||||||
const routeStatus = status?.routeStatus;
|
|
||||||
const fromChain = status?.fromChain?.chainData.chainId;
|
|
||||||
const toChain = status?.toChain?.chainData.chainId;
|
|
||||||
|
|
||||||
if (!routeStatus?.length) return TransferStatusStep.FromChain;
|
|
||||||
|
|
||||||
const currentStatus = routeStatus[routeStatus?.length - 1];
|
|
||||||
|
|
||||||
if (currentStatus.chainId === toChain) {
|
|
||||||
return currentStatus.status !== 'success'
|
|
||||||
? TransferStatusStep.ToChain
|
|
||||||
: TransferStatusStep.Complete;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (currentStatus.chainId === fromChain && currentStatus.status !== 'success') {
|
|
||||||
return TransferStatusStep.FromChain;
|
|
||||||
}
|
|
||||||
|
|
||||||
return TransferStatusStep.Bridge;
|
|
||||||
}, [status]);
|
|
||||||
|
|
||||||
const steps = useMemo(
|
|
||||||
() => [
|
|
||||||
{
|
|
||||||
label: stringGetter({
|
|
||||||
key: type === 'deposit' ? STRING_KEYS.INITIATED_DEPOSIT : STRING_KEYS.INITIATED_WITHDRAWAL,
|
|
||||||
}),
|
|
||||||
step: TransferStatusStep.FromChain,
|
|
||||||
link: status?.fromChain?.transactionUrl,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: stringGetter({ key: STRING_KEYS.BRIDGING_TOKENS }),
|
|
||||||
step: TransferStatusStep.Bridge,
|
|
||||||
link: status?.axelarTransactionUrl,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: stringGetter({
|
|
||||||
key: type === 'deposit' ? STRING_KEYS.DEPOSIT_TO_CHAIN : STRING_KEYS.WITHDRAW_TO_CHAIN,
|
|
||||||
params: {
|
|
||||||
CHAIN: status?.toChain?.chainData.chainName,
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
step: TransferStatusStep.ToChain,
|
|
||||||
link: status?.toChain?.transactionUrl,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
[status]
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!status) return <LoadingDots size={3} />;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Styled.BridgingStatus>
|
|
||||||
{steps.map((step) => (
|
|
||||||
<Styled.Step key={step.step}>
|
|
||||||
<Styled.row>
|
|
||||||
{step.step === currentStep ? (
|
|
||||||
<Styled.Icon>
|
|
||||||
<Styled.Spinner />
|
|
||||||
</Styled.Icon>
|
|
||||||
) : step.step < currentStep ? (
|
|
||||||
<Styled.Icon state="complete">
|
|
||||||
<Icon iconName={IconName.Check} />
|
|
||||||
</Styled.Icon>
|
|
||||||
) : (
|
|
||||||
<Styled.Icon state="default">{step.step + 1}</Styled.Icon>
|
|
||||||
)}
|
|
||||||
{step.link && currentStep >= step.step ? (
|
|
||||||
<Link href={step.link}>
|
|
||||||
<Styled.Label highlighted={currentStep >= step.step}>
|
|
||||||
{step.label}
|
|
||||||
<Icon iconName={IconName.LinkOut} />
|
|
||||||
</Styled.Label>
|
|
||||||
</Link>
|
|
||||||
) : (
|
|
||||||
<Styled.Label highlighted={currentStep >= step.step}>
|
|
||||||
{step.label}
|
|
||||||
</Styled.Label>
|
|
||||||
)}
|
|
||||||
</Styled.row>
|
|
||||||
</Styled.Step>
|
|
||||||
))}
|
|
||||||
</Styled.BridgingStatus>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const Styled: Record<string, AnyStyledComponent> = {};
|
|
||||||
|
|
||||||
Styled.BridgingStatus = styled.div`
|
|
||||||
${layoutMixins.flexColumn};
|
|
||||||
|
|
||||||
gap: 1rem;
|
|
||||||
padding: 1rem 0;
|
|
||||||
`;
|
|
||||||
|
|
||||||
Styled.Step = styled.div`
|
|
||||||
${layoutMixins.spacedRow};
|
|
||||||
`;
|
|
||||||
|
|
||||||
Styled.row = styled.div`
|
|
||||||
${layoutMixins.inlineRow};
|
|
||||||
gap: 0.5rem;
|
|
||||||
`;
|
|
||||||
|
|
||||||
Styled.Icon = styled.div<{ state: 'complete' | 'default' }>`
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
|
|
||||||
height: 2rem;
|
|
||||||
width: 2rem;
|
|
||||||
|
|
||||||
border-radius: 50%;
|
|
||||||
|
|
||||||
background-color: var(--color-layer-3);
|
|
||||||
|
|
||||||
${({ state }) =>
|
|
||||||
({
|
|
||||||
['complete']: css`
|
|
||||||
color: var(--color-positive);
|
|
||||||
`,
|
|
||||||
['default']: css`
|
|
||||||
color: var(--color-text-0);
|
|
||||||
`,
|
|
||||||
}[state])}
|
|
||||||
`;
|
|
||||||
|
|
||||||
Styled.Spinner = styled(LoadingSpinner)`
|
|
||||||
--spinner-width: 1.25rem;
|
|
||||||
|
|
||||||
color: var(--color-accent);
|
|
||||||
`;
|
|
||||||
|
|
||||||
Styled.Label = styled(Styled.row)<{ highlighted?: boolean }>`
|
|
||||||
${({ highlighted }) =>
|
|
||||||
highlighted
|
|
||||||
? css`
|
|
||||||
color: var(--color-text-2);
|
|
||||||
`
|
|
||||||
: css`
|
|
||||||
color: var(--color-text-0);
|
|
||||||
`}
|
|
||||||
`;
|
|
||||||
@@ -33,7 +33,7 @@ import { Details } from '@/components/Details';
|
|||||||
import { LoadingSpace } from '@/components/Loading/LoadingSpinner';
|
import { LoadingSpace } from '@/components/Loading/LoadingSpinner';
|
||||||
import { Output, OutputType } from '@/components/Output';
|
import { Output, OutputType } from '@/components/Output';
|
||||||
|
|
||||||
import { OrderSide } from '@dydxprotocol/v4-client';
|
import { OrderSide } from '@dydxprotocol/v4-client-js';
|
||||||
|
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
const theme = buildChartTheme({
|
const theme = buildChartTheme({
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import styled, { AnyStyledComponent } from 'styled-components';
|
|||||||
import { useDispatch, useSelector } from 'react-redux';
|
import { useDispatch, useSelector } from 'react-redux';
|
||||||
|
|
||||||
import { AbacusApiStatus } from '@/constants/abacus';
|
import { AbacusApiStatus } from '@/constants/abacus';
|
||||||
import { DydxV4Network } from '@/constants/networks';
|
import { CLIENT_NETWORK_CONFIGS } from '@/constants/networks';
|
||||||
import { UNICODE } from '@/constants/unicode';
|
import { UNICODE } from '@/constants/unicode';
|
||||||
|
|
||||||
import { STRING_KEYS } from '@/constants/localization';
|
import { STRING_KEYS } from '@/constants/localization';
|
||||||
@@ -44,7 +44,7 @@ export const ExchangeOfflineDialog = ({ preventClose, setIsOpen }: ElementProps)
|
|||||||
>
|
>
|
||||||
<Styled.Content>
|
<Styled.Content>
|
||||||
<p>{statusErrorMessage}</p>
|
<p>{statusErrorMessage}</p>
|
||||||
{selectedNetwork === DydxV4Network.V4Testnet2 && (
|
{CLIENT_NETWORK_CONFIGS[selectedNetwork].dydxChainId === 'dydx-testnet-2' && (
|
||||||
<Styled.Link href="https://status.v4testnet.dydx.exchange">
|
<Styled.Link href="https://status.v4testnet.dydx.exchange">
|
||||||
{stringGetter({ key: STRING_KEYS.LEARN_MORE })} {UNICODE.ARROW_RIGHT}
|
{stringGetter({ key: STRING_KEYS.LEARN_MORE })} {UNICODE.ARROW_RIGHT}
|
||||||
</Styled.Link>
|
</Styled.Link>
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import { useSignTypedData } from 'wagmi';
|
import { useSignTypedData } from 'wagmi';
|
||||||
import styled, { type AnyStyledComponent, css } from 'styled-components';
|
import styled, { type AnyStyledComponent, css } from 'styled-components';
|
||||||
import { useDispatch, useSelector } from 'react-redux';
|
import { useSelector } from 'react-redux';
|
||||||
import { AES } from 'crypto-js';
|
import { AES } from 'crypto-js';
|
||||||
|
|
||||||
import { EvmDerivedAccountStatus } from '@/constants/account';
|
import { EvmDerivedAccountStatus } from '@/constants/account';
|
||||||
@@ -9,7 +9,7 @@ import { AlertType } from '@/constants/alerts';
|
|||||||
import { AnalyticsEvent } from '@/constants/analytics';
|
import { AnalyticsEvent } from '@/constants/analytics';
|
||||||
import { ButtonAction } from '@/constants/buttons';
|
import { ButtonAction } from '@/constants/buttons';
|
||||||
import { STRING_KEYS } from '@/constants/localization';
|
import { STRING_KEYS } from '@/constants/localization';
|
||||||
import { CLIENT_NETWORK_CONFIGS, DydxV4Network } from '@/constants/networks';
|
import { CLIENT_NETWORK_CONFIGS } from '@/constants/networks';
|
||||||
import { DydxAddress, SIGN_TYPED_DATA } from '@/constants/wallets';
|
import { DydxAddress, SIGN_TYPED_DATA } from '@/constants/wallets';
|
||||||
|
|
||||||
import { useAccounts, useBreakpoints, useDydxClient, useStringGetter } from '@/hooks';
|
import { useAccounts, useBreakpoints, useDydxClient, useStringGetter } from '@/hooks';
|
||||||
@@ -54,7 +54,7 @@ export const GenerateKeys = ({
|
|||||||
// 1. Switch network
|
// 1. Switch network
|
||||||
const selectedNetwork = useSelector(getSelectedNetwork);
|
const selectedNetwork = useSelector(getSelectedNetwork);
|
||||||
|
|
||||||
const chainId = Number(CLIENT_NETWORK_CONFIGS[selectedNetwork as DydxV4Network].ethereumChainId);
|
const chainId = Number(CLIENT_NETWORK_CONFIGS[selectedNetwork].ethereumChainId);
|
||||||
|
|
||||||
const { isMatchingNetwork, matchNetwork, isSwitchingNetwork } = useMatchingEvmNetwork({
|
const { isMatchingNetwork, matchNetwork, isSwitchingNetwork } = useMatchingEvmNetwork({
|
||||||
chainId,
|
chainId,
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { type FormEvent, useCallback, useEffect, useMemo, useState } from 'react
|
|||||||
import styled, { type AnyStyledComponent } from 'styled-components';
|
import styled, { type AnyStyledComponent } from 'styled-components';
|
||||||
import { type NumberFormatValues } from 'react-number-format';
|
import { type NumberFormatValues } from 'react-number-format';
|
||||||
import { shallowEqual, useSelector } from 'react-redux';
|
import { shallowEqual, useSelector } from 'react-redux';
|
||||||
import { TESTNET_CHAIN_ID } from '@dydxprotocol/v4-client';
|
import { TESTNET_CHAIN_ID } from '@dydxprotocol/v4-client-js';
|
||||||
import { ethers } from 'ethers';
|
import { ethers } from 'ethers';
|
||||||
|
|
||||||
import { TransferInputField, TransferInputTokenResource, TransferType } from '@/constants/abacus';
|
import { TransferInputField, TransferInputTokenResource, TransferType } from '@/constants/abacus';
|
||||||
@@ -13,7 +13,6 @@ import { NumberSign } from '@/constants/numbers';
|
|||||||
|
|
||||||
import { useAccounts, useDebounce, useStringGetter } from '@/hooks';
|
import { useAccounts, useDebounce, useStringGetter } from '@/hooks';
|
||||||
import { useAccountBalance } from '@/hooks/useAccountBalance';
|
import { useAccountBalance } from '@/hooks/useAccountBalance';
|
||||||
import { useLocalNotifications } from '@/hooks/useLocalNotifications';
|
|
||||||
|
|
||||||
import { layoutMixins } from '@/styles/layoutMixins';
|
import { layoutMixins } from '@/styles/layoutMixins';
|
||||||
import { formMixins } from '@/styles/formMixins';
|
import { formMixins } from '@/styles/formMixins';
|
||||||
@@ -51,14 +50,11 @@ export const DepositForm = ({ onDeposit, onError }: DepositFormProps) => {
|
|||||||
|
|
||||||
const { signerWagmi } = useAccounts();
|
const { signerWagmi } = useAccounts();
|
||||||
|
|
||||||
const { addTransferNotification } = useLocalNotifications();
|
|
||||||
|
|
||||||
const {
|
const {
|
||||||
requestPayload,
|
requestPayload,
|
||||||
token,
|
token,
|
||||||
chain: chainIdStr,
|
chain: chainIdStr,
|
||||||
resources,
|
resources,
|
||||||
summary,
|
|
||||||
} = useSelector(getTransferInputs, shallowEqual) || {};
|
} = useSelector(getTransferInputs, shallowEqual) || {};
|
||||||
const chainId = chainIdStr ? parseInt(chainIdStr) : undefined;
|
const chainId = chainIdStr ? parseInt(chainIdStr) : undefined;
|
||||||
|
|
||||||
@@ -73,6 +69,8 @@ export const DepositForm = ({ onDeposit, onError }: DepositFormProps) => {
|
|||||||
const debouncedAmount = useDebounce<string>(fromAmount, 500);
|
const debouncedAmount = useDebounce<string>(fromAmount, 500);
|
||||||
|
|
||||||
// Async Data
|
// Async Data
|
||||||
|
const [transactionHash, setTransactionHash] = useState<string>();
|
||||||
|
|
||||||
const { balance, queryStatus, isQueryFetching } = useAccountBalance({
|
const { balance, queryStatus, isQueryFetching } = useAccountBalance({
|
||||||
addressOrDenom: sourceToken?.address || undefined,
|
addressOrDenom: sourceToken?.address || undefined,
|
||||||
assetSymbol: sourceToken?.symbol || undefined,
|
assetSymbol: sourceToken?.symbol || undefined,
|
||||||
@@ -191,12 +189,11 @@ export const DepositForm = ({ onDeposit, onError }: DepositFormProps) => {
|
|||||||
onDeposit?.();
|
onDeposit?.();
|
||||||
|
|
||||||
if (txHash) {
|
if (txHash) {
|
||||||
addTransferNotification({
|
setTransactionHash(txHash);
|
||||||
txHash,
|
abacusStateManager.setTransferStatus({
|
||||||
|
hash: txHash,
|
||||||
toChainId: TESTNET_CHAIN_ID,
|
toChainId: TESTNET_CHAIN_ID,
|
||||||
fromChainId: chainIdStr || undefined,
|
fromChainId: chainId?.toString(),
|
||||||
toAmount: summary?.usdcSize || undefined,
|
|
||||||
triggeredAt: Date.now(),
|
|
||||||
});
|
});
|
||||||
abacusStateManager.clearTransferInputValues();
|
abacusStateManager.clearTransferInputValues();
|
||||||
setFromAmount('');
|
setFromAmount('');
|
||||||
@@ -289,7 +286,17 @@ export const DepositForm = ({ onDeposit, onError }: DepositFormProps) => {
|
|||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
</Styled.WithDetailsReceipt>
|
</Styled.WithDetailsReceipt>
|
||||||
{errorMessage && <AlertMessage type={AlertType.Error}>{errorMessage}</AlertMessage>}
|
{errorMessage ? (
|
||||||
|
<AlertMessage type={AlertType.Error}>{errorMessage}</AlertMessage>
|
||||||
|
) : (
|
||||||
|
transactionHash && (
|
||||||
|
<AlertMessage type={AlertType.Success}>
|
||||||
|
<Styled.TransactionInfo>
|
||||||
|
{stringGetter({ key: STRING_KEYS.DEPOSIT_IN_PROGRESS })}
|
||||||
|
</Styled.TransactionInfo>
|
||||||
|
</AlertMessage>
|
||||||
|
)
|
||||||
|
)}
|
||||||
<DepositButtonAndReceipt
|
<DepositButtonAndReceipt
|
||||||
isDisabled={isDisabled}
|
isDisabled={isDisabled}
|
||||||
isLoading={isLoading}
|
isLoading={isLoading}
|
||||||
|
|||||||
@@ -3,18 +3,18 @@ import type { ChangeEvent, FormEvent } from 'react';
|
|||||||
import styled, { type AnyStyledComponent } from 'styled-components';
|
import styled, { type AnyStyledComponent } from 'styled-components';
|
||||||
import type { NumberFormatValues } from 'react-number-format';
|
import type { NumberFormatValues } from 'react-number-format';
|
||||||
import { shallowEqual, useSelector } from 'react-redux';
|
import { shallowEqual, useSelector } from 'react-redux';
|
||||||
import { TESTNET_CHAIN_ID } from '@dydxprotocol/v4-client';
|
import { TESTNET_CHAIN_ID } from '@dydxprotocol/v4-client-js';
|
||||||
|
|
||||||
import { TransferInputField, TransferInputTokenResource, TransferType } from '@/constants/abacus';
|
import { TransferInputField, TransferInputTokenResource, TransferType } from '@/constants/abacus';
|
||||||
import { AlertType } from '@/constants/alerts';
|
import { AlertType } from '@/constants/alerts';
|
||||||
import { ButtonAction, ButtonSize, ButtonType } from '@/constants/buttons';
|
import { ButtonSize } from '@/constants/buttons';
|
||||||
import { STRING_KEYS } from '@/constants/localization';
|
import { STRING_KEYS } from '@/constants/localization';
|
||||||
import { NumberSign, QUANTUM_MULTIPLIER } from '@/constants/numbers';
|
import { NumberSign, QUANTUM_MULTIPLIER } from '@/constants/numbers';
|
||||||
|
|
||||||
import { useDebounce, useStringGetter, useSubaccount } from '@/hooks';
|
import { useDebounce, useStringGetter, useSubaccount } from '@/hooks';
|
||||||
import { useLocalNotifications } from '@/hooks/useLocalNotifications';
|
|
||||||
|
|
||||||
import { layoutMixins } from '@/styles/layoutMixins';
|
import { layoutMixins } from '@/styles/layoutMixins';
|
||||||
|
import { formMixins } from '@/styles/formMixins';
|
||||||
|
|
||||||
import { AlertMessage } from '@/components/AlertMessage';
|
import { AlertMessage } from '@/components/AlertMessage';
|
||||||
import { Button } from '@/components/Button';
|
import { Button } from '@/components/Button';
|
||||||
@@ -63,9 +63,9 @@ export const WithdrawForm = () => {
|
|||||||
[token, resources]
|
[token, resources]
|
||||||
);
|
);
|
||||||
|
|
||||||
const { addTransferNotification } = useLocalNotifications();
|
|
||||||
|
|
||||||
// Async Data
|
// Async Data
|
||||||
|
const [transactionHash, setTransactionHash] = useState<string>();
|
||||||
|
|
||||||
const debouncedAmountBN = MustBigNumber(debouncedAmount);
|
const debouncedAmountBN = MustBigNumber(debouncedAmount);
|
||||||
const withdrawAmountBN = MustBigNumber(withdrawAmount);
|
const withdrawAmountBN = MustBigNumber(withdrawAmount);
|
||||||
const freeCollateralBN = MustBigNumber(freeCollateral?.current);
|
const freeCollateralBN = MustBigNumber(freeCollateral?.current);
|
||||||
@@ -134,13 +134,10 @@ export const WithdrawForm = () => {
|
|||||||
const hash = `0x${Buffer.from(txHash.hash).toString('hex')}`;
|
const hash = `0x${Buffer.from(txHash.hash).toString('hex')}`;
|
||||||
|
|
||||||
setTransactionHash(hash);
|
setTransactionHash(hash);
|
||||||
|
abacusStateManager.setTransferStatus({
|
||||||
addTransferNotification({
|
hash,
|
||||||
txHash: hash,
|
|
||||||
fromChainId: TESTNET_CHAIN_ID,
|
fromChainId: TESTNET_CHAIN_ID,
|
||||||
toChainId: chainIdStr || undefined,
|
toChainId: chainIdStr || undefined,
|
||||||
toAmount: debouncedAmountBN.toNumber(),
|
|
||||||
triggeredAt: Date.now(),
|
|
||||||
});
|
});
|
||||||
abacusStateManager.clearTransferInputValues();
|
abacusStateManager.clearTransferInputValues();
|
||||||
setWithdrawAmount('');
|
setWithdrawAmount('');
|
||||||
@@ -288,18 +285,23 @@ export const WithdrawForm = () => {
|
|||||||
value={withdrawAmount}
|
value={withdrawAmount}
|
||||||
label={stringGetter({ key: STRING_KEYS.AMOUNT })}
|
label={stringGetter({ key: STRING_KEYS.AMOUNT })}
|
||||||
slotRight={
|
slotRight={
|
||||||
<Button
|
<Styled.FormInputButton size={ButtonSize.XSmall} onClick={onClickMax}>
|
||||||
type={ButtonType.Button}
|
|
||||||
action={ButtonAction.Secondary}
|
|
||||||
size={ButtonSize.XSmall}
|
|
||||||
onClick={onClickMax}
|
|
||||||
>
|
|
||||||
{stringGetter({ key: STRING_KEYS.MAX })}
|
{stringGetter({ key: STRING_KEYS.MAX })}
|
||||||
</Button>
|
</Styled.FormInputButton>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
</Styled.WithDetailsReceipt>
|
</Styled.WithDetailsReceipt>
|
||||||
{errorMessage && <AlertMessage type={AlertType.Error}>{errorMessage}</AlertMessage>}
|
{errorMessage ? (
|
||||||
|
<AlertMessage type={AlertType.Error}>{errorMessage}</AlertMessage>
|
||||||
|
) : (
|
||||||
|
transactionHash && (
|
||||||
|
<AlertMessage type={AlertType.Success}>
|
||||||
|
<Styled.TransactionInfo>
|
||||||
|
{stringGetter({ key: STRING_KEYS.WITHDRAW_IN_PROGRESS })}
|
||||||
|
</Styled.TransactionInfo>
|
||||||
|
</AlertMessage>
|
||||||
|
)
|
||||||
|
)}
|
||||||
<WithdrawButtonAndReceipt
|
<WithdrawButtonAndReceipt
|
||||||
isDisabled={isDisabled}
|
isDisabled={isDisabled}
|
||||||
isLoading={isLoading}
|
isLoading={isLoading}
|
||||||
@@ -350,3 +352,7 @@ Styled.Link = styled(Link)`
|
|||||||
Styled.TransactionInfo = styled.span`
|
Styled.TransactionInfo = styled.span`
|
||||||
${layoutMixins.row}
|
${layoutMixins.row}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
Styled.FormInputButton = styled(Button)`
|
||||||
|
${formMixins.inputInnerButton}
|
||||||
|
`;
|
||||||
|
|||||||
@@ -19,11 +19,11 @@ import { Output, OutputType } from '@/components/Output';
|
|||||||
import { ToggleButton } from '@/components/ToggleButton';
|
import { ToggleButton } from '@/components/ToggleButton';
|
||||||
import { WithReceipt } from '@/components/WithReceipt';
|
import { WithReceipt } from '@/components/WithReceipt';
|
||||||
|
|
||||||
import { SlippageEditor } from '../SlippageEditor';
|
|
||||||
|
|
||||||
import { getSubaccount } from '@/state/accountSelectors';
|
import { getSubaccount } from '@/state/accountSelectors';
|
||||||
import { getTransferInputs } from '@/state/inputsSelectors';
|
import { getTransferInputs } from '@/state/inputsSelectors';
|
||||||
|
|
||||||
|
import { SlippageEditor } from '../SlippageEditor';
|
||||||
|
|
||||||
type ElementProps = {
|
type ElementProps = {
|
||||||
setSlippage: (slippage: number) => void;
|
setSlippage: (slippage: number) => void;
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import type { Story } from '@ladle/react';
|
import type { Story } from '@ladle/react';
|
||||||
import styled, { AnyStyledComponent } from 'styled-components';
|
import styled, { AnyStyledComponent } from 'styled-components';
|
||||||
import { OrderSide } from '@dydxprotocol/v4-client';
|
import { OrderSide } from '@dydxprotocol/v4-client-js';
|
||||||
|
|
||||||
import { PositionSide } from '@/constants/trade';
|
import { PositionSide } from '@/constants/trade';
|
||||||
import { breakpoints } from '@/styles';
|
import { breakpoints } from '@/styles';
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { type Dispatch, type SetStateAction, useCallback, useMemo } from 'react'
|
|||||||
import styled, { AnyStyledComponent, css } from 'styled-components';
|
import styled, { AnyStyledComponent, css } from 'styled-components';
|
||||||
import { Root, Thumb, Track } from '@radix-ui/react-slider';
|
import { Root, Thumb, Track } from '@radix-ui/react-slider';
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import { OrderSide } from '@dydxprotocol/v4-client';
|
import { OrderSide } from '@dydxprotocol/v4-client-js';
|
||||||
|
|
||||||
import { type Nullable, TradeInputField } from '@/constants/abacus';
|
import { type Nullable, TradeInputField } from '@/constants/abacus';
|
||||||
import { PositionSide } from '@/constants/trade';
|
import { PositionSide } from '@/constants/trade';
|
||||||
@@ -43,9 +43,7 @@ export const LeverageSlider = ({
|
|||||||
},
|
},
|
||||||
[PositionSide.Long]: {
|
[PositionSide.Long]: {
|
||||||
min:
|
min:
|
||||||
orderSide === OrderSide.BUY
|
orderSide === OrderSide.BUY ? leverageBN.toNumber() : maxLeverageBN.negated().toNumber(),
|
||||||
? leverageBN.toNumber()
|
|
||||||
: maxLeverageBN.negated().toNumber(),
|
|
||||||
max: orderSide === OrderSide.BUY ? maxLeverageBN.toNumber() : leverageBN.toNumber(),
|
max: orderSide === OrderSide.BUY ? maxLeverageBN.toNumber() : leverageBN.toNumber(),
|
||||||
midpoint:
|
midpoint:
|
||||||
orderSide === OrderSide.SELL
|
orderSide === OrderSide.SELL
|
||||||
@@ -56,9 +54,7 @@ export const LeverageSlider = ({
|
|||||||
},
|
},
|
||||||
[PositionSide.Short]: {
|
[PositionSide.Short]: {
|
||||||
min:
|
min:
|
||||||
orderSide === OrderSide.BUY
|
orderSide === OrderSide.BUY ? leverageBN.toNumber() : maxLeverageBN.negated().toNumber(),
|
||||||
? leverageBN.toNumber()
|
|
||||||
: maxLeverageBN.negated().toNumber(),
|
|
||||||
max: orderSide === OrderSide.BUY ? maxLeverageBN.toNumber() : leverageBN.toNumber(),
|
max: orderSide === OrderSide.BUY ? maxLeverageBN.toNumber() : leverageBN.toNumber(),
|
||||||
midpoint:
|
midpoint:
|
||||||
orderSide === OrderSide.BUY
|
orderSide === OrderSide.BUY
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import type { Dispatch, SetStateAction } from 'react';
|
import type { Dispatch, SetStateAction } from 'react';
|
||||||
import { shallowEqual, useSelector } from 'react-redux';
|
import { shallowEqual, useSelector } from 'react-redux';
|
||||||
import styled, { AnyStyledComponent } from 'styled-components';
|
import styled, { AnyStyledComponent } from 'styled-components';
|
||||||
import { OrderSide } from '@dydxprotocol/v4-client';
|
import { OrderSide } from '@dydxprotocol/v4-client-js';
|
||||||
|
|
||||||
import { TradeInputField, Nullable } from '@/constants/abacus';
|
import { TradeInputField, Nullable } from '@/constants/abacus';
|
||||||
import { ButtonShape } from '@/constants/buttons';
|
import { ButtonShape } from '@/constants/buttons';
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { shallowEqual, useDispatch, useSelector } from 'react-redux';
|
import { shallowEqual, useDispatch, useSelector } from 'react-redux';
|
||||||
import { OrderSide } from '@dydxprotocol/v4-client';
|
import { OrderSide } from '@dydxprotocol/v4-client-js';
|
||||||
|
|
||||||
import type { TradeInputSummary } from '@/constants/abacus';
|
import type { TradeInputSummary } from '@/constants/abacus';
|
||||||
import { ButtonAction, ButtonSize, ButtonType } from '@/constants/buttons';
|
import { ButtonAction, ButtonSize, ButtonType } from '@/constants/buttons';
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { memo } from 'react';
|
import { memo } from 'react';
|
||||||
import styled, { css } from 'styled-components';
|
import styled, { css } from 'styled-components';
|
||||||
import { shallowEqual, useSelector } from 'react-redux';
|
import { shallowEqual, useSelector } from 'react-redux';
|
||||||
import { OrderSide } from '@dydxprotocol/v4-client';
|
import { OrderSide } from '@dydxprotocol/v4-client-js';
|
||||||
|
|
||||||
import { AbacusOrderSide } from '@/constants/abacus';
|
import { AbacusOrderSide } from '@/constants/abacus';
|
||||||
import { ButtonShape, ButtonSize } from '@/constants/buttons';
|
import { ButtonShape, ButtonSize } from '@/constants/buttons';
|
||||||
@@ -31,9 +31,7 @@ export const TradeSideToggle = memo(() => {
|
|||||||
onValueChange={(side: OrderSide) => {
|
onValueChange={(side: OrderSide) => {
|
||||||
abacusStateManager.setTradeValue({
|
abacusStateManager.setTradeValue({
|
||||||
value:
|
value:
|
||||||
side === OrderSide.BUY
|
side === OrderSide.BUY ? AbacusOrderSide.buy.rawValue : AbacusOrderSide.sell.rawValue,
|
||||||
? AbacusOrderSide.buy.rawValue
|
|
||||||
: AbacusOrderSide.sell.rawValue,
|
|
||||||
field: TradeInputField.side,
|
field: TradeInputField.side,
|
||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
|
|||||||
@@ -5,14 +5,14 @@ import { shallowEqual, useSelector } from 'react-redux';
|
|||||||
import type { SyntheticInputEvent } from 'react-number-format/types/types';
|
import type { SyntheticInputEvent } from 'react-number-format/types/types';
|
||||||
import { debounce } from 'lodash';
|
import { debounce } from 'lodash';
|
||||||
import { StdFee } from '@cosmjs/stargate';
|
import { StdFee } from '@cosmjs/stargate';
|
||||||
import { validation } from '@dydxprotocol/v4-client';
|
import { validation } from '@dydxprotocol/v4-client-js';
|
||||||
|
|
||||||
import { TransferInputField, TransferType } from '@/constants/abacus';
|
import { TransferInputField, TransferType } from '@/constants/abacus';
|
||||||
import { AlertType } from '@/constants/alerts';
|
import { AlertType } from '@/constants/alerts';
|
||||||
import { ButtonShape, ButtonSize } from '@/constants/buttons';
|
import { ButtonShape, ButtonSize } from '@/constants/buttons';
|
||||||
import { ERROR_STRING_KEYS } from '@/constants/localization/errors';
|
import { ERROR_STRING_KEYS } from '@/constants/localization/errors';
|
||||||
import { STRING_KEYS } from '@/constants/localization';
|
import { STRING_KEYS } from '@/constants/localization';
|
||||||
import { CHAIN_IDS } from '@/constants/networks';
|
import { CLIENT_NETWORK_CONFIGS } from '@/constants/networks';
|
||||||
import { NumberSign, QUANTUM_MULTIPLIER } from '@/constants/numbers';
|
import { NumberSign, QUANTUM_MULTIPLIER } from '@/constants/numbers';
|
||||||
import { DYDX_CHAIN_ASSET_COIN_DENOM, DYDX_CHAIN_INFO, DydxChainAsset } from '@/constants/wallets';
|
import { DYDX_CHAIN_ASSET_COIN_DENOM, DYDX_CHAIN_INFO, DydxChainAsset } from '@/constants/wallets';
|
||||||
|
|
||||||
@@ -228,7 +228,7 @@ export const TransferForm = ({
|
|||||||
|
|
||||||
const networkOptions = [
|
const networkOptions = [
|
||||||
{
|
{
|
||||||
chainId: CHAIN_IDS[selectedNetwork],
|
chainId: CLIENT_NETWORK_CONFIGS[selectedNetwork].dydxChainId,
|
||||||
label: (
|
label: (
|
||||||
<Styled.InlineRow>
|
<Styled.InlineRow>
|
||||||
<AssetIcon symbol="DYDX" /> {stringGetter({ key: STRING_KEYS.DYDX_CHAIN })}
|
<AssetIcon symbol="DYDX" /> {stringGetter({ key: STRING_KEYS.DYDX_CHAIN })}
|
||||||
@@ -318,7 +318,7 @@ export const TransferForm = ({
|
|||||||
/>
|
/>
|
||||||
<Styled.NetworkSelectMenu
|
<Styled.NetworkSelectMenu
|
||||||
label={stringGetter({ key: STRING_KEYS.NETWORK })}
|
label={stringGetter({ key: STRING_KEYS.NETWORK })}
|
||||||
value={CHAIN_IDS[selectedNetwork]}
|
value={CLIENT_NETWORK_CONFIGS[selectedNetwork].dydxChainId}
|
||||||
slotTriggerAfter={null}
|
slotTriggerAfter={null}
|
||||||
>
|
>
|
||||||
{networkOptions.map(({ chainId, label }) => (
|
{networkOptions.map(({ chainId, label }) => (
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import styled, { type AnyStyledComponent } from 'styled-components';
|
import styled, { type AnyStyledComponent } from 'styled-components';
|
||||||
|
|
||||||
import { useSelectedNetwork } from '@/hooks';
|
import { useSelectedNetwork } from '@/hooks';
|
||||||
|
import { layoutMixins } from '@/styles/layoutMixins';
|
||||||
import { headerMixins } from '@/styles/headerMixins';
|
import { headerMixins } from '@/styles/headerMixins';
|
||||||
|
|
||||||
import { DropdownSelectMenu } from '@/components/DropdownSelectMenu';
|
import { DropdownSelectMenu } from '@/components/DropdownSelectMenu';
|
||||||
@@ -18,7 +19,6 @@ export const NetworkSelectMenu = ({ align, sideOffset }: StyleProps) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Styled.DropdownSelectMenu
|
<Styled.DropdownSelectMenu
|
||||||
disabled={import.meta.env.MODE === 'production'}
|
|
||||||
items={networks}
|
items={networks}
|
||||||
value={selectedNetwork}
|
value={selectedNetwork}
|
||||||
onValueChange={switchNetwork}
|
onValueChange={switchNetwork}
|
||||||
@@ -32,4 +32,11 @@ const Styled: Record<string, AnyStyledComponent> = {};
|
|||||||
|
|
||||||
Styled.DropdownSelectMenu = styled(DropdownSelectMenu)`
|
Styled.DropdownSelectMenu = styled(DropdownSelectMenu)`
|
||||||
${headerMixins.dropdownTrigger}
|
${headerMixins.dropdownTrigger}
|
||||||
|
|
||||||
|
& > span:first-of-type {
|
||||||
|
${layoutMixins.textOverflow}
|
||||||
|
max-width: 5.625rem;
|
||||||
|
min-width: 0;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
`;
|
`;
|
||||||
|
|||||||
@@ -89,9 +89,9 @@ export const NotificationsMenu = ({
|
|||||||
.map(({ notification, key, displayData }) => ({
|
.map(({ notification, key, displayData }) => ({
|
||||||
value: key,
|
value: key,
|
||||||
label: displayData.title ?? '',
|
label: displayData.title ?? '',
|
||||||
description: displayData.customMenuContent || displayData.description,
|
description: displayData.description,
|
||||||
slotBefore: !displayData.customMenuContent && displayData.icon,
|
slotBefore: displayData.icon,
|
||||||
slotAfter: !displayData.customMenuContent && (
|
slotAfter: (
|
||||||
<>
|
<>
|
||||||
<$Output
|
<$Output
|
||||||
type={OutputType.RelativeTime}
|
type={OutputType.RelativeTime}
|
||||||
|
|||||||
@@ -1,45 +1,13 @@
|
|||||||
import { type MenuItem } from '@/constants/menus';
|
import { type MenuItem } from '@/constants/menus';
|
||||||
import { type DydxNetwork, DydxV3Network, DydxV4Network } from '@/constants/networks';
|
import { type DydxNetwork, NETWORK_ENDPOINTS } from '@/constants/networks';
|
||||||
|
import { useStringGetter } from '@/hooks';
|
||||||
|
|
||||||
export const useNetworks = (): MenuItem<DydxNetwork>[] =>
|
export const useNetworks = (): MenuItem<DydxNetwork>[] => {
|
||||||
import.meta.env.MODE === 'production'
|
const stringGetter = useStringGetter();
|
||||||
? [
|
|
||||||
{
|
return NETWORK_ENDPOINTS.environments.map(({ stringKey, environment }) => ({
|
||||||
value: DydxV4Network.V4Testnet2,
|
key: environment,
|
||||||
label: 'Testnet',
|
label: stringGetter({ key: stringKey }),
|
||||||
slotBefore: <b>v4</b>,
|
value: environment,
|
||||||
},
|
}));
|
||||||
]
|
};
|
||||||
: [
|
|
||||||
{
|
|
||||||
value: DydxV4Network.V4Mainnet,
|
|
||||||
label: 'Mainnet',
|
|
||||||
slotBefore: <b>v4</b>,
|
|
||||||
disabled: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: DydxV4Network.V4Staging,
|
|
||||||
label: 'Staging',
|
|
||||||
slotBefore: <b>v4</b>,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: DydxV4Network.V4Testnet2,
|
|
||||||
label: 'Testnet-2',
|
|
||||||
slotBefore: <b>v4</b>,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: DydxV4Network.V4Local,
|
|
||||||
label: 'Dev',
|
|
||||||
slotBefore: <b>v4</b>,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: DydxV3Network.V3Mainnet,
|
|
||||||
label: 'Mainnet',
|
|
||||||
slotBefore: <b>v3</b>,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: DydxV3Network.V3Testnet,
|
|
||||||
label: 'Testnet',
|
|
||||||
slotBefore: <b>v3</b>,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { useEffect } from 'react';
|
import { useEffect } from 'react';
|
||||||
import styled, { type AnyStyledComponent, css } from 'styled-components';
|
import styled, { type AnyStyledComponent, css } from 'styled-components';
|
||||||
import { shallowEqual, useDispatch, useSelector } from 'react-redux';
|
import { shallowEqual, useDispatch, useSelector } from 'react-redux';
|
||||||
import { OrderSide } from '@dydxprotocol/v4-client';
|
import { OrderSide } from '@dydxprotocol/v4-client-js';
|
||||||
import type { ColumnSize } from '@react-types/table';
|
import type { ColumnSize } from '@react-types/table';
|
||||||
|
|
||||||
import { type Asset, type SubaccountFill } from '@/constants/abacus';
|
import { type Asset, type SubaccountFill } from '@/constants/abacus';
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { useMemo } from 'react';
|
import { useMemo } from 'react';
|
||||||
import styled, { type AnyStyledComponent, css, keyframes } from 'styled-components';
|
import styled, { type AnyStyledComponent, css, keyframes } from 'styled-components';
|
||||||
import { shallowEqual, useSelector } from 'react-redux';
|
import { shallowEqual, useSelector } from 'react-redux';
|
||||||
import { OrderSide } from '@dydxprotocol/v4-client';
|
import { OrderSide } from '@dydxprotocol/v4-client-js';
|
||||||
|
|
||||||
import { MarketTrade } from '@/constants/abacus';
|
import { MarketTrade } from '@/constants/abacus';
|
||||||
import { STRING_KEYS } from '@/constants/localization';
|
import { STRING_KEYS } from '@/constants/localization';
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { useCallback, useEffect, useMemo, useState } from 'react';
|
|||||||
import { shallowEqual, useSelector } from 'react-redux';
|
import { shallowEqual, useSelector } from 'react-redux';
|
||||||
import styled, { type AnyStyledComponent, css, keyframes } from 'styled-components';
|
import styled, { type AnyStyledComponent, css, keyframes } from 'styled-components';
|
||||||
|
|
||||||
import { OrderSide } from '@dydxprotocol/v4-client';
|
import { OrderSide } from '@dydxprotocol/v4-client-js';
|
||||||
import { type OrderbookLine, TradeInputField } from '@/constants/abacus';
|
import { type OrderbookLine, TradeInputField } from '@/constants/abacus';
|
||||||
import { STRING_KEYS } from '@/constants/localization';
|
import { STRING_KEYS } from '@/constants/localization';
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { useEffect } from 'react';
|
|||||||
import styled, { css, type AnyStyledComponent } from 'styled-components';
|
import styled, { css, type AnyStyledComponent } from 'styled-components';
|
||||||
import { shallowEqual, useDispatch, useSelector } from 'react-redux';
|
import { shallowEqual, useDispatch, useSelector } from 'react-redux';
|
||||||
import { DateTime } from 'luxon';
|
import { DateTime } from 'luxon';
|
||||||
import { OrderSide } from '@dydxprotocol/v4-client';
|
import { OrderSide } from '@dydxprotocol/v4-client-js';
|
||||||
import { ColumnSize } from '@react-types/table';
|
import { ColumnSize } from '@react-types/table';
|
||||||
import type { Dispatch } from '@reduxjs/toolkit';
|
import type { Dispatch } from '@reduxjs/toolkit';
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user