From 4d91181df2b8a8ba6ecf3b1c7d23abd0f8d669ac Mon Sep 17 00:00:00 2001 From: Enrico Barbieri Date: Fri, 24 Jan 2025 15:31:37 +0100 Subject: [PATCH] Add MoonPay onramp option (#4027) * feat: :heavy_plus_sign: Add MoonPay react and nodejs libraries * feat: :bento: Add MoonPay branding * feat: Add MoonPay url signing endpoint * feat: :lipstick: Add MoonPay buy widget * docs: :wrench: Add MoonPay env placeholders * chore: :globe_with_meridians: Add missing translation for MoonPay subtitle * fix: :globe_with_meridians: Fix wrong localization key in moonpay onramp * chore: update lockfile * feat: update copy to "Buy crypto" * feat: update moonpay widget border * feat: improve modals layout with hideDefaultBackButton * feat: add more margin between header and list * feat: add onRequestBack handler * feat: add custom header * feat: add system-based moonpay theme * feat: add payment methods assets * feat: update Moonpay selection UI * feat: localize moonpay country support * refactor: use useMedia instead of window.matchMedia --------- Co-authored-by: Enrico Barbieri Co-authored-by: fabryscript --- packages/web/.env | 5 ++ packages/web/hooks/bridge.tsx | 4 ++ packages/web/integrations/fiat-ramps.ts | 7 ++ packages/web/integrations/moonpay/index.tsx | 53 +++++++++++++++ packages/web/integrations/moonpay/types.ts | 3 + packages/web/localizations/de.json | 6 +- packages/web/localizations/en.json | 6 +- packages/web/localizations/es.json | 6 +- packages/web/localizations/fa.json | 6 +- packages/web/localizations/fr.json | 6 +- packages/web/localizations/gu.json | 6 +- packages/web/localizations/hi.json | 6 +- packages/web/localizations/ja.json | 6 +- packages/web/localizations/ko.json | 6 +- packages/web/localizations/pl.json | 6 +- packages/web/localizations/pt-br.json | 6 +- packages/web/localizations/ro.json | 6 +- packages/web/localizations/ru.json | 6 +- packages/web/localizations/tr.json | 6 +- packages/web/localizations/zh-cn.json | 6 +- packages/web/localizations/zh-hk.json | 6 +- packages/web/localizations/zh-tw.json | 6 +- packages/web/modals/base.tsx | 26 +++++--- .../web/modals/fiat-on-ramp-selection.tsx | 66 ++++++++++++++++--- packages/web/modals/fiat-ramps.tsx | 32 ++++++++- packages/web/package.json | 2 + packages/web/pages/_app.tsx | 42 +++++++----- .../api/integrations/moonpay/sign-url.ts | 38 +++++++++++ packages/web/pages/components.tsx | 1 + packages/web/public/icons/sprite.svg | 7 ++ packages/web/public/logos/moonpay.svg | 3 + .../web/public/payment-methods/apple-pay.svg | 11 ++++ .../web/public/payment-methods/mastercard.svg | 7 ++ packages/web/public/payment-methods/visa.svg | 15 +++++ yarn.lock | 10 +++ 35 files changed, 366 insertions(+), 68 deletions(-) create mode 100644 packages/web/integrations/moonpay/index.tsx create mode 100644 packages/web/integrations/moonpay/types.ts create mode 100644 packages/web/pages/api/integrations/moonpay/sign-url.ts create mode 100644 packages/web/public/logos/moonpay.svg create mode 100644 packages/web/public/payment-methods/apple-pay.svg create mode 100644 packages/web/public/payment-methods/mastercard.svg create mode 100644 packages/web/public/payment-methods/visa.svg diff --git a/packages/web/.env b/packages/web/.env index 71442d636a..fddfcb7ae9 100644 --- a/packages/web/.env +++ b/packages/web/.env @@ -52,3 +52,8 @@ NEXT_PUBLIC_SPEND_LIMIT_CONTRACT_ADDRESS=osmo10xqv8rlpkflywm92k5wdmplzy7khtasl9c # Disable TRPC logs in development # NEXT_PUBLIC_TRPC_LOGS=off + + +# Moonpay public and private keys +# MOONPAY_PRIVATE_KEY= +# NEXT_PUBLIC_MOONPAY_PUBLIC_KEY= \ No newline at end of file diff --git a/packages/web/hooks/bridge.tsx b/packages/web/hooks/bridge.tsx index bf2e536238..4f509ccbd9 100644 --- a/packages/web/hooks/bridge.tsx +++ b/packages/web/hooks/bridge.tsx @@ -404,6 +404,10 @@ export const ImmersiveBridge = () => { onRequestClose={() => { setFiatRampParams(null); }} + onRequestBack={() => { + setFiatRampParams(null); + toggleFiatOnRampSelection(true); + }} assetKey={fiatRampParams.assetKey} fiatRampKey={fiatRampParams.fiatRampKey} /> diff --git a/packages/web/integrations/fiat-ramps.ts b/packages/web/integrations/fiat-ramps.ts index 650899ac77..a77da2aeeb 100644 --- a/packages/web/integrations/fiat-ramps.ts +++ b/packages/web/integrations/fiat-ramps.ts @@ -2,6 +2,7 @@ import { SpriteIconId } from "~/config"; // Fiat on/off ramps export type FiatRampKey = + | "moonpay" | "kado" | "transak" | "layerswapcoinbase" @@ -15,6 +16,12 @@ export const FiatRampDisplayInfos: Record< logoId?: SpriteIconId; } > = { + moonpay: { + rampKey: "moonpay", + iconUrl: "/logos/moonpay.svg", + displayName: "MoonPay", + logoId: "moonpay-logo", + }, kado: { rampKey: "kado", iconUrl: "/logos/kado.svg", diff --git a/packages/web/integrations/moonpay/index.tsx b/packages/web/integrations/moonpay/index.tsx new file mode 100644 index 0000000000..34c83945a7 --- /dev/null +++ b/packages/web/integrations/moonpay/index.tsx @@ -0,0 +1,53 @@ +import { apiClient } from "@osmosis-labs/utils"; +import { observer } from "mobx-react-lite"; +import dynamic from "next/dynamic"; +import { FunctionComponent } from "react"; +import { useMedia } from "react-use"; + +import { MoonpaySignUrlResponse } from "~/integrations/moonpay/types"; +import { ModalBaseProps } from "~/modals"; +import { useStore } from "~/stores"; + +const MoonPayBuyWidget = dynamic( + () => import("@moonpay/moonpay-react").then((mod) => mod.MoonPayBuyWidget), + { ssr: false } +); + +async function generateMoonpayUrlSignature(url: string): Promise { + return ( + await apiClient( + "/api/integrations/moonpay/sign-url", + { + method: "POST", + data: { + url, + }, + } + ) + ).signature; +} + +export const Moonpay: FunctionComponent< + { assetKey: string } & Pick +> = observer(({ assetKey, isOpen }) => { + const { chainStore, accountStore } = useStore(); + + const prefersDark = useMedia("(prefers-color-scheme: dark)"); + + const account = accountStore.getWallet(chainStore.osmosis.chainId); + + let walletAddress = account?.address; + + return ( + + ); +}); diff --git a/packages/web/integrations/moonpay/types.ts b/packages/web/integrations/moonpay/types.ts new file mode 100644 index 0000000000..df78fcac72 --- /dev/null +++ b/packages/web/integrations/moonpay/types.ts @@ -0,0 +1,3 @@ +export interface MoonpaySignUrlResponse { + readonly signature: string; +} diff --git a/packages/web/localizations/de.json b/packages/web/localizations/de.json index f3c5c963f4..ff724667fb 100644 --- a/packages/web/localizations/de.json +++ b/packages/web/localizations/de.json @@ -245,10 +245,12 @@ "insufficientFunds": "Unzureichende Mittel" }, "fiatOnrampSelection": { - "chooseOnramp": "Wählen Sie Fiat Onramp", + "chooseOnramp": "Krypto kaufen", "kadoSubtitle": "Unterstützt OSMO, USDC", + "moonpaySubtitle": "Unterstützt OSMO, USDC", "transakSubtitle": "Unterstützt OSMO", - "onrampMoneySubtitle": "Unterstützt OSMO, USDC" + "onrampMoneySubtitle": "Unterstützt OSMO, USDC", + "moonpayCountrySupport": "165+ Länder" }, "incentive": { "title": "Anreizarten" diff --git a/packages/web/localizations/en.json b/packages/web/localizations/en.json index 9ea8c6a95a..f0883e2684 100644 --- a/packages/web/localizations/en.json +++ b/packages/web/localizations/en.json @@ -245,10 +245,12 @@ "insufficientFunds": "Insufficient funds" }, "fiatOnrampSelection": { - "chooseOnramp": "Choose Fiat Onramp", + "chooseOnramp": "Buy crypto", "kadoSubtitle": "Supports OSMO, USDC", + "moonpaySubtitle": "Supports OSMO, USDC", "transakSubtitle": "Supports OSMO", - "onrampMoneySubtitle": "Supports OSMO, USDC" + "onrampMoneySubtitle": "Supports OSMO, USDC", + "moonpayCountrySupport": "165+ countries" }, "incentive": { "title": "Incentive types" diff --git a/packages/web/localizations/es.json b/packages/web/localizations/es.json index 1b454ee07c..4c60038201 100644 --- a/packages/web/localizations/es.json +++ b/packages/web/localizations/es.json @@ -245,10 +245,12 @@ "insufficientFunds": "Fondos insuficientes" }, "fiatOnrampSelection": { - "chooseOnramp": "Seleccionar acceso de Fiat", + "chooseOnramp": "Comprar criptomonedas", "kadoSubtitle": "Soporta OSMO, USDC", + "moonpaySubtitle": "Compatible con OSMO y USDC", "transakSubtitle": "Soporta OSMO", - "onrampMoneySubtitle": "Soporta OSMO, USDC" + "onrampMoneySubtitle": "Soporta OSMO, USDC", + "moonpayCountrySupport": "Más de 165 países" }, "incentive": { "title": "Tipos de incentivos" diff --git a/packages/web/localizations/fa.json b/packages/web/localizations/fa.json index 8dd5f6c0c9..23c8e4ac7f 100644 --- a/packages/web/localizations/fa.json +++ b/packages/web/localizations/fa.json @@ -245,10 +245,12 @@ "insufficientFunds": "بودجه ناکافی" }, "fiatOnrampSelection": { - "chooseOnramp": "انتخاب حساب بانکی Onramp", + "chooseOnramp": "کریپتو بخر", "kadoSubtitle": "پشتیبانی OSMO, USDC", + "moonpaySubtitle": "پشتیبانی از OSMO، USDC", "transakSubtitle": "پشتیبانی OSMO", - "onrampMoneySubtitle": "پشتیبانی از OSMO، USDC" + "onrampMoneySubtitle": "پشتیبانی از OSMO، USDC", + "moonpayCountrySupport": "165+ کشور" }, "incentive": { "title": "انواع مشوق" diff --git a/packages/web/localizations/fr.json b/packages/web/localizations/fr.json index 1d2d606971..ad70464f1b 100644 --- a/packages/web/localizations/fr.json +++ b/packages/web/localizations/fr.json @@ -245,10 +245,12 @@ "insufficientFunds": "Fonds insuffisants" }, "fiatOnrampSelection": { - "chooseOnramp": "Choisir une rampe de paiement en Fiat", + "chooseOnramp": "Acheter des crypto-monnaies", "kadoSubtitle": "Prend en charge OSMO, USDC", + "moonpaySubtitle": "Prend en charge OSMO, USDC", "transakSubtitle": "Prend en charge OSMO", - "onrampMoneySubtitle": "Prend en charge OSMO, USDC" + "onrampMoneySubtitle": "Prend en charge OSMO, USDC", + "moonpayCountrySupport": "Plus de 165 pays" }, "incentive": { "title": "Types d'incitations" diff --git a/packages/web/localizations/gu.json b/packages/web/localizations/gu.json index 866ea5a52f..153d40da46 100644 --- a/packages/web/localizations/gu.json +++ b/packages/web/localizations/gu.json @@ -245,10 +245,12 @@ "insufficientFunds": "અપૂરતું ભંડોળ" }, "fiatOnrampSelection": { - "chooseOnramp": "ફિયાટ ઓનરેમ્પ પસંદ કરો", + "chooseOnramp": "ક્રિપ્ટો ખરીદો", "kadoSubtitle": "OSMO, USDC ને સપોર્ટ કરે છે", + "moonpaySubtitle": "OSMO, USDC ને સપોર્ટ કરે છે", "transakSubtitle": "OSMO ને સપોર્ટ કરે છે", - "onrampMoneySubtitle": "OSMO, USDC ને સપોર્ટ કરે છે" + "onrampMoneySubtitle": "OSMO, USDC ને સપોર્ટ કરે છે", + "moonpayCountrySupport": "165+ દેશો" }, "incentive": { "title": "પ્રોત્સાહન પ્રકારો" diff --git a/packages/web/localizations/hi.json b/packages/web/localizations/hi.json index e546f079a4..9700f2d0d7 100644 --- a/packages/web/localizations/hi.json +++ b/packages/web/localizations/hi.json @@ -245,10 +245,12 @@ "insufficientFunds": "अपर्याप्त कोष" }, "fiatOnrampSelection": { - "chooseOnramp": "फिएट ऑनरैंप चुनें", + "chooseOnramp": "क्रिप्टो खरीदें", "kadoSubtitle": "OSMO, यूएसडीसी का समर्थन करता है", + "moonpaySubtitle": "OSMO, USDC का समर्थन करता है", "transakSubtitle": "OSMO का समर्थन करता है", - "onrampMoneySubtitle": "OSMO, यूएसडीसी का समर्थन करता है" + "onrampMoneySubtitle": "OSMO, यूएसडीसी का समर्थन करता है", + "moonpayCountrySupport": "165+ देश" }, "incentive": { "title": "प्रोत्साहन के प्रकार" diff --git a/packages/web/localizations/ja.json b/packages/web/localizations/ja.json index 0f6e650829..bad807ffb0 100644 --- a/packages/web/localizations/ja.json +++ b/packages/web/localizations/ja.json @@ -245,10 +245,12 @@ "insufficientFunds": "残高不足" }, "fiatOnrampSelection": { - "chooseOnramp": "フィアット オンランプを選択してください", + "chooseOnramp": "暗号通貨を購入する", "kadoSubtitle": "OSMO、USDCをサポート", + "moonpaySubtitle": "OSMO、USDCをサポート", "transakSubtitle": "OSMOをサポート", - "onrampMoneySubtitle": "OSMO、USDCをサポート" + "onrampMoneySubtitle": "OSMO、USDCをサポート", + "moonpayCountrySupport": "165か国以上" }, "incentive": { "title": "インセンティブの種類" diff --git a/packages/web/localizations/ko.json b/packages/web/localizations/ko.json index f3562e4099..1fdaf67562 100644 --- a/packages/web/localizations/ko.json +++ b/packages/web/localizations/ko.json @@ -245,10 +245,12 @@ "insufficientFunds": "자금 부족" }, "fiatOnrampSelection": { - "chooseOnramp": "피아트 온램프 선택", + "chooseOnramp": "암호화폐를 구매하세요", "kadoSubtitle": "OSMO, USDC를 지원합니다", + "moonpaySubtitle": "OSMO, USDC 지원", "transakSubtitle": "OSMO를 지원합니다", - "onrampMoneySubtitle": "OSMO, USDC 지원" + "onrampMoneySubtitle": "OSMO, USDC 지원", + "moonpayCountrySupport": "165+ 국가" }, "incentive": { "title": "인센티브 유형" diff --git a/packages/web/localizations/pl.json b/packages/web/localizations/pl.json index 72005cab7f..10fc9a5e72 100644 --- a/packages/web/localizations/pl.json +++ b/packages/web/localizations/pl.json @@ -245,10 +245,12 @@ "insufficientFunds": "Niewystarczające środki" }, "fiatOnrampSelection": { - "chooseOnramp": "Wybierz rampę Fiat", + "chooseOnramp": "Kup kryptowalutę", "kadoSubtitle": "Obsługuje OSMO, USDC", + "moonpaySubtitle": "Obsługuje OSMO, USDC", "transakSubtitle": "Obsługuje OSMO", - "onrampMoneySubtitle": "Obsługuje OSMO, USDC" + "onrampMoneySubtitle": "Obsługuje OSMO, USDC", + "moonpayCountrySupport": "165+ krajów" }, "incentive": { "title": "Rodzaje zachęt" diff --git a/packages/web/localizations/pt-br.json b/packages/web/localizations/pt-br.json index aef1df2819..f4638c5e7b 100644 --- a/packages/web/localizations/pt-br.json +++ b/packages/web/localizations/pt-br.json @@ -245,10 +245,12 @@ "insufficientFunds": "Fundos insuficientes" }, "fiatOnrampSelection": { - "chooseOnramp": "Escolher rampa Fiat", + "chooseOnramp": "Comprar cripto", "kadoSubtitle": "Suporta OSMO, USDC", + "moonpaySubtitle": "Suporta OSMO, USDC", "transakSubtitle": "Suporta OSMO", - "onrampMoneySubtitle": "Suporta OSMO, USDC" + "onrampMoneySubtitle": "Suporta OSMO, USDC", + "moonpayCountrySupport": "Mais de 165 países" }, "incentive": { "title": "Tipos de incentivo" diff --git a/packages/web/localizations/ro.json b/packages/web/localizations/ro.json index 16ebbe6520..03f03e1f9c 100644 --- a/packages/web/localizations/ro.json +++ b/packages/web/localizations/ro.json @@ -245,10 +245,12 @@ "insufficientFunds": "Fonduri insuficiente" }, "fiatOnrampSelection": { - "chooseOnramp": "Alegeți rampa fiat", + "chooseOnramp": "Cumpărați cripto", "kadoSubtitle": "Acceptă OSMO, USDC", + "moonpaySubtitle": "Suporta OSMO, USDC", "transakSubtitle": "Acceptă OSMO", - "onrampMoneySubtitle": "Suporta OSMO, USDC" + "onrampMoneySubtitle": "Suporta OSMO, USDC", + "moonpayCountrySupport": "Peste 165 de țări" }, "incentive": { "title": "Tipuri de stimulente" diff --git a/packages/web/localizations/ru.json b/packages/web/localizations/ru.json index a52c5bbdf6..2b4e3072a5 100644 --- a/packages/web/localizations/ru.json +++ b/packages/web/localizations/ru.json @@ -245,10 +245,12 @@ "insufficientFunds": "Недостаточно средств" }, "fiatOnrampSelection": { - "chooseOnramp": "Выбирайте Фиат Онрамп", + "chooseOnramp": "Купить криптовалюту", "kadoSubtitle": "Поддерживает OSMO, USDC", + "moonpaySubtitle": "Поддерживает OSMO, USDC", "transakSubtitle": "Поддерживает ОСМО", - "onrampMoneySubtitle": "Поддерживает OSMO, USDC" + "onrampMoneySubtitle": "Поддерживает OSMO, USDC", + "moonpayCountrySupport": "165+ стран" }, "incentive": { "title": "Типы стимулов" diff --git a/packages/web/localizations/tr.json b/packages/web/localizations/tr.json index c8cfa844c5..3f0604c376 100644 --- a/packages/web/localizations/tr.json +++ b/packages/web/localizations/tr.json @@ -245,10 +245,12 @@ "insufficientFunds": "Yetersiz bakiye" }, "fiatOnrampSelection": { - "chooseOnramp": "Fiat Onramp Seçin", + "chooseOnramp": "Kripto satın al", "kadoSubtitle": "OSMO, USDC'yi destekler", + "moonpaySubtitle": "OSMO ve USDC'yi destekler", "transakSubtitle": "OSMO'yu destekler", - "onrampMoneySubtitle": "OSMO, USDC'yi destekler" + "onrampMoneySubtitle": "OSMO, USDC'yi destekler", + "moonpayCountrySupport": "165+ ülke" }, "incentive": { "title": "Teşvik türleri" diff --git a/packages/web/localizations/zh-cn.json b/packages/web/localizations/zh-cn.json index ec063e8299..ac0219d2a9 100644 --- a/packages/web/localizations/zh-cn.json +++ b/packages/web/localizations/zh-cn.json @@ -245,10 +245,12 @@ "insufficientFunds": "不充足的资金" }, "fiatOnrampSelection": { - "chooseOnramp": "选择法币入口", + "chooseOnramp": "购买加密货币", "kadoSubtitle": "支持OSMO, USDC", + "moonpaySubtitle": "支持OSMO、USDC", "transakSubtitle": "支持OSMO", - "onrampMoneySubtitle": "支持OSMO、USDC" + "onrampMoneySubtitle": "支持OSMO、USDC", + "moonpayCountrySupport": "165+ 个国家" }, "incentive": { "title": "激励类型" diff --git a/packages/web/localizations/zh-hk.json b/packages/web/localizations/zh-hk.json index ddd9e95be9..dc0f8bace1 100644 --- a/packages/web/localizations/zh-hk.json +++ b/packages/web/localizations/zh-hk.json @@ -245,10 +245,12 @@ "insufficientFunds": "不充足的資金" }, "fiatOnrampSelection": { - "chooseOnramp": "選擇法幣入口", + "chooseOnramp": "購買加密貨幣", "kadoSubtitle": "支援OSMO, USDC", + "moonpaySubtitle": "支援OSMO、USDC", "transakSubtitle": "支援OSMO", - "onrampMoneySubtitle": "支援OSMO、USDC" + "onrampMoneySubtitle": "支援OSMO、USDC", + "moonpayCountrySupport": "超過 165 個國家" }, "incentive": { "title": "激勵類型" diff --git a/packages/web/localizations/zh-tw.json b/packages/web/localizations/zh-tw.json index 98b25a3068..f93196cdeb 100644 --- a/packages/web/localizations/zh-tw.json +++ b/packages/web/localizations/zh-tw.json @@ -245,10 +245,12 @@ "insufficientFunds": "不充足的資金" }, "fiatOnrampSelection": { - "chooseOnramp": "選擇法幣入口", + "chooseOnramp": "購買加密貨幣", "kadoSubtitle": "支援OSMO, USDC", + "moonpaySubtitle": "支援OSMO、USDC", "transakSubtitle": "支援OSMO", - "onrampMoneySubtitle": "支援OSMO、USDC" + "onrampMoneySubtitle": "支援OSMO、USDC", + "moonpayCountrySupport": "超過 165 個國家" }, "incentive": { "title": "激勵類型" diff --git a/packages/web/modals/base.tsx b/packages/web/modals/base.tsx index 054c6bf0ee..2995279841 100644 --- a/packages/web/modals/base.tsx +++ b/packages/web/modals/base.tsx @@ -23,6 +23,7 @@ export interface ModalBaseProps { bodyOpenClassName?: string; overlayClassName?: string; hideCloseButton?: boolean; + hideDefaultBackButton?: boolean; } export const ModalBase = ({ @@ -36,6 +37,7 @@ export const ModalBase = ({ bodyOpenClassName, overlayClassName, hideCloseButton, + hideDefaultBackButton, children, }: PropsWithChildren) => { const { isMobile } = useWindowSize(); @@ -65,14 +67,22 @@ export const ModalBase = ({ >
{onRequestBack && ( - - } - onClick={onRequestBack} - /> + <> + {!hideDefaultBackButton && ( + + } + onClick={onRequestBack} + /> + )} + )} {typeof title === "string" ? (
diff --git a/packages/web/modals/fiat-on-ramp-selection.tsx b/packages/web/modals/fiat-on-ramp-selection.tsx index 2527a4af34..e2bfbc5f59 100644 --- a/packages/web/modals/fiat-on-ramp-selection.tsx +++ b/packages/web/modals/fiat-on-ramp-selection.tsx @@ -1,4 +1,5 @@ import { observer } from "mobx-react-lite"; +import Image from "next/image"; import React, { FunctionComponent } from "react"; import { Icon } from "~/components/assets"; @@ -16,6 +17,11 @@ const Options = ( subtitle: string; } > => [ + { + ...FiatRampDisplayInfos.moonpay, + initialAsset: "OSMO", + subtitle: t("components.fiatOnrampSelection.moonpaySubtitle"), + }, { ...FiatRampDisplayInfos.kado, initialAsset: "USDC", @@ -43,14 +49,11 @@ export const FiatOnrampSelectionModal: FunctionComponent< return ( - {t("components.fiatOnrampSelection.chooseOnramp")} - - } + title={
{t("components.fiatOnrampSelection.chooseOnramp")}
} + hideDefaultBackButton {...modalProps} > -
+
{Options(t).map( ({ rampKey, displayName, initialAsset, logoId, subtitle }) => ( ) )} @@ -77,3 +108,18 @@ export const FiatOnrampSelectionModal: FunctionComponent< ); }); + +const MOONPAY_SUPPORTED_PROVIDERS = [ + { + id: "apple-pay", + icon: "/payment-methods/apple-pay.svg", + }, + { + id: "mastercard", + icon: "/payment-methods/mastercard.svg", + }, + { + id: "visa", + icon: "/payment-methods/visa.svg", + }, +]; diff --git a/packages/web/modals/fiat-ramps.tsx b/packages/web/modals/fiat-ramps.tsx index 0206603c66..a04ce48f54 100644 --- a/packages/web/modals/fiat-ramps.tsx +++ b/packages/web/modals/fiat-ramps.tsx @@ -1,12 +1,23 @@ import { FunctionComponent, useEffect } from "react"; +import { Icon } from "~/components/assets"; +import { IconButton } from "~/components/ui/button"; import { FiatRampKey } from "~/integrations"; import { Kado } from "~/integrations/kado"; import { Layerswap } from "~/integrations/layerswap"; +import { Moonpay } from "~/integrations/moonpay"; import { OnrampMoney } from "~/integrations/onrampmoney"; import { useTransakModal } from "~/integrations/transak"; import { ModalBase, ModalBaseProps } from "~/modals"; +const FIAT_RAMPS_PRETTY_NAMES: Record = { + kado: "Kado", + layerswapcoinbase: "Coinbase Layer Swap", + moonpay: "MoonPay", + onrampmoney: "Onramp.money", + transak: "Transak", +}; + export const FiatRampsModal: FunctionComponent< { fiatRampKey: FiatRampKey; @@ -35,13 +46,32 @@ export const FiatRampsModal: FunctionComponent< +
+ } + aria-label="Back" + className="size-12 text-wosmongton-200 hover:text-osmoverse-100 md:size-8" + onClick={props.onRequestBack} + /> +
{FIAT_RAMPS_PRETTY_NAMES[fiatRampKey]}
+ } + onClick={props.onRequestClose} + /> +
{(() => { switch (fiatRampKey) { case "kado": return ; + case "moonpay": + return ; case "onrampmoney": return ; case "layerswapcoinbase": diff --git a/packages/web/package.json b/packages/web/package.json index 5db6b87bf3..917c501c32 100644 --- a/packages/web/package.json +++ b/packages/web/package.json @@ -42,6 +42,8 @@ "@keplr-wallet/common": "0.10.24-ibc.go.v7.hot.fix", "@keplr-wallet/crypto": "0.12.48", "@keplr-wallet/types": "0.10.24-ibc.go.v7.hot.fix", + "@moonpay/moonpay-node": "^0.2.7", + "@moonpay/moonpay-react": "^1.8.2", "@next/bundle-analyzer": "^12.1.6", "@opentelemetry/api": "^1.9.0", "@opentelemetry/api-logs": "^0.52.1", diff --git a/packages/web/pages/_app.tsx b/packages/web/pages/_app.tsx index eeb7b63663..3a9ed96fd1 100644 --- a/packages/web/pages/_app.tsx +++ b/packages/web/pages/_app.tsx @@ -70,6 +70,13 @@ enableStaticRendering(typeof window === "undefined"); const DEFAULT_LANGUAGE = "en"; +import dynamic from "next/dynamic"; + +const MoonPayProvider = dynamic( + () => import("@moonpay/moonpay-react").then((mod) => mod.MoonPayProvider), + { ssr: false } +); + function MyApp({ Component, pageProps }: AppProps) { useAmplitudeAnalytics({ init: true }); @@ -81,21 +88,26 @@ function MyApp({ Component, pageProps }: AppProps) { > - }> - - - - - {Component && } - - - + + }> + + + + + {Component && } + + + + diff --git a/packages/web/pages/api/integrations/moonpay/sign-url.ts b/packages/web/pages/api/integrations/moonpay/sign-url.ts new file mode 100644 index 0000000000..1a66a13897 --- /dev/null +++ b/packages/web/pages/api/integrations/moonpay/sign-url.ts @@ -0,0 +1,38 @@ +import { MoonPay } from "@moonpay/moonpay-node"; +import { NextApiRequest, NextApiResponse } from "next"; + +/** + * Signs a MoonPay URL for client side usage as specified in https://dev.moonpay.com/docs/on-ramp-enhance-security-using-signed-urls + */ +export default async function signMoonPayUrl( + req: NextApiRequest, + res: NextApiResponse +) { + if (req.method !== "POST") { + return res.status(405).send({ error: "Method not allowed" }); + } + if (!process.env.MOONPAY_PRIVATE_KEY) { + return res.status(500).send({ error: "Moonpay private key not set" }); + } + + const moonPay = new MoonPay(process.env.MOONPAY_PRIVATE_KEY); + const { url: moonPayUrl } = await req.body; + + if (!moonPayUrl) { + return res.status(400).send({ error: "Moonpay url not provided" }); + } + + try { + const signature = moonPay.url.generateSignature(moonPayUrl); + + if (!signature) { + return res.status(500).send({ error: "Failed to generate signature" }); + } + + return res.status(200).send({ signature }); + } catch (e) { + return res + .status(500) + .send({ error: "An unexpected error occurred. Please try again." }); + } +} diff --git a/packages/web/pages/components.tsx b/packages/web/pages/components.tsx index 0d36db247d..2a9cb07e6f 100644 --- a/packages/web/pages/components.tsx +++ b/packages/web/pages/components.tsx @@ -740,6 +740,7 @@ const Icons = () => ( "close-small", "tune", "help-circle", + "moonpay-logo", "kado-logo", "transak-logo", "more-menu", diff --git a/packages/web/public/icons/sprite.svg b/packages/web/public/icons/sprite.svg index 2e797c0ffb..2c7da96390 100644 --- a/packages/web/public/icons/sprite.svg +++ b/packages/web/public/icons/sprite.svg @@ -229,6 +229,13 @@ fill="#282750" /> +