Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Display error when relay fee is greater than xdai amount #2219

Open
wants to merge 9 commits into
base: master
Choose a base branch
from
22 changes: 11 additions & 11 deletions app/src/components/common/form/textfield_custom_symbol/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,18 @@ import { CommonDisabledCSS } from '../common_styled'

interface Props {
disabled?: boolean
error?: boolean
formField: any
symbol: any
shouldDisplayMaxButton?: boolean
onClickMaxButton?: () => void
style?: CSSProperties | undefined
}

const FieldWrapper = styled.div`
const FieldWrapper = styled.div<{ error?: boolean }>`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we make this into style(TYPE.BodyRegular) and remove couple of prperties like font-size,font-weight,line-height

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mmmm will leave this one, styled(TYPE.bodyRegular) doesn't appear to apply font styling in the same way using the> input selector does

align-items: center;
background-color: ${props => props.theme.textfield.backgroundColor};
border-color: ${props => props.theme.textfield.borderColor};
border-color: ${props => (props.error ? props.theme.alert : props.theme.border1)};
border-style: ${props => props.theme.textfield.borderStyle};
border-width: ${props => props.theme.textfield.borderWidth};
border-radius: ${props => props.theme.textfield.borderRadius};
Expand All @@ -26,16 +27,16 @@ const FieldWrapper = styled.div`
width: 100%;

&:hover {
border-color: ${props => props.theme.textfield.borderColorOnHover};
border-color: ${props => (props.error ? props.theme.alert : props.theme.border2)};
.btn--max {
border-color: ${props => props.theme.textfield.borderColorOnHover};
border-color: ${props => (props.error ? props.theme.alert : props.theme.border2)};
}
}

&:focus-within {
border-color: ${props => props.theme.textfield.borderColorActive};
border-color: ${props => (props.error ? props.theme.alert : props.theme.border3)};
.btn--max {
border-color: ${props => props.theme.textfield.borderColorActive};
border-color: ${props => (props.error ? props.theme.alert : props.theme.border3)};
}
}

Expand All @@ -44,12 +45,12 @@ const FieldWrapper = styled.div`
> input {
background-color: transparent;
border: none;
color: ${props => props.theme.textfield.color};
color: ${props => props.theme.text2};
flex-grow: 1;
font-family: ${props => props.theme.fonts.fontFamily};
font-size: ${props => props.theme.textfield.fontSize};
font-weight: ${props => props.theme.textfield.fontWeight};
line-height: 1.2;
font-weight: 400;
line-height: 18px;
margin: 0 5px 0 0;
min-width: 0;
outline: ${props => props.theme.textfield.outline};
Expand Down Expand Up @@ -91,7 +92,7 @@ const FieldWrapper = styled.div`
`

const Symbol = styled.span<{ marginRight?: boolean }>`
color: ${props => props.theme.colors.primary};
color: ${props => props.theme.text2};
flex-shrink: 0;
font-size: 14px;
font-weight: 500;
Expand Down Expand Up @@ -124,7 +125,6 @@ const MaxButton = styled.span`

export const TextfieldCustomSymbol = (props: Props) => {
const { disabled, formField, onClickMaxButton, shouldDisplayMaxButton, symbol, ...restProps } = props

// eslint-disable-next-line no-warning-comments
//TODO: use a input[text] instead of passing a <Textfield />
return (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ const Wrapper = styled.div<{ margin?: boolean }>`
border: ${({ theme }) => theme.borders.borderLineDisabled};
align-content: center;
padding: 4px 20px;
margin-bottom: ${props => (!props.margin ? '20px' : '0')};
margin-bottom: ${props => (props.margin ? '20px' : '0')};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I couldn't find figma designs but seems that because you flipped evaluation in some cases where it was previously set we have double margins...Like if value inputted in negative on market_buy component. Or this is how its supposed to be I couldn't find figma @pimato ?
Screenshot 2021-08-26 at 14 58 13

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@pimato Also seems that color on this error message when value is negative is different then the error message on form...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

filled this back to !props.margin and changed up the alert color 👍

`

const AlertWrapper = styled.div`
Expand Down Expand Up @@ -59,7 +59,7 @@ export const WarningMessage = (props: Props) => {
grayscale,
href,
hyperlinkDescription,
marginBottom,
marginBottom = true,
...restProps
} = props
return (
Expand Down
2 changes: 1 addition & 1 deletion app/src/components/market/common_styled/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ export const ErrorsWrapper = styled.div`
`

export const GenericError = styled.p<{ margin?: string }>`
color: ${props => props.theme.colors.error};
color: ${props => props.theme.alert};
font-size: 13px;
font-weight: 500;
line-height: 1.5;
Expand Down
1 change: 1 addition & 0 deletions app/src/components/market/market_buy/market_buy.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,7 @@ const MarketBuyWrapper: React.FC<Props> = (props: Props) => {
<ReactTooltip id="walletBalanceTooltip" />

<TextfieldCustomPlaceholder
error={!!amountError}
formField={
<BigNumberInput
decimals={collateral.decimals}
Expand Down
1 change: 1 addition & 0 deletions app/src/components/market/market_buy/scalar_market_buy.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,7 @@ export const ScalarMarketBuy = (props: Props) => {
</CurrenciesWrapper>
<ReactTooltip id="walletBalanceTooltip" />
<TextfieldCustomPlaceholder
error={!!amountError}
formField={
<BigNumberInput
decimals={collateral.decimals}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import {
MAX_MARKET_FEE,
} from '../../../../../common/constants'
import { useConnectedWeb3Context } from '../../../../../contexts'
import { useCollateralBalance, useCpkAllowance, useCpkProxy } from '../../../../../hooks'
import { useCollateralBalance, useCpkAllowance, useCpkProxy, useRelay } from '../../../../../hooks'
import { useGraphMarketsFromQuestion } from '../../../../../hooks/graph/useGraphMarketsFromQuestion'
import { BalanceState, fetchAccountBalance } from '../../../../../store/reducer'
import { MarketCreationStatus } from '../../../../../util/market_creation_status_data'
Expand Down Expand Up @@ -252,6 +252,8 @@ const FundingAndFeeStep: React.FC<Props> = (props: Props) => {
const { proxyIsUpToDate, updateProxy } = useCpkProxy(collateral.address === pseudoNativeAssetAddress)
const isUpdated = RemoteData.hasData(proxyIsUpToDate) ? proxyIsUpToDate.data : true

const { relayFeeGreaterThanAmount, relayFeeGreaterThanBalance } = useRelay(amount || new BigNumber(0), collateral)

useEffect(() => {
dispatch(fetchAccountBalance(account, provider, collateral))
}, [dispatch, account, provider, collateral])
Expand Down Expand Up @@ -284,10 +286,14 @@ const FundingAndFeeStep: React.FC<Props> = (props: Props) => {
? null
: !maybeCollateralBalance.eq(collateralBalance)
? null
: relayFeeGreaterThanBalance
? 'Insufficient Dai in your Omen Account'
: maybeCollateralBalance.isZero() && funding.gt(maybeCollateralBalance)
? `Insufficient balance`
: funding.gt(maybeCollateralBalance)
? `Value must be less than or equal to ${collateralBalanceFormatted} ${collateral.symbol}`
: relayFeeGreaterThanAmount
? 'Relay fee is greater than buy amount'
Comment on lines +290 to +297
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@hexyls Also one more consideration. I was looking through the codebase now and seems that in this pr and throught the codebase in components(marketBuy,marketSell,fundingAndFee and MarketPoolLiqudity) we have almost exactly the same amount error evaluations. Wondering does it make sense to make separate component or service dedicated to it? So we don't mess up in future if we have to add some new error handling. What do you think?

Copy link
Contributor

@Mi-Lan Mi-Lan Aug 26, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if you consider this makes sense to do we can even move it also into separate issue...

: null

const isCreateMarketbuttonDisabled =
Expand Down Expand Up @@ -471,6 +477,7 @@ const FundingAndFeeStep: React.FC<Props> = (props: Props) => {
/>
</CurrenciesWrapper>
<TextfieldCustomPlaceholder
error={!!amountError}
formField={
<BigNumberInput
decimals={collateral.decimals}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,7 @@ const MarketPoolLiquidityWrapper: React.FC<Props> = (props: Props) => {
</CurrenciesWrapper>

<TextfieldCustomPlaceholder
error={!!collateralAmountError}
formField={
<BigNumberInput
decimals={collateral.decimals}
Expand Down Expand Up @@ -215,6 +216,7 @@ const MarketPoolLiquidityWrapper: React.FC<Props> = (props: Props) => {
<TokenBalance text="Pool Tokens" value={sharesBalance} />

<TextfieldCustomPlaceholder
error={!!sharesAmountError}
formField={
<BigNumberInput
decimals={collateral.decimals}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,7 @@ export const ScalarMarketPoolLiquidity = (props: Props) => {
</CurrenciesWrapper>

<TextfieldCustomPlaceholder
error={!!collateralAmountError}
formField={
<BigNumberInput
decimals={collateral.decimals}
Expand Down Expand Up @@ -243,6 +244,7 @@ export const ScalarMarketPoolLiquidity = (props: Props) => {
<TokenBalance text="Pool Tokens" value={sharesBalance} />

<TextfieldCustomPlaceholder
error={!!sharesAmountError}
formField={
<BigNumberInput
decimals={collateral.decimals}
Expand All @@ -263,7 +265,6 @@ export const ScalarMarketPoolLiquidity = (props: Props) => {
shouldDisplayMaxButton
symbol="Shares"
/>

{sharesAmountError && <GenericError>{sharesAmountError}</GenericError>}
</>
)}
Expand Down
1 change: 1 addition & 0 deletions app/src/components/market/market_sell/market_sell.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ const MarketSellWrapper: React.FC<Props> = (props: Props) => {
<TokenBalance text="Your Shares" value={selectedOutcomeBalance} />
<ReactTooltip id="walletBalanceTooltip" />
<TextfieldCustomPlaceholder
error={!!amountError}
formField={
<BigNumberInput
decimals={collateral.decimals}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ export const ScalarMarketSell = (props: Props) => {
/>

<TextfieldCustomPlaceholder
error={!!amountError}
formField={
<BigNumberInput
decimals={collateral.decimals}
Expand Down
1 change: 1 addition & 0 deletions app/src/hooks/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,4 @@ export { useRealityLink } from './useRealityLink'
export { useSymbol } from './useSymbol'
export { useMultipleQueries } from './useMultipleQueries'
export { useAirdropService } from './useAirdropService'
export { useRelay } from './useRelay'
67 changes: 67 additions & 0 deletions app/src/hooks/useRelay.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import { BigNumber } from 'ethers/utils'
import { useEffect, useState } from 'react'

import { useConnectedWeb3Context } from '../contexts/connectedWeb3'
import { RelayService } from '../services'
import { getNativeAsset } from '../util/networks'
import { Token } from '../util/types'

interface Status {
active: boolean
}

interface RelayServiceResponse {
relayAddress: string
relayFee: BigNumber
relayFeeGreaterThanAmount: boolean
relayFeeGreaterThanBalance: boolean
}

export const useRelay = (amount?: BigNumber, collateral?: Token): RelayServiceResponse => {
const { account, balances, networkId, relay } = useConnectedWeb3Context()

const [relayAddress, setRelayAddress] = useState('')
const [relayFee, setRelayFee] = useState(new BigNumber('0'))
const [relayFeeGreaterThanAmount, setRelayFeeGreaterThanAmount] = useState(false)
const [relayFeeGreaterThanBalance, setRelayFeeGreaterThanBalance] = useState(false)

const fetchRelayInfo = async (status?: Status) => {
const relayService = new RelayService()
const { address, fee } = await relayService.getInfo()
if (!status || status.active) {
setRelayAddress(address)

const feeBN = new BigNumber(fee)
setRelayFee(feeBN)
setRelayFeeGreaterThanBalance(feeBN.gt(balances.xDaiBalance))
}
}

useEffect(() => {
const status = { active: true }
if (account && relay) {
fetchRelayInfo(status)
} else {
setRelayAddress('')
setRelayFee(new BigNumber('0'))
setRelayFeeGreaterThanBalance(false)
}
return () => {
status.active = false
}
Comment on lines +49 to +51
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wondering just out of learning purposes why are you returning this status.active=false. And what does it do?

Copy link
Contributor Author

@hexyls hexyls Sep 2, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this prevents against race conditions when requesting data, e.g. imagine we start requesting data while the user is using the relay and the user switches accounts mid request - it is possible that the state could be updated with data we don't want once the relayService.getInfo() request finishes.

The line you commented will make sure status.active is set to false if the hook is updated, so in our scenario above once relayService.getInfo() is finished we check status.active, if it is true that means the hook has not updated since the request was made and it is safe to update the state.

// eslint-disable-next-line
}, [account, networkId, relay])

useEffect(() => {
if (account && relay && collateral && amount) {
const native = getNativeAsset(networkId, relay)
const feeGreaterThanAmount =
relay && amount && !amount.isZero() && relayFee.gt(amount) && collateral.address === native.address
setRelayFeeGreaterThanAmount(feeGreaterThanAmount)
} else {
setRelayFeeGreaterThanAmount(false)
}
}, [amount, collateral, account, relay, networkId, relayFee])

return { relayAddress, relayFee, relayFeeGreaterThanAmount, relayFeeGreaterThanBalance }
}
19 changes: 17 additions & 2 deletions app/src/pages/market_sections/market_buy_container.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,14 @@ import { STANDARD_DECIMALS } from '../../common/constants'
import { MarketBuy } from '../../components/market/market_buy/market_buy'
import { ScalarMarketBuy } from '../../components/market/market_buy/scalar_market_buy'
import { ConnectedWeb3Context, useConnectedWeb3Context } from '../../contexts'
import { useAsyncDerivedValue, useCollateralBalance, useContracts, useCpkAllowance, useCpkProxy } from '../../hooks'
import {
useAsyncDerivedValue,
useCollateralBalance,
useContracts,
useCpkAllowance,
useCpkProxy,
useRelay,
} from '../../hooks'
import { CPKService, MarketMakerService } from '../../services'
import { getNativeAsset, pseudoNativeAssetAddress } from '../../util/networks'
import { RemoteData } from '../../util/remote_data'
Expand Down Expand Up @@ -117,6 +124,8 @@ const MarketBuyContainer: React.FC<Props> = (props: Props) => {
context,
)

const { relayFeeGreaterThanAmount, relayFeeGreaterThanBalance } = useRelay(amount, collateral)

useEffect(() => {
setIsNegativeAmount((amount || Zero).lt(Zero))
}, [amount, collateral.decimals])
Expand Down Expand Up @@ -200,10 +209,14 @@ const MarketBuyContainer: React.FC<Props> = (props: Props) => {
? null
: maybeCollateralBalance === null
? null
: relayFeeGreaterThanBalance
? 'Insufficient Dai in your Omen Account'
: maybeCollateralBalance.isZero() && amount?.gt(maybeCollateralBalance)
? `Insufficient balance`
: amount?.gt(maybeCollateralBalance)
? `Value must be less than or equal to ${currentBalance} ${collateral.symbol}`
: relayFeeGreaterThanAmount
? 'Relay fee is greater than buy amount'
: null

const unlockCollateral = async () => {
Expand Down Expand Up @@ -244,7 +257,9 @@ const MarketBuyContainer: React.FC<Props> = (props: Props) => {
hasEnoughAllowance !== Ternary.True) ||
amountError !== null ||
isNegativeAmount ||
!isUpdated
!isUpdated ||
relayFeeGreaterThanAmount ||
relayFeeGreaterThanBalance

const shouldDisplayMaxButton = collateral.address !== pseudoNativeAssetAddress
const sharesTotal = bigNumberToString(tradedShares, collateral.decimals)
Expand Down
23 changes: 21 additions & 2 deletions app/src/pages/market_sections/market_pool_liquidity_container.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,14 @@ import { STANDARD_DECIMALS } from '../../common/constants'
import { MarketPoolLiquidity } from '../../components/market/market_pooling/market_pool_liquidity'
import { ScalarMarketPoolLiquidity } from '../../components/market/market_pooling/scalar_market_pool_liquidity'
import { useConnectedWeb3Context } from '../../contexts'
import { useCollateralBalance, useContracts, useCpkAllowance, useCpkProxy, useFundingBalance } from '../../hooks'
import {
useCollateralBalance,
useContracts,
useCpkAllowance,
useCpkProxy,
useFundingBalance,
useRelay,
} from '../../hooks'
import { getLogger } from '../../util/logger'
import { pseudoNativeAssetAddress } from '../../util/networks'
import { RemoteData } from '../../util/remote_data'
Expand Down Expand Up @@ -125,23 +132,34 @@ const MarketPoolLiquidityContainer: React.FC<Props> = (props: Props) => {
const walletBalance = bigNumberToString(collateralBalance, collateral.decimals, 5)
const sharesBalance = bigNumberToString(fundingBalance, collateral.decimals)

const { relayFeeGreaterThanAmount, relayFeeGreaterThanBalance } = useRelay(
amountToFund || new BigNumber(0),
collateral,
)

const { proxyIsUpToDate, updateProxy } = useCpkProxy()
const isUpdated = RemoteData.hasData(proxyIsUpToDate) ? proxyIsUpToDate.data : true

const collateralAmountError = isTransactionProcessing
? null
: maybeCollateralBalance === null
? null
: relayFeeGreaterThanBalance
? 'Insufficient Dai in your Omen Account'
: maybeCollateralBalance.isZero() && amountToFund?.gt(maybeCollateralBalance)
? `Insufficient balance`
: amountToFund?.gt(maybeCollateralBalance)
? `Value must be less than or equal to ${walletBalance} ${collateral.symbol}`
: relayFeeGreaterThanAmount
? 'Relay fee is greater than buy amount'
: null

const sharesAmountError = isTransactionProcessing
? null
: maybeFundingBalance === null
? null
: relayFeeGreaterThanBalance
? 'Insufficient Dai in your Omen Account'
: maybeFundingBalance.isZero() && amountToRemove?.gt(maybeFundingBalance)
? `Insufficient balance`
: amountToRemove?.gt(fundingBalance)
Expand All @@ -161,7 +179,8 @@ const MarketPoolLiquidityContainer: React.FC<Props> = (props: Props) => {
(!cpk?.isSafeApp && collateral.address !== pseudoNativeAssetAddress && hasEnoughAllowance !== Ternary.True) ||
collateralAmountError !== null ||
currentDate > resolutionDate ||
isNegativeAmountToFund
isNegativeAmountToFund ||
relayFeeGreaterThanAmount

const totalUserShareAmounts = calcRemoveFundingSendAmounts(
fundingBalance,
Expand Down
Loading