Compare commits

..
Author SHA1 Message Date
jaredvu d2749e6e59 Fix import order 2023-12-19 16:24:49 -08:00
jaredvu 582dade27e Lazy import pages 2023-12-19 16:23:50 -08:00
Jared Vu 001aad3abc Navigate to the Markets page if the current marketId is not included in subscribed markets (#198)
* Navigate to markets if current url is invalid

* nits
2023-12-19 15:58:49 -08:00
Jared Vu f8db5e1ba0 Update abacus to 1.1.25: Good til time fix (#199) 2023-12-19 09:49:51 -08:00
Jared Vu f8bec0fb3d Update Withdraw form receipt (#200) 2023-12-19 09:49:37 -08:00
Bill 8bf23b7e9c bump abacus (#197) 2023-12-15 15:12:35 -08:00
Jared Vu 3f10e045f4 bump abacus & wagmi (#196) 2023-12-15 09:26:41 -08:00
Bill 71d1a0321b Do not block website if NobleClient cannot init, and other onboarding fixes (#193) 2023-12-13 08:11:19 -08:00
Bill 0f16396c8d Implement CCTP withdraw (#188)
* Implement CCTP withdraw

* bump packages

* address comments
2023-12-12 10:12:37 -08:00
Jared Vu 2709d79f59 Firefox issues (#190)
* remove row flicker on hover

* Fix border for AccountInfoConnectedState on mobile

* Remove sticky position to allow button click

* Fix: AccountInfo not displaying on mobile firefox

* Fix css var name

* Restore filter on Table row hover

* Remove PerspectiveArea. broken on firefox

* Symbol no longer exists on AbacusType

* HorizontalPanel: memoize tabConfig

* input: firefox cant click between chars
2023-12-12 08:37:50 -08:00
Bill ab0eec5d4f Update noble tesnet rpc (#192) 2023-12-12 11:35:21 -05:00
27 changed files with 1010 additions and 456 deletions
+2 -2
View File
@@ -39,7 +39,7 @@
"@cosmjs/proto-signing": "^0.31.0",
"@cosmjs/stargate": "^0.31.0",
"@cosmjs/tendermint-rpc": "^0.31.0",
"@dydxprotocol/v4-abacus": "^1.1.22",
"@dydxprotocol/v4-abacus": "^1.1.25",
"@dydxprotocol/v4-client-js": "^1.0.11",
"@dydxprotocol/v4-localization": "^1.0.18",
"@ethersproject/providers": "^5.7.2",
@@ -111,7 +111,7 @@
"styled-components": "^5.3.11",
"use-latest": "^1.2.1",
"viem": "^1.12.2",
"wagmi": "^1.4.5"
"wagmi": "^1.4.12"
},
"devDependencies": {
"@babel/core": "^7.22.5",
+663 -128
View File
File diff suppressed because it is too large Load Diff
-20
View File
@@ -1,29 +1,9 @@
[
{
"chainId": "42161",
"tokenAddress": "0xff970a61a04b1ca14834a43f5de4533ebddb5cc8",
"name": "Arbitrum"
},
{
"chainId": "43114",
"tokenAddress": "0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E",
"name": "Avalanche"
},
{
"chainId": "8453",
"tokenAddress": "0x66627F389ae46D881773B7131139b2411980E09E",
"name": "Base"
},
{
"chainId": "1",
"tokenAddress": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
"name": "Ethereum"
},
{
"chainId": "10",
"tokenAddress": "0x7F5c764cBc14f9669B88837ca1490cCa17c31607",
"name": "OP Mainnet"
},
{
"chainId": "421613",
"tokenAddress": "0xfd064a18f3bf249cf1f87fc203e90d8f650f2d63",
+14 -14
View File
@@ -71,7 +71,7 @@
"https://validator.v4dev.dydx.exchange"
],
"0xsquid": "https://testnet.api.0xsquid.com",
"nobleValidator": "https://rpc.testnet.noble.strange.love",
"nobleValidator": "https://noble-testnet-rpc.polkachu.com/",
"faucet": "https://faucet.v4dev.dydx.exchange"
},
"links": {
@@ -145,7 +145,7 @@
"http://54.92.118.111"
],
"0xsquid": "https://testnet.api.0xsquid.com",
"nobleValidator": "https://rpc.testnet.noble.strange.love"
"nobleValidator": "https://noble-testnet-rpc.polkachu.com/"
},
"links": {
"tos": "https://dydx.exchange/v4-terms",
@@ -218,7 +218,7 @@
"http://validator.v4dev4.dydx.exchange"
],
"0xsquid": "https://testnet.api.0xsquid.com",
"nobleValidator": "https://rpc.testnet.noble.strange.love"
"nobleValidator": "https://noble-testnet-rpc.polkachu.com/"
},
"links": {
"tos": "https://dydx.exchange/v4-terms",
@@ -291,7 +291,7 @@
"http://18.223.78.50"
],
"0xsquid": "https://testnet.api.0xsquid.com",
"nobleValidator": "https://rpc.testnet.noble.strange.love"
"nobleValidator": "https://noble-testnet-rpc.polkachu.com/"
},
"links": {
"tos": "https://dydx.exchange/v4-terms",
@@ -365,7 +365,7 @@
"https://validator.v4staging.dydx.exchange"
],
"0xsquid": "https://testnet.api.squidrouter.com",
"nobleValidator": "https://rpc.testnet.noble.strange.love"
"nobleValidator": "https://noble-testnet-rpc.polkachu.com/"
},
"links": {
"tos": "https://dydx.exchange/v4-terms",
@@ -440,7 +440,7 @@
"https://validator.v4staging.dydx.exchange"
],
"0xsquid": "https://testnet.api.squidrouter.com",
"nobleValidator": "https://rpc.testnet.noble.strange.love"
"nobleValidator": "https://noble-testnet-rpc.polkachu.com/"
},
"links": {
"tos": "https://dydx.exchange/v4-terms",
@@ -513,7 +513,7 @@
"https://validator-uswest1.v4staging.dydx.exchange"
],
"0xsquid": "https://testnet.api.squidrouter.com",
"nobleValidator": "https://rpc.testnet.noble.strange.love"
"nobleValidator": "https://noble-testnet-rpc.polkachu.com/"
},
"links": {
"tos": "https://dydx.exchange/v4-terms",
@@ -591,7 +591,7 @@
"https://dydx-rpc.liquify.com/api=8878132/dydx"
],
"0xsquid": "https://testnet.api.squidrouter.com",
"nobleValidator": "https://rpc.testnet.noble.strange.love",
"nobleValidator": "https://noble-testnet-rpc.polkachu.com/",
"faucet": "https://faucet.v4testnet.dydx.exchange"
},
"links": {
@@ -666,7 +666,7 @@
"https://validator.v4testnet.dydx.exchange"
],
"0xsquid": "https://testnet.api.squidrouter.com",
"nobleValidator": "https://rpc.testnet.noble.strange.love",
"nobleValidator": "https://noble-testnet-rpc.polkachu.com/",
"faucet": "https://faucet.v4testnet.dydx.exchange"
},
"links": {
@@ -742,7 +742,7 @@
"https://dydx-testnet.nodefleet.org"
],
"0xsquid": "https://testnet.api.squidrouter.com",
"nobleValidator": "https://rpc.testnet.noble.strange.love",
"nobleValidator": "https://noble-testnet-rpc.polkachu.com/",
"faucet": "https://faucet.v4testnet.dydx.exchange"
},
"links": {
@@ -818,7 +818,7 @@
"https://test-dydx.kingnodes.com"
],
"0xsquid": "https://testnet.api.squidrouter.com",
"nobleValidator": "https://rpc.testnet.noble.strange.love",
"nobleValidator": "https://noble-testnet-rpc.polkachu.com/",
"faucet": "https://faucet.v4testnet.dydx.exchange"
},
"links": {
@@ -894,7 +894,7 @@
"https://dydx-rpc.liquify.com/api=8878132/dydx"
],
"0xsquid": "https://testnet.api.squidrouter.com",
"nobleValidator": "https://rpc.testnet.noble.strange.love",
"nobleValidator": "https://noble-testnet-rpc.polkachu.com/",
"faucet": "https://faucet.v4testnet.dydx.exchange"
},
"links": {
@@ -970,7 +970,7 @@
"https://dydx-testnet-rpc.polkachu.com/"
],
"0xsquid": "https://testnet.api.squidrouter.com",
"nobleValidator": "https://rpc.testnet.noble.strange.love",
"nobleValidator": "https://noble-testnet-rpc.polkachu.com/",
"faucet": "https://faucet.v4testnet.dydx.exchange"
},
"links": {
@@ -1037,7 +1037,7 @@
"https://dydx-testnet-full-rpc.public.blastapi.io/"
],
"0xsquid": "https://testnet.api.squidrouter.com",
"nobleValidator": "https://rpc.testnet.noble.strange.love",
"nobleValidator": "https://noble-testnet-rpc.polkachu.com/",
"faucet": "https://faucet.v4testnet.dydx.exchange"
},
"links": {
+13 -12
View File
@@ -1,4 +1,4 @@
import { Suspense } from 'react';
import { lazy, Suspense } from 'react';
import { Navigate, Route, Routes } from 'react-router-dom';
import styled, { AnyStyledComponent, css } from 'styled-components';
import { WagmiConfig } from 'wagmi';
@@ -25,16 +25,6 @@ import { SubaccountProvider } from '@/hooks/useSubaccount';
import { GuardedMobileRoute } from '@/components/GuardedMobileRoute';
import MarketsPage from '@/pages/markets/Markets';
import PortfolioPage from '@/pages/portfolio/Portfolio';
import { AlertsPage } from '@/pages/AlertsPage';
import ProfilePage from '@/pages/Profile';
import { SettingsPage } from '@/pages/settings/Settings';
import TradePage from '@/pages/trade/Trade';
import { RewardsPage } from '@/pages/rewards/RewardsPage';
import { TermsOfUsePage } from '@/pages/TermsOfUsePage';
import { PrivacyPolicyPage } from '@/pages/PrivacyPolicyPage';
import { HeaderDesktop } from '@/layout/Header/HeaderDesktop';
import { FooterDesktop } from '@/layout/Footer/FooterDesktop';
import { FooterMobile } from '@/layout/Footer/FooterMobile';
@@ -46,11 +36,22 @@ import { config } from '@/lib/wagmi';
import { breakpoints } from '@/styles';
import { layoutMixins } from '@/styles/layoutMixins';
import { LoadingSpace } from './components/Loading/LoadingSpinner';
import '@/styles/constants.css';
import '@/styles/fonts.css';
import '@/styles/web3modal.css';
const MarketsPage = lazy(() => import('@/pages/markets/Markets'));
const PortfolioPage = lazy(() => import('@/pages/portfolio/Portfolio'));
const AlertsPage = lazy(() => import('@/pages/AlertsPage'));
const ProfilePage = lazy(() => import('@/pages/Profile'));
const SettingsPage = lazy(() => import('@/pages/settings/Settings'));
const TradePage = lazy(() => import('@/pages/trade/Trade'));
const RewardsPage = lazy(() => import('@/pages/rewards/RewardsPage'));
const TermsOfUsePage = lazy(() => import('@/pages/TermsOfUsePage'));
const PrivacyPolicyPage = lazy(() => import('@/pages/PrivacyPolicyPage'));
const queryClient = new QueryClient();
const Content = () => {
@@ -69,7 +70,7 @@ const Content = () => {
{isNotTablet && <HeaderDesktop />}
<Styled.Main>
<Suspense fallback={null}>
<Suspense fallback={<LoadingSpace id="main" />}>
<Routes>
<Route path={AppRoute.Trade}>
<Route path=":market" element={<TradePage />} />
+7 -5
View File
@@ -31,10 +31,12 @@ type ElementProps<TabItemsValue> = {
};
type StyleProps = {
fullWidthTabs?: boolean;
className?: string;
fullWidthTabs?: boolean;
};
export type CollapsibleTabsProps<TabItemsValue> = ElementProps<TabItemsValue> & StyleProps;
export const CollapsibleTabs = <TabItemsValue extends string>({
defaultValue,
items,
@@ -43,8 +45,9 @@ export const CollapsibleTabs = <TabItemsValue extends string>({
onOpenChange,
fullWidthTabs,
className,
}: ElementProps<TabItemsValue> & StyleProps) => {
}: CollapsibleTabsProps<TabItemsValue>) => {
const [value, setValue] = useState(defaultValue);
const currentItem = items.find((item) => item.value === value);
@@ -86,8 +89,8 @@ export const CollapsibleTabs = <TabItemsValue extends string>({
</Styled.Header>
<Styled.CollapsibleContent>
{items.map(({ value, content }) => (
<Styled.TabsContent key={value} value={value}>
{items.map(({ asChild, value, content }) => (
<Styled.TabsContent key={value} asChild={asChild} value={value}>
{content}
</Styled.TabsContent>
))}
@@ -219,7 +222,6 @@ Styled.Header = styled.header`
Styled.CollapsibleContent = styled(CollapsibleContent)`
${layoutMixins.stack}
${layoutMixins.perspectiveArea}
box-shadow: none;
`;
-1
View File
@@ -198,7 +198,6 @@ Styled.InputContainer = styled.div`
border-radius: inherit;
input {
user-select: all;
flex: 1;
width: 100%;
}
+5 -2
View File
@@ -21,6 +21,7 @@ export type TabItem<TabItemsValue> = {
content?: React.ReactNode;
subitems?: TabItem<TabItemsValue>[];
customTrigger?: ReactNode;
asChild?: boolean;
};
type ElementProps<TabItemsValue> = {
@@ -41,6 +42,8 @@ type StyleProps = {
className?: string;
};
export type TabsProps<TabItemsValue> = ElementProps<TabItemsValue> & StyleProps;
export const Tabs = <TabItemsValue extends string>({
defaultValue,
value,
@@ -107,9 +110,10 @@ export const Tabs = <TabItemsValue extends string>({
sharedContent
) : (
<Styled.Stack>
{items.map(({ value, content, forceMount }) => (
{items.map(({ asChild, value, content, forceMount }) => (
<Styled.Content
key={value}
asChild={asChild}
value={value}
forceMount={forceMount}
$hide={forceMount && currentItem?.value !== value}
@@ -242,7 +246,6 @@ Styled.Trigger = styled(Trigger)<{ $withBorders?: boolean }>`
Styled.Stack = styled.div`
${layoutMixins.stack}
${layoutMixins.perspectiveArea}
box-shadow: none;
`;
+28 -11
View File
@@ -5,16 +5,15 @@ import { useMatch, useNavigate } from 'react-router-dom';
import { LocalStorageKey } from '@/constants/localStorage';
import { DEFAULT_MARKETID } from '@/constants/markets';
import { AppRoute } from '@/constants/routes';
import { useLocalStorage } from '@/hooks/useLocalStorage';
import { getSelectedNetwork } from '@/state/appSelectors';
import { closeDialogInTradeBox } from '@/state/dialogs';
import { setCurrentMarketId } from '@/state/perpetuals';
import { getMarketIds } from '@/state/perpetualsSelectors';
import abacusStateManager from '@/lib/abacus';
import { useLocalStorage } from './useLocalStorage';
import { getMarketIds } from '@/state/perpetualsSelectors';
export const useCurrentMarketId = () => {
const navigate = useNavigate();
const match = useMatch(`/${AppRoute.Trade}/:marketId`);
@@ -33,17 +32,35 @@ export const useCurrentMarketId = () => {
if (marketIds.length === 0) return marketId ?? lastViewedMarket;
if (!marketIds.includes(marketId ?? lastViewedMarket)) return DEFAULT_MARKETID;
return marketId ?? lastViewedMarket;
}, [marketIds, marketId]);
}, [hasMarketIds, marketId]);
useEffect(() => {
setLastViewedMarket(validId);
dispatch(setCurrentMarketId(validId));
dispatch(closeDialogInTradeBox());
// If v4_markets has not been subscribed to yet or marketId is not specified, default to validId
if (!hasMarketIds || !marketId) {
setLastViewedMarket(validId);
dispatch(setCurrentMarketId(validId));
dispatch(closeDialogInTradeBox());
navigate(`${AppRoute.Trade}/${validId}`, {
replace: true,
});
}, [validId]);
if (validId !== marketId) {
navigate(`${AppRoute.Trade}/${validId}`, {
replace: true,
});
}
} else {
// If v4_markets has been subscribed to, check if marketId is valid
if (!marketIds.includes(marketId)) {
// If marketId is not valid (i.e. final settlement), navigate to markets page
navigate(AppRoute.Markets, {
replace: true,
});
} else {
// If marketId is valid, set currentMarketId
setLastViewedMarket(marketId);
dispatch(setCurrentMarketId(marketId));
dispatch(closeDialogInTradeBox());
}
}
}, [hasMarketIds, marketId]);
useEffect(() => {
// Check for marketIds otherwise Abacus will silently fail its isMarketValid check
+15 -6
View File
@@ -65,9 +65,13 @@ class DydxChainTransactions implements AbacusDYDXChainTransactionsProtocol {
}
setNobleWallet(nobleWallet: LocalWallet) {
this.nobleWallet = nobleWallet;
if (this.nobleClient) {
this.nobleClient.connect(nobleWallet);
try {
this.nobleWallet = nobleWallet;
if (this.nobleClient) {
this.nobleClient.connect(nobleWallet);
}
} catch (e) {
log('DydxChainTransactions/setNobleWallet', e);
}
}
@@ -114,10 +118,15 @@ class DydxChainTransactions implements AbacusDYDXChainTransactionsProtocol {
this.compositeClient = compositeClient;
if (nobleValidatorUrl) {
this.nobleClient = new NobleClient(nobleValidatorUrl);
if (this.nobleWallet) await this.nobleClient.connect(this.nobleWallet);
try {
if (nobleValidatorUrl) {
this.nobleClient = new NobleClient(nobleValidatorUrl);
if (this.nobleWallet) await this.nobleClient.connect(this.nobleWallet);
}
} catch (e) {
log('DydxChainTransactions/connectNetwork/NobleClient', e);
}
// Dispatch custom event to notify other parts of the app that the network has been connected
const customEvent = new CustomEvent('abacus:connectNetwork', {
detail: parsedParams,
+3 -1
View File
@@ -1,4 +1,6 @@
import { DialogPlacement } from '@/components/Dialog';
import { NotificationsMenu } from '@/views/menus/NotificationsMenu';
export const AlertsPage = () => <NotificationsMenu placement={DialogPlacement.Inline} />;
const AlertsPage = () => <NotificationsMenu placement={DialogPlacement.Inline} />;
export default AlertsPage;
+3 -1
View File
@@ -2,7 +2,7 @@ import styled, { AnyStyledComponent } from 'styled-components';
import { articleMixins } from '@/styles/articleMixins';
export const PrivacyPolicyPage = () => (
const PrivacyPolicyPage = () => (
<Styled.Article>
<header>
<h1>Privacy Policy</h1>
@@ -10,6 +10,8 @@ export const PrivacyPolicyPage = () => (
</Styled.Article>
);
export default PrivacyPolicyPage;
const Styled: Record<string, AnyStyledComponent> = {};
Styled.Article = styled.article`
+3 -1
View File
@@ -2,7 +2,7 @@ import styled, { AnyStyledComponent } from 'styled-components';
import { articleMixins } from '@/styles/articleMixins';
export const TermsOfUsePage = () => (
const TermsOfUsePage = () => (
<Styled.Article>
<header>
<h1>Sample Terms of Use</h1>
@@ -1076,6 +1076,8 @@ export const TermsOfUsePage = () => (
</Styled.Article>
);
export default TermsOfUsePage;
const Styled: Record<string, AnyStyledComponent> = {};
Styled.Article = styled.article`
+58 -53
View File
@@ -1,17 +1,20 @@
import { lazy, Suspense } from 'react';
import { shallowEqual, useDispatch, useSelector } from 'react-redux';
import styled, { type AnyStyledComponent } from 'styled-components';
import { Navigate, Route, Routes } from 'react-router-dom';
import { OnboardingState } from '@/constants/account';
import { ButtonAction } from '@/constants/buttons';
import { DialogTypes } from '@/constants/dialogs';
import { STRING_KEYS } from '@/constants/localization';
import { HistoryRoute, PortfolioRoute } from '@/constants/routes';
import { useAccountBalance, useBreakpoints, useDocumentTitle, useStringGetter } from '@/hooks';
import { layoutMixins } from '@/styles/layoutMixins';
import { FillsTable, FillsTableColumnKey } from '@/views/tables/FillsTable';
import { FundingPaymentsTable } from '@/views/tables/FundingPaymentsTable';
import { TransferHistoryTable } from '@/views/tables/TransferHistoryTable';
import { Button } from '@/components/Button';
import { Icon, IconName } from '@/components/Icon';
import { NavigationMenu } from '@/components/NavigationMenu';
import { WithSidebar } from '@/components/WithSidebar';
@@ -20,15 +23,15 @@ import { getOnboardingState, getSubaccount } from '@/state/accountSelectors';
import { openDialog } from '@/state/dialogs';
import { PortfolioNavMobile } from './PortfolioNavMobile';
import { Overview } from './Overview';
import { Positions } from './Positions';
import { Orders } from './Orders';
import { Fees } from './Fees';
import { History } from './History';
import { LoadingSpace } from '@/components/Loading/LoadingSpinner';
import { layoutMixins } from '@/styles/layoutMixins';
import { Button } from '@/components/Button';
import { ButtonAction } from '@/constants/buttons';
const Overview = lazy(() => import('./Overview').then((module) => ({ default: module.Overview })));
const Positions = lazy(() =>
import('./Positions').then((module) => ({ default: module.Positions }))
);
const Orders = lazy(() => import('./Orders').then((module) => ({ default: module.Orders })));
const Fees = lazy(() => import('./Fees').then((module) => ({ default: module.Fees })));
const History = lazy(() => import('./History').then((module) => ({ default: module.History })));
export default () => {
const dispatch = useDispatch();
@@ -44,49 +47,51 @@ export default () => {
useDocumentTitle(stringGetter({ key: STRING_KEYS.PORTFOLIO }));
const routesComponent = (
<Routes>
<Route path={PortfolioRoute.Overview} element={<Overview />} />
<Route path={PortfolioRoute.Positions} element={<Positions />} />
<Route path={PortfolioRoute.Orders} element={<Orders />} />
<Route path={PortfolioRoute.Fees} element={<Fees />} />
<Route path={PortfolioRoute.History} element={<History />}>
<Route index path="*" element={<Navigate to={HistoryRoute.Trades} />} />
<Route
path={HistoryRoute.Trades}
element={
<FillsTable
columnKeys={
isTablet
? [
FillsTableColumnKey.Time,
FillsTableColumnKey.TypeAmount,
FillsTableColumnKey.PriceFee,
]
: [
FillsTableColumnKey.Time,
FillsTableColumnKey.Market,
FillsTableColumnKey.Side,
FillsTableColumnKey.AmountPrice,
FillsTableColumnKey.TotalFee,
FillsTableColumnKey.Type,
FillsTableColumnKey.Liquidity,
]
}
withOuterBorder={isNotTablet}
/>
}
/>
<Route
path={HistoryRoute.Transfers}
element={<TransferHistoryTable withOuterBorder={isNotTablet} />}
/>
<Route
path={HistoryRoute.Payments}
element={<FundingPaymentsTable withOuterBorder={isNotTablet} />}
/>
</Route>
<Route path="*" element={<Navigate to={PortfolioRoute.Overview} replace />} />
</Routes>
<Suspense fallback={<LoadingSpace id="portfolio" />}>
<Routes>
<Route path={PortfolioRoute.Overview} element={<Overview />} />
<Route path={PortfolioRoute.Positions} element={<Positions />} />
<Route path={PortfolioRoute.Orders} element={<Orders />} />
<Route path={PortfolioRoute.Fees} element={<Fees />} />
<Route path={PortfolioRoute.History} element={<History />}>
<Route index path="*" element={<Navigate to={HistoryRoute.Trades} />} />
<Route
path={HistoryRoute.Trades}
element={
<FillsTable
columnKeys={
isTablet
? [
FillsTableColumnKey.Time,
FillsTableColumnKey.TypeAmount,
FillsTableColumnKey.PriceFee,
]
: [
FillsTableColumnKey.Time,
FillsTableColumnKey.Market,
FillsTableColumnKey.Side,
FillsTableColumnKey.AmountPrice,
FillsTableColumnKey.TotalFee,
FillsTableColumnKey.Type,
FillsTableColumnKey.Liquidity,
]
}
withOuterBorder={isNotTablet}
/>
}
/>
<Route
path={HistoryRoute.Transfers}
element={<TransferHistoryTable withOuterBorder={isNotTablet} />}
/>
<Route
path={HistoryRoute.Payments}
element={<FundingPaymentsTable withOuterBorder={isNotTablet} />}
/>
</Route>
<Route path="*" element={<Navigate to={PortfolioRoute.Overview} replace />} />
</Routes>
</Suspense>
);
return isTablet ? (
@@ -191,7 +196,7 @@ Styled.SideBar = styled.div`
Styled.Footer = styled.div`
${layoutMixins.row}
flex-wrap: wrap;
padding: 1rem;
gap: 0.5rem;
+3 -1
View File
@@ -21,7 +21,7 @@ import { DYDXBalancePanel } from './DYDXBalancePanel';
import { MigratePanel } from './MigratePanel';
import { LaunchIncentivesPanel } from './LaunchIncentivesPanel';
export const RewardsPage = () => {
const RewardsPage = () => {
const dispatch = useDispatch();
const stringGetter = useStringGetter();
const { governanceLearnMore, stakingLearnMore } = useURLConfigs();
@@ -84,6 +84,8 @@ export const RewardsPage = () => {
);
};
export default RewardsPage;
const Styled: Record<string, AnyStyledComponent> = {};
Styled.Page = styled.div`
+3 -1
View File
@@ -25,7 +25,7 @@ import { useNetworks } from '@/views/menus/useNetworks';
import { SettingsHeader } from './SettingsHeader';
import { ComingSoonSpace } from '@/components/ComingSoon';
export const SettingsPage = () => {
const SettingsPage = () => {
const stringGetter = useStringGetter();
const { pathname } = useLocation();
const dispatch = useDispatch();
@@ -105,3 +105,5 @@ export const SettingsPage = () => {
</>
);
};
export default SettingsPage;
+131 -116
View File
@@ -1,8 +1,7 @@
import { useState } from 'react';
import { useMemo, useState } from 'react';
import { shallowEqual, useSelector } from 'react-redux';
import styled, { type AnyStyledComponent } from 'styled-components';
import { AbacusOrderStatus } from '@/constants/abacus';
import { STRING_KEYS } from '@/constants/localization';
import { useBreakpoints, useStringGetter } from '@/hooks';
@@ -28,7 +27,6 @@ import {
getCurrentMarketTradeInfoNumbers,
getHasUnseenFillUpdates,
getHasUnseenOrderUpdates,
getLatestOrderStatus,
getTradeInfoNumbers,
} from '@/state/accountSelectors';
@@ -82,125 +80,142 @@ export const HorizontalPanel = ({ isOpen = true, setIsOpen }: ElementProps) => {
showCurrentMarket ? numOpenOrders : numTotalOpenOrders
);
const tabItems = [
{
value: InfoSection.Position,
label: stringGetter({
key: showCurrentMarket ? STRING_KEYS.POSITION : STRING_KEYS.POSITIONS,
}),
const tabItems = useMemo(
() => [
{
asChild: true,
value: InfoSection.Position,
label: stringGetter({
key: showCurrentMarket ? STRING_KEYS.POSITION : STRING_KEYS.POSITIONS,
}),
tag: showCurrentMarket ? null : shortenNumberForDisplay(numTotalPositions),
tag: showCurrentMarket ? null : shortenNumberForDisplay(numTotalPositions),
content: showCurrentMarket ? (
<PositionInfo showNarrowVariation={isTablet} />
) : (
<PositionsTable
columnKeys={
isTablet
? [
PositionsTableColumnKey.Details,
PositionsTableColumnKey.IndexEntry,
PositionsTableColumnKey.PnL,
]
: [
PositionsTableColumnKey.Market,
PositionsTableColumnKey.Side,
PositionsTableColumnKey.Size,
PositionsTableColumnKey.Leverage,
PositionsTableColumnKey.LiquidationAndOraclePrice,
PositionsTableColumnKey.UnrealizedPnl,
PositionsTableColumnKey.RealizedPnl,
PositionsTableColumnKey.AverageOpenAndClose,
]
}
onNavigate={() => setView(PanelView.CurrentMarket)}
/>
),
},
{
value: InfoSection.Orders,
label: stringGetter({ key: STRING_KEYS.ORDERS }),
content: showCurrentMarket ? (
<PositionInfo showNarrowVariation={isTablet} />
) : (
<PositionsTable
columnKeys={
isTablet
? [
PositionsTableColumnKey.Details,
PositionsTableColumnKey.IndexEntry,
PositionsTableColumnKey.PnL,
]
: [
PositionsTableColumnKey.Market,
PositionsTableColumnKey.Side,
PositionsTableColumnKey.Size,
PositionsTableColumnKey.Leverage,
PositionsTableColumnKey.LiquidationAndOraclePrice,
PositionsTableColumnKey.UnrealizedPnl,
PositionsTableColumnKey.RealizedPnl,
PositionsTableColumnKey.AverageOpenAndClose,
]
}
onNavigate={() => setView(PanelView.CurrentMarket)}
/>
),
},
{
asChild: true,
value: InfoSection.Orders,
label: stringGetter({ key: STRING_KEYS.ORDERS }),
slotRight: isWaitingForOrderToIndex ? (
<Styled.LoadingSpinner />
) : (
ordersTagNumber && (
<Tag type={TagType.Number} isHighlighted={hasUnseenOrderUpdates}>
{ordersTagNumber}
slotRight: isWaitingForOrderToIndex ? (
<Styled.LoadingSpinner />
) : (
ordersTagNumber && (
<Tag type={TagType.Number} isHighlighted={hasUnseenOrderUpdates}>
{ordersTagNumber}
</Tag>
)
),
content: (
<OrdersTable
currentMarket={showCurrentMarket ? currentMarketId : undefined}
columnKeys={
isTablet
? [OrdersTableColumnKey.StatusFill, OrdersTableColumnKey.PriceType]
: [
!showCurrentMarket && OrdersTableColumnKey.Market,
OrdersTableColumnKey.Status,
OrdersTableColumnKey.Side,
OrdersTableColumnKey.AmountFill,
OrdersTableColumnKey.Price,
OrdersTableColumnKey.Trigger,
OrdersTableColumnKey.GoodTil,
!isAccountViewOnly && OrdersTableColumnKey.Actions,
].filter(isTruthy)
}
/>
),
},
{
asChild: true,
value: InfoSection.Fills,
label: stringGetter({ key: STRING_KEYS.FILLS }),
slotRight: fillsTagNumber && (
<Tag type={TagType.Number} isHighlighted={hasUnseenFillUpdates}>
{fillsTagNumber}
</Tag>
)
),
),
content: (
<OrdersTable
currentMarket={showCurrentMarket ? currentMarketId : undefined}
columnKeys={
isTablet
? [OrdersTableColumnKey.StatusFill, OrdersTableColumnKey.PriceType]
: [
!showCurrentMarket && OrdersTableColumnKey.Market,
OrdersTableColumnKey.Status,
OrdersTableColumnKey.Side,
OrdersTableColumnKey.AmountFill,
OrdersTableColumnKey.Price,
OrdersTableColumnKey.Trigger,
OrdersTableColumnKey.GoodTil,
!isAccountViewOnly && OrdersTableColumnKey.Actions,
].filter(isTruthy)
}
/>
),
},
{
value: InfoSection.Fills,
label: stringGetter({ key: STRING_KEYS.FILLS }),
content: (
<FillsTable
currentMarket={showCurrentMarket ? currentMarketId : undefined}
columnKeys={
isTablet
? [
FillsTableColumnKey.Time,
FillsTableColumnKey.TypeAmount,
FillsTableColumnKey.PriceFee,
]
: [
!showCurrentMarket && FillsTableColumnKey.Market,
FillsTableColumnKey.Time,
FillsTableColumnKey.Type,
FillsTableColumnKey.Side,
FillsTableColumnKey.AmountTag,
FillsTableColumnKey.Price,
FillsTableColumnKey.TotalFee,
FillsTableColumnKey.Liquidity,
].filter(isTruthy)
}
columnWidths={{
[FillsTableColumnKey.TypeAmount]: '100%',
}}
/>
),
},
// TODO - TRCL-1693 - re-enable when funding payments are supported
// {
// value: InfoSection.Payments,
// label: stringGetter({ key: STRING_KEYS.PAYMENTS }),
slotRight: fillsTagNumber && (
<Tag type={TagType.Number} isHighlighted={hasUnseenFillUpdates}>
{fillsTagNumber}
</Tag>
),
content: (
<FillsTable
currentMarket={showCurrentMarket ? currentMarketId : undefined}
columnKeys={
isTablet
? [
FillsTableColumnKey.Time,
FillsTableColumnKey.TypeAmount,
FillsTableColumnKey.PriceFee,
]
: [
!showCurrentMarket && FillsTableColumnKey.Market,
FillsTableColumnKey.Time,
FillsTableColumnKey.Type,
FillsTableColumnKey.Side,
FillsTableColumnKey.AmountTag,
FillsTableColumnKey.Price,
FillsTableColumnKey.TotalFee,
FillsTableColumnKey.Liquidity,
].filter(isTruthy)
}
columnWidths={{
[FillsTableColumnKey.TypeAmount]: '100%',
}}
/>
),
},
// TODO - TRCL-1693 - re-enable when funding payments are supported
// {
// value: InfoSection.Payments,
// label: stringGetter({ key: STRING_KEYS.PAYMENTS }),
// tag: shortenNumberForDisplay(
// showCurrentMarket ? numFundingPayments : numTotalFundingPayments
// ),
// content: (
// <FundingPaymentsTable currentMarket={showCurrentMarket ? currentMarket?.id : undefined} />
// ),
// },
];
// tag: shortenNumberForDisplay(
// showCurrentMarket ? numFundingPayments : numTotalFundingPayments
// ),
// content: (
// <FundingPaymentsTable currentMarket={showCurrentMarket ? currentMarket?.id : undefined} />
// ),
// },
],
[
stringGetter,
currentMarketId,
showCurrentMarket,
isTablet,
isWaitingForOrderToIndex,
isAccountViewOnly,
ordersTagNumber,
fillsTagNumber,
hasUnseenFillUpdates,
hasUnseenOrderUpdates,
]
);
return isTablet ? (
<MobileTabs defaultValue={InfoSection.Position} items={tabItems} withBorders={false} />
-5
View File
@@ -877,11 +877,6 @@ export const layoutMixins: Record<
}
`,
perspectiveArea: css`
perspective: 100rem;
transform-style: preserve-3d;
`,
absolute: css`
position: absolute;
top: 0;
-1
View File
@@ -63,7 +63,6 @@ Styled.AccountInfoSectionContainer = styled.div<{ showAccountInfo?: boolean }>`
${layoutMixins.column}
height: var(--account-info-section-height);
min-height: var(--account-info-section-height);
overflow-x: clip;
${({ showAccountInfo }) =>
!showAccountInfo &&
@@ -203,7 +203,6 @@ const Styled: Record<string, AnyStyledComponent> = {};
Styled.Stack = styled.div`
${layoutMixins.stack}
${layoutMixins.perspectiveArea}
`;
Styled.CornerButton = styled(Button)`
@@ -293,7 +292,14 @@ Styled.TransferButtons = styled.div`
Styled.ConnectedAccountInfoContainer = styled.div<{ $showHeader?: boolean }>`
${layoutMixins.column}
${layoutMixins.withOuterAndInnerBorders}
@media ${breakpoints.notTablet} {
${layoutMixins.withOuterAndInnerBorders}
}
@media ${breakpoints.tablet} {
${layoutMixins.withInnerBorder}
}
${({ $showHeader }) =>
$showHeader &&
-5
View File
@@ -213,13 +213,8 @@ Styled.MarketDetails = styled.div`
`;
Styled.Header = styled.header`
/* max-width: fit-content; */
${layoutMixins.column}
gap: 1.25rem;
position: sticky;
bottom: 3rem;
`;
Styled.WrapRow = styled.div`
+1 -7
View File
@@ -453,13 +453,6 @@ Styled.Actions = styled.footer`
> :last-child {
flex: 2;
}
position: sticky;
bottom: clamp(0.5rem, 7.5%, 2rem);
@media ${breakpoints.tablet} {
bottom: 0;
}
`;
Styled.Output = styled(Output)<{ sign: NumberSign; smallText?: boolean; margin?: string }>`
@@ -514,6 +507,7 @@ Styled.PositionInfo = styled.div`
Styled.DetachedSection = styled(DetachedSection)`
padding: 0 1.5rem;
position: relative;
`;
Styled.DetachedScrollableSection = styled(DetachedScrollableSection)`
-1
View File
@@ -82,7 +82,6 @@ const Styled: Record<string, AnyStyledComponent> = {};
Styled.PriceChart = styled.div<{ isChartReady?: boolean }>`
${layoutMixins.stack}
${layoutMixins.perspectiveArea}
height: 100%;
@@ -165,7 +165,7 @@ export const DepositButtonAndReceipt = ({
},
{
key: 'slippage',
label: <span>{stringGetter({ key: STRING_KEYS.SLIPPAGE })}</span>,
label: <span>{stringGetter({ key: STRING_KEYS.MAX_SLIPPAGE })}</span>,
value: (
<SlippageEditor
disabled
@@ -57,7 +57,6 @@ export const TokenSelectMenu = ({ selectedToken, onSelectToken }: ElementProps)
<Tag>{type === TransferType.deposit ? 'USDC' : selectedToken?.symbol}</Tag>
</>
),
tooltip: 'swap',
},
]}
>
@@ -89,7 +89,7 @@ export const WithdrawButtonAndReceipt = ({
const showSubitemsToggle = showFeeBreakdown
? stringGetter({ key: STRING_KEYS.HIDE_ALL_DETAILS })
: stringGetter({ key: STRING_KEYS.SHOW_ALL_DETAILS });
const totalFees = (summary?.bridgeFee || 0) + (summary?.gasFee || 0);
const submitButtonReceipt = [
@@ -99,11 +99,56 @@ export const WithdrawButtonAndReceipt = ({
value: <Output type={OutputType.Fiat} value={totalFees} />,
subitems: feeSubitems,
},
{
key: 'slippage',
label: <span>{stringGetter({ key: STRING_KEYS.MAX_SLIPPAGE })}</span>,
value: (
<SlippageEditor
disabled
slippage={slippage}
setIsEditing={setIsEditingSlipapge}
setSlippage={setSlippage}
/>
),
},
{
key: 'exchange-rate',
label: <span>{stringGetter({ key: STRING_KEYS.EXCHANGE_RATE })}</span>,
value: withdrawToken && typeof summary?.exchangeRate === 'number' && (
<Styled.ExchangeRate>
<Output type={OutputType.Asset} value={1} fractionDigits={0} tag="USDC" />
=
<Output
type={OutputType.Asset}
value={summary?.exchangeRate}
tag={withdrawToken?.symbol}
/>
</Styled.ExchangeRate>
),
},
{
key: 'estimatedRouteDuration',
label: <span>{stringGetter({ key: STRING_KEYS.ESTIMATED_TIME })}</span>,
value: typeof summary?.estimatedRouteDuration === 'number' && (
<Output
type={OutputType.Text}
value={stringGetter({
key: STRING_KEYS.X_MINUTES_LOWERCASED,
params: {
X:
summary?.estimatedRouteDuration < 60
? '< 1'
: Math.round(summary?.estimatedRouteDuration / 60),
},
})}
/>
),
},
{
key: 'wallet',
label: (
<span>
{stringGetter({ key: STRING_KEYS.AMOUNT_RECEIVED })}{' '}
{stringGetter({ key: STRING_KEYS.MINIMUM_AMOUNT_RECEIVED })}{' '}
{withdrawToken && <Tag>{withdrawToken?.symbol}</Tag>}
</span>
),
@@ -130,51 +175,6 @@ export const WithdrawButtonAndReceipt = ({
/>
),
},
{
key: 'exchange-rate',
label: <span>{stringGetter({ key: STRING_KEYS.EXCHANGE_RATE })}</span>,
value: withdrawToken && typeof summary?.exchangeRate === 'number' && (
<Styled.ExchangeRate>
<Output type={OutputType.Asset} value={1} fractionDigits={0} tag="USDC" />
=
<Output
type={OutputType.Asset}
value={summary?.exchangeRate}
tag={withdrawToken?.symbol}
/>
</Styled.ExchangeRate>
),
},
{
key: 'slippage',
label: <span>{stringGetter({ key: STRING_KEYS.SLIPPAGE })}</span>,
value: (
<SlippageEditor
disabled
slippage={slippage}
setIsEditing={setIsEditingSlipapge}
setSlippage={setSlippage}
/>
),
},
{
key: 'estimatedRouteDuration',
label: <span>{stringGetter({ key: STRING_KEYS.ESTIMATED_TIME })}</span>,
value: typeof summary?.estimatedRouteDuration === 'number' && (
<Output
type={OutputType.Text}
value={stringGetter({
key: STRING_KEYS.X_MINUTES_LOWERCASED,
params: {
X:
summary?.estimatedRouteDuration < 60
? '< 1'
: Math.round(summary?.estimatedRouteDuration / 60),
},
})}
/>
),
},
];
const isFormValid = !isDisabled && !isEditingSlippage;
+2 -11
View File
@@ -230,14 +230,7 @@ const getOrdersTableColumnDef = ({
label: `${stringGetter({ key: STRING_KEYS.STATUS })} / ${stringGetter({
key: STRING_KEYS.FILL,
})}`,
renderCell: ({
asset,
createdAtMilliseconds,
size,
status,
totalFilled,
resources,
}) => {
renderCell: ({ asset, createdAtMilliseconds, size, status, totalFilled, resources }) => {
const { statusIconColor, statusStringKey } = getStatusIconInfo({
status,
totalFilled,
@@ -345,9 +338,7 @@ export const OrdersTable = ({
if (hasUnseenOrderUpdates) dispatch(viewedOrders());
}, [hasUnseenOrderUpdates]);
const symbol = currentMarket
? allAssets[allPerpetualMarkets[currentMarket]?.assetId]?.symbol
: null;
const symbol = currentMarket ? allAssets[allPerpetualMarkets[currentMarket]?.assetId]?.id : null;
const ordersData = orders.map((order: SubaccountOrder) =>
getHydratedTradingData({