deprecate usesquidrouter

This commit is contained in:
Bill He
2023-08-28 11:15:45 -07:00
parent 5093823b25
commit 196185aa7e
11 changed files with 163 additions and 141 deletions
+1
View File
@@ -930,6 +930,7 @@ export const APP_STRING_KEYS = {
SLOW_WITHDRAW_PENDING: 'NOTIFICATIONS.SLOW_WITHDRAW_PENDING',
SUSPICIOUS_TRADE: 'NOTIFICATIONS.SUSPICIOUS_TRADE',
SUSPICIOUS_TRADE_BODY: 'NOTIFICATIONS.SUSPICIOUS_TRADE_BODY',
WITHDRAW_IN_PROGRESS: 'NOTIFICATIONS.WITHDRAW_IN_PROGRESS',
// Email Notifications
ACCOUNT_DESCRIPTION: 'EMAIL_NOTIFICATIONS.ACCOUNT_DESCRIPTION',
+3
View File
@@ -78,6 +78,9 @@ export const ERROR_STRING_KEYS = {
RESTRICTED_OPEN_POSITIONS_WITHDRAW: 'ERRORS.WITHDRAW_MODAL.RESTRICTED_OPEN_POSITIONS_WITHDRAW',
WITHDRAW_MORE_THAN_FREE_DUE_TO_FEE: 'ERRORS.WITHDRAW_MODAL.WITHDRAW_MORE_THAN_FREE_DUE_TO_FEE',
WITHDRAW_MORE_THAN_FREE: 'ERRORS.WITHDRAW_MODAL.WITHDRAW_MORE_THAN_FREE',
WITHDRAW_MUST_SPECIFY_ADDRESS: 'ERRORS.DEPOSIT_MODAL.WITHDRAW_MUST_SPECIFY_ADDRESS',
WITHDRAW_MUST_SPECIFY_ASSET: 'ERRORS.DEPOSIT_MODAL.WITHDRAW_MUST_SPECIFY_ASSET',
WITHDRAW_MUST_SPECIFY_CHAIN: 'ERRORS.DEPOSIT_MODAL.WITHDRAW_MUST_SPECIFY_CHAIN',
// Transfer modal errors
TRANSFER_INVALID_ETH_ADDRESS: 'ERRORS.TRANSFER_MODAL.TRANSFER_INVALID_ETH_ADDRESS',
-2
View File
@@ -18,7 +18,6 @@ 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';
@@ -44,6 +43,5 @@ export {
useShouldShowFooter,
useSelectedNetwork,
useStringGetter,
useSquidRouter,
useSubaccount,
};
-49
View File
@@ -4,9 +4,7 @@ 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';
@@ -69,50 +67,3 @@ 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,
};
};
+2 -1
View File
@@ -944,7 +944,8 @@
"SLOW_WITHDRAW_PENDING_DESCRIPTION": "You have {AMOUNT_ELEMENT} in pending slow withdraws. You will receive a notification when your funds have been confirmed on Layer 2.",
"SLOW_WITHDRAW_PENDING": "Slow withdraw(s) pending",
"SUSPICIOUS_TRADE": "Suspicious activity",
"SUSPICIOUS_TRADE_BODY": "We have noticed suspicious trading activity related to your account on dYdX, including potential wash trading activity. We will be reviewing your activity on an ongoing basis. If we notice similar activity in the future, then you will be permanently blocked from performing transfers within the protocol and from placing orders other than market orders that reduce your positions."
"SUSPICIOUS_TRADE_BODY": "We have noticed suspicious trading activity related to your account on dYdX, including potential wash trading activity. We will be reviewing your activity on an ongoing basis. If we notice similar activity in the future, then you will be permanently blocked from performing transfers within the protocol and from placing orders other than market orders that reduce your positions.",
"WITHDRAW_IN_PROGRESS": "Withdrawal(s) in progress"
},
"EMAIL_NOTIFICATIONS": {
"ACCOUNT_DESCRIPTION": "Deposits, Withdrawals, Account Updates",
+4 -1
View File
@@ -65,7 +65,10 @@
"MIN_SLOW_WITHDRAW_AMOUNT": "Slow withdraw amount must be greater than or equal to 10, or your entire account balance.",
"RESTRICTED_OPEN_POSITIONS_WITHDRAW": "Your account is restricted. You must close all your positions before you can withdraw.",
"WITHDRAW_MORE_THAN_FREE_DUE_TO_FEE": "You cannot withdraw more than your free collateral. Make sure you account for the fast withdraw fee when entering an amount.",
"WITHDRAW_MORE_THAN_FREE": "You cannot withdraw more than your free collateral."
"WITHDRAW_MORE_THAN_FREE": "You cannot withdraw more than your free collateral.",
"WITHDRAW_MUST_SPECIFY_ADDRESS": "Please enter a destination address.",
"WITHDRAW_MUST_SPECIFY_ASSET": "Please select an asset to withdraw to.",
"WITHDRAW_MUST_SPECIFY_CHAIN": "Please select a source chain to withdraw to."
},
"TRANSFER_MODAL": {
"TRANSFER_INVALID_ETH_ADDRESS": "We could not find an account associated with this wallet address.",
@@ -73,14 +73,16 @@ export const AccountInfoConnectedState = () => {
<Styled.Header>
<span>{stringGetter({ key: STRING_KEYS.ACCOUNT })}</span>
<Styled.TransferButtons>
<Styled.Button
state={{ isDisabled: !dydxAccounts }}
onClick={() => dispatch(openDialog({ type: DialogTypes.Withdraw }))}
shape={ButtonShape.Pill}
size={ButtonSize.XSmall}
>
{stringGetter({ key: STRING_KEYS.WITHDRAW })}
</Styled.Button>
{import.meta.env.MODE !== 'production' && (
<Styled.Button
state={{ isDisabled: !dydxAccounts }}
onClick={() => dispatch(openDialog({ type: DialogTypes.Withdraw }))}
shape={ButtonShape.Pill}
size={ButtonSize.XSmall}
>
{stringGetter({ key: STRING_KEYS.WITHDRAW })}
</Styled.Button>
)}
<Styled.Button
state={{ isDisabled: !dydxAccounts }}
onClick={() => dispatch(openDialog({ type: DialogTypes.Deposit }))}
@@ -284,7 +286,7 @@ Styled.Header = styled.header`
Styled.TransferButtons = styled.div`
${layoutMixins.row}
gap: 1rem;
`
`;
Styled.ConnectedAccountInfoContainer = styled.div<{ $showHeader?: boolean }>`
${layoutMixins.column}
@@ -2,6 +2,8 @@ import { type FormEvent, useCallback, useEffect, useMemo, useState } from 'react
import styled, { type AnyStyledComponent } from 'styled-components';
import { type NumberFormatValues } from 'react-number-format';
import { shallowEqual, useSelector } from 'react-redux';
import { TESTNET_CHAIN_ID } from '@dydxprotocol/v4-client';
import { ethers } from 'ethers';
import {
TransferInputField,
@@ -14,7 +16,7 @@ import { ButtonSize } from '@/constants/buttons';
import { StringGetterFunction, STRING_KEYS } from '@/constants/localization';
import { NumberSign } from '@/constants/numbers';
import { useDebounce, useStringGetter, useSquidRouter } from '@/hooks';
import { useAccounts, useDebounce, useStringGetter } from '@/hooks';
import { useAccountBalance } from '@/hooks/useAccountBalance';
import { layoutMixins } from '@/styles/layoutMixins';
@@ -23,7 +25,6 @@ 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';
@@ -40,6 +41,7 @@ import { TokenSelectMenu } from './TokenSelectMenu';
import { DepositButtonAndReceipt } from './DepositForm/DepositButtonAndReceipt';
import { getTransferInputs } from '@/state/inputsSelectors';
import { set } from 'lodash';
type DepositFormProps = {
onDeposit?: () => void;
@@ -51,7 +53,7 @@ export const DepositForm = ({ onDeposit, onError }: DepositFormProps) => {
const [error, setError] = useState<Error | null>(null);
const [isLoading, setIsLoading] = useState(false);
const { submitDeposit, axelarscanURL } = useSquidRouter();
const { signerWagmi } = useAccounts();
const { requestPayload, token, chain, resources } = useSelector(getTransferInputs) || {};
@@ -156,6 +158,57 @@ export const DepositForm = ({ onDeposit, onError }: DepositFormProps) => {
}
}, [balance, setFromAmount]);
const onSubmit = useCallback(
async (e: FormEvent) => {
try {
e.preventDefault();
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');
}
setIsLoading(true);
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,
};
const txHash = await signerWagmi.sendTransaction(tx);
onDeposit?.();
if (txHash) {
setTransactionHash(txHash);
abacusStateManager.setTransferStatus({
hash: txHash,
toChainId: TESTNET_CHAIN_ID,
fromChainId: sourceChain?.chainId?.toString(),
});
abacusStateManager.clearTransferInputValues();
setFromAmount('');
}
} catch (error) {
setError(error);
} finally {
setIsLoading(false);
}
},
[requestPayload, signerWagmi, sourceChain]
);
const amountInputReceipt = [
{
key: 'amount',
@@ -191,7 +244,7 @@ export const DepositForm = ({ onDeposit, onError }: DepositFormProps) => {
})
: stringGetter({ key: STRING_KEYS.SOMETHING_WENT_WRONG });
}
if (fromAmount) {
if (!sourceChain) {
return stringGetter({ key: STRING_KEYS.MUST_SPECIFY_CHAIN });
@@ -199,13 +252,13 @@ export const DepositForm = ({ onDeposit, onError }: DepositFormProps) => {
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])
}, [error, balance, sourceChain, fromAmount, sourceToken]);
const isDisabled =
Boolean(errorMessage) ||
@@ -219,21 +272,7 @@ export const DepositForm = ({ onDeposit, onError }: DepositFormProps) => {
}
return (
<Styled.Form
onSubmit={async (e: FormEvent) => {
try {
e.preventDefault();
setIsLoading(true);
const txHash = await submitDeposit(requestPayload);
onDeposit?.();
setTransactionHash(txHash);
} catch (error) {
setError(error);
} finally {
setIsLoading(false);
}
}}
>
<Styled.Form onSubmit={onSubmit}>
<ChainSelectMenu selectedChain={sourceChain || undefined} onSelectChain={onSelectChain} />
<TokenSelectMenu selectedToken={sourceToken || undefined} onSelectToken={onSelectToken} />
<Styled.WithDetailsReceipt side="bottom" detailItems={amountInputReceipt}>
@@ -257,12 +296,6 @@ export const DepositForm = ({ onDeposit, onError }: DepositFormProps) => {
<Styled.TransactionInfo>
{stringGetter({ key: STRING_KEYS.DEPOSIT_IN_PROGRESS })}
</Styled.TransactionInfo>
<Styled.TransactionInfo>
<Styled.Link href={`${axelarscanURL}/gmp/${transactionHash}`}>
{stringGetter({ key: STRING_KEYS.VIEW_TRANSACTION })}
<Icon iconName={IconName.LinkOut} />
</Styled.Link>
</Styled.TransactionInfo>
</AlertMessage>
)
)}
@@ -58,6 +58,7 @@ export const DepositButtonAndReceipt = ({
sourceToken,
isDisabled,
isLoading,
slotError,
}: ElementProps) => {
const [showFeeBreakdown, setShowFeeBreakdown] = useState(false);
@@ -173,7 +174,6 @@ export const DepositButtonAndReceipt = ({
];
const isFormValid = !isDisabled && !isEditingSlippage;
const isLoading = isFormValid && !requestPayload;
return (
<Styled.WithReceipt
@@ -209,7 +209,10 @@ export const DepositButtonAndReceipt = ({
<Button
action={ButtonAction.Primary}
type={ButtonType.Submit}
state={{ isDisabled: !isFormValid, isLoading }}
state={{
isDisabled: !isFormValid,
isLoading: (isFormValid && !requestPayload) || isLoading,
}}
>
{stringGetter({ key: STRING_KEYS.DEPOSIT_FUNDS })}
</Button>
@@ -2,9 +2,8 @@ import { useCallback, useEffect, useMemo, useState } from 'react';
import type { ChangeEvent, FormEvent } from 'react';
import styled, { type AnyStyledComponent } from 'styled-components';
import type { NumberFormatValues } from 'react-number-format';
import type { TokenData, ChainData } from '@0xsquid/sdk';
import { shallowEqual, useSelector } from 'react-redux';
import { parseUnits } from 'viem';
import { TESTNET_CHAIN_ID } from '@dydxprotocol/v4-client';
import {
TransferInputField,
@@ -15,11 +14,9 @@ import {
import { AlertType } from '@/constants/alerts';
import { ButtonAction, ButtonSize, ButtonType } from '@/constants/buttons';
import { STRING_KEYS } from '@/constants/localization';
import { CLIENT_NETWORK_CONFIGS, type DydxV4Network } from '@/constants/networks';
import { NumberSign, QUANTUM_MULTIPLIER } from '@/constants/numbers';
import { useAccounts, useDebounce, useStringGetter, useSquidRouter, useSubaccount } from '@/hooks';
import { SQUID_WITHDRAW_ROUTE_DEFAULTS } from '@/hooks/useSquidRouter';
import { useDebounce, useStringGetter, useSubaccount } from '@/hooks';
import { layoutMixins } from '@/styles/layoutMixins';
@@ -27,7 +24,6 @@ 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 { OutputType } from '@/components/Output';
@@ -44,8 +40,6 @@ import { MustBigNumber } from '@/lib/numbers';
import { TokenSelectMenu } from './TokenSelectMenu';
import { WithdrawButtonAndReceipt } from './WithdrawForm/WithdrawButtonAndReceipt';
import { parse } from 'path';
import { s } from 'vitest/dist/types-2b1c412e';
export const WithdrawForm = () => {
const stringGetter = useStringGetter();
@@ -55,8 +49,6 @@ export const WithdrawForm = () => {
const { simulateWithdraw, sendSquidWithdraw } = useSubaccount();
const { freeCollateral } = useSelector(getSubaccount, shallowEqual) || {};
const { axelarscanURL } = useSquidRouter();
// User input
const [withdrawAmount, setWithdrawAmount] = useState('');
const [slippage, setSlippage] = useState(0.01); // 0.1% slippage
@@ -99,52 +91,68 @@ export const WithdrawForm = () => {
useEffect(() => {
const setTransferValue = async () => {
const hasInvalidInput = debouncedAmountBN.isNaN() || debouncedAmountBN.lte(0);
try {
setIsLoading(true);
const hasInvalidInput = debouncedAmountBN.isNaN() || debouncedAmountBN.lte(0);
if (hasInvalidInput) {
abacusStateManager.setTransferValue({
value: 0,
field: TransferInputField.usdcSize,
});
} else {
const stdFee = await simulateWithdraw(parseFloat(debouncedAmount));
const amount =
parseFloat(debouncedAmount) -
parseFloat(stdFee?.amount[0]?.amount || '0') / QUANTUM_MULTIPLIER;
const stdFee = await simulateWithdraw(parseFloat(debouncedAmount));
const amount = hasInvalidInput
? 0
: parseFloat(debouncedAmount) -
parseFloat(stdFee?.amount[0]?.amount || '0') / QUANTUM_MULTIPLIER;
abacusStateManager.setTransferValue({
value: amount.toString(),
field: TransferInputField.usdcSize,
});
abacusStateManager.setTransferValue({
value: hasInvalidInput ? 0 : amount.toString(),
field: TransferInputField.usdcSize,
});
setError(null);
setError(null);
}
} catch (error) {
setError(error);
} finally {
setIsLoading(false);
}
};
setTransferValue();
}, [debouncedAmountBN.toNumber()]);
/**
* @todo Withdrawing involves two steps.
* 1. MsgCreateTransfer for withdrawing from the subaccount.
* 2. MsgTransfer to IBC transfer the funds to the destination chain. 0xSquid will provide the IBC path instructions.
*/
const onSubmit = useCallback(
async (e: FormEvent) => {
e.preventDefault();
try {
e.preventDefault();
if (!requestPayload?.data || !debouncedAmountBN.toNumber()) {
throw new Error('Invalid request payload');
}
const txHash = await sendSquidWithdraw(debouncedAmountBN.toNumber(), requestPayload?.data);
setIsLoading(true);
const txHash = await sendSquidWithdraw(debouncedAmountBN.toNumber(), requestPayload?.data);
if (txHash?.hash) {
const hash = `0x${Buffer.from(txHash.hash).toString('hex')}`;
setTransactionHash(hash);
abacusStateManager.setTransferStatus({
hash: `0x${Buffer.from(txHash.hash).toString('hex')}`,
fromChainId: 'dydx-testnet-2',
hash,
fromChainId: TESTNET_CHAIN_ID,
toChainId: toChain?.chainId?.toString(),
})
});
abacusStateManager.clearTransferInputValues();
setWithdrawAmount('');
}
} catch (error) {
setError(error);
} finally {
setIsLoading(false);
}
},
[setTransactionHash, requestPayload, debouncedAmountBN]
[setTransactionHash, requestPayload, debouncedAmountBN, toChain]
);
const onChangeAddress = useCallback((e: ChangeEvent<HTMLInputElement>) => {
@@ -165,6 +173,7 @@ export const WithdrawForm = () => {
(newSlippage: number) => {
setSlippage(newSlippage);
// TODO: to be implemented via abacus
// if (MustBigNumber(newSlippage).gt(0) && debouncedAmountBN.gt(0)) {
// fetchRoute({ newAmount: debouncedAmount, newSlippage });
// }
@@ -221,12 +230,38 @@ export const WithdrawForm = () => {
},
];
let errorMessage = !toAddress ? 'Please enter a destination address' : undefined;
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 (!toAddress) return stringGetter({ key: STRING_KEYS.WITHDRAW_MUST_SPECIFY_ADDRESS });
if (debouncedAmountBN) {
if (!toChain) {
return stringGetter({ key: STRING_KEYS.WITHDRAW_MUST_SPECIFY_CHAIN });
} else if (!toToken) {
return stringGetter({ key: STRING_KEYS.WITHDRAW_MUST_SPECIFY_ASSET });
}
}
if (MustBigNumber(debouncedAmountBN).gt(MustBigNumber(freeCollateralBN))) {
return stringGetter({ key: STRING_KEYS.WITHDRAW_MORE_THAN_FREE });
}
return undefined;
}, [error, freeCollateralBN, toChain, debouncedAmountBN, toToken]);
const isDisabled =
!!errorMessage ||
!toToken ||
!toChain ||
!toAddress ||
debouncedAmountBN.isNaN() ||
debouncedAmountBN.isZero();
@@ -271,20 +306,14 @@ export const WithdrawForm = () => {
transactionHash && (
<AlertMessage type={AlertType.Success}>
<Styled.TransactionInfo>
{stringGetter({ key: STRING_KEYS.DEPOSIT_IN_PROGRESS })}
</Styled.TransactionInfo>
<Styled.TransactionInfo>
<Styled.Link href={`${axelarscanURL}/gmp/${transactionHash}`}>
{stringGetter({ key: STRING_KEYS.VIEW_TRANSACTION })}
<Icon iconName={IconName.LinkOut} />
</Styled.Link>
{stringGetter({ key: STRING_KEYS.WITHDRAW_IN_PROGRESS })}
</Styled.TransactionInfo>
</AlertMessage>
)
)}
<WithdrawButtonAndReceipt
isDisabled={isDisabled}
setError={undefined}
isLoading={isLoading}
setSlippage={onSetSlippage}
slippage={slippage}
withdrawChain={toChain || undefined}
@@ -32,7 +32,6 @@ import { getSubaccount } from '@/state/accountSelectors';
import { getTransferInputs } from '@/state/inputsSelectors';
type ElementProps = {
setError?: Dispatch<SetStateAction<Error | undefined>>;
setSlippage: (slippage: number) => void;
slippage: number;
@@ -40,10 +39,10 @@ type ElementProps = {
withdrawToken?: TransferInputTokenResource;
isDisabled?: boolean;
isLoading?: boolean;
};
export const WithdrawButtonAndReceipt = ({
setError,
setSlippage,
slippage,
@@ -51,6 +50,7 @@ export const WithdrawButtonAndReceipt = ({
withdrawToken,
isDisabled,
isLoading,
}: ElementProps) => {
const [showFeeBreakdown, setShowFeeBreakdown] = useState(false);
const [isEditingSlippage, setIsEditingSlipapge] = useState(false);
@@ -165,7 +165,6 @@ export const WithdrawButtonAndReceipt = ({
];
const isFormValid = !isDisabled && !isEditingSlippage && queryStatus !== 'error';
const isLoading = isFormValid && !requestPayload;
return (
<Styled.WithReceipt
@@ -177,9 +176,8 @@ export const WithdrawButtonAndReceipt = ({
<Styled.ToggleButton
shape={ButtonShape.Pill}
size={ButtonSize.XSmall}
state={{ isDisabled: !hasSubitems }}
isPressed={showFeeBreakdown}
onPressedChanged={() => setShowFeeBreakdown(!showFeeBreakdown)}
onPressedChange={setShowFeeBreakdown}
slotLeft={<Icon iconName={IconName.Caret} />}
>
{showSubitemsToggle}
@@ -194,7 +192,7 @@ export const WithdrawButtonAndReceipt = ({
type={ButtonType.Submit}
state={{
isDisabled: !isFormValid,
isLoading,
isLoading: (isFormValid && !requestPayload) || isLoading,
}}
>
{stringGetter({ key: STRING_KEYS.WITHDRAW })}