diff --git a/locales/base/translation.json b/locales/base/translation.json
index 919e22375e4..5df45be589d 100644
--- a/locales/base/translation.json
+++ b/locales/base/translation.json
@@ -2601,9 +2601,13 @@
"moreInformation": "More information",
"estNetworkFee": "Est. Network Fee",
"maxNetworkFee": "Max Network Fee",
- "networkFeeDescription": "The network fee is required by the network to process the deposit transaction.",
- "networkFeeDescriptionWithdrawal": "The network fee is required by the network to process the withdrawal transaction.",
- "networkSwapFeeDescription": "The network fee is required by the network to process the deposit transactions. The {{appName}} fee of {{appFeePercentage}}% is charged for your use of our product.",
+ "estCrossChainFee": "Est. Cross-chain Fee",
+ "maxCrossChainFee": "Max Cross-chain Fee",
+ "description_deposit": "The network fee is required by the network to process the deposit transaction.",
+ "description_withdraw": "The network fee is required by the network to process the withdrawal transaction.",
+ "description_depositSwapFee": "The network fee is required by the network to process the deposit transactions. The {{appName}} fee of {{appFeePercentage}}% is charged for your use of our product.",
+ "description_depositCrossChain": "The network fee is required by the network to process the deposit transaction. The cross-chain fee is charged by the cross-chain provider.",
+ "description_depositCrossChainWithSwapFee": "The network fee is required by the network to process the deposit transactions. The {{appName}} fee of {{appFeePercentage}}% is charged for your use of our product. The cross-chain fee is charged by the cross-chain provider.",
"appSwapFee": "{{appName}} Fee"
},
"swapBottomSheet": {
diff --git a/src/earn/EarnEnterAmount.test.tsx b/src/earn/EarnEnterAmount.test.tsx
index 74b25b2fe6e..739d9587c13 100644
--- a/src/earn/EarnEnterAmount.test.tsx
+++ b/src/earn/EarnEnterAmount.test.tsx
@@ -146,8 +146,8 @@ const mockCrossChainSwapTransaction: SwapTransaction = {
...mockSwapTransaction,
swapType: 'cross-chain',
estimatedDuration: 300,
- maxCrossChainFee: '0.1',
- estimatedCrossChainFee: '0.05',
+ maxCrossChainFee: '1000000000000000',
+ estimatedCrossChainFee: '500000000000000',
sellTokenAddress: mockCeloAddress,
price: '4',
guaranteedPrice: '4',
@@ -876,6 +876,8 @@ describe('EarnEnterAmount', () => {
const replaceSeparators = (value: string) =>
value.replace(/\./g, '|').replace(/,/g, group).replace(/\|/g, decimal)
+ const defaultFormat = BigNumber.config().FORMAT
+
beforeEach(() => {
jest
.mocked(getNumberFormatSettings)
@@ -889,6 +891,10 @@ describe('EarnEnterAmount', () => {
})
})
+ afterEach(() => {
+ BigNumber.config({ FORMAT: defaultFormat })
+ })
+
const mockStore = createMockStore({
tokens: {
tokenBalances: {
@@ -971,7 +977,7 @@ describe('EarnEnterAmount', () => {
isPreparingTransactions: false,
})
- const { getByTestId, getByText } = render(
+ const { getByTestId, getByText, queryByTestId } = render(
@@ -980,9 +986,16 @@ describe('EarnEnterAmount', () => {
fireEvent.changeText(getByTestId('EarnEnterAmount/TokenAmountInput'), '1')
fireEvent.press(getByTestId('LabelWithInfo/FeeLabel'))
expect(getByText('earnFlow.enterAmount.feeBottomSheet.feeDetails')).toBeVisible()
- expect(getByTestId('EstNetworkFee/Value')).toBeTruthy()
- expect(getByTestId('MaxNetworkFee/Value')).toBeTruthy()
- expect(getByText('earnFlow.enterAmount.feeBottomSheet.networkFeeDescription')).toBeVisible()
+ expect(getByTestId('EstNetworkFee')).toBeTruthy()
+ expect(getByTestId('MaxNetworkFee')).toBeTruthy()
+ expect(queryByTestId('SwapFee')).toBeFalsy()
+ expect(queryByTestId('EstCrossChainFee')).toBeFalsy()
+ expect(queryByTestId('MaxCrossChainFee')).toBeFalsy()
+ expect(getByTestId('EstNetworkFee/Value')).toHaveTextContent('₱0.012 (0.000006 ETH)')
+ expect(getByTestId('MaxNetworkFee/Value')).toHaveTextContent('₱0.012 (0.000006 ETH)')
+ expect(
+ getByText('earnFlow.enterAmount.feeBottomSheet.description, {"context":"deposit"}')
+ ).toBeVisible()
})
it('should show swap fees on the FeeDetailsBottomSheet when swap transaction is present', async () => {
@@ -997,6 +1010,43 @@ describe('EarnEnterAmount', () => {
isPreparingTransactions: false,
})
+ const { getByTestId, getByText, queryByTestId } = render(
+
+
+
+ )
+
+ fireEvent.changeText(getByTestId('EarnEnterAmount/TokenAmountInput'), '1')
+ fireEvent.press(getByTestId('LabelWithInfo/FeeLabel'))
+ expect(getByText('earnFlow.enterAmount.feeBottomSheet.feeDetails')).toBeVisible()
+ expect(getByTestId('EstNetworkFee')).toBeTruthy()
+ expect(getByTestId('MaxNetworkFee')).toBeTruthy()
+ expect(getByTestId('SwapFee')).toBeTruthy()
+ expect(queryByTestId('EstCrossChainFee')).toBeFalsy()
+ expect(queryByTestId('MaxCrossChainFee')).toBeFalsy()
+ expect(getByTestId('EstNetworkFee/Value')).toHaveTextContent('₱0.012 (0.000006 ETH)')
+ expect(getByTestId('MaxNetworkFee/Value')).toHaveTextContent('₱0.012 (0.000006 ETH)')
+ expect(getByTestId('SwapFee/Value')).toHaveTextContent('₱0.008 (0.006 USDC)')
+ expect(
+ getByText(
+ 'earnFlow.enterAmount.feeBottomSheet.description, {"context":"depositSwapFee","appFeePercentage":"0.6"}'
+ )
+ ).toBeVisible()
+ expect(getByTestId('FeeDetailsBottomSheet/GotIt')).toBeVisible()
+ })
+
+ it('should show swap and cross chain fees on the FeeDetailsBottomSheet when cross chain swap transaction is present', async () => {
+ jest.mocked(usePrepareEnterAmountTransactionsCallback).mockReturnValue({
+ prepareTransactionsResult: {
+ prepareTransactionsResult: mockPreparedTransaction,
+ swapTransaction: mockCrossChainSwapTransaction,
+ },
+ refreshPreparedTransactions: jest.fn(),
+ clearPreparedTransactions: jest.fn(),
+ prepareTransactionError: undefined,
+ isPreparingTransactions: false,
+ })
+
const { getByTestId, getByText } = render(
@@ -1006,12 +1056,19 @@ describe('EarnEnterAmount', () => {
fireEvent.changeText(getByTestId('EarnEnterAmount/TokenAmountInput'), '1')
fireEvent.press(getByTestId('LabelWithInfo/FeeLabel'))
expect(getByText('earnFlow.enterAmount.feeBottomSheet.feeDetails')).toBeVisible()
- expect(getByTestId('EstNetworkFee/Value')).toBeTruthy()
- expect(getByTestId('MaxNetworkFee/Value')).toBeTruthy()
- expect(getByTestId('SwapFee/Value')).toBeTruthy()
+ expect(getByTestId('EstNetworkFee')).toBeTruthy()
+ expect(getByTestId('MaxNetworkFee')).toBeTruthy()
+ expect(getByTestId('SwapFee')).toBeTruthy()
+ expect(getByTestId('EstCrossChainFee')).toBeTruthy()
+ expect(getByTestId('MaxCrossChainFee')).toBeTruthy()
+ expect(getByTestId('EstNetworkFee/Value')).toHaveTextContent('₱0.012 (0.000006 ETH)')
+ expect(getByTestId('MaxNetworkFee/Value')).toHaveTextContent('₱0.012 (0.000006 ETH)')
+ expect(getByTestId('SwapFee/Value')).toHaveTextContent('₱0.008 (0.006 USDC)')
+ expect(getByTestId('EstCrossChainFee/Value')).toHaveTextContent('₱1.00 (0.0005 ETH)')
+ expect(getByTestId('MaxCrossChainFee/Value')).toHaveTextContent('₱2.00 (0.001 ETH)')
expect(
getByText(
- 'earnFlow.enterAmount.feeBottomSheet.networkSwapFeeDescription, {"appFeePercentage":"0.6"}'
+ 'earnFlow.enterAmount.feeBottomSheet.description, {"context":"depositCrossChainWithSwapFee","appFeePercentage":"0.6"}'
)
).toBeVisible()
expect(getByTestId('FeeDetailsBottomSheet/GotIt')).toBeVisible()
diff --git a/src/earn/EarnEnterAmount.tsx b/src/earn/EarnEnterAmount.tsx
index 86d32baf7e0..e0f195ae8eb 100644
--- a/src/earn/EarnEnterAmount.tsx
+++ b/src/earn/EarnEnterAmount.tsx
@@ -42,7 +42,8 @@ import { StatsigFeatureGates } from 'src/statsig/types'
import Colors from 'src/styles/colors'
import { typeScale } from 'src/styles/fonts'
import { Spacing } from 'src/styles/styles'
-import { SwapTransaction } from 'src/swap/types'
+import getCrossChainFee from 'src/swap/getCrossChainFee'
+import { SwapFeeAmount, SwapTransaction } from 'src/swap/types'
import { useSwappableTokens, useTokenInfo } from 'src/tokens/hooks'
import { feeCurrenciesSelector } from 'src/tokens/selectors'
import { TokenBalance } from 'src/tokens/slice'
@@ -226,6 +227,21 @@ export default function EarnEnterAmount({ route }: Props) {
})
}
+ const crossChainFeeCurrency = useSelector((state) =>
+ feeCurrenciesSelector(state, inputToken.networkId)
+ ).find((token) => token.isNative)
+ const crossChainFee =
+ swapTransaction?.swapType === 'cross-chain' && prepareTransactionsResult
+ ? getCrossChainFee({
+ feeCurrency: crossChainFeeCurrency,
+ preparedTransactions: prepareTransactionsResult,
+ estimatedCrossChainFee: swapTransaction.estimatedCrossChainFee,
+ maxCrossChainFee: swapTransaction.maxCrossChainFee,
+ fromTokenId: inputToken.tokenId,
+ sellAmount: swapTransaction.sellAmount,
+ })
+ : undefined
+
// This is for withdrawals as we want the user to be able to input the amounts in the deposit token
const { transactionToken, transactionTokenAmount } = useMemo(() => {
const transactionToken = isWithdrawal ? withdrawToken : inputToken
@@ -500,6 +516,7 @@ export default function EarnEnterAmount({ route }: Props) {
token={inputToken}
tokenAmount={processedAmounts.token.bignum}
isWithdrawal={isWithdrawal}
+ crossChainFee={crossChainFee}
/>
)}
{swapTransaction && processedAmounts.token.bignum && (
@@ -745,7 +762,7 @@ function TransactionDepositDetails({
)
}
-// Might be sharable with src/swap/FeeInfoBottomSheet.tsx
+// TODO(ACT-1534) src/swap/FeeInfoBottomSheet.tsx
function FeeDetailsBottomSheet({
forwardedRef,
testID,
@@ -757,6 +774,7 @@ function FeeDetailsBottomSheet({
token,
tokenAmount,
isWithdrawal,
+ crossChainFee,
}: {
forwardedRef: React.RefObject
testID: string
@@ -768,6 +786,7 @@ function FeeDetailsBottomSheet({
token: TokenBalance
tokenAmount: BigNumber
isWithdrawal: boolean
+ crossChainFee?: SwapFeeAmount
}) {
const { t } = useTranslation()
const inputToken = useTokenInfo(pool.dataProps.depositTokenId)
@@ -858,23 +877,71 @@ function FeeDetailsBottomSheet({
)}
+ {crossChainFee && crossChainFee.token && (
+ <>
+
+
+
+
+ {t('earnFlow.enterAmount.feeBottomSheet.estCrossChainFee')}
+
+
+ {'≈ '}
+
+ {' ('}
+
+ {')'}
+
+
+ {crossChainFee.maxAmount && (
+
+
+ {t('earnFlow.enterAmount.feeBottomSheet.maxCrossChainFee')}
+
+
+ {'≈ '}
+
+ {' ('}
+
+ {')'}
+
+
+ )}
+
+ >
+ )}
{t('earnFlow.enterAmount.feeBottomSheet.moreInformation')}
- {swapFeeAmount ? (
-
- {t('earnFlow.enterAmount.feeBottomSheet.networkSwapFeeDescription', {
- appFeePercentage: swapTransaction?.appFeePercentageIncludedInPrice,
- })}
-
- ) : (
-
- {isWithdrawal
- ? t('earnFlow.enterAmount.feeBottomSheet.networkFeeDescriptionWithdrawal')
- : t('earnFlow.enterAmount.feeBottomSheet.networkFeeDescription')}
-
- )}
+
+ {t('earnFlow.enterAmount.feeBottomSheet.description', {
+ context: isWithdrawal
+ ? 'withdraw'
+ : swapFeeAmount
+ ? crossChainFee
+ ? 'depositCrossChainWithSwapFee'
+ : 'depositSwapFee'
+ : crossChainFee
+ ? 'depositCrossChain'
+ : 'deposit',
+ appFeePercentage: swapTransaction?.appFeePercentageIncludedInPrice,
+ })}
+