diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index a7f94ab..1c17717 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -15836,6 +15836,12 @@ packages:
resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==}
dev: true
+ file:../../abacus/build/packages/js/dydxprotocol-abacus-0.2.28.tgz:
+ resolution: {integrity: sha512-aOT+QROV5aL0QLNq7QINW6Bw3Vz8ds7LOoC4MQfPDsGGqgyundpAcPkLmgcbIk0Ft8BQsdOz+HbbAYL4n7Iqlg==, tarball: file:../../abacus/build/packages/js/dydxprotocol-abacus-0.2.28.tgz}
+ name: '@dydxprotocol/abacus'
+ version: 0.2.28
+ dev: false
+
github.com/release-it/conventional-changelog/a4acfeac76369937a6566d698a5ae9180eceb413(release-it@15.11.0):
resolution: {tarball: https://codeload.github.com/release-it/conventional-changelog/tar.gz/a4acfeac76369937a6566d698a5ae9180eceb413}
id: github.com/release-it/conventional-changelog/a4acfeac76369937a6566d698a5ae9180eceb413
diff --git a/src/App.tsx b/src/App.tsx
index 1869616..db877bb 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -14,6 +14,8 @@ import { DialogAreaProvider, useDialogArea } from './hooks/useDialogArea';
import { LocaleProvider } from './hooks/useLocaleSeparators';
import { NotificationsProvider } from './hooks/useNotifications';
import { SubaccountProvider } from './hooks/useSubaccount';
+import { SquidProvider } from '@/hooks/useSquidRouter';
+
import { GuardedMobileRoute } from '@/components/GuardedMobileRoute';
import MarketsPage from '@/pages/markets/Markets';
@@ -106,7 +108,9 @@ const App = () => (
-
+
+
+
diff --git a/src/components/SearchSelectMenu.tsx b/src/components/SearchSelectMenu.tsx
index 1fd1ef7..3a810d4 100644
--- a/src/components/SearchSelectMenu.tsx
+++ b/src/components/SearchSelectMenu.tsx
@@ -19,6 +19,7 @@ type ElementProps = {
disabled?: boolean;
label?: string;
items: MenuConfig;
+ slotEmpty?: ReactNode;
withSearch?: boolean;
withReceiptItems?: DetailsItem[];
};
@@ -52,12 +53,10 @@ export const SearchSelectMenu = ({
const Trigger = asChild ? (
children
) : (
- <>
-
- {children}
-
+
+ {label ? {children} : children}
- >
+
);
return (
@@ -86,7 +85,7 @@ export const SearchSelectMenu = ({
const Styled: Record = {};
Styled.MenuTrigger = styled.div`
- height: 3.5rem;
+ height: var(--form-input-height);
${layoutMixins.spacedRow}
align-items: center;
@@ -117,7 +116,7 @@ Styled.WithDetailsReceipt = styled(WithDetailsReceipt)`
Styled.Popover = styled(Popover)`
max-height: 30vh;
margin-top: 1rem;
- border: 1px solid var(--color-layer-6);
+ border: var(--border-width) solid var(--color-layer-6);
border-radius: 0.5rem;
z-index: 2;
box-shadow: none;
@@ -136,6 +135,8 @@ Styled.ComboboxMenu = styled(ComboboxMenu)`
--comboboxMenu-item-checked-textColor: var(--color-text-2);
--comboboxMenu-item-highlighted-textColor: var(--color-text-2);
+ --stickyArea1-topHeight: var(--form-input-height);
+
input:focus {
outline: none;
}
diff --git a/src/constants/abacus.ts b/src/constants/abacus.ts
index a769f95..af005ff 100644
--- a/src/constants/abacus.ts
+++ b/src/constants/abacus.ts
@@ -12,6 +12,10 @@ export type AbacusDydxChainQueriesProtocol = Omit<
Abacus.exchange.dydx.abacus.protocols.DYDXChainQueriesProtocol,
'__doNotUseOrImplementIt'
>;
+export type AbacusDYDXChainTransactionsProtocol = Omit<
+ Abacus.exchange.dydx.abacus.protocols.DYDXChainTransactionsProtocol,
+ '__doNotUseOrImplementIt'
+>;
export type AbacusRestProtocol = Omit<
Abacus.exchange.dydx.abacus.protocols.RestProtocol,
'__doNotUseOrImplementIt'
@@ -44,6 +48,10 @@ export const QueryType = Abacus.exchange.dydx.abacus.protocols.QueryType;
const queryTypes = [...QueryType.values()] as const;
export type QueryTypes = (typeof queryTypes)[number];
+export const TransactionType = Abacus.exchange.dydx.abacus.protocols.TransactionType;
+const TransactionTypes = [...TransactionType.values()] as const;
+export type TransactionTypes = (typeof TransactionTypes)[number];
+
export type NetworkConfig = {
chainId: string;
indexerUrl: string;
@@ -98,6 +106,8 @@ export type ClosePositionInputs = Abacus.exchange.dydx.abacus.output.input.Close
export type TradeInputSummary = Abacus.exchange.dydx.abacus.output.input.TradeInputSummary;
export type TransferInputs = Abacus.exchange.dydx.abacus.output.input.TransferInput;
export type InputError = Abacus.exchange.dydx.abacus.output.input.ValidationError;
+export type TransferInputTokenResource = Abacus.exchange.dydx.abacus.output.input.TransferInputTokenResource;
+export type TransferInputChainResource = Abacus.exchange.dydx.abacus.output.input.TransferInputChainResource;
export const ErrorType = Abacus.exchange.dydx.abacus.output.input.ErrorType;
export const InputSelectionOption = Abacus.exchange.dydx.abacus.output.input.SelectionOption;
diff --git a/src/constants/dialogs.ts b/src/constants/dialogs.ts
index 5655452..ed20d3f 100644
--- a/src/constants/dialogs.ts
+++ b/src/constants/dialogs.ts
@@ -12,6 +12,7 @@ export enum DialogTypes {
Receive = 'Receive',
Trade = 'Trade',
Transfer = 'Transfer',
+ Withdraw = 'Withdraw',
}
export enum TradeBoxDialogTypes {
diff --git a/src/hooks/index.ts b/src/hooks/index.ts
index bc0c3cd..950dc76 100644
--- a/src/hooks/index.ts
+++ b/src/hooks/index.ts
@@ -2,6 +2,7 @@ import { useApiState } from './useApiState';
import { useBreakpoints } from './useBreakpoints';
import { useCommandMenu } from './useCommandMenu';
import { useCurrentMarketId } from './useCurrentMarketId';
+import { useDebounce } from './useDebounce';
import { useInterval } from './useInterval';
import { useDocumentTitle } from './useDocumentTitle';
import { useDydxClient } from './useDydxClient';
@@ -17,6 +18,7 @@ import { useOnClickOutside } from './useOnClickOutside';
import { usePageTitlePriceUpdates } from './usePageTitlePriceUpdates';
import { useShouldShowFooter } from './useShouldShowFooter';
import { useSelectedNetwork } from './useSelectedNetwork';
+import { useSquidRouter } from './useSquidRouter';
import { useStringGetter } from './useStringGetter';
import { useSubaccount } from './useSubaccount';
@@ -25,6 +27,7 @@ export {
useBreakpoints,
useCommandMenu,
useCurrentMarketId,
+ useDebounce,
useDocumentTitle,
useDydxClient,
useAccountBalance,
@@ -41,5 +44,6 @@ export {
useShouldShowFooter,
useSelectedNetwork,
useStringGetter,
+ useSquidRouter,
useSubaccount,
};
diff --git a/src/hooks/useAccountBalance.ts b/src/hooks/useAccountBalance.ts
index 1885b90..ea9269a 100644
--- a/src/hooks/useAccountBalance.ts
+++ b/src/hooks/useAccountBalance.ts
@@ -3,7 +3,7 @@ import { useSelector } from 'react-redux';
import { useBalance } from 'wagmi';
import { StargateClient } from '@cosmjs/stargate';
import { useQuery } from 'react-query';
-import { formatUnits } from 'ethers';
+import { formatUnits } from 'viem';
import { CLIENT_NETWORK_CONFIGS, type DydxV4Network } from '@/constants/networks';
import { QUANTUM_MULTIPLIER } from '@/constants/numbers';
@@ -43,7 +43,7 @@ export const useAccountBalance = ({
assetSymbol,
bech32AddrPrefix,
chainId,
- decimals,
+ decimals = 0,
rpc,
isCosmosChain,
}: UseAccountBalanceProps = {}) => {
@@ -66,7 +66,7 @@ export const useAccountBalance = ({
});
const cosmosQueryFn = useCallback(async () => {
- if (dydxAddress && bech32AddrPrefix && rpc) {
+ if (dydxAddress && bech32AddrPrefix && rpc && addressOrDenom) {
const address = convertBech32Address({
address: dydxAddress,
bech32Prefix: bech32AddrPrefix,
@@ -76,14 +76,7 @@ export const useAccountBalance = ({
const balanceAsCoin = await client.getBalance(address, addressOrDenom);
await client.disconnect();
- /**
- * Hardcode decimals because most cosmos coins default to 6 decimals.
- * Squids testnet has some coins as having 18 decimals instead of 6.
- * @url https://github1s.com/cosmos/cosmjs/blob/HEAD/packages/amino/src/coins.ts#L8-L16
- *
- * @todo: change '6' to 'decimals' when Squid testnet data is updated.
- * */
- return formatUnits(balanceAsCoin.amount, decimals);
+ return formatUnits(BigInt(balanceAsCoin.amount), decimals);
}
}, [addressOrDenom, chainId, rpc]);
@@ -109,11 +102,7 @@ export const useAccountBalance = ({
return {
balance,
nativeTokenBalance,
- isBalanceError: isCosmosChain
- ? cosmosQuery.status === 'error' && !cosmosQuery.isFetching
- : evmQuery.status === 'error' && evmQuery.fetchStatus === 'idle',
- isBalanceLoading: isCosmosChain
- ? cosmosQuery.status === 'loading' && cosmosQuery.isFetching
- : evmQuery.status === 'loading' && evmQuery.fetchStatus === 'fetching',
+ queryStatus: isCosmosChain ? cosmosQuery.status : evmQuery.status,
+ isQueryFetching: isCosmosChain ? cosmosQuery.isFetching : evmQuery.fetchStatus === 'fetching',
};
};
diff --git a/src/hooks/useAccounts.tsx b/src/hooks/useAccounts.tsx
index feae33a..c1ce52f 100644
--- a/src/hooks/useAccounts.tsx
+++ b/src/hooks/useAccounts.tsx
@@ -63,6 +63,8 @@ const useAccountsContext = () => {
forgetEvmSignature(previousEvmAddress);
}
+ if (evmAddress) abacusStateManager.setEvmAddress(evmAddress);
+
setPreviousEvmAddress(evmAddress);
}, [evmAddress]);
diff --git a/src/hooks/useDebounce.ts b/src/hooks/useDebounce.ts
new file mode 100644
index 0000000..5b38cc4
--- /dev/null
+++ b/src/hooks/useDebounce.ts
@@ -0,0 +1,21 @@
+import { useEffect, useState } from 'react';
+
+/**
+ * https://usehooks-ts.com/react-hook/use-debounce
+ * @param value
+ * @param delay
+ * @returns the debouncedValue
+ */
+export function useDebounce(value: T, delay?: number): T {
+ const [debouncedValue, setDebouncedValue] = useState(value);
+
+ useEffect(() => {
+ const timer = setTimeout(() => setDebouncedValue(value), delay || 500);
+
+ return () => {
+ clearTimeout(timer);
+ };
+ }, [value, delay]);
+
+ return debouncedValue;
+}
diff --git a/src/hooks/useInitializePage.ts b/src/hooks/useInitializePage.ts
index f7f41dd..b9c66a6 100644
--- a/src/hooks/useInitializePage.ts
+++ b/src/hooks/useInitializePage.ts
@@ -6,7 +6,6 @@ import { LocalStorageKey } from '@/constants/localStorage';
import {
DEFAULT_APP_ENVIRONMENT,
DydxNetwork,
- isDydxV4Network,
isValidDydxNetwork,
} from '@/constants/networks';
@@ -16,8 +15,6 @@ import { initializeLocalization } from '@/state/app';
import abacusStateManager from '@/lib/abacus';
-import squidRouter from '@/lib/squidRouter';
-
export const useInitializePage = () => {
const dispatch = useDispatch();
@@ -31,9 +28,5 @@ export const useInitializePage = () => {
useEffect(() => {
dispatch(initializeLocalization());
abacusStateManager.start({ network: localStorageNetwork });
-
- if (isDydxV4Network(localStorageNetwork)) {
- squidRouter.switchNetwork(localStorageNetwork);
- }
}, []);
};
diff --git a/src/hooks/useSquidRouter.tsx b/src/hooks/useSquidRouter.tsx
new file mode 100644
index 0000000..8cd0cf8
--- /dev/null
+++ b/src/hooks/useSquidRouter.tsx
@@ -0,0 +1,118 @@
+import { createContext, useCallback, useContext, useEffect, useMemo, useState } from 'react';
+import { ethers } from 'ethers';
+import { useSelector } from 'react-redux';
+import { Squid, type GetRoute, type RouteResponse, ChainData, ChainType } from '@0xsquid/sdk';
+import { USDC_DENOM } from '@dydxprotocol/v4-client';
+
+import { TransferInputs } from '@/constants/abacus';
+import { DydxV4Network, isDydxV4Network } from '@/constants/networks';
+import { useAccounts } from '@/hooks/useAccounts';
+
+import { getSelectedNetwork } from '@/state/appSelectors';
+
+const SQUID_BASE_URL: Record = {
+ [DydxV4Network.V4Testnet2]: 'https://squid-api-git-feat-cosmos-maintestnet-0xsquid.vercel.app',
+ [DydxV4Network.V4Staging]: undefined,
+ [DydxV4Network.V4Local]: undefined,
+ [DydxV4Network.V4Mainnet]: 'https://api.0xsquid.com',
+};
+
+/**
+ * @description Deposit route defaults for IBC Testnet
+ * */
+export const SQUID_DEPOSIT_ROUTE_DEFAULTS = {
+ toChain: 'dydx-testnet-2',
+ toToken: USDC_DENOM,
+ enableForecall: false, // instant execution service, defaults to true
+};
+
+export const SQUID_WITHDRAW_ROUTE_DEFAULTS = {
+ fromChain: 'dydx-testnet-2',
+ fromToken: USDC_DENOM,
+ enableForecall: false, // instant execution service, defaults to true
+};
+
+const useSquidContext = () => {
+ const selectedNetwork = useSelector(getSelectedNetwork);
+ const [_, setInitialized] = useState(false);
+
+ const initializeClient = async () => {
+ setInitialized(false);
+ if (!squid) return;
+ await squid.init();
+ setInitialized(true);
+ };
+
+ const squid = useMemo(
+ () =>
+ isDydxV4Network(selectedNetwork)
+ ? new Squid({ baseUrl: SQUID_BASE_URL[selectedNetwork as DydxV4Network] })
+ : undefined,
+ [selectedNetwork]
+ );
+
+ useEffect(() => {
+ if (squid) {
+ initializeClient();
+ }
+ }, [squid]);
+
+ return squid;
+};
+
+type SquidContextType = ReturnType;
+const SquidContext = createContext(undefined);
+SquidContext.displayName = '0xSquid';
+
+export const SquidProvider = ({ ...props }) => (
+
+);
+
+export const useSquid = () => useContext(SquidContext);
+
+export const useSquidRouter = () => {
+ const squid = useSquid();
+ const { signerWagmi } = useAccounts();
+
+ const submitDeposit = useCallback(
+ async (requestPayload: TransferInputs['requestPayload']) => {
+ if (!signerWagmi) {
+ throw new Error('Missing signer');
+ }
+ if (
+ !requestPayload?.targetAddress ||
+ !requestPayload.data ||
+ !requestPayload.value ||
+ !requestPayload.gasLimit ||
+ !requestPayload.gasPrice ||
+ !requestPayload.routeType
+ ) {
+ throw new Error('Missing request payload');
+ }
+ let tx = {
+ to: requestPayload.targetAddress as `0x${string}`,
+ data: requestPayload.data as `0x${string}`,
+ gasLimit: ethers.toBigInt(requestPayload.gasLimit),
+ value:
+ requestPayload.routeType !== 'SEND' ? ethers.toBigInt(requestPayload.value) : undefined,
+ };
+ return await signerWagmi.sendTransaction(tx);
+ },
+ [signerWagmi]
+ );
+
+ const getStatus = useCallback(
+ async (transactionId: string) => {
+ const status = await squid?.getStatus({ transactionId });
+ return status;
+ },
+ [squid]
+ );
+
+ return {
+ getStatus,
+ submitDeposit,
+
+ axelarscanURL: squid?.axelarscanURL,
+ };
+};
diff --git a/src/hooks/useSubaccount.tsx b/src/hooks/useSubaccount.tsx
index 2ce92c5..2a5888c 100644
--- a/src/hooks/useSubaccount.tsx
+++ b/src/hooks/useSubaccount.tsx
@@ -3,7 +3,7 @@ import { useDispatch } from 'react-redux';
import type { Nullable } from '@dydxprotocol/abacus';
import Long from 'long';
import type { IndexedTx } from '@cosmjs/stargate';
-import { type Coin } from '@cosmjs/proto-signing';
+import { EncodeObject, type Coin } from '@cosmjs/proto-signing';
import { Method } from '@cosmjs/tendermint-rpc';
import {
@@ -301,6 +301,32 @@ export const useSubaccountContext = ({ localDydxWallet }: { localDydxWallet?: Lo
return result;
},
+
+ sendSquidWithdraw: async ({
+ subaccount,
+ payload,
+ }:{
+ subaccount: SubaccountClient;
+ payload: string;
+ }) => {
+ const decode = (str: string):string => Buffer.from(str, 'base64').toString('binary');
+ const decoded = decode(payload);
+
+ const json = JSON.parse(decoded);
+
+ const ibcMsg: EncodeObject = {
+ typeUrl: json.msgTypeUrl,
+ value: json.msg,
+ };
+ const encodeObjects: Promise = Promise.resolve([ibcMsg]);
+
+ await compositeClient?.send(
+ subaccount.wallet,
+ () => encodeObjects,
+ false
+ )
+ },
+
}),
[compositeClient]
);
diff --git a/src/layout/DialogManager.tsx b/src/layout/DialogManager.tsx
index 740e2a2..e647bc2 100644
--- a/src/layout/DialogManager.tsx
+++ b/src/layout/DialogManager.tsx
@@ -17,6 +17,7 @@ import { OnboardingDialog } from '@/views/dialogs/OnboardingDialog';
import { ReceiveDialog } from '@/views/dialogs/ReceiveDialog';
import { TradeDialog } from '@/views/dialogs/TradeDialog';
import { TransferDialog } from '@/views/dialogs/TransferDialog';
+import { WithdrawDialog } from '@/views/dialogs/WithdrawDialog';
import { OrderDetailsDialog } from '@/views/dialogs/DetailsDialog/OrderDetailsDialog';
import { FillDetailsDialog } from '@/views/dialogs/DetailsDialog/FillDetailsDialog';
@@ -53,5 +54,6 @@ export const DialogManager = () => {
[DialogTypes.Receive]: ,
[DialogTypes.Trade]: ,
[DialogTypes.Transfer]: ,
+ [DialogTypes.Withdraw]: ,
}[type];
};
diff --git a/src/lib/abacus/index.ts b/src/lib/abacus/index.ts
index 1d43a86..939b96e 100644
--- a/src/lib/abacus/index.ts
+++ b/src/lib/abacus/index.ts
@@ -147,6 +147,10 @@ class AbacusStateManager {
this.stateManager.accountAddress = walletAddress;
};
+ setEvmAddress = (evmAddress: string) => {
+ this.stateManager.sourceAddress = evmAddress;
+ };
+
setSubaccountNumber = (subaccountNumber: number) =>
(this.stateManager.subaccountNumber = subaccountNumber);
diff --git a/src/lib/squidRouter.ts b/src/lib/squidRouter.ts
deleted file mode 100644
index 67cd35f..0000000
--- a/src/lib/squidRouter.ts
+++ /dev/null
@@ -1,140 +0,0 @@
-import { RouteResponse, Squid } from '@0xsquid/sdk';
-import type { GetRoute, ChainData, RouteData, TokenData } from '@0xsquid/sdk';
-
-import { DEFAULT_APP_ENVIRONMENT, DydxV4Network } from '@/constants/networks';
-
-import { log } from './telemetry';
-
-/**
- * @todo dYdX chain will eventually be added to squidSDK as an option for toChain and
- * USDC from Noble chain will also be a possible toToken in the near future. We will
- * need to eventually change these constants.
- * */
-const SQUID_TESTNET_ROUTE_DEFAULTS = {
- toChain: 'osmo-test-4', // Osmosis Testnet
- toToken: 'uausdc', // aUSDC
- enableForecall: true, // instant execution service, defaults to true
- quoteOnly: false, // optional, defaults to false
-};
-
-// This config is for dev only! Used for testing General Message Passing (route provided by 0xSquid)
-const SQUID_TESTNET_AVAX_TO_AXELAR_WITH_GMP = {
- toChain: 'axelar-testnet-lisbon-3',
- toToken: 'uosmo',
- enableForecall: false,
- quoteOnly: false,
-};
-
-const SQUID_MAINNET_ROUTE_DEFAULTS = {
- toChain: 'osmosis-1', // Osmosis Testnet
- toToken: 'uusdc', // aUSDC
- enableForecall: true, // instant execution service, defaults to true
- quoteOnly: false, // optional, defaults to false
-};
-
-class SquidFactory {
- private client: Squid;
- private isInitialized: boolean;
-
- constructor(baseUrl: string) {
- this.client = new Squid({ baseUrl });
- this.isInitialized = false;
- }
-
- async init() {
- if (this.isInitialized) return;
-
- try {
- await this.client.init();
- this.isInitialized = true;
- } catch (error) {
- log('SquidFactory/init', error);
- }
- }
-
- getClient = () => this.client;
-}
-
-const squidClientTestnet = new SquidFactory('https://testnet.api.0xsquid.com'); // new SquidFactory('https://squid-2gwsw7ij1-0xsquid.vercel.app');
-const squidClientMainnet = new SquidFactory('https://api.0xsquid.com');
-
-const SQUID_CLIENT_BY_NETWORK: Record = {
- [DydxV4Network.V4Local]: squidClientTestnet,
- [DydxV4Network.V4Mainnet]: squidClientMainnet,
- [DydxV4Network.V4Staging]: squidClientTestnet,
- [DydxV4Network.V4Testnet2]: squidClientTestnet,
-};
-
-class SquidRouter {
- private client: Squid;
- private network: DydxV4Network;
-
- constructor() {
- this.network = DEFAULT_APP_ENVIRONMENT;
- this.client = SQUID_CLIENT_BY_NETWORK[this.network].getClient();
- }
-
- /**
- * @description the default destination chain/token and other hardcoded options
- */
- get SQUID_ROUTE_DEFAULTS() {
- return {
- [DydxV4Network.V4Local]: SQUID_TESTNET_ROUTE_DEFAULTS,
- [DydxV4Network.V4Staging]: SQUID_TESTNET_ROUTE_DEFAULTS,
- [DydxV4Network.V4Testnet2]: SQUID_TESTNET_ROUTE_DEFAULTS,
- [DydxV4Network.V4Mainnet]: SQUID_MAINNET_ROUTE_DEFAULTS,
- }[this.network];
- }
-
- /**
- * @description updates the client to the correct 0xSquid environment based on which dYdX v4 network is selected.
- * @param network dYdX v4 network that is currently selected
- */
- switchNetwork = (network: DydxV4Network) => {
- this.client = SQUID_CLIENT_BY_NETWORK[network].getClient();
- };
-
- /**
- * @description initializes the Squid client if it was not previously initialized (API request)
- */
- initializeClient = () => SQUID_CLIENT_BY_NETWORK[this.network].init();
-
- /**
- * @returns list of chains supported by Axelar
- */
- getChains = (): ChainData[] => this.client.chains;
-
- /**
- * @returns list of tokens supported by Axelar
- */
- getTokens = (): TokenData[] => this.client.tokens;
-
- /**
- * @param getRouteParams
- * @returns 0xSquid RouteData
- */
- getRoute = async (getRouteParams: GetRoute): Promise => {
- const resp = await this.client.getRoute(getRouteParams);
- return resp;
- };
-
- /**
- * @params {
- * @route the 0xSquid RouteData
- * @signer the EVM/Cosmos Signer used to sign the Axelar bridge
- * }
- * @returns transaction information after the route has been executed
- */
- executeRoute = async ({ route, signer }: { route: RouteData; signer: any }) => {
- const tx = await this.client.executeRoute({
- signer,
- route,
- });
-
- return await tx.wait();
- };
-}
-
-const squidRouter = new SquidRouter();
-
-export default squidRouter;
diff --git a/src/lib/wagmi.ts b/src/lib/wagmi.ts
index 0c2c35d..1bef169 100644
--- a/src/lib/wagmi.ts
+++ b/src/lib/wagmi.ts
@@ -38,6 +38,10 @@ export const WAGMI_SUPPORTED_CHAINS: Chain[] = [
optimismGoerli,
];
+export const WAGMI_SUPPORTED_CHAIN_MAP = Object.fromEntries(
+ WAGMI_SUPPORTED_CHAINS.map((supportedChain) => [supportedChain.id, supportedChain])
+);
+
const { chains, publicClient, webSocketPublicClient } = configureChains(WAGMI_SUPPORTED_CHAINS, [
alchemyProvider({ apiKey: import.meta.env.VITE_ALCHEMY_API_KEY }),
jsonRpcProvider({
@@ -162,7 +166,13 @@ const createWalletConnect2ConnectorWithId = (walletconnect2Id: string) =>
});
// Custom connector from wallet selection
-import { type WalletConnection, WalletConnectionType, type WalletType, walletConnectionTypes, wallets } from '@/constants/wallets';
+import {
+ type WalletConnection,
+ WalletConnectionType,
+ type WalletType,
+ walletConnectionTypes,
+ wallets,
+} from '@/constants/wallets';
export const resolveWagmiConnector = ({
walletType,
@@ -174,15 +184,12 @@ export const resolveWagmiConnector = ({
const walletConfig = wallets[walletType];
const walletConnectionConfig = walletConnectionTypes[walletConnection.type];
- return (
- walletConnection.type === WalletConnectionType.InjectedEip1193 && walletConnection.provider ?
- createInjectedConnectorWithProvider(walletConnection.provider)
- : walletConnection.type === WalletConnectionType.WalletConnect1 && walletConfig.walletconnect1Name ?
- createWalletConnect1ConnectorWithName(walletConfig.walletconnect1Name)
- : walletConnection.type === WalletConnectionType.WalletConnect2 && walletConfig.walletconnect2Id ?
- createWalletConnect2ConnectorWithId(walletConfig.walletconnect2Id)
- : connectors.find(
- ({ id }: { id: string }) => id === walletConnectionConfig.wagmiConnectorId
- )
- );
+ return walletConnection.type === WalletConnectionType.InjectedEip1193 && walletConnection.provider
+ ? createInjectedConnectorWithProvider(walletConnection.provider)
+ : walletConnection.type === WalletConnectionType.WalletConnect1 &&
+ walletConfig.walletconnect1Name
+ ? createWalletConnect1ConnectorWithName(walletConfig.walletconnect1Name)
+ : walletConnection.type === WalletConnectionType.WalletConnect2 && walletConfig.walletconnect2Id
+ ? createWalletConnect2ConnectorWithId(walletConfig.walletconnect2Id)
+ : connectors.find(({ id }: { id: string }) => id === walletConnectionConfig.wagmiConnectorId);
};
diff --git a/src/state/appMiddleware.ts b/src/state/appMiddleware.ts
index 23b5258..c48c494 100644
--- a/src/state/appMiddleware.ts
+++ b/src/state/appMiddleware.ts
@@ -2,13 +2,11 @@ import type { PayloadAction } from '@reduxjs/toolkit';
import { AbacusApiStatus } from '@/constants/abacus';
import { DialogTypes } from '@/constants/dialogs';
-import { isDydxV4Network } from '@/constants/networks';
import { setApiState, setSelectedNetwork } from '@/state/app';
import { resetPerpetualsState } from '@/state/perpetuals';
import abacusStateManager from '@/lib/abacus';
-import squidRouter from '@/lib/squidRouter';
import { openDialog } from './dialogs';
import { getActiveDialog } from './dialogsSelectors';
@@ -22,10 +20,6 @@ export default (store: any) => (next: any) => async (action: PayloadAction)
case setSelectedNetwork.type: {
store.dispatch(resetPerpetualsState());
abacusStateManager.switchNetwork(payload);
-
- if (isDydxV4Network(payload)) {
- squidRouter.switchNetwork(payload);
- }
break;
}
case setApiState.type: {
diff --git a/src/styles/popoverMixins.ts b/src/styles/popoverMixins.ts
index 47932cf..17be685 100644
--- a/src/styles/popoverMixins.ts
+++ b/src/styles/popoverMixins.ts
@@ -61,7 +61,7 @@ export const popoverMixins = {
${layoutMixins.spacedRow}
grid-template-columns: 1fr auto;
- padding-right: 1rem;
+ gap: 0;
border: 1px solid var(--color-layer-6);
`,
diff --git a/src/views/AccountInfo/AccountInfoConnectedState.tsx b/src/views/AccountInfo/AccountInfoConnectedState.tsx
index d04be9a..3af94e9 100644
--- a/src/views/AccountInfo/AccountInfoConnectedState.tsx
+++ b/src/views/AccountInfo/AccountInfoConnectedState.tsx
@@ -72,16 +72,24 @@ export const AccountInfoConnectedState = () => {
{!showHeader ? null : (
{stringGetter({ key: STRING_KEYS.ACCOUNT })}
-
- dispatch(openDialog({ type: DialogTypes.Deposit }))}
- shape={ButtonShape.Pill}
- size={ButtonSize.XSmall}
- slotLeft={}
- >
- {stringGetter({ key: STRING_KEYS.MANAGE_FUNDS })}
-
+
+ dispatch(openDialog({ type: DialogTypes.Withdraw }))}
+ shape={ButtonShape.Pill}
+ size={ButtonSize.XSmall}
+ >
+ {stringGetter({ key: STRING_KEYS.WITHDRAW })}
+
+ dispatch(openDialog({ type: DialogTypes.Deposit }))}
+ shape={ButtonShape.Pill}
+ size={ButtonSize.XSmall}
+ >
+ {stringGetter({ key: STRING_KEYS.DEPOSIT })}
+
+
)}
@@ -273,6 +281,11 @@ Styled.Header = styled.header`
padding: 0 1.25rem;
`;
+Styled.TransferButtons = styled.div`
+ ${layoutMixins.row}
+ gap: 1rem;
+`
+
Styled.ConnectedAccountInfoContainer = styled.div<{ $showHeader?: boolean }>`
${layoutMixins.column}
${layoutMixins.withOuterAndInnerBorders}
diff --git a/src/views/dialogs/DepositDialog.tsx b/src/views/dialogs/DepositDialog.tsx
index 43cee62..9baa069 100644
--- a/src/views/dialogs/DepositDialog.tsx
+++ b/src/views/dialogs/DepositDialog.tsx
@@ -6,8 +6,8 @@ import { useBreakpoints, useStringGetter } from '@/hooks';
import { Dialog, DialogPlacement } from '@/components/Dialog';
-import { DepositForm } from '@/views/forms/DepositForm';
-import { TestnetDepositForm } from '@/views/forms/TestnetDepositForm';
+import { DepositForm } from '@/views/forms/AccountManagementForms/DepositForm';
+import { TestnetDepositForm } from '@/views/forms/AccountManagementForms/TestnetDepositForm';
import { layoutMixins } from '@/styles/layoutMixins';
@@ -32,12 +32,12 @@ export const DepositDialog = ({ setIsOpen }: ElementProps) => {
>
{showTestDeposit ? : }
- {/* TODO TRCL-1693 - uncomment when deposit form is ready
+ {/* TODO TRCL-1693 - uncomment when deposit form is ready */}
{import.meta.env.MODE !== 'production' && (
setShowTestDeposit(!showTestDeposit)}>
{showTestDeposit ? 'Show deposit form (Under Construction)' : 'Show test faucet'}
- )} */}
+ )}
);
diff --git a/src/views/dialogs/OnboardingDialog.tsx b/src/views/dialogs/OnboardingDialog.tsx
index 66079c9..11593f3 100644
--- a/src/views/dialogs/OnboardingDialog.tsx
+++ b/src/views/dialogs/OnboardingDialog.tsx
@@ -19,7 +19,7 @@ import { GreenCheckCircle } from '@/components/GreenCheckCircle';
import { Icon } from '@/components/Icon';
import { Ring } from '@/components/Ring';
-import { TestnetDepositForm } from '@/views/forms/TestnetDepositForm';
+import { TestnetDepositForm } from '@/views/forms/AccountManagementForms/TestnetDepositForm';
import { track } from '@/lib/analytics';
diff --git a/src/views/dialogs/WithdrawDialog.tsx b/src/views/dialogs/WithdrawDialog.tsx
new file mode 100644
index 0000000..13ab110
--- /dev/null
+++ b/src/views/dialogs/WithdrawDialog.tsx
@@ -0,0 +1,56 @@
+import styled, { type AnyStyledComponent } from 'styled-components';
+
+import { STRING_KEYS } from '@/constants/localization';
+import { useBreakpoints, useStringGetter } from '@/hooks';
+
+import { Dialog, DialogPlacement } from '@/components/Dialog';
+
+import { WithdrawForm } from '@/views/forms/AccountManagementForms/WithdrawForm';
+
+import { layoutMixins } from '@/styles/layoutMixins';
+
+type ElementProps = {
+ setIsOpen: (open: boolean) => void;
+};
+
+export const WithdrawDialog = ({ setIsOpen }: ElementProps) => {
+ const stringGetter = useStringGetter();
+ const { isTablet } = useBreakpoints();
+
+ return (
+
+ );
+};
+
+const Styled: Record = {};
+
+Styled.TextToggle = styled.div`
+ ${layoutMixins.stickyFooter}
+ color: var(--color-accent);
+ cursor: pointer;
+
+ margin-top: auto;
+
+ &:hover {
+ text-decoration: underline;
+ }
+`;
+
+Styled.Content = styled.div`
+ ${layoutMixins.stickyArea0}
+ --stickyArea0-bottomHeight: 2rem;
+ --stickyArea0-bottomGap: 1rem;
+ --stickyArea0-totalInsetBottom: 0.5rem;
+
+ ${layoutMixins.flexColumn}
+ gap: 1rem;
+`;
diff --git a/src/views/forms/DepositForm/ChainSelectMenu.tsx b/src/views/forms/AccountManagementForms/ChainSelectMenu.tsx
similarity index 50%
rename from src/views/forms/DepositForm/ChainSelectMenu.tsx
rename to src/views/forms/AccountManagementForms/ChainSelectMenu.tsx
index 1d84f4c..94853de 100644
--- a/src/views/forms/DepositForm/ChainSelectMenu.tsx
+++ b/src/views/forms/AccountManagementForms/ChainSelectMenu.tsx
@@ -1,29 +1,43 @@
import type { ChainData } from '@0xsquid/sdk';
import styled, { type AnyStyledComponent } from 'styled-components';
+import { shallowEqual, useSelector } from 'react-redux';
+import { TransferInputChainResource, TransferType } from '@/constants/abacus';
import { STRING_KEYS } from '@/constants/localization';
import { useStringGetter } from '@/hooks';
-import { WithLabel } from '@/components/WithLabel';
import { SearchSelectMenu } from '@/components/SearchSelectMenu';
import { layoutMixins } from '@/styles/layoutMixins';
import { popoverMixins } from '@/styles/popoverMixins';
+import { getTransferInputs } from '@/state/inputsSelectors';
+
type ElementProps = {
- chains?: ChainData[];
- currentChain?: ChainData;
- setCurrentChain: (chain: ChainData) => void;
+ label?: string;
+ selectedChain?: TransferInputChainResource;
+ onSelectChain: (chain: TransferInputChainResource) => void;
};
-export const ChainSelectMenu = ({ chains = [], currentChain, setCurrentChain }: ElementProps) => {
+export const ChainSelectMenu = ({
+ label,
+ selectedChain,
+ onSelectChain,
+}: ElementProps) => {
const stringGetter = useStringGetter();
+ const { type, depositOptions, withdrawalOptions, resources } =
+ useSelector(getTransferInputs, shallowEqual) || {};
+ const chains =
+ (type === TransferType.deposit ? depositOptions : withdrawalOptions)?.chains?.toArray() || [];
- const chainItems = Object.values(chains).map((chain: ChainData) => ({
- value: chain.chainId.toString(),
- label: chain.chainName,
- onSelect: () => setCurrentChain(chain),
- slotBefore: ,
+ const chainItems = Object.values(chains).map((chain) => ({
+ value: chain.type,
+ label: chain.stringKey,
+ onSelect: () => {
+ const selectedChain = resources?.chainResources?.get(chain.type);
+ selectedChain && onSelectChain(selectedChain);
+ },
+ slotBefore: ,
}));
return (
@@ -35,12 +49,12 @@ export const ChainSelectMenu = ({ chains = [], currentChain, setCurrentChain }:
items: chainItems,
},
]}
- label="Source"
+ label={label || (type === TransferType.deposit ? 'Source' : 'Destination')}
>
- {currentChain ? (
+ {selectedChain ? (
<>
- {currentChain?.chainName}
+ {selectedChain?.chainName}
>
) : (
stringGetter({ key: STRING_KEYS.SELECT_CHAIN })
@@ -67,4 +81,4 @@ Styled.ChainRow = styled.div`
gap: 0.5rem;
color: var(--color-text-2);
font: var(--font-base-book);
-`;
+`;
\ No newline at end of file
diff --git a/src/views/forms/AccountManagementForms/DepositForm.tsx b/src/views/forms/AccountManagementForms/DepositForm.tsx
new file mode 100644
index 0000000..0f6bb42
--- /dev/null
+++ b/src/views/forms/AccountManagementForms/DepositForm.tsx
@@ -0,0 +1,305 @@
+import { type FormEvent, useCallback, useEffect, useMemo, useState } from 'react';
+import styled, { type AnyStyledComponent } from 'styled-components';
+import { type NumberFormatValues } from 'react-number-format';
+import { shallowEqual, useSelector } from 'react-redux';
+
+import {
+ TransferInputField,
+ TransferInputChainResource,
+ TransferInputTokenResource,
+ TransferType,
+} from '@/constants/abacus';
+import { AlertType } from '@/constants/alerts';
+import { ButtonSize } from '@/constants/buttons';
+import { StringGetterFunction, STRING_KEYS } from '@/constants/localization';
+import { NumberSign } from '@/constants/numbers';
+
+import { useDebounce, useStringGetter, useSquidRouter } from '@/hooks';
+import { useAccountBalance } from '@/hooks/useAccountBalance';
+
+import { layoutMixins } from '@/styles/layoutMixins';
+
+import { AlertMessage } from '@/components/AlertMessage';
+import { Button } from '@/components/Button';
+import { DiffOutput } from '@/components/DiffOutput';
+import { FormInput } from '@/components/FormInput';
+import { Icon, IconName } from '@/components/Icon';
+import { InputType } from '@/components/Input';
+import { Link } from '@/components/Link';
+import { LoadingSpace } from '@/components/Loading/LoadingSpinner';
+import { OutputType } from '@/components/Output';
+import { Tag } from '@/components/Tag';
+import { WithDetailsReceipt } from '@/components/WithDetailsReceipt';
+
+import abacusStateManager from '@/lib/abacus';
+import { MustBigNumber } from '@/lib/numbers';
+
+import { ChainSelectMenu } from './ChainSelectMenu';
+import { TokenSelectMenu } from './TokenSelectMenu';
+
+import { DepositButtonAndReceipt } from './DepositForm/DepositButtonAndReceipt';
+
+import { getTransferInputs } from '@/state/inputsSelectors';
+
+type DepositFormProps = {
+ onDeposit?: () => void;
+ onError?: () => void;
+};
+
+export const DepositForm = ({ onDeposit, onError }: DepositFormProps) => {
+ const stringGetter = useStringGetter();
+ const [error, setError] = useState(null);
+ const [isLoading, setIsLoading] = useState(false);
+
+ const { submitDeposit, axelarscanURL } = useSquidRouter();
+
+ const { requestPayload, token, chain, resources } = useSelector(getTransferInputs) || {};
+
+ // User inputs
+ const sourceChain = useMemo(
+ () => (chain ? resources?.chainResources?.get(chain) : undefined),
+ [chain, resources]
+ );
+
+ const sourceToken = useMemo(
+ () => (token ? resources?.tokenResources?.get(token) : undefined),
+ [token, resources]
+ );
+
+ const [fromAmount, setFromAmount] = useState('');
+ const [slippage, setSlippage] = useState(0.01); // 1% slippage
+ const debouncedAmount = useDebounce(fromAmount, 500);
+
+ // Async Data
+ const [transactionHash, setTransactionHash] = useState();
+
+ const { balance, queryStatus, isQueryFetching } = useAccountBalance({
+ addressOrDenom: sourceToken?.address || undefined,
+ assetSymbol: sourceToken?.symbol || undefined,
+ chainId: sourceChain?.chainId || undefined,
+ decimals: sourceToken?.decimals || undefined,
+ rpc: sourceChain?.rpc || undefined,
+ isCosmosChain: false,
+ });
+
+ // BN
+ const debouncedAmountBN = MustBigNumber(debouncedAmount);
+ const balanceBN = MustBigNumber(balance);
+
+ useEffect(() => {
+ const hasInvalidInput =
+ debouncedAmountBN.isNaN() || debouncedAmountBN.lte(0) || debouncedAmountBN.gte(balanceBN);
+
+ abacusStateManager.setTransferValue({
+ value: hasInvalidInput ? 0 : debouncedAmount,
+ field: TransferInputField.size,
+ });
+
+ setError(null);
+ }, [debouncedAmountBN.toNumber()]);
+
+ useEffect(() => {
+ abacusStateManager.setTransferValue({
+ value: TransferType.deposit.rawValue,
+ field: TransferInputField.type,
+ });
+
+ return () => {
+ abacusStateManager.clearTransferInputValues();
+ };
+ }, []);
+
+ useEffect(() => {
+ if (error) onError?.();
+ }, [error]);
+
+ const onSelectChain = useCallback((chain: TransferInputChainResource) => {
+ if (chain) {
+ abacusStateManager.clearTransferInputValues();
+ abacusStateManager.setTransferValue({
+ field: TransferInputField.chain,
+ value: chain.chainId,
+ });
+ setFromAmount('');
+ }
+ }, []);
+
+ const onSelectToken = useCallback((token: TransferInputTokenResource) => {
+ if (token) {
+ abacusStateManager.clearTransferInputValues();
+ abacusStateManager.setTransferValue({
+ field: TransferInputField.token,
+ value: token.address,
+ });
+ setFromAmount('');
+ }
+ }, []);
+
+ const onChangeAmount = useCallback(
+ ({ value }: NumberFormatValues) => {
+ setFromAmount(value);
+ },
+ [setFromAmount]
+ );
+
+ const onSetSlippage = useCallback(
+ (newSlippage: number) => {
+ setSlippage(newSlippage);
+ // TODO: to be implemented via abacus
+ },
+ [setSlippage, debouncedAmount]
+ );
+
+ const onClickMax = useCallback(() => {
+ if (balance) {
+ setFromAmount(balanceBN.toString());
+ }
+ }, [balance, setFromAmount]);
+
+ const amountInputReceipt = [
+ {
+ key: 'amount',
+ label: (
+
+ {stringGetter({ key: STRING_KEYS.AVAILABLE })}{' '}
+ {sourceToken && {sourceToken.symbol}}
+
+ ),
+ value: (
+
+ ),
+ },
+ ];
+
+ const errorMessage = useMemo(() => {
+ if (error) {
+ return error?.message
+ ? stringGetter({
+ key: STRING_KEYS.SOMETHING_WENT_WRONG_WITH_MESSAGE,
+ params: { ERROR_MESSAGE: error.message },
+ })
+ : stringGetter({ key: STRING_KEYS.SOMETHING_WENT_WRONG });
+ }
+
+ if (fromAmount) {
+ if (!sourceChain) {
+ return stringGetter({ key: STRING_KEYS.MUST_SPECIFY_CHAIN });
+ } else if (!sourceToken) {
+ return stringGetter({ key: STRING_KEYS.MUST_SPECIFY_ASSET });
+ }
+ }
+
+ if (MustBigNumber(fromAmount).gt(MustBigNumber(balance))) {
+ return stringGetter({ key: STRING_KEYS.DEPOSIT_MORE_THAN_BALANCE });
+ }
+
+ return undefined;
+ }, [error, balance, sourceChain, fromAmount, sourceToken])
+
+ const isDisabled =
+ Boolean(errorMessage) ||
+ !sourceToken ||
+ !sourceChain ||
+ debouncedAmountBN.isNaN() ||
+ debouncedAmountBN.isZero();
+
+ if (!resources) {
+ return ;
+ }
+
+ return (
+ {
+ try {
+ e.preventDefault();
+ setIsLoading(true);
+ const txHash = await submitDeposit(requestPayload);
+ onDeposit?.();
+ setTransactionHash(txHash);
+ } catch (error) {
+ setError(error);
+ } finally {
+ setIsLoading(false);
+ }
+ }}
+ >
+
+
+
+
+ {stringGetter({ key: STRING_KEYS.MAX })}
+
+ }
+ />
+
+ {errorMessage ? (
+ {errorMessage}
+ ) : (
+ transactionHash && (
+
+
+ {stringGetter({ key: STRING_KEYS.DEPOSIT_IN_PROGRESS })}
+
+
+
+ {stringGetter({ key: STRING_KEYS.VIEW_TRANSACTION })}
+
+
+
+
+ )
+ )}
+
+
+ );
+};
+
+const Styled: Record = {};
+
+Styled.Form = styled.form`
+ ${layoutMixins.flexColumn}
+ gap: 1.5rem;
+
+ ${layoutMixins.stickyArea1}
+ min-height: calc(100% - var(--stickyArea0-bottomHeight));
+`;
+
+Styled.WithDetailsReceipt = styled(WithDetailsReceipt)`
+ --withReceipt-backgroundColor: var(--color-layer-2);
+`;
+
+Styled.Link = styled(Link)`
+ color: var(--color-accent);
+
+ &:visited {
+ color: var(--color-accent);
+ }
+`;
+
+Styled.TransactionInfo = styled.span`
+ ${layoutMixins.row}
+`;
diff --git a/src/views/forms/DepositForm/DepositButtonAndReceipt.tsx b/src/views/forms/AccountManagementForms/DepositForm/DepositButtonAndReceipt.tsx
similarity index 75%
rename from src/views/forms/DepositForm/DepositButtonAndReceipt.tsx
rename to src/views/forms/AccountManagementForms/DepositForm/DepositButtonAndReceipt.tsx
index f7595a1..9939a8a 100644
--- a/src/views/forms/DepositForm/DepositButtonAndReceipt.tsx
+++ b/src/views/forms/AccountManagementForms/DepositForm/DepositButtonAndReceipt.tsx
@@ -1,4 +1,4 @@
-import { type Dispatch, type SetStateAction, useState } from 'react';
+import { type Dispatch, useMemo, type SetStateAction, useState, type ReactNode } from 'react';
import styled, { type AnyStyledComponent, css } from 'styled-components';
import { shallowEqual, useSelector } from 'react-redux';
import type { RouteData, TokenData } from '@0xsquid/sdk';
@@ -12,6 +12,7 @@ import {
ButtonType,
} from '@/constants/buttons';
+import { TransferInputTokenResource } from '@/constants/abacus';
import { STRING_KEYS } from '@/constants/localization';
import { NumberSign } from '@/constants/numbers';
@@ -30,11 +31,11 @@ import { ToggleButton } from '@/components/ToggleButton';
import { WithReceipt } from '@/components/WithReceipt';
import { getSubaccountBuyingPower, getSubaccountEquity } from '@/state/accountSelectors';
+import { getTransferInputs } from '@/state/inputsSelectors';
import { BIG_NUMBERS, MustBigNumber } from '@/lib/numbers';
-import squidRouter from '@/lib/squidRouter';
-import { SlippageEditor } from './SlippageEditor';
+import { SlippageEditor } from '../SlippageEditor';
type ElementProps = {
isDisabled?: boolean;
@@ -43,8 +44,9 @@ type ElementProps = {
chainId?: string | number;
setError?: Dispatch>;
slippage: number;
+ slotError?: ReactNode;
setSlippage: (slippage: number) => void;
- sourceToken?: TokenData;
+ sourceToken?: TransferInputTokenResource;
squidRoute?: RouteData;
};
@@ -54,10 +56,9 @@ export const DepositButtonAndReceipt = ({
slippage,
setSlippage,
sourceToken,
- squidRoute,
isDisabled,
- isLoading,
+ slotError,
}: ElementProps) => {
const [showFeeBreakdown, setShowFeeBreakdown] = useState(false);
const [isEditingSlippage, setIsEditingSlipapge] = useState(false);
@@ -78,35 +79,23 @@ export const DepositButtonAndReceipt = ({
const { current: buyingPower, postOrder: newBuyingPower } =
useSelector(getSubaccountBuyingPower, shallowEqual) || {};
- const { gasCosts, feeCosts } = squidRoute?.estimate || {};
+ const { summary, requestPayload } = useSelector(getTransferInputs, shallowEqual) || {};
- const totalGasCosts =
- gasCosts?.reduce(
- (acc: BigNumber, { amountUSD }: { amountUSD: string }) => acc.plus(MustBigNumber(amountUSD)),
- BIG_NUMBERS.ZERO
- ) || BIG_NUMBERS.ZERO;
+ const feeSubitems: DetailsItem[] = [];
- const totalFeeCosts =
- feeCosts?.reduce(
- (acc: BigNumber, { amountUSD }: { amountUSD: string }) => acc.plus(MustBigNumber(amountUSD)),
- BIG_NUMBERS.ZERO
- ) || BIG_NUMBERS.ZERO;
-
- const totalFees = totalGasCosts.plus(totalFeeCosts);
-
- const feeSubitems: DetailsItem[] = feeCosts
- ? feeCosts.map(({ amountUSD, name }: { amountUSD: string; name: string }) => ({
- key: name,
- label: {name},
- value: ,
- }))
- : [];
-
- if (gasCosts) {
+ if (typeof summary?.gasFee === 'number') {
feeSubitems.push({
key: 'gas-fees',
label: {stringGetter({ key: STRING_KEYS.GAS_FEE })},
- value: ,
+ value: ,
+ });
+ }
+
+ if (typeof summary?.bridgeFee === 'number') {
+ feeSubitems.push({
+ key: 'bridge-fees',
+ label: Bridge Fee,
+ value: ,
});
}
@@ -128,9 +117,9 @@ export const DepositButtonAndReceipt = ({
),
},
@@ -154,27 +143,20 @@ export const DepositButtonAndReceipt = ({
{
key: 'exchange-rate',
label: {stringGetter({ key: STRING_KEYS.EXCHANGE_RATE })},
- value: sourceToken && squidRoute && (
+ value: typeof summary?.exchangeRate === 'number' && (
-
),
},
{
key: 'total-fees',
label: {stringGetter({ key: STRING_KEYS.TOTAL_FEES })},
- value: squidRoute && ,
+ value: typeof summary?.bridgeFee === 'number' && typeof summary?.gasFee === 'number' && (
+
+ ),
subitems: feeSubitems,
},
{
@@ -191,6 +173,7 @@ export const DepositButtonAndReceipt = ({
];
const isFormValid = !isDisabled && !isEditingSlippage;
+ const isLoading = isFormValid && !requestPayload;
return (
}
+ slotError={slotError}
>
{!isMatchingNetwork ? (
) : (
-
+ }
+ />
+
+ {errorMessage ? (
+ {errorMessage}
+ ) : (
+ transactionHash && (
+
+
+ {stringGetter({ key: STRING_KEYS.DEPOSIT_IN_PROGRESS })}
+
+
+
+ {stringGetter({ key: STRING_KEYS.VIEW_TRANSACTION })}
+
+
+
+
+ )
+ )}
+
+
+ );
+};
+
+const Styled: Record = {};
+
+Styled.DiffOutput = styled(DiffOutput)`
+ --diffOutput-valueWithDiff-fontSize: 1em;
+`;
+
+Styled.Form = styled.form`
+ min-height: calc(100% - var(--stickyArea0-bottomHeight));
+
+ ${layoutMixins.flexColumn}
+ gap: 1.25rem;
+
+ ${layoutMixins.stickyArea1}
+`;
+
+Styled.DestinationRow = styled.div`
+ ${layoutMixins.spacedRow}
+ grid-template-columns: 1fr 1fr;
+ gap: 1rem;
+`;
+
+Styled.WithDetailsReceipt = styled(WithDetailsReceipt)`
+ --withReceipt-backgroundColor: var(--color-layer-2);
+`;
+
+Styled.Link = styled(Link)`
+ color: var(--color-accent);
+
+ &:visited {
+ color: var(--color-accent);
+ }
+`;
+
+Styled.TransactionInfo = styled.span`
+ ${layoutMixins.row}
+`;
\ No newline at end of file
diff --git a/src/views/forms/AccountManagementForms/WithdrawForm/WithdrawButtonAndReceipt.tsx b/src/views/forms/AccountManagementForms/WithdrawForm/WithdrawButtonAndReceipt.tsx
new file mode 100644
index 0000000..f393d80
--- /dev/null
+++ b/src/views/forms/AccountManagementForms/WithdrawForm/WithdrawButtonAndReceipt.tsx
@@ -0,0 +1,249 @@
+import { type Dispatch, type SetStateAction, useState } from 'react';
+import { shallowEqual, useSelector } from 'react-redux';
+import styled, { type AnyStyledComponent } from 'styled-components';
+import { ChainType } from '@0xsquid/sdk';
+import type { ChainData, CosmosChain, RouteData, TokenData } from '@0xsquid/sdk';
+import BigNumber from 'bignumber.js';
+import { parseUnits } from 'viem';
+
+import { TransferInputChainResource, TransferInputTokenResource } from '@/constants/abacus';
+import { ButtonAction, ButtonShape, ButtonSize, ButtonType } from '@/constants/buttons';
+import { STRING_KEYS } from '@/constants/localization';
+import { NumberSign } from '@/constants/numbers';
+import { useStringGetter } from '@/hooks';
+import { useAccountBalance } from '@/hooks/useAccountBalance';
+import { layoutMixins } from '@/styles/layoutMixins';
+
+import { Button } from '@/components/Button';
+
+import { Details, DetailsItem } from '@/components/Details';
+import { DiffOutput } from '@/components/DiffOutput';
+import { Icon, IconName } from '@/components/Icon';
+import { Output, OutputType } from '@/components/Output';
+import { Tag } from '@/components/Tag';
+import { ToggleButton } from '@/components/ToggleButton';
+import { WithReceipt } from '@/components/WithReceipt';
+
+import { BIG_NUMBERS, MustBigNumber } from '@/lib/numbers';
+
+import { SlippageEditor } from '../SlippageEditor';
+
+import { getSubaccount } from '@/state/accountSelectors';
+import { getTransferInputs } from '@/state/inputsSelectors';
+
+type ElementProps = {
+ setError?: Dispatch>;
+ setSlippage: (slippage: number) => void;
+
+ slippage: number;
+ withdrawChain?: TransferInputChainResource;
+ withdrawToken?: TransferInputTokenResource;
+
+ isDisabled?: boolean;
+ isLoading?: boolean;
+};
+
+export const WithdrawButtonAndReceipt = ({
+ setError,
+ setSlippage,
+
+ slippage,
+ withdrawChain,
+ withdrawToken,
+
+ isDisabled,
+ isLoading,
+}: ElementProps) => {
+ const [showFeeBreakdown, setShowFeeBreakdown] = useState(false);
+ const [isEditingSlippage, setIsEditingSlipapge] = useState(false);
+ const stringGetter = useStringGetter();
+
+ const { balance, queryStatus } = useAccountBalance({
+ addressOrDenom: withdrawToken?.address || undefined,
+ assetSymbol: withdrawToken?.symbol || undefined,
+ chainId: withdrawChain?.chainId || undefined,
+ decimals: withdrawToken?.decimals || undefined,
+ rpc: withdrawChain?.rpc || undefined,
+ isCosmosChain: false,
+ });
+
+ const balanceBN = MustBigNumber(balance);
+ // const newBalance =
+ // // toAmountMin && withdrawToken && parseUnits(toAmountMin, withdrawToken.decimals).toString();
+
+ const { leverage } = useSelector(getSubaccount, shallowEqual) || {};
+ const { summary, requestPayload } = useSelector(getTransferInputs) || {};
+
+ const feeSubitems: DetailsItem[] = [];
+
+ if (typeof summary?.gasFee === 'number') {
+ feeSubitems.push({
+ key: 'gas-fees',
+ label: {stringGetter({ key: STRING_KEYS.GAS_FEE })},
+ value: ,
+ });
+ }
+
+ if (typeof summary?.bridgeFee === 'number') {
+ feeSubitems.push({
+ key: 'bridge-fees',
+ label: Bridge Fee,
+ value: ,
+ });
+ }
+
+ const hasSubitems = feeSubitems.length > 0;
+
+ const showSubitemsToggle = showFeeBreakdown
+ ? stringGetter({ key: STRING_KEYS.HIDE_ALL_DETAILS })
+ : stringGetter({ key: STRING_KEYS.SHOW_ALL_DETAILS });
+
+ const submitButtonReceipt = [
+ {
+ key: 'total-fees',
+ label: {stringGetter({ key: STRING_KEYS.TOTAL_FEES })},
+ value: typeof summary?.bridgeFee === 'number' && typeof summary?.gasFee === 'number' && (
+
+ ),
+ subitems: feeSubitems,
+ },
+ {
+ key: 'leverage',
+ label: {stringGetter({ key: STRING_KEYS.LEVERAGE })},
+ value: (
+
+ ),
+ },
+ {
+ key: 'exchange-rate',
+ label: {stringGetter({ key: STRING_KEYS.EXCHANGE_RATE })},
+ value: withdrawToken && (
+
+
+ =
+
+
+ ),
+ },
+ {
+ key: 'slippage',
+ label: {stringGetter({ key: STRING_KEYS.SLIPPAGE })},
+ value: (
+
+ ),
+ },
+ // {
+ // key: 'wallet',
+ // label: (
+ //
+ // {stringGetter({ key: STRING_KEYS.WALLET })}{' '}
+ // {withdrawToken && {withdrawToken?.symbol}}
+ //
+ // ),
+ // value: (
+ //
+ // ),
+ // },
+ ];
+
+ return (
+
+
+ {hasSubitems && (
+
+ setShowFeeBreakdown(!showFeeBreakdown)}
+ slotLeft={}
+ >
+ {showSubitemsToggle}
+
+
+ )}
+
+ }
+ >
+
+ {stringGetter({ key: STRING_KEYS.WITHDRAW })}
+
+
+ );
+};
+
+const Styled: Record = {};
+
+Styled.DiffOutput = styled(DiffOutput)`
+ --diffOutput-valueWithDiff-fontSize: 1em;
+`;
+
+Styled.ExchangeRate = styled.span`
+ ${layoutMixins.row}
+ gap: 0.5ch;
+`;
+
+Styled.WithReceipt = styled(WithReceipt)`
+ --withReceipt-backgroundColor: var(--color-layer-2);
+`;
+
+Styled.CollapsibleDetails = styled.div`
+ ${layoutMixins.column}
+ padding: 0.375rem 1rem 0.5rem;
+ gap: 0.5rem;
+`;
+
+Styled.Details = styled(Details)`
+ font-size: 0.8125em;
+`;
+
+Styled.DetailButtons = styled.div`
+ ${layoutMixins.spacedRow}
+`;
+
+Styled.ToggleButton = styled(ToggleButton)`
+ --button-toggle-off-backgroundColor: transparent;
+ --button-toggle-on-backgroundColor: transparent;
+ --button-toggle-on-textColor: var(--color-text-0);
+
+ svg {
+ width: 0.875em;
+ height: 0.875em;
+ }
+
+ &[data-state='on'] {
+ svg {
+ transform: rotate(180deg);
+ }
+ }
+`;
diff --git a/src/views/forms/DepositForm.tsx b/src/views/forms/DepositForm.tsx
deleted file mode 100644
index d64d522..0000000
--- a/src/views/forms/DepositForm.tsx
+++ /dev/null
@@ -1,428 +0,0 @@
-import { type FormEvent, useCallback, useEffect, useMemo, useState } from 'react';
-import { useSelector } from 'react-redux';
-import styled, { type AnyStyledComponent } from 'styled-components';
-import type { ChainData, CosmosChain, RouteData, TokenData } from '@0xsquid/sdk';
-import { type NumberFormatValues } from 'react-number-format';
-import debounce from 'lodash/debounce';
-import { parseUnits } from 'ethers';
-
-import { TransferInputField } from '@/constants/abacus';
-import { AlertType } from '@/constants/alerts';
-import { ButtonSize } from '@/constants/buttons';
-import { StringGetterFunction, STRING_KEYS } from '@/constants/localization';
-import { NumberSign } from '@/constants/numbers';
-import { CLIENT_NETWORK_CONFIGS, type DydxV4Network } from '@/constants/networks';
-
-import { useAccounts, useDydxClient, useStringGetter } from '@/hooks';
-import { useAccountBalance } from '@/hooks/useAccountBalance';
-import { layoutMixins } from '@/styles/layoutMixins';
-
-import { AlertMessage } from '@/components/AlertMessage';
-import { Button } from '@/components/Button';
-import { DiffOutput } from '@/components/DiffOutput';
-import { FormInput } from '@/components/FormInput';
-import { InputType } from '@/components/Input';
-import { Link } from '@/components/Link';
-import { OutputType } from '@/components/Output';
-import { Tag } from '@/components/Tag';
-import { WithLabel } from '@/components/WithLabel';
-import { WithDetailsReceipt } from '@/components/WithDetailsReceipt';
-
-import abacusStateManager from '@/lib/abacus';
-import { convertBech32Address } from '@/lib/addressUtils';
-import { MustBigNumber } from '@/lib/numbers';
-import squidRouter from '@/lib/squidRouter';
-
-import { useSquidData } from './DepositForm/useSquidData';
-import { ChainSelectMenu } from './DepositForm/ChainSelectMenu';
-import { DepositButtonAndReceipt } from './DepositForm/DepositButtonAndReceipt';
-import { TokenSelectMenu } from './DepositForm/TokenSelectMenu';
-import { log } from '@/lib/telemetry';
-
-import { getSelectedNetwork } from '@/state/appSelectors';
-
-type DepositFormProps = {
- onDeposit?: () => void;
- onError?: () => void;
-};
-
-// debounced function should be outside our functional component
-const debouncedGetRoute = debounce(
- async ({
- amount,
- currentChain,
- cosmosAddress,
- fromAmount,
- setAbacusTransferInput,
- setError,
- setIsLoading,
- setSquidRoute,
- slippage,
- sourceToken,
- }) => {
- if (!currentChain || !sourceToken || !fromAmount || !cosmosAddress) return;
- setIsLoading(true);
- setSquidRoute(undefined);
- setError(undefined);
-
- const params = {
- fromChain: currentChain.chainId,
- fromToken: sourceToken.address,
- fromAmount: parseUnits(amount, sourceToken.decimals).toString(),
- toAddress: convertBech32Address({ address: cosmosAddress, bech32Prefix: 'osmo' }), // the recipient of the trade
- slippage: slippage * 100,
- ...squidRouter.SQUID_ROUTE_DEFAULTS,
- };
-
- try {
- const { route } = await squidRouter.getRoute(params);
- setSquidRoute(route);
- setAbacusTransferInput(route.estimate.toAmountUSD);
- } catch (error) {
- log('DepositForm/getRoute', error);
- setError(error);
- } finally {
- setIsLoading(false);
- }
- },
- 1000,
- { trailing: true }
-);
-
-const getDepositFormErrorMessage = ({
- error,
- balance,
- currentChain,
- fromAmount,
- sourceToken,
- stringGetter,
-}: {
- error?: any;
- balance?: string;
- currentChain?: ChainData;
- fromAmount: string;
- sourceToken?: TokenData;
- stringGetter: StringGetterFunction;
-}): string | undefined => {
- if (error) {
- return error?.message
- ? stringGetter({
- key: STRING_KEYS.SOMETHING_WENT_WRONG_WITH_MESSAGE,
- params: { ERROR_MESSAGE: error.message },
- })
- : stringGetter({ key: STRING_KEYS.SOMETHING_WENT_WRONG });
- }
-
- if (fromAmount) {
- if (!currentChain) {
- return stringGetter({ key: STRING_KEYS.MUST_SPECIFY_CHAIN });
- } else if (!sourceToken) {
- return stringGetter({ key: STRING_KEYS.MUST_SPECIFY_ASSET });
- }
- }
-
- if (MustBigNumber(fromAmount).gt(MustBigNumber(balance))) {
- return stringGetter({ key: STRING_KEYS.DEPOSIT_MORE_THAN_BALANCE });
- }
-
- return undefined;
-};
-
-export const DepositForm = ({ onDeposit, onError }: DepositFormProps) => {
- const stringGetter = useStringGetter();
-
- const { dydxAddress: cosmosAddress, signerWagmi, signerGraz } = useAccounts();
-
- // const { networkConfig } = useDydxClient();
- const selectedNetwork = useSelector(getSelectedNetwork);
- const evmChainId = Number(CLIENT_NETWORK_CONFIGS[selectedNetwork as DydxV4Network].ethereumChainId);
-
- const { chains, tokens } = useSquidData(signerGraz ? 'cosmos' : 'evm');
-
- // User inputs
- const defaultChain: ChainData | undefined = useMemo(
- () => chains?.find(({ chainId }) => chainId === evmChainId) ?? undefined,
- [chains]
- );
- const [currentChain, setCurrentChain] = useState(defaultChain);
-
- const defaultToken: TokenData | undefined = useMemo(
- () => tokens?.filter(({ chainId }) => chainId === currentChain?.chainId)?.[0] ?? undefined,
- [currentChain]
- );
- const [sourceToken, setSourceToken] = useState(defaultToken);
- const [fromAmount, setFromAmount] = useState('');
- const [slippage, setSlippage] = useState(0.001); // 0.1% slippage
-
- // Async Data
- const [squidRoute, setSquidRoute] = useState();
- const [transactionHash, setTransactionHash] = useState();
-
- // Form states
- const [error, setError] = useState();
- const [isLoading, setIsLoading] = useState(false);
-
- useEffect(() => {
- setCurrentChain(defaultChain);
-
- return () => {
- abacusStateManager.clearTransferInputValues();
- };
- }, [defaultChain]);
-
- useEffect(() => {
- setSourceToken(defaultToken);
- setSquidRoute(undefined);
- setFromAmount('');
- }, [currentChain]);
-
- // @ts-ignore ibcDenom exists but is not typed properly on 0xSquid SDK
- const addressOrDenom = sourceToken?.ibcDenom || sourceToken?.address;
- const bech32AddrPrefix = (currentChain as CosmosChain)?.bech32Config?.bech32PrefixAccAddr;
-
- const { balance, isBalanceError, isBalanceLoading } = useAccountBalance({
- addressOrDenom,
- assetSymbol: sourceToken?.symbol,
- bech32AddrPrefix,
- chainId: currentChain?.chainId,
- decimals: sourceToken?.decimals,
- rpc: currentChain?.rpc,
- isCosmosChain: currentChain?.chainType === 'cosmos',
- });
-
- // BN
- const fromAmountBN = MustBigNumber(fromAmount);
- const balanceBN = MustBigNumber(balance);
-
- const requestDeposit = async () => {
- if (!squidRoute) {
- log('DepositForm/requestDeposit', new Error('No squid route'));
- return;
- }
-
- try {
- setIsLoading(true);
- setError(undefined);
- setTransactionHash(undefined);
-
- const txReceipt = await squidRouter.executeRoute({
- route: squidRoute,
- signer: signerGraz || signerWagmi,
- });
- console.log('DepositForm/executeRoute', { txReceipt });
- setFromAmount('');
- setTransactionHash(txReceipt?.transactionHash);
- } catch (error) {
- log('DepositForm/executeRoute', error);
- setError(error);
- } finally {
- setIsLoading(false);
- }
- };
-
- const setAbacusTransferInput = (value: string | number) => {
- abacusStateManager.setTransferValue({ value, field: TransferInputField.usdcSize });
- };
-
- const getRoute = useCallback(
- ({ newAmount, newSlippage }: { newAmount: string; newSlippage?: number }) => {
- debouncedGetRoute.cancel();
-
- if (MustBigNumber(newAmount).gt(0) && MustBigNumber(newAmount).lte(balanceBN)) {
- debouncedGetRoute({
- amount: newAmount,
- currentChain,
- cosmosAddress,
- fromAmount,
- setAbacusTransferInput,
- setError,
- setIsLoading,
- setSquidRoute,
- slippage: newSlippage || slippage,
- sourceToken,
- });
- } else {
- setSquidRoute(undefined);
- setAbacusTransferInput(0);
- }
- },
- [currentChain, sourceToken, fromAmount, slippage]
- );
-
- const onChangeAmount = ({ value }: NumberFormatValues) => {
- setFromAmount(value);
- getRoute({ newAmount: value });
- };
-
- const onSetSlippage = (newSlippage: number) => {
- setSlippage(newSlippage);
-
- if (MustBigNumber(newSlippage).gt(0) && fromAmountBN.gt(0)) {
- getRoute({ newAmount: fromAmount, newSlippage });
- }
- };
-
- const onClickMax = () => {
- if (balance) {
- setFromAmount(balanceBN.toString());
- }
- };
-
- const amountInputReceipt = [
- {
- key: 'amount',
- label: (
-
- {stringGetter({ key: STRING_KEYS.AVAILABLE })}{' '}
- {sourceToken && {sourceToken.symbol}}
-
- ),
- value: (
-
- ),
- },
- ];
-
- const errorMessage = getDepositFormErrorMessage({
- error,
- balance,
- currentChain,
- fromAmount,
- sourceToken,
- stringGetter,
- });
-
- const isDisabled =
- Boolean(errorMessage) ||
- !sourceToken ||
- !currentChain ||
- fromAmountBN.isNaN() ||
- fromAmountBN.isZero() ||
- !squidRoute;
-
- const alertMessage = {
- type: errorMessage ? AlertType.Error : AlertType.Info,
- message:
- errorMessage ||
- (transactionHash && (
-
- {stringGetter({ key: STRING_KEYS.VIEW_DETAILS })}
- {' on '}
-
- Axelar
-
- .
-
- )),
- };
-
- return (
- {
- e.preventDefault();
- requestDeposit();
- }}
- >
-
- {
- setSourceToken(token);
-
- if (fromAmount) {
- debouncedGetRoute({
- amount: fromAmount,
- currentChain,
- cosmosAddress,
- fromAmount,
- setError,
- setIsLoading,
- setSquidRoute,
- slippage,
- sourceToken: token,
- });
- } else {
- setSquidRoute(undefined);
- }
- }}
- />
-
-
-
- {stringGetter({ key: STRING_KEYS.MAX })}
-
- }
- />
-
-
- {alertMessage.message && (
- {alertMessage.message}
- )}
-
-
-
-
- );
-};
-
-const Styled: Record = {};
-
-Styled.Form = styled.form`
- ${layoutMixins.flexColumn}
- gap: 1.5rem;
-
- ${layoutMixins.stickyArea1}
- min-height: calc(100% - var(--stickyArea0-bottomHeight));
-`;
-
-Styled.WithDetailsReceipt = styled(WithDetailsReceipt)`
- --withReceipt-backgroundColor: var(--color-layer-2);
-`;
-
-Styled.FormInput = styled(FormInput)`
- --formInput-backgroundColor: var(--color-layer-4);
- --formInput-input-height: 3.375rem;
- border: 1px solid var(--color-layer-6);
-`;
-
-Styled.Link = styled(Link)`
- color: var(--color-accent);
-`;
-
-Styled.AlertMessage = styled(AlertMessage)`
- cursor: normal;
- user-select: none;
- margin: 0;
-`;
-
-Styled.Footer = styled.footer`
- ${layoutMixins.stickyFooter}
- margin-top: auto;
-`;
diff --git a/src/views/forms/DepositForm/TokenSelectMenu.tsx b/src/views/forms/DepositForm/TokenSelectMenu.tsx
deleted file mode 100644
index f93d2c5..0000000
--- a/src/views/forms/DepositForm/TokenSelectMenu.tsx
+++ /dev/null
@@ -1,89 +0,0 @@
-import type { ChainData, TokenData } from '@0xsquid/sdk';
-import styled, { type AnyStyledComponent } from 'styled-components';
-
-import { STRING_KEYS } from '@/constants/localization';
-import { useStringGetter } from '@/hooks';
-
-import { SearchSelectMenu } from '@/components/SearchSelectMenu';
-import { Tag } from '@/components/Tag';
-import { WithLabel } from '@/components/WithLabel';
-
-import { layoutMixins } from '@/styles/layoutMixins';
-
-type ElementProps = {
- chain?: ChainData;
- tokens?: TokenData[];
- sourceToken?: TokenData;
- setSourceToken: (token: TokenData) => void;
-};
-
-export const TokenSelectMenu = ({
- tokens = [],
- chain,
- sourceToken,
- setSourceToken,
-}: ElementProps) => {
- const stringGetter = useStringGetter();
-
- const tokenItems = Object.values(tokens)
- .filter((token: TokenData) => token.chainId === chain?.chainId)
- .map((token: TokenData) => ({
- value: token.address,
- label: token.name,
- onSelect: () => setSourceToken(token),
- slotBefore: ,
- }));
-
- return (
-
- {sourceToken?.symbol}→USDC
- >
- ),
- tooltip: 'swap',
- withTooltipIcon: true,
- },
- ]}
- >
-
- {sourceToken ? (
- <>
- {sourceToken?.name}{' '}
- {sourceToken?.symbol}
- >
- ) : (
- stringGetter({ key: STRING_KEYS.SELECT_ASSET })
- )}
-
-
- );
-};
-
-const Styled: Record = {};
-
-Styled.AssetRow = styled.div`
- ${layoutMixins.row}
- gap: 0.5rem;
- color: var(--color-text-2);
- font: var(--font-base-book);
-`;
-
-Styled.Img = styled.img`
- width: 1.25rem;
- height: 1.25rem;
- border-radius: 50%;
-`;
diff --git a/src/views/forms/DepositForm/useSquidData.ts b/src/views/forms/DepositForm/useSquidData.ts
deleted file mode 100644
index 166b3c7..0000000
--- a/src/views/forms/DepositForm/useSquidData.ts
+++ /dev/null
@@ -1,33 +0,0 @@
-import { useEffect, useState } from 'react';
-import type { ChainData, TokenData } from '@0xsquid/sdk';
-
-import squidRouter from '@/lib/squidRouter';
-import { WAGMI_SUPPORTED_CHAINS } from '@/lib/wagmi';
-
-/**
- * @description hook to return chains and tokens supported by squid
- * @note Limit to EVM chains | Cosmos chains can only be used as destination on 0xSquid as of 02/21/2023
- */
-export const useSquidData = (selectedChainType: 'cosmos' | 'evm') => {
- const [, setHasInitialized] = useState(false);
-
- useEffect(() => {
- (async () => {
- await squidRouter.initializeClient();
- setHasInitialized(true);
- })();
- }, []);
-
- const chainData: ChainData[] = squidRouter.getChains();
- const tokenData: TokenData[] = squidRouter.getTokens();
- const wagmiChainIds = Object.fromEntries(
- WAGMI_SUPPORTED_CHAINS.map((supportedChain) => [supportedChain.id, supportedChain])
- );
-
- return {
- chains: chainData.filter(({ chainId, chainType }) =>
- selectedChainType === 'evm' ? wagmiChainIds[chainId] : chainType === 'cosmos'
- ),
- tokens: tokenData,
- };
-};