Compare commits

..
Author SHA1 Message Date
Aleka Cheung 24de450ff2 add faucet url 2024-01-24 15:24:15 -05:00
Aleka Cheung 7da64c2183 fix http->https in validator v4dev4 url 2024-01-24 15:00:01 -05:00
aleka cd30c9c7d9 add collapsible table (#231)
* add collapsible table

* update to add a TR inside table instead
2024-01-24 12:26:32 -05:00
aleka 414e38afec Delay wagmi connection if remember me is enabled (#210)
* connect wagmi on deposit if remember me

* use alert message instead of button message

* clear input state when closing transfers forms to renable trade place order button
2024-01-23 13:45:14 -05:00
Bill e93850484b CCTP deposit/withdraw to throw error if nobleClient is not initialized (#215)
* CCTP deposit/withdraw to throw error if nobleClient is not initialized

* update error str
2024-01-22 09:55:26 -08:00
25 changed files with 226 additions and 2963 deletions
-1
View File
@@ -1 +0,0 @@
if('serviceWorker' in navigator) navigator.serviceWorker.register('/dev-sw.js?dev-sw', { scope: '/', type: 'classic' })
-3
View File
@@ -44,8 +44,6 @@
"@dydxprotocol/v4-localization": "^1.1.11", "@dydxprotocol/v4-localization": "^1.1.11",
"@ethersproject/providers": "^5.7.2", "@ethersproject/providers": "^5.7.2",
"@js-joda/core": "^5.5.3", "@js-joda/core": "^5.5.3",
"@privy-io/react-auth": "^1.53.1",
"@privy-io/wagmi-connector": "^0.1.12",
"@radix-ui/react-accordion": "^1.1.2", "@radix-ui/react-accordion": "^1.1.2",
"@radix-ui/react-checkbox": "^1.0.4", "@radix-ui/react-checkbox": "^1.0.4",
"@radix-ui/react-collapsible": "^1.0.3", "@radix-ui/react-collapsible": "^1.0.3",
@@ -153,7 +151,6 @@
"url-polyfill": "^1.1.12", "url-polyfill": "^1.1.12",
"util": "^0.12.5", "util": "^0.12.5",
"vite": "^4.3.9", "vite": "^4.3.9",
"vite-plugin-pwa": "^0.17.4",
"vite-plugin-svgr": "^3.2.0", "vite-plugin-svgr": "^3.2.0",
"vitest": "^0.32.2", "vitest": "^0.32.2",
"w3name": "^1.0.8", "w3name": "^1.0.8",
+46 -2708
View File
File diff suppressed because it is too large Load Diff
+4 -3
View File
@@ -215,10 +215,11 @@
} }
], ],
"validators": [ "validators": [
"http://validator.v4dev4.dydx.exchange" "https://validator.v4dev4.dydx.exchange"
], ],
"0xsquid": "https://testnet.api.0xsquid.com", "0xsquid": "https://testnet.api.0xsquid.com",
"nobleValidator": "https://noble-testnet-rpc.polkachu.com/" "nobleValidator": "https://noble-testnet-rpc.polkachu.com/",
"faucet": "https://faucet.v4dev4.dydx.exchange"
}, },
"links": { "links": {
"tos": "https://dydx.exchange/v4-terms", "tos": "https://dydx.exchange/v4-terms",
@@ -473,7 +474,7 @@
"apps": { "apps": {
"ios": { "ios": {
"minimalVersion": "1.0", "minimalVersion": "1.0",
"build":40000, "build": 40000,
"url": "https://apps.apple.com/app/dydx/id1564787350" "url": "https://apps.apple.com/app/dydx/id1564787350"
} }
} }
+1 -8
View File
@@ -2,8 +2,6 @@ import { lazy, Suspense } from 'react';
import { Navigate, Route, Routes } from 'react-router-dom'; import { Navigate, Route, Routes } from 'react-router-dom';
import styled, { AnyStyledComponent, css } from 'styled-components'; import styled, { AnyStyledComponent, css } from 'styled-components';
import { WagmiConfig } from 'wagmi'; import { WagmiConfig } from 'wagmi';
import { PrivyProvider } from '@privy-io/react-auth';
import { PrivyWagmiConnector } from '@privy-io/wagmi-connector';
import { QueryClient, QueryClientProvider } from 'react-query'; import { QueryClient, QueryClientProvider } from 'react-query';
import { GrazProvider } from 'graz'; import { GrazProvider } from 'graz';
@@ -34,7 +32,7 @@ import { NotificationsToastArea } from '@/layout/NotificationsToastArea';
import { DialogManager } from '@/layout/DialogManager'; import { DialogManager } from '@/layout/DialogManager';
import { GlobalCommandDialog } from '@/views/dialogs/GlobalCommandDialog'; import { GlobalCommandDialog } from '@/views/dialogs/GlobalCommandDialog';
import { config, privyConfig } from '@/lib/wagmi'; import { config } from '@/lib/wagmi';
import { breakpoints } from '@/styles'; import { breakpoints } from '@/styles';
import { layoutMixins } from '@/styles/layoutMixins'; import { layoutMixins } from '@/styles/layoutMixins';
@@ -122,13 +120,8 @@ const wrapProvider = (Component: React.ComponentType<any>, props?: any) => {
}; };
const providers = [ const providers = [
wrapProvider(PrivyProvider, {
appId: import.meta.env.VITE_PRIVY_APP_ID,
config: privyConfig,
}),
wrapProvider(QueryClientProvider, { client: queryClient }), wrapProvider(QueryClientProvider, { client: queryClient }),
wrapProvider(GrazProvider), wrapProvider(GrazProvider),
wrapProvider(PrivyWagmiConnector, { wagmiChainsConfig: config }),
wrapProvider(WagmiConfig, { config }), wrapProvider(WagmiConfig, { config }),
wrapProvider(LocaleProvider), wrapProvider(LocaleProvider),
wrapProvider(RestrictionProvider), wrapProvider(RestrictionProvider),
-1
View File
@@ -11,6 +11,5 @@ export const DetachedScrollableSection = styled.section`
export const AttachedExpandingSection = styled.section` export const AttachedExpandingSection = styled.section`
${layoutMixins.contentSectionAttached} ${layoutMixins.contentSectionAttached}
${layoutMixins.expandingColumnWithHeader}
gap: var(--border-width); gap: var(--border-width);
`; `;
+70 -9
View File
@@ -33,17 +33,20 @@ import {
import { useAsyncList } from 'react-stately'; import { useAsyncList } from 'react-stately';
import { useBreakpoints } from '@/hooks'; import { useBreakpoints, useStringGetter } from '@/hooks';
import { MediaQueryKeys } from '@/hooks/useBreakpoints'; import { MediaQueryKeys } from '@/hooks/useBreakpoints';
import { Checkbox } from '@/components/Checkbox';
import { breakpoints } from '@/styles'; import { breakpoints } from '@/styles';
import { layoutMixins } from '@/styles/layoutMixins'; import { layoutMixins } from '@/styles/layoutMixins';
import { CaretIcon } from '@/icons';
import { STRING_KEYS } from '@/constants/localization';
import { MustBigNumber } from '@/lib/numbers';
import { Icon, IconName } from './Icon'; import { Icon, IconName } from './Icon';
import { Tag } from './Tag'; import { Tag } from './Tag';
import { MustBigNumber } from '@/lib/numbers'; import { Button } from './Button';
export { TableCell } from './Table/TableCell'; export { TableCell } from './Table/TableCell';
export { TableColumnHeader } from './Table/TableColumnHeader'; export { TableColumnHeader } from './Table/TableColumnHeader';
@@ -65,7 +68,7 @@ export type TableItem<TableRowData> = {
onSelect?: (key: TableRowData) => void; onSelect?: (key: TableRowData) => void;
}; };
export type ColumnDef<TableRowData extends object> = { type ColumnDef<TableRowData extends object> = {
columnKey: string; columnKey: string;
label: React.ReactNode; label: React.ReactNode;
tag?: React.ReactNode; tag?: React.ReactNode;
@@ -80,7 +83,7 @@ export type ColumnDef<TableRowData extends object> = {
width?: ColumnSize; width?: ColumnSize;
}; };
type ElementProps<TableRowData extends object | CustomRowConfig, TableRowKey extends Key> = { export type ElementProps<TableRowData extends object | CustomRowConfig, TableRowKey extends Key> = {
label?: string; label?: string;
columns: ColumnDef<TableRowData>[]; columns: ColumnDef<TableRowData>[];
data: TableRowData[]; data: TableRowData[];
@@ -92,6 +95,7 @@ type ElementProps<TableRowData extends object | CustomRowConfig, TableRowKey ext
selectionBehavior?: 'replace' | 'toggle'; selectionBehavior?: 'replace' | 'toggle';
onRowAction?: (key: TableRowKey, row: TableRowData) => void; onRowAction?: (key: TableRowKey, row: TableRowData) => void;
slotEmpty?: React.ReactNode; slotEmpty?: React.ReactNode;
initialNumRowsToShow?: number;
// collection: TableCollection<string>; // collection: TableCollection<string>;
// children: React.ReactNode; // children: React.ReactNode;
}; };
@@ -121,6 +125,7 @@ export const Table = <TableRowData extends object, TableRowKey extends Key>({
selectionMode = 'single', selectionMode = 'single',
selectionBehavior = 'toggle', selectionBehavior = 'toggle',
slotEmpty, slotEmpty,
initialNumRowsToShow = data.length,
// shouldRowRender, // shouldRowRender,
// collection, // collection,
@@ -136,6 +141,7 @@ export const Table = <TableRowData extends object, TableRowKey extends Key>({
style, style,
}: ElementProps<TableRowData, TableRowKey> & StyleProps) => { }: ElementProps<TableRowData, TableRowKey> & StyleProps) => {
const [selectedKeys, setSelectedKeys] = useState(new Set<TableRowKey>()); const [selectedKeys, setSelectedKeys] = useState(new Set<TableRowKey>());
const [numRowsToShow, setNumRowsToShow] = useState(initialNumRowsToShow);
const currentBreakpoints = useBreakpoints(); const currentBreakpoints = useBreakpoints();
const shownColumns = columns.filter( const shownColumns = columns.filter(
@@ -209,6 +215,12 @@ export const Table = <TableRowData extends object, TableRowKey extends Key>({
onRowAction && onRowAction &&
((key: TableRowKey) => onRowAction(key, data.find((row) => getRowKey(row) === key)!)) ((key: TableRowKey) => onRowAction(key, data.find((row) => getRowKey(row) === key)!))
} }
numColumns={shownColumns.length}
onViewMoreClick={
numRowsToShow !== undefined && numRowsToShow < data.length
? () => setNumRowsToShow(data.length)
: undefined
}
// shouldRowRender={shouldRowRender} // shouldRowRender={shouldRowRender}
hideHeader={hideHeader} hideHeader={hideHeader}
withGradientCardRows={withGradientCardRows} withGradientCardRows={withGradientCardRows}
@@ -233,7 +245,7 @@ export const Table = <TableRowData extends object, TableRowKey extends Key>({
)} )}
</TableHeader> </TableHeader>
<TableBody items={list.items}> <TableBody items={list.items.slice(0, numRowsToShow)}>
{(item) => ( {(item) => (
<Row key={getRowKey(item)}> <Row key={getRowKey(item)}>
{(columnKey) => ( {(columnKey) => (
@@ -267,6 +279,8 @@ const TableRoot = <TableRowData extends object | CustomRowConfig, TableRowKey ex
onRowAction?: (key: TableRowKey) => void; onRowAction?: (key: TableRowKey) => void;
// shouldRowRender?: (prevRowData: object, currentRowData: object) => boolean; // shouldRowRender?: (prevRowData: object, currentRowData: object) => boolean;
children: CollectionChildren<TableRowData>; children: CollectionChildren<TableRowData>;
numColumns: number;
onViewMoreClick?: () => void;
hideHeader?: boolean; hideHeader?: boolean;
withGradientCardRows?: boolean; withGradientCardRows?: boolean;
@@ -276,7 +290,7 @@ const TableRoot = <TableRowData extends object | CustomRowConfig, TableRowKey ex
withScrollSnapColumns?: boolean; withScrollSnapColumns?: boolean;
withScrollSnapRows?: boolean; withScrollSnapRows?: boolean;
}) => { }) => {
const { selectionMode, selectionBehavior } = props; const { selectionMode, selectionBehavior, numColumns, onViewMoreClick } = props;
const state = useTableState<TableRowData>({ const state = useTableState<TableRowData>({
...props, ...props,
@@ -337,6 +351,7 @@ const TableRoot = <TableRowData extends object | CustomRowConfig, TableRowKey ex
<TableBodyRowGroup <TableBodyRowGroup
withGradientCardRows={props.withGradientCardRows} withGradientCardRows={props.withGradientCardRows}
withInnerBorders={props.withInnerBorders} withInnerBorders={props.withInnerBorders}
withOuterBorder={props.withOuterBorder}
> >
{/* {Array.from(collection.getChildren!(collection.body.key), (row) => */} {/* {Array.from(collection.getChildren!(collection.body.key), (row) => */}
{[...collection.body.childNodes].map((row) => {[...collection.body.childNodes].map((row) =>
@@ -382,6 +397,9 @@ const TableRoot = <TableRowData extends object | CustomRowConfig, TableRowKey ex
</TableRow> </TableRow>
) )
)} )}
{onViewMoreClick ? (
<ViewMoreRow colSpan={numColumns} onClick={onViewMoreClick} />
) : undefined}
</TableBodyRowGroup> </TableBodyRowGroup>
</Styled.Table> </Styled.Table>
); );
@@ -415,6 +433,7 @@ const TableBodyRowGroup = ({
children, children,
withGradientCardRows, withGradientCardRows,
withInnerBorders, withInnerBorders,
withOuterBorder,
}: { children: React.ReactNode } & StyleProps) => { }: { children: React.ReactNode } & StyleProps) => {
const { rowGroupProps } = useTableRowGroup(); const { rowGroupProps } = useTableRowGroup();
@@ -423,6 +442,7 @@ const TableBodyRowGroup = ({
{...rowGroupProps} {...rowGroupProps}
withGradientCardRows={withGradientCardRows} withGradientCardRows={withGradientCardRows}
withInnerBorders={withInnerBorders} withInnerBorders={withInnerBorders}
withOuterBorder={withOuterBorder}
> >
{children} {children}
</Styled.Tbody> </Styled.Tbody>
@@ -489,6 +509,23 @@ const TableColumnHeader = <TableRowData extends object>({
); );
}; };
export const ViewMoreRow = ({ colSpan, onClick }: { colSpan: number; onClick: () => void }) => {
const stringGetter = useStringGetter();
return (
<Styled.Tr key="viewmore">
<Styled.Td
colSpan={colSpan}
onMouseDown={(e: MouseEvent) => e.preventDefault()}
onPointerDown={(e: MouseEvent) => e.preventDefault()}
>
<Styled.ViewMoreButton slotRight={<CaretIcon />} onClick={onClick}>
{stringGetter({ key: STRING_KEYS.VIEW_MORE })}
</Styled.ViewMoreButton>
</Styled.Td>
</Styled.Tr>
);
};
export const TableRow = <TableRowData extends object>({ export const TableRow = <TableRowData extends object>({
item, item,
children, children,
@@ -660,7 +697,7 @@ Styled.Empty = styled.div<{ withOuterBorder: boolean }>`
justify-items: center; justify-items: center;
align-content: center; align-content: center;
padding: 2rem; padding: 4rem;
gap: 0.75em; gap: 0.75em;
color: var(--color-text-0); color: var(--color-text-0);
@@ -868,6 +905,18 @@ Styled.Tbody = styled.tbody<StyleProps>`
--stickyArea2-paddingLeft: var(--border-width); --stickyArea2-paddingLeft: var(--border-width);
--stickyArea2-paddingRight: var(--border-width); --stickyArea2-paddingRight: var(--border-width);
tr:first-of-type {
box-shadow: 0 calc(var(--border-width)) 0 0 var(--border-color);
}
`}
${({ withOuterBorder }) =>
withOuterBorder &&
css`
tr:last-of-type:not(:only-of-type) {
box-shadow: 0 calc(-1 * var(--border-width)) 0 0 var(--border-color);
}
tr:first-of-type { tr:first-of-type {
box-shadow: none; box-shadow: none;
} }
@@ -922,3 +971,15 @@ Styled.Row = styled.div`
${layoutMixins.inlineRow} ${layoutMixins.inlineRow}
padding: var(--tableCell-padding); padding: var(--tableCell-padding);
`; `;
Styled.ViewMoreButton = styled(Button)`
--button-backgroundColor: var(--color-layer-2);
--button-textColor: var(--color-text-1);
width: 100%;
svg {
width: 0.675rem;
margin-left: 0.5ch;
}
`;
-11
View File
@@ -31,7 +31,6 @@ import { DydxNetwork, ENVIRONMENT_CONFIG_MAP } from './networks';
export enum WalletConnectionType { export enum WalletConnectionType {
CoinbaseWalletSdk = 'coinbaseWalletSdk', CoinbaseWalletSdk = 'coinbaseWalletSdk',
CosmosSigner = 'CosmosSigner', CosmosSigner = 'CosmosSigner',
Privy = 'Privy',
InjectedEip1193 = 'injectedEip1193', InjectedEip1193 = 'injectedEip1193',
WalletConnect2 = 'walletConnect2', WalletConnect2 = 'walletConnect2',
} }
@@ -69,9 +68,6 @@ export const walletConnectionTypes: Record<WalletConnectionType, WalletConnectio
[WalletConnectionType.CosmosSigner]: { [WalletConnectionType.CosmosSigner]: {
name: 'CosmosSigner', name: 'CosmosSigner',
}, },
[WalletConnectionType.Privy]: {
name: 'Privy',
},
}; };
// Wallets // Wallets
@@ -94,7 +90,6 @@ export enum WalletType {
WalletConnect2 = 'WALLETCONNECT_2', WalletConnect2 = 'WALLETCONNECT_2',
// TestWallet = 'TEST_WALLET', // TestWallet = 'TEST_WALLET',
OtherWallet = 'OTHER_WALLET', OtherWallet = 'OTHER_WALLET',
Privy = 'PRIVY',
} }
const WALLET_CONNECT_EXPLORER_RECOMMENDED_WALLETS = { const WALLET_CONNECT_EXPLORER_RECOMMENDED_WALLETS = {
@@ -248,12 +243,6 @@ export const wallets: Record<WalletType, WalletConfig> = {
icon: KeplrIcon, icon: KeplrIcon,
connectionTypes: [WalletConnectionType.CosmosSigner], connectionTypes: [WalletConnectionType.CosmosSigner],
}, },
[WalletType.Privy]: {
type: WalletType.Privy,
stringKey: STRING_KEYS.KEPLR,
icon: GenericWalletIcon,
connectionTypes: [WalletConnectionType.Privy],
},
}; };
// Injected EIP-1193 Providers // Injected EIP-1193 Providers
+4 -55
View File
@@ -1,19 +1,13 @@
import { useCallback, useContext, createContext, useEffect, useState, useMemo } from 'react'; import { useCallback, useContext, createContext, useEffect, useState, useMemo } from 'react';
import { useDispatch, useSelector } from 'react-redux'; import { useDispatch } from 'react-redux';
import { AES, enc } from 'crypto-js'; import { AES, enc } from 'crypto-js';
import { NOBLE_BECH32_PREFIX, LocalWallet, type Subaccount } from '@dydxprotocol/v4-client-js'; import { NOBLE_BECH32_PREFIX, LocalWallet, type Subaccount } from '@dydxprotocol/v4-client-js';
import { OnboardingGuard, OnboardingState, type EvmDerivedAddresses } from '@/constants/account'; import { OnboardingGuard, OnboardingState, type EvmDerivedAddresses } from '@/constants/account';
import { DialogTypes } from '@/constants/dialogs'; import { DialogTypes } from '@/constants/dialogs';
import { LocalStorageKey, LOCAL_STORAGE_VERSIONS } from '@/constants/localStorage'; import { LocalStorageKey, LOCAL_STORAGE_VERSIONS } from '@/constants/localStorage';
import { import { DydxAddress, EvmAddress, PrivateInformation } from '@/constants/wallets';
DydxAddress,
EvmAddress,
PrivateInformation,
WalletConnectionType,
getSignTypedData,
} from '@/constants/wallets';
import { setOnboardingState, setOnboardingGuard } from '@/state/account'; import { setOnboardingState, setOnboardingGuard } from '@/state/account';
import { forceOpenDialog } from '@/state/dialogs'; import { forceOpenDialog } from '@/state/dialogs';
@@ -26,11 +20,6 @@ import { useLocalStorage } from './useLocalStorage';
import { useRestrictions } from './useRestrictions'; import { useRestrictions } from './useRestrictions';
import { useWalletConnection } from './useWalletConnection'; import { useWalletConnection } from './useWalletConnection';
import { useSignTypedData } from 'wagmi';
import { getSelectedNetwork } from '@/state/appSelectors';
import { ENVIRONMENT_CONFIG_MAP } from '@/constants/networks';
import { usePrivy } from '@privy-io/react-auth';
const AccountsContext = createContext<ReturnType<typeof useAccountsContext> | undefined>(undefined); const AccountsContext = createContext<ReturnType<typeof useAccountsContext> | undefined>(undefined);
AccountsContext.displayName = 'Accounts'; AccountsContext.displayName = 'Accounts';
@@ -164,7 +153,6 @@ const useAccountsContext = () => {
// dYdX wallet / onboarding state // dYdX wallet / onboarding state
const [localDydxWallet, setLocalDydxWallet] = useState<LocalWallet>(); const [localDydxWallet, setLocalDydxWallet] = useState<LocalWallet>();
const [localNobleWallet, setLocalNobleWallet] = useState<LocalWallet>();
const [hdKey, setHdKey] = useState<PrivateInformation>(); const [hdKey, setHdKey] = useState<PrivateInformation>();
const dydxAccounts = useMemo(() => localDydxWallet?.accounts, [localDydxWallet]); const dydxAccounts = useMemo(() => localDydxWallet?.accounts, [localDydxWallet]);
@@ -174,11 +162,6 @@ const useAccountsContext = () => {
[localDydxWallet] [localDydxWallet]
); );
const nobleAddress = useMemo(
() => localNobleWallet?.address,
[localNobleWallet]
);
const setWalletFromEvmSignature = async (signature: string) => { const setWalletFromEvmSignature = async (signature: string) => {
const { wallet, mnemonic, privateKey, publicKey } = await getWalletFromEvmSignature({ const { wallet, mnemonic, privateKey, publicKey } = await getWalletFromEvmSignature({
signature, signature,
@@ -193,20 +176,6 @@ const useAccountsContext = () => {
} }
}, [evmAddress, dydxAddress]); }, [evmAddress, dydxAddress]);
const selectedNetwork = useSelector(getSelectedNetwork);
const chainId = Number(ENVIRONMENT_CONFIG_MAP[selectedNetwork].ethereumChainId);
const signTypedData = getSignTypedData(selectedNetwork);
const { signTypedDataAsync } = useSignTypedData({
...signTypedData,
domain: {
...signTypedData.domain,
chainId,
},
});
const { ready, authenticated } = usePrivy();
useEffect(() => { useEffect(() => {
(async () => { (async () => {
if (connectedDydxAddress && signerGraz) { if (connectedDydxAddress && signerGraz) {
@@ -223,17 +192,7 @@ const useAccountsContext = () => {
const evmDerivedAccount = evmDerivedAddresses[evmAddress]; const evmDerivedAccount = evmDerivedAddresses[evmAddress];
if (walletConnectionType === WalletConnectionType.Privy && authenticated && ready) { if (evmDerivedAccount?.encryptedSignature) {
try {
const signature = await signTypedDataAsync();
await setWalletFromEvmSignature(signature);
dispatch(setOnboardingState(OnboardingState.AccountConnected));
} catch (error) {
log('useAccounts/decryptSignature', error);
forgetEvmSignature();
}
} else if (evmDerivedAccount?.encryptedSignature) {
try { try {
const signature = decryptSignature(evmDerivedAccount.encryptedSignature); const signature = decryptSignature(evmDerivedAccount.encryptedSignature);
@@ -252,15 +211,7 @@ const useAccountsContext = () => {
dispatch(setOnboardingState(OnboardingState.Disconnected)); dispatch(setOnboardingState(OnboardingState.Disconnected));
} }
})(); })();
}, [ }, [evmAddress, evmDerivedAddresses, signerWagmi, connectedDydxAddress, signerGraz]);
evmAddress,
evmDerivedAddresses,
signerWagmi,
connectedDydxAddress,
signerGraz,
authenticated,
ready,
]);
// abacus // abacus
useEffect(() => { useEffect(() => {
@@ -273,7 +224,6 @@ const useAccountsContext = () => {
if (hdKey?.mnemonic) { if (hdKey?.mnemonic) {
const nobleWallet = await LocalWallet.fromMnemonic(hdKey.mnemonic, NOBLE_BECH32_PREFIX); const nobleWallet = await LocalWallet.fromMnemonic(hdKey.mnemonic, NOBLE_BECH32_PREFIX);
abacusStateManager.setNobleWallet(nobleWallet); abacusStateManager.setNobleWallet(nobleWallet);
setLocalNobleWallet(nobleWallet);
} }
}; };
setNobleWallet(); setNobleWallet();
@@ -372,7 +322,6 @@ const useAccountsContext = () => {
localDydxWallet, localDydxWallet,
dydxAccounts, dydxAccounts,
dydxAddress, dydxAddress,
nobleAddress,
// Onboarding state // Onboarding state
saveHasAcknowledgedTerms, saveHasAcknowledgedTerms,
-1
View File
@@ -21,7 +21,6 @@ export const useDisplayedWallets = () => {
// WalletType.BitKeep, // WalletType.BitKeep,
// WalletType.Coin98, // WalletType.Coin98,
WalletType.Privy,
WalletType.OtherWallet, WalletType.OtherWallet,
].filter(isTruthy); ].filter(isTruthy);
}; };
+2 -13
View File
@@ -1,9 +1,5 @@
import { useCallback, useEffect, useMemo } from 'react'; import { useCallback, useEffect, useMemo } from 'react';
import { useNetwork, useSwitchNetwork } from 'wagmi'; import { useNetwork, useSwitchNetwork } from 'wagmi';
import { useSwitchNetwork as useSwitchNetworkPrivy } from '@privy-io/wagmi-connector';
import { WalletConnectionType } from '@/constants/wallets';
import { useWalletConnection } from './useWalletConnection';
export const useMatchingEvmNetwork = ({ export const useMatchingEvmNetwork = ({
chainId, chainId,
@@ -15,10 +11,7 @@ export const useMatchingEvmNetwork = ({
onError?: (error: Error) => void; onError?: (error: Error) => void;
}) => { }) => {
const { chain } = useNetwork(); const { chain } = useNetwork();
const { walletConnectionType } = useWalletConnection();
const { isLoading, switchNetworkAsync } = useSwitchNetwork({ onError }); const { isLoading, switchNetworkAsync } = useSwitchNetwork({ onError });
const { isLoading: isLoadingPrivy, switchNetworkAsync: switchNetworkAsyncPrivy } =
useSwitchNetworkPrivy({ onError });
// If chainId is not a number, we can assume it is a non EVM compatible chain // If chainId is not a number, we can assume it is a non EVM compatible chain
const isMatchingNetwork = useMemo( const isMatchingNetwork = useMemo(
@@ -28,11 +21,7 @@ export const useMatchingEvmNetwork = ({
const matchNetwork = useCallback(async () => { const matchNetwork = useCallback(async () => {
if (!isMatchingNetwork) { if (!isMatchingNetwork) {
if (walletConnectionType === WalletConnectionType.Privy) { await switchNetworkAsync?.(Number(chainId));
await switchNetworkAsyncPrivy?.(Number(chainId));
} else {
await switchNetworkAsync?.(Number(chainId));
}
} }
}, [chainId, chain]); }, [chainId, chain]);
@@ -45,6 +34,6 @@ export const useMatchingEvmNetwork = ({
return { return {
isMatchingNetwork, isMatchingNetwork,
matchNetwork, matchNetwork,
isSwitchingNetwork: isLoading || isLoadingPrivy, isSwitchingNetwork: isLoading,
}; };
}; };
+20 -12
View File
@@ -1,7 +1,7 @@
import { useCallback, useEffect, useState, useMemo } from 'react'; import { useCallback, useEffect, useState, useMemo } from 'react';
import { useSelector } from 'react-redux'; import { useSelector } from 'react-redux';
import { usePrivy, useLogout } from '@privy-io/react-auth';
import { EvmDerivedAddresses } from '@/constants/account';
import { LocalStorageKey } from '@/constants/localStorage'; import { LocalStorageKey } from '@/constants/localStorage';
import { ENVIRONMENT_CONFIG_MAP } from '@/constants/networks'; import { ENVIRONMENT_CONFIG_MAP } from '@/constants/networks';
@@ -107,21 +107,20 @@ export const useWalletConnection = () => {
const { connectAsync: connectWagmi } = useConnectWagmi({ connector: wagmiConnector }); const { connectAsync: connectWagmi } = useConnectWagmi({ connector: wagmiConnector });
const { suggestAndConnect: connectGraz } = useConnectGraz(); const { suggestAndConnect: connectGraz } = useConnectGraz();
const { login, ready, authenticated } = usePrivy(); const [evmDerivedAddresses] = useLocalStorage({
const { logout } = useLogout(); key: LocalStorageKey.EvmDerivedAddresses,
defaultValue: {} as EvmDerivedAddresses,
});
const connectWallet = useCallback( const connectWallet = useCallback(
async ({ walletType }: { walletType: WalletType }) => { async ({ walletType, forceConnect }: { walletType?: WalletType; forceConnect?: boolean }) => {
if (!walletType) return { walletType, walletConnectionType };
const walletConnection = getWalletConnection({ walletType }); const walletConnection = getWalletConnection({ walletType });
try { try {
if (!walletConnection) { if (!walletConnection) {
throw new Error('Onboarding: No wallet connection found.'); throw new Error('Onboarding: No wallet connection found.');
} else if (walletConnection.type === WalletConnectionType.Privy) {
if (!isConnectedWagmi && !authenticated && ready) {
login();
}
} else if (walletConnection.type === WalletConnectionType.CosmosSigner) { } else if (walletConnection.type === WalletConnectionType.CosmosSigner) {
const cosmosWalletType = { const cosmosWalletType = {
[WalletType.Keplr as string]: CosmosWalletType.KEPLR, [WalletType.Keplr as string]: CosmosWalletType.KEPLR,
@@ -140,7 +139,11 @@ export const useWalletConnection = () => {
}); });
} }
} else { } else {
if (!isConnectedWagmi) { const isAccountConnected = Boolean(
evmAddress && evmDerivedAddresses[evmAddress]?.encryptedSignature
);
// if account connected (via remember me), do not show wagmi popup until forceConnect
if (!isConnectedWagmi && (forceConnect || !isAccountConnected)) {
await connectWagmi({ await connectWagmi({
connector: resolveWagmiConnector({ connector: resolveWagmiConnector({
walletType, walletType,
@@ -164,7 +167,7 @@ export const useWalletConnection = () => {
walletConnectionType: walletConnection.type, walletConnectionType: walletConnection.type,
}; };
}, },
[isConnectedGraz, signerGraz, isConnectedWagmi, signerWagmi, login, ready, authenticated] [isConnectedGraz, signerGraz, isConnectedWagmi, signerWagmi]
); );
const disconnectWallet = useCallback(async () => { const disconnectWallet = useCallback(async () => {
@@ -173,7 +176,6 @@ export const useWalletConnection = () => {
if (isConnectedWagmi) await disconnectWagmi(); if (isConnectedWagmi) await disconnectWagmi();
if (isConnectedGraz) await disconnectGraz(); if (isConnectedGraz) await disconnectGraz();
if (authenticated) await logout();
}, [isConnectedGraz, isConnectedWagmi]); }, [isConnectedGraz, isConnectedWagmi]);
// Wallet selection // Wallet selection
@@ -237,6 +239,12 @@ export const useWalletConnection = () => {
evmAddressWagmi, evmAddressWagmi,
signerWagmi, signerWagmi,
publicClientWagmi, publicClientWagmi,
isConnectedWagmi,
connectWallet: () =>
connectWallet({
walletType: selectedWalletType,
forceConnect: true,
}),
// Wallet connection (Cosmos) // Wallet connection (Cosmos)
dydxAddress, dydxAddress,
+4
View File
@@ -56,6 +56,10 @@ class DydxChainTransactions implements AbacusDYDXChainTransactionsProtocol {
this.store = undefined; this.store = undefined;
} }
get isNobleClientConnected(): boolean {
return this.nobleClient?.isConnected ?? false;
}
setStore(store: RootStore): void { setStore(store: RootStore): void {
this.store = store; this.store = store;
} }
+10 -5
View File
@@ -171,6 +171,15 @@ class AbacusStateManager {
this.setTransferValue({ value: null, field: TransferInputField.usdcSize }); this.setTransferValue({ value: null, field: TransferInputField.usdcSize });
}; };
resetInputState = () => {
this.clearTransferInputValues();
this.setTransferValue({
field: TransferInputField.type,
value: null,
});
this.clearTradeInputValues();
};
// ------ Set Data ------ // // ------ Set Data ------ //
setStore = (store: RootStore) => { setStore = (store: RootStore) => {
this.store = store; this.store = store;
@@ -262,11 +271,7 @@ class AbacusStateManager {
) => this.stateManager.cancelOrder(orderId, callback); ) => this.stateManager.cancelOrder(orderId, callback);
cctpWithdraw = ( cctpWithdraw = (
callback: ( callback: (success: boolean, parsingError: Nullable<ParsingError>, data: string) => void
success: boolean,
parsingError: Nullable<ParsingError>,
data: string,
) => void
): void => this.stateManager.commitCCTPWithdraw(callback); ): void => this.stateManager.commitCCTPWithdraw(callback);
// ------ Utils ------ // // ------ Utils ------ //
-14
View File
@@ -1,6 +1,5 @@
import { createConfig, configureChains, mainnet, Chain } from 'wagmi'; import { createConfig, configureChains, mainnet, Chain } from 'wagmi';
import { goerli } from 'wagmi/chains'; import { goerli } from 'wagmi/chains';
import type { PrivyClientConfig } from '@privy-io/react-auth';
import { import {
arbitrum, arbitrum,
@@ -86,19 +85,6 @@ export const WAGMI_SUPPORTED_CHAINS: Chain[] = [
kava, kava,
]; ];
export const privyConfig: PrivyClientConfig = {
embeddedWallets: {
createOnLogin: 'users-without-wallets',
requireUserPasswordOnCreate: true,
noPromptOnSignature: true,
},
loginMethods: ['email', 'sms', 'twitter', 'google', 'apple'],
appearance: {
theme: '#28283c',
},
defaultChain: sepolia
};
const { chains, publicClient, webSocketPublicClient } = configureChains( const { chains, publicClient, webSocketPublicClient } = configureChains(
WAGMI_SUPPORTED_CHAINS, WAGMI_SUPPORTED_CHAINS,
[ [
-6
View File
@@ -62,12 +62,6 @@ export const getWalletConnection = ({
type: WalletConnectionType.CosmosSigner, type: WalletConnectionType.CosmosSigner,
}; };
} }
case WalletConnectionType.Privy: {
return {
type: WalletConnectionType.Privy,
};
}
} }
} }
}; };
@@ -1,4 +1,6 @@
import { useState } from 'react';
import styled, { AnyStyledComponent } from 'styled-components'; import styled, { AnyStyledComponent } from 'styled-components';
import { useDispatch } from 'react-redux';
import { AlertType } from '@/constants/alerts'; import { AlertType } from '@/constants/alerts';
import { STRING_KEYS } from '@/constants/localization'; import { STRING_KEYS } from '@/constants/localization';
@@ -11,7 +13,7 @@ import { Button } from '@/components/Button';
import { Icon } from '@/components/Icon'; import { Icon } from '@/components/Icon';
import { Link } from '@/components/Link'; import { Link } from '@/components/Link';
import { useAccounts, useBreakpoints, useStringGetter, useURLConfigs } from '@/hooks'; import { useAccounts, useStringGetter, useURLConfigs } from '@/hooks';
import { useDisplayedWallets } from '@/hooks/useDisplayedWallets'; import { useDisplayedWallets } from '@/hooks/useDisplayedWallets';
import { breakpoints } from '@/styles'; import { breakpoints } from '@/styles';
@@ -25,8 +27,6 @@ export const ChooseWallet = () => {
const { selectWalletType, selectedWalletType, selectedWalletError } = useAccounts(); const { selectWalletType, selectedWalletType, selectedWalletError } = useAccounts();
const { isMobile } = useBreakpoints();
return ( return (
<> <>
{selectedWalletType && selectedWalletError && ( {selectedWalletType && selectedWalletError && (
@@ -56,11 +56,7 @@ export const ChooseWallet = () => {
slotLeft={<Styled.Icon iconComponent={wallets[walletType].icon} />} slotLeft={<Styled.Icon iconComponent={wallets[walletType].icon} />}
size={ButtonSize.Small} size={ButtonSize.Small}
> >
<div> <div>{stringGetter({ key: wallets[walletType].stringKey })}</div>
{walletType !== WalletType.Privy && import.meta.env.VITE_PRIVY_APP_ID
? stringGetter({ key: wallets[walletType].stringKey })
: `Socials ${isMobile ? '' : '(Email, SMS, etc.)'}`}
</div>
</Styled.WalletButton> </Styled.WalletButton>
))} ))}
</Styled.Wallets> </Styled.Wallets>
@@ -72,6 +72,7 @@ export const GenerateKeys = ({
if (message) { if (message) {
log('GenerateKeys/switchNetwork', error, { walletErrorType }); log('GenerateKeys/switchNetwork', error, { walletErrorType });
setError(message); setError(message);
throw error;
} }
} }
}; };
@@ -34,30 +34,11 @@ export const ChainSelectMenu = ({ label, selectedChain, onSelectChain }: Element
slotBefore: <Styled.Img src={chain.iconUrl} alt="" />, slotBefore: <Styled.Img src={chain.iconUrl} alt="" />,
})); }));
const selectedOption = selectedChain === 'coinbase' ? { const selectedOption = chains.find((item) => item.type === selectedChain);
stringKey: 'Coinbase',
iconUrl: '/wallets/coinbase-wallet.png',
} : chains.find((item) => item.type === selectedChain);
const exchanges = [
{
value: 'coinbase',
label: 'Coinbase',
onSelect: () => {
onSelectChain('coinbase');
},
slotBefore: <Styled.Img src="/wallets/coinbase-wallet.png" alt="" />,
}
];
return ( return (
<SearchSelectMenu <SearchSelectMenu
items={[ items={[
{
group: 'exchanges',
groupLabel: 'Exchanges',
items: exchanges,
},
{ {
group: 'chains', group: 'chains',
groupLabel: stringGetter({ key: STRING_KEYS.CHAINS }), groupLabel: stringGetter({ key: STRING_KEYS.CHAINS }),
@@ -17,6 +17,7 @@ import type { EvmAddress } from '@/constants/wallets';
import { useAccounts, useDebounce, useStringGetter, useSelectedNetwork } from '@/hooks'; import { useAccounts, useDebounce, useStringGetter, useSelectedNetwork } from '@/hooks';
import { useAccountBalance, CHAIN_DEFAULT_TOKEN_ADDRESS } from '@/hooks/useAccountBalance'; import { useAccountBalance, CHAIN_DEFAULT_TOKEN_ADDRESS } from '@/hooks/useAccountBalance';
import { useLocalNotifications } from '@/hooks/useLocalNotifications'; import { useLocalNotifications } from '@/hooks/useLocalNotifications';
import { useWalletConnection } from '@/hooks/useWalletConnection';
import { layoutMixins } from '@/styles/layoutMixins'; import { layoutMixins } from '@/styles/layoutMixins';
import { formMixins } from '@/styles/formMixins'; import { formMixins } from '@/styles/formMixins';
@@ -38,14 +39,12 @@ import abacusStateManager from '@/lib/abacus';
import { MustBigNumber } from '@/lib/numbers'; import { MustBigNumber } from '@/lib/numbers';
import { getNobleChainId, NATIVE_TOKEN_ADDRESS } from '@/lib/squid'; import { getNobleChainId, NATIVE_TOKEN_ADDRESS } from '@/lib/squid';
import { log } from '@/lib/telemetry'; import { log } from '@/lib/telemetry';
import { parseWalletError, truncateAddress } from '@/lib/wallet'; import { parseWalletError } from '@/lib/wallet';
import { ChainSelectMenu } from './ChainSelectMenu'; import { ChainSelectMenu } from './ChainSelectMenu';
import { TokenSelectMenu } from './TokenSelectMenu'; import { TokenSelectMenu } from './TokenSelectMenu';
import { DepositButtonAndReceipt } from './DepositForm/DepositButtonAndReceipt'; import { DepositButtonAndReceipt } from './DepositForm/DepositButtonAndReceipt';
import { QrCode } from '@/components/QrCode';
import { CopyButton } from '@/components/CopyButton';
type DepositFormProps = { type DepositFormProps = {
onDeposit?: () => void; onDeposit?: () => void;
@@ -57,9 +56,8 @@ export const DepositForm = ({ onDeposit, onError }: DepositFormProps) => {
const [error, setError] = useState<Error | null>(null); const [error, setError] = useState<Error | null>(null);
const [isLoading, setIsLoading] = useState(false); const [isLoading, setIsLoading] = useState(false);
const { selectedNetwork } = useSelectedNetwork(); const { selectedNetwork } = useSelectedNetwork();
const [isCoinbase, setIsCoinbase] = useState(false);
const { evmAddress, signerWagmi, publicClientWagmi, nobleAddress } = useAccounts(); const { evmAddress, signerWagmi, publicClientWagmi } = useAccounts();
const { addTransferNotification } = useLocalNotifications(); const { addTransferNotification } = useLocalNotifications();
@@ -123,11 +121,7 @@ export const DepositForm = ({ onDeposit, onError }: DepositFormProps) => {
}); });
return () => { return () => {
abacusStateManager.clearTransferInputValues(); abacusStateManager.resetInputState();
abacusStateManager.setTransferValue({
field: TransferInputField.type,
value: null,
});
}; };
}, []); }, []);
@@ -136,10 +130,7 @@ export const DepositForm = ({ onDeposit, onError }: DepositFormProps) => {
}, [error]); }, [error]);
const onSelectChain = useCallback((chain: string) => { const onSelectChain = useCallback((chain: string) => {
if (chain === 'coinbase') { if (chain) {
setIsCoinbase(true);
} else if (chain) {
setIsCoinbase(false);
abacusStateManager.clearTransferInputValues(); abacusStateManager.clearTransferInputValues();
abacusStateManager.setTransferValue({ abacusStateManager.setTransferValue({
field: TransferInputField.chain, field: TransferInputField.chain,
@@ -241,6 +232,10 @@ export const DepositForm = ({ onDeposit, onError }: DepositFormProps) => {
throw new Error('Missing request payload'); throw new Error('Missing request payload');
} }
if (isCctp && !abacusStateManager.chainTransactions.isNobleClientConnected) {
throw new Error('Noble RPC endpoint unaccessible');
}
setIsLoading(true); setIsLoading(true);
await validateTokenApproval(); await validateTokenApproval();
@@ -370,43 +365,11 @@ export const DepositForm = ({ onDeposit, onError }: DepositFormProps) => {
return <LoadingSpace id="DepositForm" />; return <LoadingSpace id="DepositForm" />;
} }
if (isCoinbase) { const [requireUserActionInWallet, setRequireUserActionInWallet] = useState(false);
return (
<Styled.Form onSubmit={onSubmit}>
<ChainSelectMenu
selectedChain={isCoinbase ? 'coinbase' : chainIdStr || undefined}
onSelectChain={onSelectChain}
/>
{nobleAddress && (
<>
<Styled.ReceiveQr
side="bottom"
detailItems={[
{
key: 'nobleAddress',
label: "Noble Address",
value: nobleAddress,
},
]}
>
<QrCode size={432} value={nobleAddress} />
</Styled.ReceiveQr>
<p>
* This address only supports transfers of USDC to the Noble chain.
</p>
<CopyButton value={nobleAddress} />
</>
)}
</Styled.Form>
);
}
return ( return (
<Styled.Form onSubmit={onSubmit}> <Styled.Form onSubmit={onSubmit}>
<ChainSelectMenu <ChainSelectMenu selectedChain={chainIdStr || undefined} onSelectChain={onSelectChain} />
selectedChain={isCoinbase ? 'coinbase' : chainIdStr || undefined}
onSelectChain={onSelectChain}
/>
<TokenSelectMenu selectedToken={sourceToken || undefined} onSelectToken={onSelectToken} /> <TokenSelectMenu selectedToken={sourceToken || undefined} onSelectToken={onSelectToken} />
<Styled.WithDetailsReceipt side="bottom" detailItems={amountInputReceipt}> <Styled.WithDetailsReceipt side="bottom" detailItems={amountInputReceipt}>
<FormInput <FormInput
@@ -422,7 +385,11 @@ export const DepositForm = ({ onDeposit, onError }: DepositFormProps) => {
/> />
</Styled.WithDetailsReceipt> </Styled.WithDetailsReceipt>
{errorMessage && <AlertMessage type={AlertType.Error}>{errorMessage}</AlertMessage>} {errorMessage && <AlertMessage type={AlertType.Error}>{errorMessage}</AlertMessage>}
{requireUserActionInWallet && (
<AlertMessage type={AlertType.Warning}>
{stringGetter({ key: STRING_KEYS.CHECK_WALLET_FOR_REQUEST })}
</AlertMessage>
)}
<Styled.Footer> <Styled.Footer>
<DepositButtonAndReceipt <DepositButtonAndReceipt
isDisabled={isDisabled} isDisabled={isDisabled}
@@ -431,6 +398,8 @@ export const DepositForm = ({ onDeposit, onError }: DepositFormProps) => {
setSlippage={onSetSlippage} setSlippage={onSetSlippage}
slippage={slippage} slippage={slippage}
sourceToken={sourceToken || undefined} sourceToken={sourceToken || undefined}
setRequireUserActionInWallet={setRequireUserActionInWallet}
setError={setError}
/> />
</Styled.Footer> </Styled.Footer>
</Styled.Form> </Styled.Form>
@@ -467,13 +436,3 @@ Styled.TransactionInfo = styled.span`
Styled.FormInputButton = styled(Button)` Styled.FormInputButton = styled(Button)`
${formMixins.inputInnerButton} ${formMixins.inputInnerButton}
`; `;
Styled.Exchange = styled.div`
${layoutMixins.flexColumn}
gap: 1rem;
align-items: center;
`;
Styled.ReceiveQr = styled(WithDetailsReceipt)`
`;
@@ -1,8 +1,7 @@
import { type Dispatch, type ReactNode, type SetStateAction, useState, useMemo } from 'react'; import { type Dispatch, type SetStateAction, useState, type ReactNode, useEffect } from 'react';
import styled, { type AnyStyledComponent } from 'styled-components'; import styled, { type AnyStyledComponent } from 'styled-components';
import { shallowEqual, useSelector } from 'react-redux'; import { shallowEqual, useSelector } from 'react-redux';
import type { RouteData } from '@0xsquid/sdk'; import type { RouteData } from '@0xsquid/sdk';
import { formatUnits } from 'viem';
import { ButtonAction, ButtonShape, ButtonSize, ButtonType } from '@/constants/buttons'; import { ButtonAction, ButtonShape, ButtonSize, ButtonType } from '@/constants/buttons';
@@ -12,6 +11,7 @@ import { NumberSign, TOKEN_DECIMALS } from '@/constants/numbers';
import { useStringGetter, useTokenConfigs } from '@/hooks'; import { useStringGetter, useTokenConfigs } from '@/hooks';
import { useMatchingEvmNetwork } from '@/hooks/useMatchingEvmNetwork'; import { useMatchingEvmNetwork } from '@/hooks/useMatchingEvmNetwork';
import { useWalletConnection } from '@/hooks/useWalletConnection';
import { layoutMixins } from '@/styles/layoutMixins'; import { layoutMixins } from '@/styles/layoutMixins';
@@ -39,7 +39,8 @@ type ElementProps = {
isLoading?: boolean; isLoading?: boolean;
chainId?: string | number; chainId?: string | number;
setError?: Dispatch<SetStateAction<Error | undefined>>; setError?: Dispatch<SetStateAction<Error | null>>;
setRequireUserActionInWallet: (val: boolean) => void;
slippage: number; slippage: number;
slotError?: ReactNode; slotError?: ReactNode;
setSlippage: (slippage: number) => void; setSlippage: (slippage: number) => void;
@@ -57,6 +58,7 @@ export const DepositButtonAndReceipt = ({
isDisabled, isDisabled,
isLoading, isLoading,
slotError, slotError,
setRequireUserActionInWallet,
}: ElementProps) => { }: ElementProps) => {
const [showFeeBreakdown, setShowFeeBreakdown] = useState(false); const [showFeeBreakdown, setShowFeeBreakdown] = useState(false);
const [isEditingSlippage, setIsEditingSlipapge] = useState(false); const [isEditingSlippage, setIsEditingSlipapge] = useState(false);
@@ -64,6 +66,24 @@ export const DepositButtonAndReceipt = ({
const canAccountTrade = useSelector(calculateCanAccountTrade, shallowEqual); const canAccountTrade = useSelector(calculateCanAccountTrade, shallowEqual);
const { connectWallet, isConnectedWagmi } = useWalletConnection();
const connectWagmi = async () => {
try {
setRequireUserActionInWallet(false);
await connectWallet();
setRequireUserActionInWallet(false);
} catch (e) {
setRequireUserActionInWallet(true);
}
};
useEffect(() => {
if (!isConnectedWagmi && canAccountTrade) {
connectWagmi();
}
}, [isConnectedWagmi, canAccountTrade]);
const { const {
matchNetwork: switchNetwork, matchNetwork: switchNetwork,
isSwitchingNetwork, isSwitchingNetwork,
@@ -80,7 +100,7 @@ export const DepositButtonAndReceipt = ({
useSelector(getSubaccountBuyingPower, shallowEqual) || {}; useSelector(getSubaccountBuyingPower, shallowEqual) || {};
const { isCctp, summary, requestPayload } = useSelector(getTransferInputs, shallowEqual) || {}; const { isCctp, summary, requestPayload } = useSelector(getTransferInputs, shallowEqual) || {};
const { usdcDecimals, usdcLabel } = useTokenConfigs(); const { usdcLabel } = useTokenConfigs();
const feeSubitems: DetailsItem[] = []; const feeSubitems: DetailsItem[] = [];
@@ -116,7 +136,9 @@ export const DepositButtonAndReceipt = ({
{stringGetter({ key: STRING_KEYS.EXPECTED_DEPOSIT_AMOUNT })} <Tag>{usdcLabel}</Tag> {stringGetter({ key: STRING_KEYS.EXPECTED_DEPOSIT_AMOUNT })} <Tag>{usdcLabel}</Tag>
</span> </span>
), ),
value: <Output type={OutputType.Fiat} fractionDigits={TOKEN_DECIMALS} value={summary?.toAmount} />, value: (
<Output type={OutputType.Fiat} fractionDigits={TOKEN_DECIMALS} value={summary?.toAmount} />
),
subitems: [ subitems: [
{ {
key: 'minimum-deposit-amount', key: 'minimum-deposit-amount',
@@ -126,7 +148,11 @@ export const DepositButtonAndReceipt = ({
</span> </span>
), ),
value: ( value: (
<Output type={OutputType.Fiat} fractionDigits={TOKEN_DECIMALS} value={summary?.toAmountMin} /> <Output
type={OutputType.Fiat}
fractionDigits={TOKEN_DECIMALS}
value={summary?.toAmountMin}
/>
), ),
tooltip: 'minimum-deposit-amount', tooltip: 'minimum-deposit-amount',
}, },
@@ -253,6 +279,8 @@ export const DepositButtonAndReceipt = ({
> >
{!canAccountTrade ? ( {!canAccountTrade ? (
<OnboardingTriggerButton size={ButtonSize.Base} /> <OnboardingTriggerButton size={ButtonSize.Base} />
) : !isConnectedWagmi ? (
<Button action={ButtonAction.Primary} onClick={connectWallet} state={{ isLoading: true }} />
) : !isMatchingNetwork ? ( ) : !isMatchingNetwork ? (
<Button <Button
action={ButtonAction.Primary} action={ButtonAction.Primary}
@@ -101,11 +101,7 @@ export const WithdrawForm = () => {
}); });
return () => { return () => {
abacusStateManager.clearTransferInputValues(); abacusStateManager.resetInputState();
abacusStateManager.setTransferValue({
field: TransferInputField.type,
value: null,
});
}; };
}, []); }, []);
@@ -148,6 +144,10 @@ export const WithdrawForm = () => {
throw new Error('Invalid request payload'); throw new Error('Invalid request payload');
} }
if (isCctp && !abacusStateManager.chainTransactions.isNobleClientConnected) {
throw new Error('Noble RPC endpoint unaccessible');
}
setIsLoading(true); setIsLoading(true);
setError(undefined); setError(undefined);
+1 -5
View File
@@ -118,11 +118,7 @@ export const TransferForm = ({
onChangeAsset(selectedAsset); onChangeAsset(selectedAsset);
return () => { return () => {
abacusStateManager.clearTransferInputValues(); abacusStateManager.resetInputState();
abacusStateManager.setTransferValue({
field: TransferInputField.type,
value: null,
});
}; };
}, []); }, []);
-2
View File
@@ -36,8 +36,6 @@ import { openDialog } from '@/state/dialogs';
import { MustBigNumber } from '@/lib/numbers'; import { MustBigNumber } from '@/lib/numbers';
import { getHydratedTradingData } from '@/lib/orders'; import { getHydratedTradingData } from '@/lib/orders';
import { tableMixins } from '@/styles/tableMixins';
import { breakpoints } from '@/styles';
const MOBILE_FILLS_PER_PAGE = 50; const MOBILE_FILLS_PER_PAGE = 50;
-7
View File
@@ -2,7 +2,6 @@ import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react'; import react from '@vitejs/plugin-react';
import path from 'path'; import path from 'path';
import svgr from 'vite-plugin-svgr'; import svgr from 'vite-plugin-svgr';
import { VitePWA } from 'vite-plugin-pwa';
// https://vitejs.dev/config/ // https://vitejs.dev/config/
export default defineConfig(({ mode }) => ({ export default defineConfig(({ mode }) => ({
@@ -51,12 +50,6 @@ export default defineConfig(({ mode }) => ({
svgr({ svgr({
exportAsDefault: true, exportAsDefault: true,
}), }),
VitePWA({
registerType: 'autoUpdate',
devOptions: {
enabled: true,
},
}),
], ],
publicDir: 'public', publicDir: 'public',
})); }));