Skip to content

Commit

Permalink
feat(seamless limits): added support for over balance limit
Browse files Browse the repository at this point in the history
  • Loading branch information
milan-bc committed Dec 30, 2021
1 parent e0adb3b commit aed21e2
Show file tree
Hide file tree
Showing 10 changed files with 173 additions and 66 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -1440,6 +1440,7 @@ type MessagesType = {
'modals.sendcrypto.coinselect.subtitle': 'Select the wallet you want to send from.'
'modals.sendcrypto.coinselect.title': 'Send Crypto'
'modals.sendcrypto.enteramount.title': 'Send'
'modals.sendcrypto.enteramount.over_balance': 'The max you can send from this wallet is {coin} {amount}. Buy {coin} {amount} now to send this amount.'
'modals.sendcrypto.enteramount.over_limits': 'Sending from Trade Accounts cannot exceed {currency}{amount} a {period}. You have {currency}{remainingAmount} remaining.'
'modals.sendeth.amountnotzeromessage': 'Invalid amount'
'modals.sendeth.cointitle': 'Send {coinDisplayName}'
Expand Down Expand Up @@ -1554,6 +1555,8 @@ type MessagesType = {
'modals.simplebuy.checkout.sell.belowmin': 'To offset fees and market volatility, the minimum amount for any sell is {amount} {currency}.'
'modals.simplebuy.checkout.buy.abovemax': 'The maximum amount of {coin} you can buy with your {currency} {amount}'
'modals.simplebuy.checkout.sell.abovemax': 'The maximum amount of {coin} you can sell from this account is {amount}.'
'modals.simplebuy.checkout.buy.over_balance': 'Swapping from Trade Accounts cannot exceed {limit} a {period}. You have {currency}{amount} remaining.'
'modals.simplebuy.checkout.buy.over_limit': 'You can buy up to {amount} per transaction. Upgrade to Gold & buy larger amounts with your bank or card.'
'modals.simplebuy.checkout.not_enough_funds_for_sell': 'Not Enough funds for Sell'
'modals.simplebuy.checkout.dailylimitexceeded': "You've reached your daily trading limit"
'modals.simplebuy.checkout.buymax': 'Buy Max'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import { Form } from 'components/Form'
import { model } from 'data'
import { convertBaseToStandard, convertStandardToBase } from 'data/components/exchange/services'
import { BSCheckoutFormValuesType, SwapBaseCounterTypes } from 'data/types'
import { getEffectiveLimit } from 'services/custodial'
import { getEffectiveLimit, getEffectivePeriod } from 'services/custodial'
import { CRYPTO_DECIMALS, FIAT_DECIMALS, formatTextAmount } from 'services/forms'

import { AlertButton } from '../../../components'
Expand Down Expand Up @@ -375,8 +375,10 @@ const Success: React.FC<InjectedFormProps<{}, Props> & Props> = (props) => {
})

const effectiveLimit = getEffectiveLimit(crossBorderLimits)
const effectivePeriod = getEffectivePeriod(crossBorderLimits)

const showLimitError = showError && amtError === 'ABOVE_MAX_LIMIT'

return (
<CustomForm onSubmit={props.handleSubmit}>
<FlyoutWrapper style={{ borderBottom: 'grey000', paddingBottom: '0px' }}>
Expand Down Expand Up @@ -509,7 +511,6 @@ const Success: React.FC<InjectedFormProps<{}, Props> & Props> = (props) => {
{getPeriodTitleText(props.formValues.period)}
</Scheduler>
)}

{(!props.isSddFlow || props.orderType === OrderType.SELL) && props.pair && (
<Amounts>
<MaxAvailableWrapper orderType={orderType}>
Expand Down Expand Up @@ -556,7 +557,13 @@ const Success: React.FC<InjectedFormProps<{}, Props> & Props> = (props) => {
</ActionsItem>
<ActionsItem>
<div onClick={handleMaxClick} onKeyDown={handleMaxClick} role='button' tabIndex={0}>
<Cartridge error={amtError === 'ABOVE_MAX'}>
<Cartridge
error={
amtError === 'ABOVE_MAX' ||
amtError === 'ABOVE_BALANCE' ||
amtError === 'ABOVE_LIMIT'
}
>
<FormattedMessage
id='modals.simplebuy.checkout.maxbuy'
defaultMessage='Max Buy'
Expand All @@ -566,7 +573,6 @@ const Success: React.FC<InjectedFormProps<{}, Props> & Props> = (props) => {
</ActionsItem>
</ActionsRow>
)}

<Payment
{...props}
method={method}
Expand Down Expand Up @@ -629,6 +635,8 @@ const Success: React.FC<InjectedFormProps<{}, Props> & Props> = (props) => {
: `${min} ${Currencies[fiatCurrency].units[fiatCurrency].symbol}`
}}
/>
) : amtError === 'ABOVE_LIMIT' || amtError === 'ABOVE_BALANCE' ? (
<FormattedMessage id='copy.over_your_limit' defaultMessage='Over Your Limit' />
) : (
<FormattedMessage
id='copy.above_max'
Expand Down Expand Up @@ -714,10 +722,40 @@ const Success: React.FC<InjectedFormProps<{}, Props> & Props> = (props) => {
}}
/>
))}

