From 87df0a5fc32ef700738b7823621b4306c4a470b6 Mon Sep 17 00:00:00 2001 From: Martin Homola Date: Wed, 26 Feb 2025 17:16:51 +0100 Subject: [PATCH] feat(trading): otc market banner --- packages/suite/src/support/messages.ts | 18 ++++ .../common/TradingForm/TradingFormOffer.tsx | 2 + .../TradingForm/TradingFormOfferOTC.tsx | 95 +++++++++++++++++++ suite-common/trading/src/invityAPI.ts | 16 ++++ suite-common/trading/src/types.ts | 8 ++ 5 files changed, 139 insertions(+) create mode 100644 packages/suite/src/views/wallet/trading/common/TradingForm/TradingFormOfferOTC.tsx diff --git a/packages/suite/src/support/messages.ts b/packages/suite/src/support/messages.ts index 6116d280951..245d8ef59fd 100644 --- a/packages/suite/src/support/messages.ts +++ b/packages/suite/src/support/messages.ts @@ -1416,6 +1416,24 @@ export default defineMessages({ defaultMessage: 'View details', id: 'TR_TRADING_VIEW_DETAILS', }, + TR_TRADING_OTC_INFO_BUY: { + defaultMessage: + 'For purchases over {minimumFiat} {fiatSymbol}, consider using our OTC partner:', + id: 'TR_TRADING_OTC_INFO_BUY', + }, + TR_TRADING_OTC_INFO_SELL: { + defaultMessage: + 'For sales over {minimumFiat} {fiatSymbol}, consider using our OTC partner:', + id: 'TR_TRADING_OTC_INFO_SELL', + }, + TR_TRADING_OTC_LINK_BUY: { + defaultMessage: 'Buy with Mercuryo', + id: 'TR_TRADING_OTC_LINK_BUY', + }, + TR_TRADING_OTC_LINK_SELL: { + defaultMessage: 'Sell with Mercuryo', + id: 'TR_TRADING_OTC_LINK_SELL', + }, TR_ADDRESS_MODAL_CLIPBOARD: { defaultMessage: 'Copy address', id: 'TR_ADDRESS_MODAL_CLIPBOARD', diff --git a/packages/suite/src/views/wallet/trading/common/TradingForm/TradingFormOffer.tsx b/packages/suite/src/views/wallet/trading/common/TradingForm/TradingFormOffer.tsx index a420556b1b9..8d613efaa82 100644 --- a/packages/suite/src/views/wallet/trading/common/TradingForm/TradingFormOffer.tsx +++ b/packages/suite/src/views/wallet/trading/common/TradingForm/TradingFormOffer.tsx @@ -28,6 +28,7 @@ import { import { TradingFormOfferCryptoAmount } from 'src/views/wallet/trading/common/TradingForm/TradingFormOfferCryptoAmount'; import { TradingFormOfferFiatAmount } from 'src/views/wallet/trading/common/TradingForm/TradingFormOfferFiatAmount'; import { TradingFormOfferItem } from 'src/views/wallet/trading/common/TradingForm/TradingFormOfferItem'; +import { TradingFormOfferOTC } from 'src/views/wallet/trading/common/TradingForm/TradingFormOfferOTC'; import { TradingFormOffersSwitcher } from 'src/views/wallet/trading/common/TradingForm/TradingFormOffersSwitcher'; const getSelectedQuote = ( @@ -158,6 +159,7 @@ export const TradingFormOffer = () => { > + {(type === 'buy' || type === 'sell') && } ); }; diff --git a/packages/suite/src/views/wallet/trading/common/TradingForm/TradingFormOfferOTC.tsx b/packages/suite/src/views/wallet/trading/common/TradingForm/TradingFormOfferOTC.tsx new file mode 100644 index 00000000000..4a398758da1 --- /dev/null +++ b/packages/suite/src/views/wallet/trading/common/TradingForm/TradingFormOfferOTC.tsx @@ -0,0 +1,95 @@ +import { useEffect, useState } from 'react'; + +import { FiatCurrencyCode } from 'invity-api'; + +import { TradingOTC, TradingTradeBuySellType, invityAPI } from '@suite-common/trading'; +import { localizeNumber } from '@suite-common/wallet-utils'; +import { Banner, Text } from '@trezor/components'; +import { spacings } from '@trezor/theme'; + +import { Translation, TrezorLink } from 'src/components/suite'; +import { useSelector } from 'src/hooks/suite'; +import { useTradingFormContext } from 'src/hooks/wallet/trading/form/useTradingCommonForm'; +import { selectLanguage } from 'src/reducers/suite/suiteReducer'; +import { isTradingBuyContext } from 'src/utils/wallet/trading/tradingTypingUtils'; + +export const TradingFormOfferOTC = () => { + const context = useTradingFormContext(); + const locale = useSelector(selectLanguage); + + const { amountInCrypto } = context.getValues(); + const fiatAmount = isTradingBuyContext(context) + ? context.getValues().fiatInput + : context.getValues().outputs[0].fiat; + const currencySelect = isTradingBuyContext(context) + ? context.getValues().currencySelect.value + : context.getValues().outputs[0].currency.value; + const [otcData, setOtcData] = useState(null); + const apiKey = invityAPI.getCurrentApiKey(); + + useEffect(() => { + if (!apiKey) return; + + const getOtcData = async () => { + const otcData = await invityAPI.getOTCData(); + + if (!otcData) return; + + setOtcData(otcData); + }; + + getOtcData(); + }, [apiKey]); + + const isCurrencyAllowed = otcData?.allowedCurrencies?.includes( + currencySelect as FiatCurrencyCode, + ); + + if ( + !otcData || + amountInCrypto || + !isCurrencyAllowed || + !fiatAmount || + Number(fiatAmount) <= Number(otcData.minimumFiat) + ) { + return null; + } + + const apiUrl = new URL(otcData.apiUrl); + const params = new URLSearchParams({ + widget_id: otcData.idWidget, + otc_id: otcData.idOtcUser, + fiat_amount: fiatAmount, + fiat_currency: currencySelect, + type: context.type, + }); + + apiUrl.search = params.toString(); + + return ( + + + {' '} + + + + + + ); +}; diff --git a/suite-common/trading/src/invityAPI.ts b/suite-common/trading/src/invityAPI.ts index 91a2af43177..4978bf73bb9 100644 --- a/suite-common/trading/src/invityAPI.ts +++ b/suite-common/trading/src/invityAPI.ts @@ -27,6 +27,7 @@ import type { import type { InvityServerEnvironment, InvityServers, + TradingOTC, TradingPaymentMethodType, TradingTradeType, TradingType, @@ -84,6 +85,9 @@ class InvityAPI { private readonly SELL_FIAT_CONFIRM = '/api/v3/sell/fiat/confirm'; private readonly SELL_FIAT_WATCH_TRADE = '/api/v3/sell/fiat/watch/{{counter}}'; + // otc service + private readonly OTC_INFO = '/api/v1/otc'; + private static accountDescriptor: string; private static apiKey: string; @@ -433,6 +437,18 @@ class InvityAPI { return { error: error.toString() }; } }; + + getOTCData = async (): Promise => { + try { + const response = await this.request(this.OTC_INFO, {}, 'GET'); + + if (response) { + return response; + } + } catch (error) { + console.error('[getOTCData]', error); + } + }; } export const invityAPI = new InvityAPI(); diff --git a/suite-common/trading/src/types.ts b/suite-common/trading/src/types.ts index bd1f905655e..5f8a43a1280 100644 --- a/suite-common/trading/src/types.ts +++ b/suite-common/trading/src/types.ts @@ -86,3 +86,11 @@ export type TradingTransaction = | TradingTransactionBuy | TradingTransactionSell | TradingTransactionExchange; + +export type TradingOTC = { + idWidget: string; + idOtcUser: string; + apiUrl: string; + minimumFiat: string; + allowedCurrencies: FiatCurrencyCode[]; +};