Add warning bnner, add granular features for geoblock, allow geoblock reduceonly
This commit is contained in:
parent
4e4fc5f455
commit
2aa2f0422c
|
@ -30,6 +30,7 @@ import { useTheme } from 'next-themes'
|
|||
import PromoBanner from './rewards/PromoBanner'
|
||||
import { useRouter } from 'next/router'
|
||||
import StatusBar from './StatusBar'
|
||||
import WarningBanner from './shared/WarningBanner'
|
||||
|
||||
export const sideBarAnimationDuration = 300
|
||||
const termsLastUpdated = 1679441610978
|
||||
|
@ -127,6 +128,7 @@ const Layout = ({ children }: { children: ReactNode }) => {
|
|||
}`}
|
||||
>
|
||||
<TopBar />
|
||||
<WarningBanner />
|
||||
{asPath !== '/rewards' ? <PromoBanner /> : null}
|
||||
{children}
|
||||
<StatusBar collapsed={isCollapsed} />
|
||||
|
|
|
@ -0,0 +1,63 @@
|
|||
import { IconButton } from '@components/shared/Button'
|
||||
import { XMarkIcon } from '@heroicons/react/20/solid'
|
||||
import Link from 'next/link'
|
||||
import useIpAddress from 'hooks/useIpAddress'
|
||||
|
||||
const BANNER_WRAPPER_CLASSES =
|
||||
'flex flex-wrap items-center justify-center border-b border-th-bkg-3 bg-th-bkg-2 px-10 py-3'
|
||||
|
||||
const LINK_TEXT_CLASSES =
|
||||
'bg-gradient-to-b from-mango-classic-theme-active to-mango-classic-theme-down bg-clip-text font-bold text-transparent lg:text-base'
|
||||
|
||||
const TEXT_CLASSES = 'mr-2 text-center text-th-fgd-1 lg:text-base'
|
||||
|
||||
const WarningBanner = () => {
|
||||
const { showWarning } = useIpAddress()
|
||||
|
||||
return showWarning ? (
|
||||
<BannerContent
|
||||
text={`Don't invest unless you're prepared to lose all the money you invest. This is a high-risk investment and you should not expect to be protected if something goes wrong.`}
|
||||
linkText="Learn More"
|
||||
/>
|
||||
) : null
|
||||
}
|
||||
|
||||
export default WarningBanner
|
||||
|
||||
const BannerContent = ({
|
||||
text,
|
||||
linkText,
|
||||
onClickLink,
|
||||
onClose,
|
||||
}: {
|
||||
text: string
|
||||
linkText: string
|
||||
onClickLink?: () => void
|
||||
onClose?: () => void
|
||||
}) => {
|
||||
return (
|
||||
<div className="relative">
|
||||
<div className={BANNER_WRAPPER_CLASSES}>
|
||||
<p className={TEXT_CLASSES}>{text}</p>
|
||||
<Link
|
||||
className={LINK_TEXT_CLASSES}
|
||||
href="https://docs.mango.markets/mango-markets/risks"
|
||||
onClick={onClickLink}
|
||||
target="blank"
|
||||
>
|
||||
{linkText}
|
||||
</Link>
|
||||
</div>
|
||||
{onClose ? (
|
||||
<IconButton
|
||||
className="absolute right-0 top-1/2 -translate-y-1/2 sm:right-2"
|
||||
hideBg
|
||||
onClick={onClose}
|
||||
size="medium"
|
||||
>
|
||||
<XMarkIcon className="h-5 w-5 text-th-fgd-3" />
|
||||
</IconButton>
|
||||
) : null}
|
||||
</div>
|
||||
)
|
||||
}
|
|
@ -88,7 +88,7 @@ const MarketSwapForm = ({
|
|||
swapMode,
|
||||
wallet: publicKey?.toBase58(),
|
||||
})
|
||||
const { ipAllowed, ipCountry } = useIpAddress()
|
||||
const { ipAllowed, swapAllowed, ipCountry } = useIpAddress()
|
||||
|
||||
const amountInAsDecimal: Decimal | null = useMemo(() => {
|
||||
return Number(debouncedAmountIn)
|
||||
|
@ -274,7 +274,7 @@ const MarketSwapForm = ({
|
|||
setShowTokenSelect={setShowTokenSelect}
|
||||
handleRepay={handleRepay}
|
||||
/>
|
||||
{ipAllowed ? (
|
||||
{ipAllowed || swapAllowed ? (
|
||||
<SwapFormSubmitButton
|
||||
loadingSwapDetails={loadingSwapDetails}
|
||||
useMargin={useMargin}
|
||||
|
|
|
@ -151,7 +151,7 @@ export const fetchJupiterTransaction = async (
|
|||
// This is the ATA account for the output token where the fee will be sent to. If you are swapping from SOL->USDC then this would be the USDC ATA you want to collect the fee.
|
||||
// feeAccount: 'fee_account_public_key',
|
||||
slippageBps: Math.ceil(slippage * 100),
|
||||
maxAccounts: 50
|
||||
maxAccounts: 50,
|
||||
}),
|
||||
})
|
||||
).json()
|
||||
|
|
|
@ -112,7 +112,7 @@ const TriggerSwapForm = ({
|
|||
}: TriggerSwapFormProps) => {
|
||||
const { t } = useTranslation(['common', 'swap', 'trade'])
|
||||
const { mangoAccountAddress } = useMangoAccount()
|
||||
const { ipAllowed, ipCountry } = useIpAddress()
|
||||
const { ipAllowed, swapAllowed, ipCountry } = useIpAddress()
|
||||
const { setShowSettingsModal } = TopBarStore()
|
||||
// const [triggerPrice, setTriggerPrice] = useState('')
|
||||
const [orderType, setOrderType] = useState(ORDER_TYPES[0])
|
||||
|
@ -854,7 +854,7 @@ const TriggerSwapForm = ({
|
|||
<InlineNotification desc={orderDescription} type="info" />
|
||||
</div>
|
||||
) : null}
|
||||
{ipAllowed ? (
|
||||
{ipAllowed || swapAllowed ? (
|
||||
<Button
|
||||
disabled={borrowExceedsLimitInPeriod || tokenPositionsFull}
|
||||
onClick={onClick}
|
||||
|
|
|
@ -72,7 +72,7 @@ const WalletSwapForm = ({ setShowTokenSelect }: WalletSwapFormProps) => {
|
|||
wallet: publicKey?.toBase58(),
|
||||
mode: 'JUPITER',
|
||||
})
|
||||
const { ipAllowed, ipCountry } = useIpAddress()
|
||||
const { ipAllowed, swapAllowed, ipCountry } = useIpAddress()
|
||||
|
||||
const walletTokens = mangoStore((s) => s.wallet.tokens)
|
||||
|
||||
|
@ -277,7 +277,7 @@ const WalletSwapForm = ({ setShowTokenSelect }: WalletSwapFormProps) => {
|
|||
loading={loadingSwapDetails}
|
||||
setShowTokenSelect={setShowTokenSelect}
|
||||
/>
|
||||
{ipAllowed ? (
|
||||
{ipAllowed || swapAllowed ? (
|
||||
<SwapFormSubmitButton
|
||||
loadingSwapDetails={loadingSwapDetails}
|
||||
useMargin={useMargin}
|
||||
|
|
|
@ -30,7 +30,7 @@ const fetchJupiterRoute = async (
|
|||
swapMode = 'ExactIn',
|
||||
feeBps = 0,
|
||||
onlyDirectRoutes = true,
|
||||
maxAccounts = 50
|
||||
maxAccounts = 50,
|
||||
) => {
|
||||
{
|
||||
const paramsString = new URLSearchParams({
|
||||
|
|
|
@ -97,7 +97,7 @@ const AdvancedTradeForm = () => {
|
|||
const [tradeFormSizeUi] = useLocalStorageState(SIZE_INPUT_UI_KEY, 'slider')
|
||||
const [savedCheckboxSettings, setSavedCheckboxSettings] =
|
||||
useLocalStorageState(TRADE_CHECKBOXES_KEY, DEFAULT_CHECKBOX_SETTINGS)
|
||||
const { ipAllowed, ipCountry } = useIpAddress()
|
||||
const { ipAllowed, perpAllowed, spotAllowed, ipCountry } = useIpAddress()
|
||||
const [soundSettings] = useLocalStorageState(
|
||||
SOUND_SETTINGS_KEY,
|
||||
INITIAL_SOUND_SETTINGS,
|
||||
|
@ -336,6 +336,36 @@ const AdvancedTradeForm = () => {
|
|||
}
|
||||
}, [selectedMarket])
|
||||
|
||||
const isSanctioned = useMemo(() => {
|
||||
return !(
|
||||
ipAllowed ||
|
||||
(selectedMarket instanceof PerpMarket && perpAllowed) ||
|
||||
(selectedMarket instanceof Serum3Market && spotAllowed)
|
||||
)
|
||||
}, [selectedMarket, ipCountry])
|
||||
|
||||
const hasPosition = useMemo(() => {
|
||||
const group = mangoStore.getState().group
|
||||
if (!mangoAccount || !selectedMarket || !group) return false
|
||||
if (selectedMarket instanceof PerpMarket) {
|
||||
const basePosition = mangoAccount
|
||||
.getPerpPosition(selectedMarket.perpMarketIndex)
|
||||
?.getBasePositionUi(selectedMarket)
|
||||
return basePosition !== undefined && basePosition != 0
|
||||
} else if (selectedMarket instanceof Serum3Market) {
|
||||
const baseBank = group.getFirstBankByTokenIndex(
|
||||
selectedMarket.baseTokenIndex,
|
||||
)
|
||||
const tokenPosition = mangoAccount.getTokenBalanceUi(baseBank)
|
||||
return tokenPosition != 0
|
||||
}
|
||||
}, [selectedMarket, ipCountry, mangoAccount])
|
||||
|
||||
const isForceReduceOnly = useMemo(() => {
|
||||
if (!selectedMarket) return false
|
||||
return selectedMarket.reduceOnly || (isSanctioned && hasPosition)
|
||||
}, [selectedMarket])
|
||||
|
||||
/*
|
||||
* Updates the limit price on page load
|
||||
*/
|
||||
|
@ -769,10 +799,13 @@ const AdvancedTradeForm = () => {
|
|||
>
|
||||
<div className="flex items-center text-xs text-th-fgd-3">
|
||||
<Checkbox
|
||||
checked={tradeForm.reduceOnly}
|
||||
checked={
|
||||
tradeForm.reduceOnly || isForceReduceOnly === true
|
||||
}
|
||||
onChange={(e) =>
|
||||
handleReduceOnlyChange(e.target.checked)
|
||||
}
|
||||
disabled={isForceReduceOnly}
|
||||
>
|
||||
{t('trade:reduce-only')}
|
||||
</Checkbox>
|
||||
|
@ -782,7 +815,7 @@ const AdvancedTradeForm = () => {
|
|||
)}
|
||||
</div>
|
||||
<div className="mb-4 mt-6 flex px-3 md:px-4">
|
||||
{ipAllowed ? (
|
||||
{!isSanctioned || isForceReduceOnly ? (
|
||||
connected ? (
|
||||
<Button
|
||||
className={`flex w-full items-center justify-center ${
|
||||
|
|
|
@ -14,6 +14,7 @@ const SANCTIONED_COUNTRIES = [
|
|||
['CU', 'Cuba'],
|
||||
['CD', 'Democratic Republic of Congo'],
|
||||
['EC', 'Ecuador'],
|
||||
['GB', 'United Kingdom'],
|
||||
['IR', 'Iran'],
|
||||
['IQ', 'Iraq'],
|
||||
['LR', 'Liberia'],
|
||||
|
@ -35,7 +36,11 @@ const SANCTIONED_COUNTRY_CODES = SANCTIONED_COUNTRIES.map(
|
|||
(country) => country[0],
|
||||
)
|
||||
|
||||
const SPOT_ALLOWED = ['GB']
|
||||
const PERP_ALLOWED: string[] = []
|
||||
const SPOT_ALLOWED: string[] = []
|
||||
const SWAP_ALLOWED: string[] = []
|
||||
const BORROW_LEND_ALLOWED: string[] = []
|
||||
const SHOW_WARNING: string[] = ['GB']
|
||||
|
||||
const fetchIpGeolocation = async () => {
|
||||
const response = await fetch(`https://country-code.mangomarkets.workers.dev`)
|
||||
|
@ -48,6 +53,10 @@ const fetchIpGeolocation = async () => {
|
|||
export default function useIpAddress() {
|
||||
const [ipAllowed, setIpAllowed] = useState(false)
|
||||
const [spotAllowed, setSpotAllowed] = useState(false)
|
||||
const [perpAllowed, setPerpAllowed] = useState(false)
|
||||
const [swapAllowed, setSwapAllowed] = useState(false)
|
||||
const [borrowLendAllowed, setBorrowLendAllowed] = useState(false)
|
||||
const [showWarning, setShowWarning] = useState(false)
|
||||
const [ipCountry, setIpCountry] = useState('')
|
||||
|
||||
const ipCountryCode = useQuery<string, Error>(
|
||||
|
@ -66,12 +75,32 @@ export default function useIpAddress() {
|
|||
setIpCountry(ipCountryCode.data)
|
||||
setIpAllowed(!SANCTIONED_COUNTRY_CODES.includes(ipCountryCode.data))
|
||||
setSpotAllowed(SPOT_ALLOWED.includes(ipCountryCode.data))
|
||||
setPerpAllowed(PERP_ALLOWED.includes(ipCountryCode.data))
|
||||
setSwapAllowed(SWAP_ALLOWED.includes(ipCountryCode.data))
|
||||
setBorrowLendAllowed(BORROW_LEND_ALLOWED.includes(ipCountryCode.data))
|
||||
setShowWarning(SHOW_WARNING.includes(ipCountryCode.data))
|
||||
}
|
||||
}, [ipCountryCode])
|
||||
|
||||
if (CLUSTER === 'mainnet-beta') {
|
||||
return { ipAllowed, spotAllowed, ipCountry }
|
||||
if (CLUSTER === 'mainnet-beta' && !process.env.NEXT_PUBLIC_DISABLE_GEOBLOCK) {
|
||||
return {
|
||||
ipAllowed,
|
||||
spotAllowed,
|
||||
perpAllowed,
|
||||
swapAllowed,
|
||||
borrowLendAllowed,
|
||||
showWarning,
|
||||
ipCountry,
|
||||
}
|
||||
} else {
|
||||
return { ipAllowed: true, spotAllowed: true, ipCountry }
|
||||
return {
|
||||
ipAllowed: true,
|
||||
spotAllowed: true,
|
||||
perpAllowed: true,
|
||||
swapAllowed: true,
|
||||
borrowLendAllowed: true,
|
||||
showWarning: true,
|
||||
ipCountry,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue