From 589a21c72c70c1e2870431347d7920afd8cfa8aa Mon Sep 17 00:00:00 2001 From: chefBingbong <133646395+ChefBingbong@users.noreply.github.com> Date: Sat, 23 Dec 2023 03:00:10 +0000 Subject: [PATCH] fix: onramp fixes an cleanup (#8656) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ## PR-Codex overview ### Focus of this PR: This PR focuses on making changes to the BuyCrypto feature in the web app. It includes updates to styles, types, components, and constants related to BuyCrypto. ### Detailed summary: - Updated styles in `BuyCrypto/styles.tsx` and added a new styled component `DropdownWrapper`. - Updated types in `BuyCrypto/types.ts`. - Updated the `toggleAccordianVisibility` function in `Accordion.tsx`. - Removed an entry in the `pancake-supported-onramp-currency-list.json` file. - Added a new import and updated the `CryptoCard` component in `Card/index.tsx`. - Added a new component `BuyCryptoTooltip` in `Tooltip.tsx`. - Added a new component `ProviderCampaign` in `ProviderCampaign.tsx`. - Updated the `BuyCryptoForm` component in `BuyCryptoForm.tsx`. - Updated constants in `constants.ts`. - Updated translations in `translations.json`. > The following files were skipped due to too many changes: `packages/localization/src/config/translations.json`, `apps/web/src/views/BuyCrypto/components/AccordionDropdown/AccordionItem.tsx` > ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}` --- apps/web/src/components/Card/index.tsx | 8 +- ...ancake-supported-onramp-currency-list.json | 8 - .../AccordionDropdown/Accordion.tsx | 2 +- .../AccordionDropdown/AccordionItem.tsx | 233 ++++++++---------- .../ProviderCampaign/ProviderCampaign.tsx | 45 ++++ .../BuyCrypto/components/Tooltip/Tooltip.tsx | 47 ++++ apps/web/src/views/BuyCrypto/constants.ts | 20 +- .../BuyCrypto/containers/BuyCryptoForm.tsx | 18 +- apps/web/src/views/BuyCrypto/styles.tsx | 5 + apps/web/src/views/BuyCrypto/types.ts | 4 +- .../localization/src/config/translations.json | 6 +- 11 files changed, 227 insertions(+), 169 deletions(-) create mode 100644 apps/web/src/views/BuyCrypto/components/ProviderCampaign/ProviderCampaign.tsx create mode 100644 apps/web/src/views/BuyCrypto/components/Tooltip/Tooltip.tsx diff --git a/apps/web/src/components/Card/index.tsx b/apps/web/src/components/Card/index.tsx index f0899909a9512..339c60e463f18 100644 --- a/apps/web/src/components/Card/index.tsx +++ b/apps/web/src/components/Card/index.tsx @@ -1,5 +1,5 @@ -import { styled } from 'styled-components' import { Box, BoxProps } from '@pancakeswap/uikit' +import { styled } from 'styled-components' export interface LightCardProps extends BoxProps { width?: string @@ -28,13 +28,15 @@ export const LightGreyCard = styled(Card)` background-color: ${({ theme }) => theme.colors.background}; ` -export const CryptoCard = styled(Card)<{ isClicked: boolean; isDisabled: boolean }>` +export const CryptoCard = styled(Card)<{ isClicked: boolean; isDisabled: boolean; elementHeight: number }>` border: 1px solid ${({ theme }) => theme.colors.cardBorder}; background-color: ${({ theme, isClicked }) => (isClicked ? theme.colors.input : theme.colors.background)}; - transition: max-height 0.4s ease-in-out, background-color 0.1s ease-in-out; + transition: max-height 0.3s ease-in-out, background-color 0.1s ease-in-out; + max-height: ${({ isClicked, elementHeight }) => (isClicked ? `${elementHeight}px` : `105px`)}; overflow: hidden; &:hover { cursor: ${({ isDisabled }) => (isDisabled ? 'not-allowed' : 'pointer')}; + pointer-events: ${({ isDisabled }) => (isDisabled ? 'none' : 'auto')}; } ` diff --git a/apps/web/src/config/constants/tokenLists/pancake-supported-onramp-currency-list.json b/apps/web/src/config/constants/tokenLists/pancake-supported-onramp-currency-list.json index f608c3d948909..4563f7212f8af 100644 --- a/apps/web/src/config/constants/tokenLists/pancake-supported-onramp-currency-list.json +++ b/apps/web/src/config/constants/tokenLists/pancake-supported-onramp-currency-list.json @@ -66,14 +66,6 @@ "chainId": 42161, "logoURI": "https://tokens.pancakeswap.finance/images/symbol/usdc.png" }, - { - "name": "USD Coin Ethereum Bridged", - "symbol": "USDC.e", - "address": "0xFF970A61A04b1cA14834A43f5dE4533eBDDB5CC8", - "chainId": 42161, - "decimals": 6, - "logoURI": "https://tokens.pancakeswap.finance/images/symbol/usdc.png" - }, { "name": "USD Coin", "symbol": "USDC", diff --git a/apps/web/src/views/BuyCrypto/components/AccordionDropdown/Accordion.tsx b/apps/web/src/views/BuyCrypto/components/AccordionDropdown/Accordion.tsx index 5e22a771273c4..241d4880b2bcd 100644 --- a/apps/web/src/views/BuyCrypto/components/AccordionDropdown/Accordion.tsx +++ b/apps/web/src/views/BuyCrypto/components/AccordionDropdown/Accordion.tsx @@ -36,7 +36,7 @@ function Accordion({ setCurrentIdx((a) => (a === idx ? '' : idx))} + toggleAccordianVisibility={() => setCurrentIdx((a) => (a === idx ? '' : idx))} quote={quote} fetching={fetching} setModalView={setModalView} diff --git a/apps/web/src/views/BuyCrypto/components/AccordionDropdown/AccordionItem.tsx b/apps/web/src/views/BuyCrypto/components/AccordionDropdown/AccordionItem.tsx index 8f0840d96178e..c92d97eadfa03 100644 --- a/apps/web/src/views/BuyCrypto/components/AccordionDropdown/AccordionItem.tsx +++ b/apps/web/src/views/BuyCrypto/components/AccordionDropdown/AccordionItem.tsx @@ -1,178 +1,143 @@ -import { Box, Flex, InfoFilledIcon, RowBetween, Text, TooltipText, useTooltip } from '@pancakeswap/uikit' -import getTimePeriods from '@pancakeswap/utils/getTimePeriods' +import { useTranslation } from '@pancakeswap/localization' +import { Flex, RowBetween, Text } from '@pancakeswap/uikit' import { CryptoCard } from 'components/Card' import { FiatOnRampModalButton } from 'components/FiatOnRampModal/FiatOnRampModal' -import Image from 'next/image' -import { Dispatch, SetStateAction, useCallback, useEffect, useRef, useState } from 'react' +import { Dispatch, SetStateAction, useEffect, useRef, useState } from 'react' +import formatLocaleNumber from 'utils/formatLocaleNumber' +import { FeeTypes, providerFeeTypes } from 'views/BuyCrypto/constants' import { getRefValue } from 'views/BuyCrypto/hooks/useGetRefValue' +import { DropdownWrapper } from 'views/BuyCrypto/styles' import { CryptoFormView, ProviderQuote } from 'views/BuyCrypto/types' -import { styled } from 'styled-components' -import { useTranslation } from '@pancakeswap/localization' -import { isMobile } from 'react-device-detect' -import formatLocaleNumber from 'utils/formatLocaleNumber' -import { CURRENT_CAMPAIGN_TIMESTAMP, ONRAMP_PROVIDERS, providerFeeTypes } from 'views/BuyCrypto/constants' -import pocketWatch from '../../../../../public/images/pocket-watch.svg' import OnRampProviderLogo from '../OnRampProviderLogo/OnRampProviderLogo' +import ProviderCampaign from '../ProviderCampaign/ProviderCampaign' +import BuyCryptoTooltip from '../Tooltip/Tooltip' -const DropdownWrapper = styled.div<{ isClicked: boolean }>` - display: ${({ isClicked }) => (isClicked ? 'none' : 'block')}; - width: 100%; - transition: display 0.6s ease-in-out; -` - -const activeProviders: { [provider in keyof typeof ONRAMP_PROVIDERS]: boolean } = { - [ONRAMP_PROVIDERS.Mercuryo]: false, - [ONRAMP_PROVIDERS.MoonPay]: false, - [ONRAMP_PROVIDERS.Transak]: false, -} +type FeeComponents = { providerFee: number; networkFee: number } -const FeeItem = ({ feeTitle, feeAmount, currency }: { feeTitle: string; feeAmount: number; currency: string }) => { +const FeeItem = ({ feeTitle, quote }: { feeTitle: FeeTypes; quote: ProviderQuote }) => { const { + t, currentLanguage: { locale }, } = useTranslation() + + const FeeEstimates: { + [feeType: string]: (args: T) => number + } = { + [FeeTypes.TotalFees]: (args) => args.networkFee + args.providerFee, + [FeeTypes.NetworkingFees]: (args) => args.networkFee, + [FeeTypes.ProviderFees]: (args) => args.providerFee, + } + return ( - - {feeTitle} - + + + {feeTitle} + + {feeTitle === FeeTypes.TotalFees && ( + + )} + - {formatLocaleNumber({ number: feeAmount, locale })} {currency} + {formatLocaleNumber({ + number: FeeEstimates[feeTitle](quote), + locale, + })}{' '} + {quote.fiatCurrency} ) } +const HeadingRow = ({ quote, quotesExist }: { quote: ProviderQuote; quotesExist: boolean }) => { + const { + t, + currentLanguage: { locale }, + } = useTranslation() + + const renderQuoteDetails = () => ( + <> + + {formatLocaleNumber({ + number: quote.quote, + locale, + })}{' '} + {quote.cryptoCurrency} + + + + {quote.cryptoCurrency} {t('rate')} + + + = {formatLocaleNumber({ number: Number(quote.price), locale })} {quote.fiatCurrency} + + + + ) + + return ( + <> + + + {quotesExist ? ( + renderQuoteDetails() + ) : ( + + )} + + + ) +} + function AccordionItem({ active, - btnOnClick, + toggleAccordianVisibility, quote, fetching, setModalView, }: { active: boolean - btnOnClick: any + toggleAccordianVisibility: () => void quote: ProviderQuote fetching: boolean setModalView: Dispatch> }) { - const { - t, - currentLanguage: { locale }, - } = useTranslation() const contentRef = useRef(null) - const [maxHeight, setMaxHeight] = useState(active ? 500 : 150) - const multiple = false - const [visibility, setVisibility] = useState(false) - const [mobileTooltipShow, setMobileTooltipShow] = useState(false) - const currentTimestamp = Math.floor(Date.now() / 1000) - const { days, hours, minutes, seconds } = getTimePeriods(currentTimestamp - CURRENT_CAMPAIGN_TIMESTAMP) - const isActive = () => (multiple ? visibility : active) - - const toggleVisibility = useCallback(() => { - setVisibility((v) => !v) - btnOnClick() - }, [setVisibility, btnOnClick]) + const [maxHeight, setMaxHeight] = useState(105) + const quotesExist = Boolean(quote.amount !== 0) useEffect(() => { - const contentEl = getRefValue(contentRef) - setMaxHeight(contentEl?.scrollHeight + 150) - }, [active]) + const contentEl = getRefValue(contentRef)?.scrollHeight + setMaxHeight(contentEl) + }, []) - const { - tooltip: buyCryptoTooltip, - tooltipVisible: buyCryptoTooltipVisible, - targetRef: buyCryptoTargetRef, - } = useTooltip( - - - {t('Price quote from provider is currently unavailable. Please try again or try a different amount')} - - , - { - placement: isMobile ? 'top' : 'bottom', - trigger: isMobile ? 'focus' : 'hover', - ...(isMobile && { manualVisible: mobileTooltipShow }), - }, - ) - - const providerFee = quote.providerFee < 3.5 && quote.provider === 'MoonPay' ? 3.5 : quote.providerFee - - if (quote.amount === 0) { - return ( - - - - - setMobileTooltipShow(false)} - display="flex" - style={{ justifyContent: 'center', alignItems: 'center' }} - > - - - {t('Quote not available')} - - - - - {buyCryptoTooltipVisible && (!isMobile || mobileTooltipShow) && buyCryptoTooltip} - - - - ) - } return ( null} - position="relative" + onClick={toggleAccordianVisibility} + ref={contentRef} isClicked={active} - isDisabled={false} + elementHeight={maxHeight} + isDisabled={!quotesExist} > - - - - {formatLocaleNumber({ - number: quote.quote, - locale, - })}{' '} - {quote.cryptoCurrency} - - - - - {quote.cryptoCurrency} {t('rate')} - - - = {formatLocaleNumber({ number: Number(quote.price), locale })} {quote.fiatCurrency} - - + - - {providerFeeTypes[quote.provider].map((feeType: string, index: number) => { - let fee = 0 - if (index === 0) fee = quote.networkFee + providerFee - else if (index === 1) fee = quote.networkFee - else fee = quote.providerFee - return + + {providerFeeTypes[quote.provider].map((feeType: FeeTypes) => { + return })} - {activeProviders[quote.provider] && seconds >= 1 ? ( - - - pocket-watch - - {t('No provider fees. Ends in %days% days and %hours% hours and %minutes% minutes.', { - days, - hours, - minutes, - })} - - - - ) : null} + { + const { t } = useTranslation() + + const currentTimestamp = Math.floor(Date.now() / 1000) + const { + days, + hours, + minutes, + seconds: campaignEndTimeInSeconds, + } = getTimePeriods(currentTimestamp - CURRENT_CAMPAIGN_TIMESTAMP) + + return ( + <> + {activeCampaigns[provider] && campaignEndTimeInSeconds >= 1 ? ( + + + pocket-watch + + {t('No provider fees. Ends in %days% days and %hours% hours and %minutes% minutes.', { + days, + hours, + minutes, + })} + + + + ) : null} + + ) +} + +export default ProviderCampaign diff --git a/apps/web/src/views/BuyCrypto/components/Tooltip/Tooltip.tsx b/apps/web/src/views/BuyCrypto/components/Tooltip/Tooltip.tsx new file mode 100644 index 0000000000000..0a63a2b60dded --- /dev/null +++ b/apps/web/src/views/BuyCrypto/components/Tooltip/Tooltip.tsx @@ -0,0 +1,47 @@ +import { Box, Flex, InfoFilledIcon, Text, TooltipText, useTooltip } from '@pancakeswap/uikit' +import { isMobile } from 'react-device-detect' + +const BuyCryptoTooltip = ({ + tooltipHeading, + tooltipText, + iconSize, + iconColor = 'textSubtle', + opacity = 1, +}: { + tooltipText: string + iconSize: string + tooltipHeading?: string + iconColor?: string + opacity?: number +}) => { + const { + tooltip: buyCryptoTooltip, + tooltipVisible: buyCryptoTooltipVisible, + targetRef: buyCryptoTargetRef, + } = useTooltip( + + {tooltipText} + , + { + placement: isMobile ? 'top' : 'bottom', + trigger: isMobile ? 'focus' : 'hover', + }, + ) + return ( + <> + + + {tooltipHeading ? ( + + {tooltipHeading} + + ) : null} + + + + {buyCryptoTooltipVisible && buyCryptoTooltip} + + ) +} + +export default BuyCryptoTooltip diff --git a/apps/web/src/views/BuyCrypto/constants.ts b/apps/web/src/views/BuyCrypto/constants.ts index 22c37ecb6bb29..df1ff9f75684f 100644 --- a/apps/web/src/views/BuyCrypto/constants.ts +++ b/apps/web/src/views/BuyCrypto/constants.ts @@ -1,15 +1,12 @@ +import { ChainId } from '@pancakeswap/chains' import { ContextData, TranslationKey } from '@pancakeswap/localization' import { SUPPORT_BUY_CRYPTO } from 'config/constants/supportChains' -import { ChainId } from '@pancakeswap/chains' export const SUPPORTED_ONRAMP_TOKENS = ['ETH', 'DAI', 'USDT', 'USDC', 'BUSD', 'BNB'] export const DEFAULT_FIAT_CURRENCIES = ['USD', 'EUR', 'GBP', 'HKD', 'CAD', 'AUD', 'BRL', 'JPY', 'KRW', 'VND'] export const WHITELISTED_FIAT_CURRENCIES_BASE = ['EUR', 'GBP', 'HKD', 'CAD', 'AUD', 'JPY', 'KRW', 'VND'] export const WHITELISTED_FIAT_CURRENCIES_LINEA = ['EUR', 'GBP', 'HKD', 'CAD', 'AUD', 'JPY', 'KRW', 'VND'] -const MOONPAY_FEE_TYPES = ['Est. Total Fees', 'Networking Fees', 'Provider Fees'] -const MERCURYO_FEE_TYPES = ['Est. Total Fees'] - const SUPPORTED_MERCURYO_BSC_TOKENS = ['BNB', 'BUSD'] const SUPPORTED_MERCURYO_ETH_TOKENS = ['ETH', 'USDT', 'DAI'] const SUPPORTED_MERCURYO_ARBITRUM_TOKENS = ['ETH', 'USDC'] @@ -35,6 +32,15 @@ export enum ONRAMP_PROVIDERS { Transak = 'Transak', } +export enum FeeTypes { + TotalFees = 'Est. Total Fees', + NetworkingFees = 'Networking Fees', + ProviderFees = 'Provider Fees', +} + +const MOONPAY_FEE_TYPES = [FeeTypes.TotalFees, FeeTypes.NetworkingFees, FeeTypes.ProviderFees] +const MERCURYO_FEE_TYPES = [FeeTypes.TotalFees] + export const supportedTokenMap: { [chainId: number]: { [ONRAMP_PROVIDERS.MoonPay]: string[] @@ -96,7 +102,7 @@ export function isBuyCryptoSupported(chain: ChainId) { return SUPPORT_BUY_CRYPTO.includes(chain) } -export const providerFeeTypes: { [provider in ONRAMP_PROVIDERS]: string[] } = { +export const providerFeeTypes: { [provider in ONRAMP_PROVIDERS]: FeeTypes[] } = { [ONRAMP_PROVIDERS.MoonPay]: MOONPAY_FEE_TYPES, [ONRAMP_PROVIDERS.Mercuryo]: MERCURYO_FEE_TYPES, [ONRAMP_PROVIDERS.Transak]: MOONPAY_FEE_TYPES, @@ -167,10 +173,6 @@ export const getChainCurrencyWarningMessages = ( ) => { const networkDisplay = getNetworkDisplay(chainId) return { - [ChainId.ARBITRUM_ONE]: t( - 'UEDC.e quotes are currently unavailable in USD on Arbitrum. Please select another currency to receive USDC.e quotes', - { chainId: networkDisplay }, - ), [ChainId.LINEA]: t('%chainId% supports limited fiat currencies. USD are not supported', { chainId: networkDisplay, }), diff --git a/apps/web/src/views/BuyCrypto/containers/BuyCryptoForm.tsx b/apps/web/src/views/BuyCrypto/containers/BuyCryptoForm.tsx index deffc5854c410..41b0b3ccad2ad 100644 --- a/apps/web/src/views/BuyCrypto/containers/BuyCryptoForm.tsx +++ b/apps/web/src/views/BuyCrypto/containers/BuyCryptoForm.tsx @@ -1,8 +1,10 @@ -import { Dispatch, SetStateAction, useCallback, useEffect, useMemo } from 'react' +import { ChainId } from '@pancakeswap/chains' import { useTranslation } from '@pancakeswap/localization' import { Currency } from '@pancakeswap/sdk' -import { ChainId } from '@pancakeswap/chains' -import { Text, Box, Message } from '@pancakeswap/uikit' +import { Box, Message, Text } from '@pancakeswap/uikit' +import { useOnRampCurrency } from 'hooks/Tokens' +import toString from 'lodash/toString' +import { Dispatch, SetStateAction, useCallback, useEffect, useMemo } from 'react' import { calculateDefaultAmount, fetchMinimumBuyAmount, @@ -10,17 +12,15 @@ import { useBuyCryptoErrorInfo, useBuyCryptoState, } from 'state/buyCrypto/hooks' -import { useOnRampCurrency } from 'hooks/Tokens' import { Field } from 'state/swap/actions' import { useTheme } from 'styled-components' -import toString from 'lodash/toString' import { CryptoFormView } from 'views/BuyCrypto/types' import { useChainId } from 'wagmi' -import { FormHeader } from './FormHeader' -import { FormContainer } from './FormContainer' import GetQuotesButton from '../components/GetQuotesButton' -import { fiatCurrencyMap, getChainCurrencyWarningMessages } from '../constants' import { CurrencySelect } from '../components/OnRampCurrencySelect' +import { fiatCurrencyMap, getChainCurrencyWarningMessages } from '../constants' +import { FormContainer } from './FormContainer' +import { FormHeader } from './FormHeader' // Since getting a quote with a number with more than 2 decimals (e.g., 123.121212), // the quote provider won't return a quote. Therefore, we restrict the fiat currency input to a maximum of 2 decimals. @@ -146,7 +146,7 @@ export function BuyCryptoForm({ value="" /> - {[ChainId.BASE, ChainId.LINEA, ChainId.ARBITRUM_ONE].includes(chainId) ? ( + {[ChainId.BASE, ChainId.LINEA].includes(chainId) ? ( {getChainCurrencyWarningMessages(t, chainId)[chainId]} diff --git a/apps/web/src/views/BuyCrypto/styles.tsx b/apps/web/src/views/BuyCrypto/styles.tsx index affa2749d0419..df59e819f0719 100644 --- a/apps/web/src/views/BuyCrypto/styles.tsx +++ b/apps/web/src/views/BuyCrypto/styles.tsx @@ -12,3 +12,8 @@ export const Wrapper = styled(Flex)` justify-content: space-between; padding: 0px 1rem 1rem 1rem; ` +export const DropdownWrapper = styled.div<{ isClicked: boolean }>` + opacity: ${({ isClicked }) => (isClicked ? '0' : '1')}; + width: 100%; + transition: opacity 0.25s ease-in-out; +` diff --git a/apps/web/src/views/BuyCrypto/types.ts b/apps/web/src/views/BuyCrypto/types.ts index 917f6a9f7fbb1..bfeeba624a4cf 100644 --- a/apps/web/src/views/BuyCrypto/types.ts +++ b/apps/web/src/views/BuyCrypto/types.ts @@ -3,13 +3,13 @@ import { ONRAMP_PROVIDERS } from './constants' export type ProviderQuote = { providerFee: number networkFee: number - amount: number quote: number + amount: number fiatCurrency: string cryptoCurrency: string provider: keyof typeof ONRAMP_PROVIDERS price?: number - noFee?: number + error?: string } export enum CryptoFormView { diff --git a/packages/localization/src/config/translations.json b/packages/localization/src/config/translations.json index c0a937c79630e..ab05bfb14f980 100644 --- a/packages/localization/src/config/translations.json +++ b/packages/localization/src/config/translations.json @@ -2660,7 +2660,7 @@ "PancakeSwap Now Live on Linea!": "PancakeSwap Now Live on Linea!", "Swap and Provide Liquidity on Linea now": "Swap and Provide Liquidity on Linea now", "day": "day", - "Quote not available": "Quote not available", + "No Quote": "No Quote", "No provider fees. Ends in %days% days and %hours% hours and %minutes% minutes.": "No provider fees. Ends in %days% days and %hours% hours and %minutes% minutes.", "Invalid Pair": "Invalid Pair", "Learn more how to fix": "Learn more how to fix", @@ -2679,7 +2679,6 @@ "zkSync Era": "zkSync Era", "Our affiliate program’s terms and conditions have been updated as of May 3rd, 2023, with changes relating to": "Our affiliate program’s terms and conditions have been updated as of May 3rd, 2023, with changes relating to", "When staking on zkSync Era, unstaking your CAKE shortly after staking could result in no rewards being earned.": "When staking on zkSync Era, unstaking your CAKE shortly after staking could result in no rewards being earned.", - "UEDC.e quotes are currently unavailable in USD on Arbitrum. Please select another currency to receive USDC.e quotes": "UEDC.e quotes are currently unavailable in USD on Arbitrum. Please select another currency to receive USDC.e quotes", "%chainId% supports limited fiat currencies. USD are not supported": "%chainId% supports limited fiat currencies. USD are not supported", "Proceed in your wallet": "Proceed in your wallet", "Enable spending %symbol%": "Enable spending %symbol%", @@ -3095,5 +3094,6 @@ "CAKE Pool APR is calculated based on the voting result and the emission of the veCAKE Pool gauge.": "CAKE Pool APR is calculated based on the voting result and the emission of the veCAKE Pool gauge.", "Revenue Sharing APR is subject to various external factors, including trading volume, and could vary weekly.": "Revenue Sharing APR is subject to various external factors, including trading volume, and could vary weekly.", "Claim Your Exclusive NFTs Now!": "Claim Your Exclusive NFTs Now!", - "Calculated based average data since vault inception.": "Calculated based average data since vault inception." + "Calculated based average data since vault inception.": "Calculated based average data since vault inception.", + "Note that Fees are just an estimation and may vary slightly when completing a purchase": "Note that Fees are just an estimation and may vary slightly when completing a purchase" }