{amtError === 'ABOVE_BALANCE' && effectiveLimit && (
<FormattedMessage
id='modals.simplebuy.checkout.buy.over_balance'
defaultMessage='Swapping from Trade Accounts cannot exceed {limit} a {period}. You have {currency}{amount} remaining.'
values={{
amount:
fix === 'FIAT'
? fiatToString({ unit: props.fiatCurrency, value: max })
: `${min} ${Currencies[fiatCurrency].units[fiatCurrency].symbol}`,
currency: fiatCurrency,
limit: formatFiat(
convertBaseToStandard('FIAT', effectiveLimit.limit.value),
0
),
period: effectivePeriod
}}
/>
)}
{(amtError === 'ABOVE_LIMIT' || true) && (
<FormattedMessage
id='modals.simplebuy.checkout.buy.over_limit'
defaultMessage='You can buy up to {amount} per transaction. Upgrade to Gold & buy larger amounts with your bank or card.'
values={{
amount:
fix === 'FIAT'
? fiatToString({ unit: props.fiatCurrency, value: max })
: `${min} ${Currencies[fiatCurrency].units[fiatCurrency].symbol}`
}}
/>
)}
</Text>
</ButtonContainer>
)}

{showLimitError &&
effectiveLimit &&
(props.orderType === OrderType.BUY ? (
Expand Down Expand Up @@ -755,7 +793,6 @@ const Success: React.FC<InjectedFormProps<{}, Props> & Props> = (props) => {
/>
</>
))}

{isDailyLimitExceeded && (
<Amounts>
<GreyBlueCartridge role='button' data-e2e='sbEnterAmountDailyLimitExceeded'>
Expand All @@ -770,20 +807,21 @@ const Success: React.FC<InjectedFormProps<{}, Props> & Props> = (props) => {
</FlyoutWrapper>

{props.isSddFlow && props.orderType === OrderType.BUY && <IncreaseLimits {...props} />}
{props.isSddFlow && props.orderType === OrderType.BUY && (
<FlyoutWrapper>
<UpgradeToGoldLine
type={Flows.BUY}
verifyIdentity={() =>
props.identityVerificationActions.verifyIdentity({
needMoreInfo: false,
origin: 'BuySell',
tier: 2
})
}
/>
</FlyoutWrapper>
)}
{(props.isSddFlow || amtError === 'ABOVE_BALANCE' || amtError === 'ABOVE_LIMIT') &&
props.orderType === OrderType.BUY && (
<FlyoutWrapper>
<UpgradeToGoldLine
type={Flows.BUY}
verifyIdentity={() =>
props.identityVerificationActions.verifyIdentity({
needMoreInfo: false,
origin: 'BuySell',
tier: 2
})
}
/>
</FlyoutWrapper>
)}

{isSufficientEthForErc20 && (
<Banner type='warning'>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export enum Limits {
ABOVE_BALANCE = 'ABOVE_BALANCE',
ABOVE_LIMIT = 'ABOVE_LIMIT',
ABOVE_MAX = 'ABOVE_MAX'
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import { convertBaseToStandard } from 'data/components/exchange/services'
import { BSCheckoutFormValuesType, BSFixType, SwapAccountType } from 'data/types'

import { Props } from './template.success'
import { Limits } from './types'

const { LIMIT } = model.components.buySell

Expand Down Expand Up @@ -89,11 +90,11 @@ export const getMaxMinSell = (
allValues?: BSCheckoutFormValuesType,
method?: BSPaymentMethodType,
account?: SwapAccountType
): { CRYPTO: string; FIAT: string } => {
): { CRYPTO: string; FIAT: string; type: Limits } => {
switch (orderType as OrderType) {
case OrderType.BUY:
// Not implemented
return { CRYPTO: '0', FIAT: '0' }
return { CRYPTO: '0', FIAT: '0', type: Limits.ABOVE_MAX }
case OrderType.SELL:
const coin = getCoinFromPair(pair.pair)
const { rate } = quote
Expand All @@ -111,19 +112,19 @@ export const getMaxMinSell = (
Number(maxSell)
).toString()
const maxFiat = getQuote(pair.pair, rate, 'CRYPTO', maxCrypto)
return { CRYPTO: maxCrypto, FIAT: maxFiat }
return { CRYPTO: maxCrypto, FIAT: maxFiat, type: Limits.ABOVE_MAX }
case 'min':
const minCrypto = new BigNumber(pair.sellMin)
.dividedBy(rate)
.toFixed(window.coins[coin] ? window.coins[coin].coinfig.precision : 2)
const minFiat = convertBaseToStandard('FIAT', pair.sellMin)

return { CRYPTO: minCrypto, FIAT: minFiat }
return { CRYPTO: minCrypto, FIAT: minFiat, type: Limits.ABOVE_MAX }
default:
return { CRYPTO: '0', FIAT: '0' }
return { CRYPTO: '0', FIAT: '0', type: Limits.ABOVE_MAX }
}
default:
return { CRYPTO: '0', FIAT: '0' }
return { CRYPTO: '0', FIAT: '0', type: Limits.ABOVE_MAX }
}
}

Expand All @@ -140,11 +141,12 @@ export const getMaxMin = (
isSddFlow = false,
sddLimit = LIMIT,
limits?: SwapUserLimitsType
): { CRYPTO: string; FIAT: string } => {
): { CRYPTO: string; FIAT: string; type?: Limits } => {
let quote: BSQuoteType | SwapQuoteStateType | BuyQuoteStateType
switch (orderType as OrderType) {
case OrderType.BUY:
quote = QUOTE as BSQuoteType | BuyQuoteStateType
let limitType = Limits.ABOVE_MAX
switch (minOrMax) {
case 'max':
// we need minimum of all max amounts including limits
Expand Down Expand Up @@ -173,10 +175,11 @@ export const getMaxMin = (
),
FIAT: isSddFlow
? convertBaseToStandard('FIAT', Number(sddLimit.max))
: convertBaseToStandard('FIAT', pair.buyMax)
: convertBaseToStandard('FIAT', pair.buyMax),
type: limitType
}

// we have to convert in case that this ammount is from maxOrder
// we have to convert in case that this amount is from maxOrder
// we have to convert it to Standard since defaultMax is in standard format
const defaultMaxCompare = limitMaxChanged
? Number(convertBaseToStandard('FIAT', limitMaxAmount))
Expand Down Expand Up @@ -208,10 +211,12 @@ export const getMaxMin = (
break
case Number(availableStandard) >= Number(limits.maxPossibleOrder):
max = limits.maxPossibleOrder
limitType = Limits.ABOVE_LIMIT
fundsChangedMax = true
break
case Number(availableStandard) < Number(limits.maxPossibleOrder):
max = availableStandard
limitType = Limits.ABOVE_BALANCE
fundsChangedMax = true
break
}
Expand All @@ -220,7 +225,7 @@ export const getMaxMin = (
const maxFiat = !fundsChangedMax ? convertBaseToStandard('FIAT', max) : max
const maxCrypto = getQuote(quote.pair, quote.rate, 'FIAT', maxFiat)

return { CRYPTO: maxCrypto, FIAT: maxFiat }
return { CRYPTO: maxCrypto, FIAT: maxFiat, type: limitType }
case 'min':
// we need maximum of all min amounts including limits
let limitMinAmount = Number(pair.buyMin)
Expand Down Expand Up @@ -320,25 +325,22 @@ export const maximumAmount = (
const method = selectedMethod || defaultMethod
if (!allValues) return false

return Number(value) >
Number(
getMaxMin(
'max',
sbBalances,
orderType,
quote,
pair,
payment,
allValues,
method,
swapAccount,
isSddFlow,
sddLimit,
limits
)[allValues.fix]
)
? 'ABOVE_MAX'
: false
const maxMinAmount = getMaxMin(
'max',
sbBalances,
orderType,
quote,
pair,
payment,
allValues,
method,
swapAccount,
isSddFlow,
sddLimit,
limits
)
const errorType = maxMinAmount.type || Limits.ABOVE_MAX
return Number(value) > Number(maxMinAmount[allValues.fix]) ? errorType : false
}

export const minimumAmount = (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -421,18 +421,32 @@ const SendEnterAmount: React.FC<InjectedFormProps<{}, Props> & Props> = (props)
)}

{amtError === 'ABOVE_MAX' && (
<AlertButton>
<FormattedMessage
id='copy.above_max'
defaultMessage='{amount} Maximum'
values={{
amount:
fix === 'FIAT'
? `${Currencies[walletCurrency].units[walletCurrency].symbol}${max}`
: `${coin}${max}`
}}
/>
</AlertButton>
<>
<AlertButton>
<FormattedMessage
id='copy.not_enough_coin'
defaultMessage='Not Enough {coin}'
values={{
coin
}}
/>
</AlertButton>
<Text
size='14px'
color='grey900'
weight={500}
style={{ marginBottom: '24px', marginTop: '24px', textAlign: 'center' }}
>
<FormattedMessage
id='modals.sendcrypto.enteramount.over_balance'
defaultMessage='The max you can send from this wallet is {coin} {amount}. Buy {coin} {amount} now to send this amount.'
values={{
amount: max,
coin
}}
/>
</Text>
</>
)}
{amtError === 'BELOW_MIN' && (
<AlertButton>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { convertCoinToCoin, convertCoinToFiat, convertFiatToCoin } from '@core/exchange'
import { convertCoinToCoin, convertFiatToCoin } from '@core/exchange'
import { convertBaseToStandard } from 'data/components/exchange/services'

import { SendFormType } from '../types'
Expand Down

0 comments on commit aed21e2

Please sign in to comment.