ip block
This commit is contained in:
parent
cfd9120169
commit
f24189185f
|
@ -28,6 +28,7 @@ import SheenLoader from './shared/SheenLoader'
|
|||
import { sleep } from 'utils'
|
||||
import ButtonGroup from './forms/ButtonGroup'
|
||||
import Decimal from 'decimal.js'
|
||||
import useIpAddress from 'hooks/useIpAddress'
|
||||
|
||||
const set = mangoStore.getState().set
|
||||
|
||||
|
@ -84,6 +85,7 @@ function DespositForm({ token: selectedToken }: StakeFormProps) {
|
|||
const { connected, publicKey } = useWallet()
|
||||
const walletTokens = mangoStore((s) => s.wallet.tokens)
|
||||
const [sizePercentage, setSizePercentage] = useState('')
|
||||
const { ipAllowed } = useIpAddress()
|
||||
|
||||
const depositBank = useMemo(() => {
|
||||
return group?.banksMapByName.get(selectedToken)?.[0]
|
||||
|
@ -115,6 +117,9 @@ function DespositForm({ token: selectedToken }: StakeFormProps) {
|
|||
}, [depositBank, usedTokens, totalTokens])
|
||||
|
||||
const handleDeposit = useCallback(async () => {
|
||||
if (!ipAllowed) {
|
||||
return
|
||||
}
|
||||
const client = mangoStore.getState().client
|
||||
const group = mangoStore.getState().group
|
||||
const actions = mangoStore.getState().actions
|
||||
|
@ -272,7 +277,10 @@ function DespositForm({ token: selectedToken }: StakeFormProps) {
|
|||
<Button
|
||||
onClick={handleDeposit}
|
||||
className="w-full"
|
||||
disabled={connected && (!inputAmount || showInsufficientBalance)}
|
||||
disabled={
|
||||
connected &&
|
||||
(!inputAmount || showInsufficientBalance || !ipAllowed)
|
||||
}
|
||||
size="large"
|
||||
>
|
||||
{submitting ? (
|
||||
|
@ -284,8 +292,10 @@ function DespositForm({ token: selectedToken }: StakeFormProps) {
|
|||
symbol: selectedToken,
|
||||
})}
|
||||
</div>
|
||||
) : (
|
||||
) : ipAllowed ? (
|
||||
`Boost! ${inputAmount} ${formatTokenSymbol(selectedToken)}`
|
||||
) : (
|
||||
'Country not allowed'
|
||||
)}
|
||||
</Button>
|
||||
) : (
|
||||
|
|
|
@ -11,6 +11,10 @@ import { useTranslation } from 'next-i18next'
|
|||
import TermsOfUseModal from './modals/TermsOfUseModal'
|
||||
import SunburstBackground from './SunburstBackground'
|
||||
import Footer from './Footer'
|
||||
import useIpAddress from 'hooks/useIpAddress'
|
||||
import RestrictedCountryModal from './shared/RestrictedCountryModal'
|
||||
|
||||
export const NON_RESTRICTED_JURISDICTION_KEY = 'non-restricted-jurisdiction-0.1'
|
||||
|
||||
export const sideBarAnimationDuration = 300
|
||||
const termsLastUpdated = 1679441610978
|
||||
|
@ -22,6 +26,25 @@ const Layout = ({ children }: { children: ReactNode }) => {
|
|||
useEffect(() => setMounted(true), [])
|
||||
if (!mounted) return null
|
||||
|
||||
// this will only show if the ip api doesn't return the country
|
||||
const RestrictedCountryCheck = () => {
|
||||
const { ipCountry, loadingIpCountry } = useIpAddress()
|
||||
const [confirmedCountry, setConfirmedCountry] = useLocalStorageState(
|
||||
NON_RESTRICTED_JURISDICTION_KEY,
|
||||
false,
|
||||
)
|
||||
const showModal = useMemo(() => {
|
||||
return !confirmedCountry && !ipCountry && !loadingIpCountry
|
||||
}, [confirmedCountry, ipCountry, loadingIpCountry])
|
||||
|
||||
return showModal ? (
|
||||
<RestrictedCountryModal
|
||||
isOpen={showModal}
|
||||
onClose={() => setConfirmedCountry(true)}
|
||||
/>
|
||||
) : null
|
||||
}
|
||||
|
||||
return (
|
||||
<main
|
||||
className={`${themeData.fonts.body.variable} ${themeData.fonts.display.variable} font-sans bg-th-primary-2`}
|
||||
|
@ -37,6 +60,7 @@ const Layout = ({ children }: { children: ReactNode }) => {
|
|||
</div>
|
||||
<DeployRefreshManager />
|
||||
<TermsOfUse />
|
||||
<RestrictedCountryCheck />
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
|
|
@ -38,6 +38,7 @@ import { sleep } from 'utils'
|
|||
import ButtonGroup from './forms/ButtonGroup'
|
||||
import Decimal from 'decimal.js'
|
||||
import { toUiDecimals } from '@blockworks-foundation/mango-v4'
|
||||
import useIpAddress from 'hooks/useIpAddress'
|
||||
|
||||
const set = mangoStore.getState().set
|
||||
|
||||
|
@ -90,6 +91,7 @@ function StakeForm({ token: selectedToken }: StakeFormProps) {
|
|||
const [leverage, setLeverage] = useState(1)
|
||||
const [refreshingWalletTokens, setRefreshingWalletTokens] = useState(false)
|
||||
const { maxSolDeposit } = useSolBalance()
|
||||
const { ipAllowed } = useIpAddress()
|
||||
|
||||
const { usedTokens, totalTokens } = useMangoAccountAccounts()
|
||||
const { group } = useMangoGroup()
|
||||
|
@ -181,6 +183,9 @@ function StakeForm({ token: selectedToken }: StakeFormProps) {
|
|||
}, [publicKey])
|
||||
|
||||
const handleDeposit = useCallback(async () => {
|
||||
if (!ipAllowed) {
|
||||
return
|
||||
}
|
||||
const client = mangoStore.getState().client
|
||||
const group = mangoStore.getState().group
|
||||
const actions = mangoStore.getState().actions
|
||||
|
@ -241,7 +246,7 @@ function StakeForm({ token: selectedToken }: StakeFormProps) {
|
|||
type: 'error',
|
||||
})
|
||||
}
|
||||
}, [stakeBank, publicKey, inputAmount, amountToBorrow])
|
||||
}, [ipAllowed, stakeBank, publicKey, amountToBorrow, inputAmount])
|
||||
|
||||
const showInsufficientBalance =
|
||||
tokenMax.maxAmount < Number(inputAmount) ||
|
||||
|
@ -556,7 +561,8 @@ function StakeForm({ token: selectedToken }: StakeFormProps) {
|
|||
Number(inputAmount) == 0 ||
|
||||
showInsufficientBalance ||
|
||||
(borrowBank && availableVaultBalance < amountToBorrow) ||
|
||||
depositLimitExceeded)
|
||||
depositLimitExceeded ||
|
||||
!ipAllowed)
|
||||
}
|
||||
size="large"
|
||||
>
|
||||
|
@ -569,8 +575,10 @@ function StakeForm({ token: selectedToken }: StakeFormProps) {
|
|||
symbol: selectedToken,
|
||||
})}
|
||||
</div>
|
||||
) : (
|
||||
) : ipAllowed ? (
|
||||
`Boost! ${inputAmount} ${formatTokenSymbol(selectedToken)}`
|
||||
) : (
|
||||
'Country not allowed'
|
||||
)}
|
||||
</Button>
|
||||
) : (
|
||||
|
|
|
@ -37,6 +37,7 @@ import ButtonGroup from './forms/ButtonGroup'
|
|||
import Decimal from 'decimal.js'
|
||||
import { Disclosure } from '@headlessui/react'
|
||||
import { sleep } from 'utils'
|
||||
import useIpAddress from 'hooks/useIpAddress'
|
||||
|
||||
const set = mangoStore.getState().set
|
||||
|
||||
|
@ -79,6 +80,7 @@ function UnstakeForm({ token: selectedToken }: UnstakeFormProps) {
|
|||
const { usedTokens, totalTokens } = useMangoAccountAccounts()
|
||||
const { group } = useMangoGroup()
|
||||
const { mangoAccount } = useMangoAccount()
|
||||
const { ipAllowed } = useIpAddress()
|
||||
|
||||
const stakeBank = useMemo(() => {
|
||||
return group?.banksMapByName.get(selectedToken)?.[0]
|
||||
|
@ -143,6 +145,9 @@ function UnstakeForm({ token: selectedToken }: UnstakeFormProps) {
|
|||
}, [borrowBank, mangoAccount])
|
||||
|
||||
const handleWithdraw = useCallback(async () => {
|
||||
if (!ipAllowed) {
|
||||
return
|
||||
}
|
||||
const client = mangoStore.getState().client
|
||||
const group = mangoStore.getState().group
|
||||
const actions = mangoStore.getState().actions
|
||||
|
@ -394,8 +399,10 @@ function UnstakeForm({ token: selectedToken }: UnstakeFormProps) {
|
|||
symbol: formatTokenSymbol(selectedToken),
|
||||
})}
|
||||
</div>
|
||||
) : (
|
||||
) : ipAllowed ? (
|
||||
`Unboost ${inputAmount} ${formatTokenSymbol(selectedToken)}`
|
||||
) : (
|
||||
'Country not allowed'
|
||||
)}
|
||||
</Button>
|
||||
) : (
|
||||
|
|
|
@ -37,6 +37,7 @@ import ButtonGroup from './forms/ButtonGroup'
|
|||
import Decimal from 'decimal.js'
|
||||
import { Disclosure } from '@headlessui/react'
|
||||
import { sleep } from 'utils'
|
||||
import useIpAddress from 'hooks/useIpAddress'
|
||||
|
||||
const set = mangoStore.getState().set
|
||||
|
||||
|
@ -69,6 +70,7 @@ function WithdrawForm({ token: selectedToken }: UnstakeFormProps) {
|
|||
const { t } = useTranslation(['common', 'account'])
|
||||
const [inputAmount, setInputAmount] = useState('')
|
||||
const [submitting, setSubmitting] = useState(false)
|
||||
const { ipAllowed } = useIpAddress()
|
||||
// const [selectedToken, setSelectedToken] = useState(
|
||||
// token || INPUT_TOKEN_DEFAULT,
|
||||
// )
|
||||
|
@ -143,6 +145,9 @@ function WithdrawForm({ token: selectedToken }: UnstakeFormProps) {
|
|||
}, [borrowBank, mangoAccount])
|
||||
|
||||
const handleWithdraw = useCallback(async () => {
|
||||
if (!ipAllowed) {
|
||||
return
|
||||
}
|
||||
const client = mangoStore.getState().client
|
||||
const group = mangoStore.getState().group
|
||||
const actions = mangoStore.getState().actions
|
||||
|
@ -357,7 +362,10 @@ function WithdrawForm({ token: selectedToken }: UnstakeFormProps) {
|
|||
<Button
|
||||
onClick={handleWithdraw}
|
||||
className="w-full"
|
||||
disabled={connected && (!inputAmount || showInsufficientBalance)}
|
||||
disabled={
|
||||
connected &&
|
||||
(!inputAmount || showInsufficientBalance || !ipAllowed)
|
||||
}
|
||||
size="large"
|
||||
>
|
||||
{submitting ? (
|
||||
|
@ -369,8 +377,10 @@ function WithdrawForm({ token: selectedToken }: UnstakeFormProps) {
|
|||
symbol: formatTokenSymbol(selectedToken),
|
||||
})}
|
||||
</div>
|
||||
) : ipAllowed ? (
|
||||
`Boost! ${inputAmount} ${formatTokenSymbol(selectedToken)}`
|
||||
) : (
|
||||
`Unboost ${inputAmount} ${formatTokenSymbol(selectedToken)}`
|
||||
'Country not allowed'
|
||||
)}
|
||||
</Button>
|
||||
) : (
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
import { ModalProps } from '../../types/modal'
|
||||
import Modal from '../shared/Modal'
|
||||
import { useTranslation } from 'next-i18next'
|
||||
import Checkbox from '@components/forms/Checkbox'
|
||||
import { useState } from 'react'
|
||||
import Button from '@components/shared/Button'
|
||||
import { SANCTIONED_COUNTRIES } from 'hooks/useIpAddress'
|
||||
|
||||
const RestrictedCountryModal = ({ isOpen, onClose }: ModalProps) => {
|
||||
const { t } = useTranslation('common')
|
||||
const [confirm, setConfirm] = useState(false)
|
||||
|
||||
return (
|
||||
<Modal isOpen={isOpen} onClose={onClose} hideClose disableOutsideClose>
|
||||
<h2 className="mb-2 text-center">{t('confirm-jurisdiction')}</h2>
|
||||
<p className="text-center">{t('confirm-jurisdiction-desc')}</p>
|
||||
<div className="thin-scroll my-4 max-h-[300px] overflow-auto rounded-lg bg-th-bkg-2 p-4">
|
||||
<ul>
|
||||
{SANCTIONED_COUNTRIES.map((country) => (
|
||||
<li key={country[0]}>{country[1]}</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
<Checkbox
|
||||
checked={confirm}
|
||||
onChange={(e) => setConfirm(e.target.checked)}
|
||||
>
|
||||
<p className="whitespace-normal">
|
||||
{t('confirm-non-restricted-jurisdiction')}
|
||||
</p>
|
||||
</Checkbox>
|
||||
<Button
|
||||
className="mt-6 w-full"
|
||||
disabled={!confirm}
|
||||
onClick={onClose}
|
||||
size="large"
|
||||
>
|
||||
{t('confirm')}
|
||||
</Button>
|
||||
</Modal>
|
||||
)
|
||||
}
|
||||
|
||||
export default RestrictedCountryModal
|
|
@ -0,0 +1,115 @@
|
|||
import { CLUSTER } from '@store/mangoStore'
|
||||
import { useQuery } from '@tanstack/react-query'
|
||||
import { useEffect, useState } from 'react'
|
||||
|
||||
export const SANCTIONED_COUNTRIES = [
|
||||
['AG', 'Antigua and Barbuda'],
|
||||
['DZ', 'Algeria'],
|
||||
['BD', 'Bangladesh'],
|
||||
['BO', 'Bolivia'],
|
||||
['BY', 'Belarus'],
|
||||
['BI', 'Burundi'],
|
||||
['MM', 'Burma (Myanmar)'],
|
||||
['CI', "Cote D'Ivoire (Ivory Coast)"],
|
||||
['CU', 'Cuba'],
|
||||
['CD', 'Democratic Republic of Congo'],
|
||||
['EC', 'Ecuador'],
|
||||
['GB', 'United Kingdom'],
|
||||
['IR', 'Iran'],
|
||||
['IQ', 'Iraq'],
|
||||
['LR', 'Liberia'],
|
||||
['LY', 'Libya'],
|
||||
['ML', 'Mali'],
|
||||
['MA', 'Morocco'],
|
||||
['NP', 'Nepal'],
|
||||
['KP', 'North Korea'],
|
||||
['SO', 'Somalia'],
|
||||
['SD', 'Sudan'],
|
||||
['SY', 'Syria'],
|
||||
['VE', 'Venezuela'],
|
||||
['YE', 'Yemen'],
|
||||
['ZW', 'Zimbabwe'],
|
||||
['US', 'United States'],
|
||||
]
|
||||
|
||||
const SANCTIONED_COUNTRY_CODES = SANCTIONED_COUNTRIES.map(
|
||||
(country) => country[0],
|
||||
)
|
||||
|
||||
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 () => {
|
||||
try {
|
||||
const response = await fetch(
|
||||
`https://country-code.mangomarkets.workers.dev`,
|
||||
)
|
||||
const parsedResponse = await response.json()
|
||||
const ipCountryCode = parsedResponse ? parsedResponse?.country : ''
|
||||
|
||||
return ipCountryCode
|
||||
} catch (e) {
|
||||
console.log('failed to fetch ip country', e)
|
||||
return ''
|
||||
}
|
||||
}
|
||||
|
||||
export default function useIpAddress() {
|
||||
const [ipAllowed, setIpAllowed] = useState(true)
|
||||
const [spotAllowed, setSpotAllowed] = useState(true)
|
||||
const [perpAllowed, setPerpAllowed] = useState(true)
|
||||
const [swapAllowed, setSwapAllowed] = useState(true)
|
||||
const [borrowLendAllowed, setBorrowLendAllowed] = useState(true)
|
||||
const [showWarning, setShowWarning] = useState(false)
|
||||
const [ipCountry, setIpCountry] = useState('')
|
||||
|
||||
const { data: ipCountryCode, isInitialLoading } = useQuery<string, Error>(
|
||||
['ip-address'],
|
||||
() => fetchIpGeolocation(),
|
||||
{
|
||||
cacheTime: 1000 * 60 * 2,
|
||||
staleTime: 1000 * 60 * 2,
|
||||
retry: 3,
|
||||
refetchOnWindowFocus: true,
|
||||
},
|
||||
)
|
||||
|
||||
useEffect(() => {
|
||||
if (ipCountryCode) {
|
||||
setIpCountry(ipCountryCode)
|
||||
setIpAllowed(!SANCTIONED_COUNTRY_CODES.includes(ipCountryCode))
|
||||
setSpotAllowed(SPOT_ALLOWED.includes(ipCountryCode))
|
||||
setPerpAllowed(PERP_ALLOWED.includes(ipCountryCode))
|
||||
setSwapAllowed(SWAP_ALLOWED.includes(ipCountryCode))
|
||||
setBorrowLendAllowed(BORROW_LEND_ALLOWED.includes(ipCountryCode))
|
||||
setShowWarning(SHOW_WARNING.includes(ipCountryCode))
|
||||
}
|
||||
}, [ipCountryCode])
|
||||
|
||||
if (CLUSTER === 'mainnet-beta' && !process.env.NEXT_PUBLIC_DISABLE_GEOBLOCK) {
|
||||
return {
|
||||
ipAllowed,
|
||||
spotAllowed,
|
||||
perpAllowed,
|
||||
swapAllowed,
|
||||
borrowLendAllowed,
|
||||
showWarning,
|
||||
ipCountry,
|
||||
loadingIpCountry: isInitialLoading,
|
||||
}
|
||||
} else {
|
||||
return {
|
||||
ipAllowed: true,
|
||||
spotAllowed: true,
|
||||
perpAllowed: true,
|
||||
swapAllowed: true,
|
||||
borrowLendAllowed: true,
|
||||
showWarning: true,
|
||||
ipCountry,
|
||||
loadingIpCountry: isInitialLoading,
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue