diff --git a/JPY.svg b/JPY.svg
new file mode 100644
index 0000000000000..4e4b9a52acca8
--- /dev/null
+++ b/JPY.svg
@@ -0,0 +1,37 @@
+
+
+
diff --git a/apps/web/.env b/apps/web/.env
index c1798c8507f6e..a21b7aa7d92b5 100644
--- a/apps/web/.env
+++ b/apps/web/.env
@@ -1,2 +1,4 @@
NEXT_PUBLIC_MM_API_URL=https://linked-pool.pancakeswap.com/quote-service
-NEXT_PUBLIC_QUOTING_API=https://swap-quoting.pancakeswap.com/quoting-service
\ No newline at end of file
+NEXT_PUBLIC_QUOTING_API=https://swap-quoting.pancakeswap.com/quoting-service
+MOONPAY_API="https://api.moonpay.com"
+MOONPAY_PUBLISHABLE_KEY="pk_live_Ch5fat39X8NvMZwih2k7hK4sDrKanSPz"
diff --git a/apps/web/.env.example b/apps/web/.env.example
index 56947d54d657d..ff2bdccb92970 100644
--- a/apps/web/.env.example
+++ b/apps/web/.env.example
@@ -3,4 +3,5 @@ NEXT_PUBLIC_NODE_REAL_API_GOERLI=
NEXT_PUBLIC_NODE_PRODUCTION=
RISK_APP_SECRET=
SERVER_NODE_REAL_API_ETH=
-SERVER_NODE_REAL_API_GOERLI=
\ No newline at end of file
+SERVER_NODE_REAL_API_GOERLI=
+NEXT_PUBLIC_MERCURYO_WIDGET_ID=
\ No newline at end of file
diff --git a/apps/web/public/AUD.svg b/apps/web/public/AUD.svg
new file mode 100644
index 0000000000000..d573e264e7ec5
--- /dev/null
+++ b/apps/web/public/AUD.svg
@@ -0,0 +1,68 @@
+
+
+
diff --git a/apps/web/public/BRL.svg b/apps/web/public/BRL.svg
new file mode 100644
index 0000000000000..80c71379abc33
--- /dev/null
+++ b/apps/web/public/BRL.svg
@@ -0,0 +1,45 @@
+
+
+
diff --git a/apps/web/public/CAD.svg b/apps/web/public/CAD.svg
new file mode 100644
index 0000000000000..647abcc52bd1f
--- /dev/null
+++ b/apps/web/public/CAD.svg
@@ -0,0 +1,43 @@
+
+
+
diff --git a/apps/web/public/EUR.svg b/apps/web/public/EUR.svg
new file mode 100644
index 0000000000000..663355ae2e70c
--- /dev/null
+++ b/apps/web/public/EUR.svg
@@ -0,0 +1,54 @@
+
+
+
diff --git a/apps/web/public/GBP.svg b/apps/web/public/GBP.svg
new file mode 100644
index 0000000000000..2f329da9eece9
--- /dev/null
+++ b/apps/web/public/GBP.svg
@@ -0,0 +1,61 @@
+
+
+
diff --git a/apps/web/public/HKD.svg b/apps/web/public/HKD.svg
new file mode 100644
index 0000000000000..e6852d45e287d
--- /dev/null
+++ b/apps/web/public/HKD.svg
@@ -0,0 +1,50 @@
+
+
+
diff --git a/apps/web/public/IDR.svg b/apps/web/public/IDR.svg
new file mode 100644
index 0000000000000..3312306b09944
--- /dev/null
+++ b/apps/web/public/IDR.svg
@@ -0,0 +1,37 @@
+
+
+
diff --git a/apps/web/public/JPY.svg b/apps/web/public/JPY.svg
new file mode 100644
index 0000000000000..4e4b9a52acca8
--- /dev/null
+++ b/apps/web/public/JPY.svg
@@ -0,0 +1,37 @@
+
+
+
diff --git a/apps/web/public/KRW.svg b/apps/web/public/KRW.svg
new file mode 100644
index 0000000000000..8df1901b16cc0
--- /dev/null
+++ b/apps/web/public/KRW.svg
@@ -0,0 +1,57 @@
+
+
+
diff --git a/apps/web/public/SGD.svg b/apps/web/public/SGD.svg
new file mode 100644
index 0000000000000..aa96d6725804d
--- /dev/null
+++ b/apps/web/public/SGD.svg
@@ -0,0 +1,52 @@
+
+
+
diff --git a/apps/web/public/TWD.svg b/apps/web/public/TWD.svg
new file mode 100644
index 0000000000000..812dc3a8dbc19
--- /dev/null
+++ b/apps/web/public/TWD.svg
@@ -0,0 +1,44 @@
+
+
+
diff --git a/apps/web/public/USD.svg b/apps/web/public/USD.svg
new file mode 100644
index 0000000000000..fd5a0d10e7fb7
--- /dev/null
+++ b/apps/web/public/USD.svg
@@ -0,0 +1,53 @@
+
+
+
diff --git a/apps/web/public/VND.svg b/apps/web/public/VND.svg
new file mode 100644
index 0000000000000..443d1c681b2d2
--- /dev/null
+++ b/apps/web/public/VND.svg
@@ -0,0 +1,38 @@
+
+
+
diff --git a/apps/web/public/images/AUD.svg b/apps/web/public/images/AUD.svg
new file mode 100644
index 0000000000000..d573e264e7ec5
--- /dev/null
+++ b/apps/web/public/images/AUD.svg
@@ -0,0 +1,68 @@
+
+
+
diff --git a/apps/web/public/images/moneyBangs.svg b/apps/web/public/images/moneyBangs.svg
new file mode 100644
index 0000000000000..0f1e68b9ff247
--- /dev/null
+++ b/apps/web/public/images/moneyBangs.svg
@@ -0,0 +1,10 @@
+
+
diff --git a/apps/web/public/images/onRampProviders/binanceConnectSvg.svg b/apps/web/public/images/onRampProviders/binanceConnectSvg.svg
new file mode 100644
index 0000000000000..06bd1fdae5eef
--- /dev/null
+++ b/apps/web/public/images/onRampProviders/binanceConnectSvg.svg
@@ -0,0 +1,40 @@
+
+
+
+
+
diff --git a/apps/web/public/images/onRampProviders/mercuryoLogo.svg b/apps/web/public/images/onRampProviders/mercuryoLogo.svg
new file mode 100644
index 0000000000000..3887337702543
--- /dev/null
+++ b/apps/web/public/images/onRampProviders/mercuryoLogo.svg
@@ -0,0 +1,2 @@
+
+
\ No newline at end of file
diff --git a/apps/web/public/images/onRampProviders/mercuryo_new_logo_black.png b/apps/web/public/images/onRampProviders/mercuryo_new_logo_black.png
new file mode 100644
index 0000000000000..5bddf9b155a4b
Binary files /dev/null and b/apps/web/public/images/onRampProviders/mercuryo_new_logo_black.png differ
diff --git a/apps/web/public/images/onRampProviders/mercuryo_new_logo_white.png b/apps/web/public/images/onRampProviders/mercuryo_new_logo_white.png
new file mode 100644
index 0000000000000..cafd0660e081f
Binary files /dev/null and b/apps/web/public/images/onRampProviders/mercuryo_new_logo_white.png differ
diff --git a/apps/web/public/images/onRampProviders/moonpaySvg.svg b/apps/web/public/images/onRampProviders/moonpaySvg.svg
new file mode 100644
index 0000000000000..1431cae809ccf
--- /dev/null
+++ b/apps/web/public/images/onRampProviders/moonpaySvg.svg
@@ -0,0 +1,53 @@
+
+
+
+
diff --git a/apps/web/src/components/Card/index.tsx b/apps/web/src/components/Card/index.tsx
index ad7e540867c46..4d6718f6edca8 100644
--- a/apps/web/src/components/Card/index.tsx
+++ b/apps/web/src/components/Card/index.tsx
@@ -28,6 +28,16 @@ export const LightGreyCard = styled(Card)`
background-color: ${({ theme }) => theme.colors.background};
`
+export const CryptoCard = styled(Card)<{ isClicked: boolean; isDisabled: boolean }>`
+ border: 1px solid ${({ theme }) => theme.colors.cardBorder};
+ background-color: ${({ theme, isClicked }) => (isClicked ? theme.colors.input : theme.colors.dropdown)};
+ transition: height 0.4s ease-in-out, background-color 0.1s ease-in-out;
+ overflow: hidden;
+ &:hover {
+ cursor: ${({ isDisabled }) => (isDisabled ? 'not-allowed' : 'pointer')};
+ }
+`
+
export const GreyCard = styled(Card)`
background-color: ${({ theme }) => theme.colors.dropdown};
`
diff --git a/apps/web/src/components/CurrencyInputPanel/index.tsx b/apps/web/src/components/CurrencyInputPanel/index.tsx
index c38a8a1512e9b..d4f1ec3e94fdd 100644
--- a/apps/web/src/components/CurrencyInputPanel/index.tsx
+++ b/apps/web/src/components/CurrencyInputPanel/index.tsx
@@ -22,6 +22,7 @@ import { useStablecoinPriceAmount } from 'hooks/useBUSDPrice'
import { formatNumber } from '@pancakeswap/utils/formatBalance'
import { StablePair } from 'views/AddLiquidity/AddStableLiquidity/hooks/useStableLPDerivedMintInfo'
+import { FiatLogo } from 'components/Logo/CurrencyLogo'
import { useAccount } from 'wagmi'
import { useCurrencyBalance } from '../../state/wallet/hooks'
import CurrencySearchModal from '../SearchModal/CurrencySearchModal'
@@ -81,6 +82,8 @@ interface CurrencyInputPanelProps {
tokensToShow?: Token[]
currencyLoading?: boolean
inputLoading?: boolean
+ title?: React.ReactNode
+ hideBalanceComp?: boolean
}
const CurrencyInputPanel = memo(function CurrencyInputPanel({
value,
@@ -111,11 +114,15 @@ const CurrencyInputPanel = memo(function CurrencyInputPanel({
tokensToShow,
currencyLoading,
inputLoading,
+ title,
+ hideBalanceComp,
}: CurrencyInputPanelProps) {
const { address: account } = useAccount()
+
const selectedCurrencyBalance = useCurrencyBalance(account ?? undefined, currency ?? undefined)
const { t } = useTranslation()
+ const mode = id
const token = pair ? pair.liquidityToken : currency?.isToken ? currency : null
const tokenAddress = token ? isAddress(token.address) : null
@@ -137,6 +144,7 @@ const CurrencyInputPanel = memo(function CurrencyInputPanel({
commonBasesType={commonBasesType}
showSearchInput={showSearchInput}
tokensToShow={tokensToShow}
+ mode={mode}
/>,
)
@@ -168,7 +176,6 @@ const CurrencyInputPanel = memo(function CurrencyInputPanel({
const isAtPercentMax = (maxAmount && value === maxAmount.toExact()) || (lpPercent && lpPercent === '100')
const balance = !hideBalance && !!currency && formatAmount(selectedCurrencyBalance, 6)
-
return (
+ {title}
{beforeButton}
) : currency ? (
-
+ id === 'onramp-input' ? (
+
+ ) : (
+
+ )
) : currencyLoading ? (
) : null}
@@ -235,7 +247,7 @@ const CurrencyInputPanel = memo(function CurrencyInputPanel({
) : null}
- {account && (
+ {account && !hideBalanceComp && (
`
+ border-bottom-left-radius: 24px;
+ border-bottom-right-radius: 24px;
+
+ height: calc(100% - 75px);
+ position: absolute;
+ width: 100%;
+`
+
+interface FiatOnRampProps {
+ provider: string
+ inputCurrency: string
+ outputCurrency: string
+ amount: string
+}
+
+interface FetchResponse {
+ urlWithSignature: string
+}
+
+const LoadingBuffer = ({ theme }: { theme: DefaultTheme }) => {
+ return (
+
+
+
+
+
+
+ )
+}
+
+const fetchMoonPaySignedUrl = async (
+ inputCurrency: string,
+ outputCurrency: string,
+ amount: string,
+ isDark: boolean,
+ account: string,
+) => {
+ try {
+ const res = await fetch(`${ONRAMP_API_BASE_URL}/generate-moonpay-sig`, {
+ headers: {
+ Accept: 'application/json',
+ 'Content-Type': 'application/json',
+ },
+ method: 'POST',
+ body: JSON.stringify({
+ type: 'MOONPAY',
+ defaultCurrencyCode: inputCurrency.toLowerCase(),
+ baseCurrencyCode: outputCurrency.toLowerCase(),
+ baseCurrencyAmount: amount,
+ redirectUrl: 'https://pancakeswap.finance',
+ theme: isDark ? 'dark' : 'light',
+ walletAddresses: account,
+ }),
+ })
+ const result: FetchResponse = await res.json()
+ return result.urlWithSignature
+ } catch (error) {
+ console.error('Error fetching signature:', error)
+ return '' // Return an empty string in case of an error
+ }
+}
+
+const fetchBinanceConnectSignedUrl = async (inputCurrency, outputCurrency, amount, account) => {
+ try {
+ const res = await fetch(`${ONRAMP_API_BASE_URL}/generate-binance-connect-sig`, {
+ headers: {
+ Accept: 'application/json',
+ 'Content-Type': 'application/json',
+ },
+ method: 'POST',
+ body: JSON.stringify({
+ cryptoCurrency: inputCurrency.toUpperCase() === 'WBTC' ? 'BTC' : inputCurrency.toUpperCase(),
+ fiatCurrency: outputCurrency.toUpperCase(),
+ amount,
+ walletAddress: account,
+ }),
+ })
+
+ const result: FetchResponse = await res.json()
+ return result.urlWithSignature
+ } catch (error) {
+ console.error('Error fetching signature:', error)
+ return '' // Return an empty string in case of an error
+ }
+}
+
+export const FiatOnRampModalButton = ({
+ provider,
+ inputCurrency,
+ outputCurrency,
+ amount,
+ disabled,
+}: FiatOnRampProps & { disabled: boolean }) => {
+ const { t } = useTranslation()
+ const [shouldCheck, setShouldCheck] = useState(false)
+ const [onPresentConfirmModal] = useModal(
+ ,
+ )
+
+ const { fiatOnarampAvailability, availabilityChecked, loading, error } = useFiatOnrampAvailability(
+ shouldCheck,
+ onPresentConfirmModal,
+ )
+
+ const handleBuyCryptoClick = useCallback(() => {
+ if (!availabilityChecked) {
+ setShouldCheck(true)
+ } else if (fiatOnarampAvailability) {
+ onPresentConfirmModal()
+ setShouldCheck(false)
+ }
+ }, [fiatOnarampAvailability, availabilityChecked, onPresentConfirmModal])
+
+ const disableBuyCryptoButton = Boolean(error || (!fiatOnarampAvailability && availabilityChecked) || loading)
+
+ let buttonText: ReactNode | string = t(`Buy with %provider%`, { provider })
+ if (disabled) {
+ buttonText = (
+ <>
+
+
+ {t('Fetching Quotes')}
+
+
+
+ >
+ )
+ }
+ return (
+ <>
+ {!disableBuyCryptoButton ? (
+
+
+ {buttonText}
+
+
+ ) : null}
+ >
+ )
+}
+
+export const FiatOnRampModal = memo(function ConfirmSwapModalComp({
+ onDismiss,
+ inputCurrency,
+ outputCurrency,
+ amount,
+ provider,
+}) {
+ const [scriptLoaded, setScriptOnLoad] = useState(Boolean(window?.mercuryoWidget))
+
+ const [error, setError] = useState(false)
+ const [signedIframeUrl, setSignedIframeUrl] = useState(null)
+ const [sig, setSig] = useState(null)
+ const [loading, setLoading] = useState(true)
+ const { t } = useTranslation()
+ const { chainId } = useActiveChainId()
+
+ const theme = useTheme()
+ const account = useAccount()
+ // const { t } = useTranslation()
+
+ const handleDismiss = useCallback(() => {
+ onDismiss?.()
+ }, [onDismiss])
+
+ const fetchSignedIframeUrl = useCallback(async () => {
+ if (!account.address) {
+ setError(t('Please connect an account before making a purchase.'))
+ return
+ }
+ setLoading(true)
+ setError(null)
+
+ try {
+ let result = ''
+ if (provider === 'MoonPay')
+ result = await fetchMoonPaySignedUrl(inputCurrency, outputCurrency, amount, theme.isDark, account.address)
+ else result = await fetchBinanceConnectSignedUrl(inputCurrency, outputCurrency, amount, account.address)
+
+ setSignedIframeUrl(result)
+ } catch (e) {
+ setError(e.toString())
+ } finally {
+ setTimeout(() => setLoading(false), 2000)
+ }
+ }, [account.address, theme.isDark, inputCurrency, outputCurrency, amount, provider, t])
+
+ useEffect(() => {
+ const fetchSig = async () => {
+ setLoading(true)
+ setError(null)
+ try {
+ const res = await fetch(`${ONRAMP_API_BASE_URL}/generate-mercuryo-sig?walletAddress=${account.address}`, {
+ headers: {
+ Accept: 'application/json',
+ 'Content-Type': 'application/json',
+ },
+ })
+ const signature = await res.json()
+ setSig(signature.signature)
+ } catch (e) {
+ setError(e.toString())
+ } finally {
+ setTimeout(() => setLoading(false), 2000)
+ }
+ }
+ fetchSig()
+ }, [account.address])
+
+ useEffect(() => {
+ if (provider === 'Mercuryo') {
+ if (sig && window?.mercuryoWidget) {
+ // @ts-ignore
+ const MC_WIDGET = window?.mercuryoWidget
+ MC_WIDGET.run({
+ widgetId: MERCURYO_WIDGET_ID,
+ fiatCurrency: outputCurrency.toUpperCase(),
+ currency: inputCurrency.toUpperCase(),
+ fiatAmount: amount,
+ currencies: chainId === ChainId.ETHEREUM ? ETHEREUM_TOKENS : mercuryoWhitelist,
+ fiatCurrencies: SUPPORTED_MERCURYO_FIAT_CURRENCIES,
+ address: account.address,
+ signature: sig,
+ height: '820px',
+ width: '400px',
+ host: document.getElementById('mercuryo-widget'),
+ theme: theme.isDark ? 'xzen' : 'phemex',
+ })
+ }
+ } else fetchSignedIframeUrl()
+ }, [
+ fetchSignedIframeUrl,
+ provider,
+ sig,
+ account.address,
+ amount,
+ inputCurrency,
+ outputCurrency,
+ theme,
+ scriptLoaded,
+ chainId,
+ ])
+
+ return (
+ <>
+
+ {error ? (
+
+
+ something went wrong!
+
+
+ ) : provider === 'Mercuryo' ? (
+ <>
+ {loading && }
+
+ >
+ ) : (
+ <>
+ {loading && }
+
+ >
+ )}
+
+