Skip to content

Commit

Permalink
fix(Trader): refetch data every 20 seconds (#11852)
Browse files Browse the repository at this point in the history
* fix(Trader): refetch data every 20 seconds

* fix: add bridge bunge refuel

* fix: validate custom gas settings

* fixup! fix: add bridge bunge refuel

* fix: run codegen

---------

Co-authored-by: swkatmask <[email protected]>
  • Loading branch information
swkatmask and swkatmask authored Oct 11, 2024
1 parent 7378bca commit fb8c8f6
Show file tree
Hide file tree
Showing 22 changed files with 426 additions and 163 deletions.
5 changes: 4 additions & 1 deletion packages/plugins/Trader/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
},
"dependencies": {
"@ethersproject/providers": "^5.7.2",
"@hookform/resolvers": "^3.6.0",
"@masknet/icons": "workspace:^",
"@masknet/plugin-infra": "workspace:^",
"@masknet/plugin-transak": "workspace:^",
Expand All @@ -36,11 +37,13 @@
"date-fns": "^2.30.0",
"fuse.js": "^7.0.0",
"immer": "^10.1.1",
"react-hook-form": "^7.53.0",
"react-router-dom": "^6.24.0",
"react-use": "^17.4.0",
"urlcat": "^3.1.0",
"use-subscription": "^1.8.0",
"web3-core": "1.10.4"
"web3-core": "1.10.4",
"zod": "^3.23.8"
},
"lingui": {
"catalogs": [
Expand Down
8 changes: 7 additions & 1 deletion packages/plugins/Trader/src/SiteAdaptor/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export const enum RoutePaths {
export const DEFAULT_SLIPPAGE = '0.5'

export const QUOTE_STALE_DURATION = 20_000
export const REFETCH_INTERVAL = 20_000

export const bridges = [
{
Expand All @@ -33,7 +34,7 @@ export const bridges = [
{
id: 315,
name: 'Across',
logoUrl: new URL('../assets/accross.svg', import.meta.url).href,
logoUrl: new URL('../assets/across.svg', import.meta.url).href,
},
{
id: 211,
Expand Down Expand Up @@ -77,4 +78,9 @@ export const bridges = [
logoUrl:
'https://static.okx.com/cdn/explorer/dex/logo/dex_Circle.png.png?x-oss-process=image/format,webp/ignore-error,1',
},
{
id: 476,
name: 'Bungee Refuel',
logoUrl: 'https://www.okx.com/cdn/web3/dex/logo/b53506a1-fc2b-439d-9696-8eaea55167ca.png',
},
]
2 changes: 1 addition & 1 deletion packages/plugins/Trader/src/SiteAdaptor/trader/Routes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { BridgeConfirm } from './views/BridgeConfirm.js'
import { BridgeQuoteRoute } from './views/BridgeQuoteRoute.js'
import { Confirm } from './views/Confirm.js'
import { HistoryView } from './views/History.js'
import { NetworkFee } from './views/NetworkFee.js'
import { NetworkFee } from './views/NetworkFee/index.js'
import { QuoteRoute } from './views/QuoteRoute.js'
import { SelectLiquidity } from './views/SelectLiquidity.js'
import { Slippage } from './views/Slippage.js'
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { OKX } from '@masknet/web3-providers'
import type { GetBridgeQuoteOptions } from '@masknet/web3-providers/types'
import { useQuery } from '@tanstack/react-query'
import { QUOTE_STALE_DURATION } from '../../constants.js'
import { QUOTE_STALE_DURATION, REFETCH_INTERVAL } from '../../constants.js'

export function useBridgeQuotes(options: Partial<GetBridgeQuoteOptions>, enabled = true) {
const valid =
Expand All @@ -19,5 +19,6 @@ export function useBridgeQuotes(options: Partial<GetBridgeQuoteOptions>, enabled
queryKey: ['okx-bridge', 'get-quotes', options],
queryFn: () => OKX.getBridgeQuote(options as GetBridgeQuoteOptions),
staleTime: QUOTE_STALE_DURATION,
refetchInterval: REFETCH_INTERVAL,
})
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { OKX } from '@masknet/web3-providers'
import type { ChainId } from '@masknet/web3-shared-evm'
import { skipToken, useQuery } from '@tanstack/react-query'
import { REFETCH_INTERVAL } from '../../constants.js'

export function useLiquidityResources(chainId: ChainId, enabled = true) {
return useQuery({
Expand All @@ -13,5 +14,6 @@ export function useLiquidityResources(chainId: ChainId, enabled = true) {
return res?.code === 0 ? res.data : undefined
}
: skipToken,
refetchInterval: REFETCH_INTERVAL,
})
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { OKX } from '@masknet/web3-providers'
import type { GetQuotesOptions } from '@masknet/web3-providers/types'
import { useQuery } from '@tanstack/react-query'
import { QUOTE_STALE_DURATION } from '../../constants.js'
import { isGreaterThan } from '@masknet/web3-shared-base'
import { useQuery } from '@tanstack/react-query'
import { QUOTE_STALE_DURATION, REFETCH_INTERVAL } from '../../constants.js'

export function useQuotes(options: Partial<GetQuotesOptions>, enabled = true) {
const valid =
Expand All @@ -12,5 +12,6 @@ export function useQuotes(options: Partial<GetQuotesOptions>, enabled = true) {
queryKey: ['okx-swap', 'get-quotes', options],
queryFn: () => OKX.getQuotes(options as GetQuotesOptions),
staleTime: QUOTE_STALE_DURATION,
refetchInterval: REFETCH_INTERVAL,
})
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { zodResolver } from '@hookform/resolvers/zod'
import { t, Trans } from '@lingui/macro'
import { Icons } from '@masknet/icons'
import { ProgressiveText } from '@masknet/shared'
Expand All @@ -14,11 +15,16 @@ import {
} from '@masknet/web3-shared-evm'
import { Box, Button, Typography } from '@mui/material'
import { BigNumber } from 'bignumber.js'
import { isEmpty } from 'lodash-es'
import { memo, useMemo, useRef, useState } from 'react'
import { Controller, useForm } from 'react-hook-form'
import { useNavigate } from 'react-router-dom'
import { GasCost } from '../../components/GasCost.js'
import { Warning } from '../../components/Warning.js'
import { useGasManagement, useTrade } from '../contexts/index.js'
import { type z as zod } from 'zod'
import { GasCost } from '../../../components/GasCost.js'
import { Warning } from '../../../components/Warning.js'
import { useGasManagement } from '../../contexts/GasManager.js'
import { useTrade } from '../../contexts/TradeProvider.js'
import { useSchema } from './schema.js'

const useStyles = makeStyles<void, 'active' | 'gasWarning' | 'gasOk'>()((theme, _, refs) => ({
container: {
Expand Down Expand Up @@ -114,6 +120,11 @@ const useStyles = makeStyles<void, 'active' | 'gasWarning' | 'gasOk'>()((theme,
color: theme.palette.maskColor.second,
marginLeft: theme.spacing(1.5),
},
error: {
color: theme.palette.maskColor.danger,
fontSize: 13,
lineHeight: '18px',
},
}))

function formatTimeCost(seconds: number | undefined) {
Expand All @@ -124,8 +135,8 @@ function formatTimeCost(seconds: number | undefined) {
}

const MIN_BASE_FEE = '0.01'
const gweiToWei = (gwei: BigNumber.Value | undefined) => formatGweiToWei(gwei ?? '0').toFixed()
const weiToGwei = (wei: BigNumber.Value | undefined) => formatWeiToGwei(wei ?? '0').toFixed()
const gweiToWei = (gwei: BigNumber.Value | undefined) => (gwei ? formatGweiToWei(gwei).toFixed() : undefined)
const weiToGwei = (wei: BigNumber.Value | undefined) => (wei ? formatWeiToGwei(wei).toFixed() : undefined)
export const NetworkFee = memo(function NetworkFee() {
const { classes, cx, theme } = useStyles()
const { chainId } = useTrade()
Expand All @@ -152,9 +163,10 @@ export const NetworkFee = memo(function NetworkFee() {
const [priorityFee = defaultPriorityFee, setPriorityFee] = useState<string>()
const [gasPrice = defaultGasPrice, setGasPrice] = useState<string>()
const customFeePrice = useMemo(
() => (isSupport1559 ? plus(baseFee ?? '0', priorityFee ?? '0') : new BigNumber(gasPrice ?? '0')),
() => (isSupport1559 ? plus(baseFee || '0', priorityFee || '0') : new BigNumber(gasPrice ?? '0')),
[isSupport1559, baseFee, priorityFee, gasPrice],
)

const isTooHigh = isGreaterThan(customFeePrice, multipliedBy(gasOptions?.fast.suggestedMaxFeePerGas ?? '0', 2))

const customBoxRef = useRef<HTMLDivElement>(null)
Expand Down Expand Up @@ -192,6 +204,20 @@ export const NetworkFee = memo(function NetworkFee() {
}
}, [gasOptions, customFeePrice])

const schema = useSchema(isSupport1559)

const {
control,
setValue,
formState: { errors },
} = useForm<zod.infer<typeof schema>>({
mode: 'onChange',
resolver: zodResolver(schema),
context: {
gasOptions,
},
})

return (
<div className={classes.container}>
<div
Expand Down Expand Up @@ -324,7 +350,7 @@ export const NetworkFee = memo(function NetworkFee() {
<Trans>Custom</Trans>
</Typography>
<Typography className={classes.boxSubtitle} variant="h3">
{formatWeiToGwei(customFeePrice ?? '0').toFixed()} Gwei
{customFeePrice ? formatWeiToGwei(customFeePrice).toFixed() : '--'} Gwei
</Typography>
</div>
<div className={classes.boxTail}>
Expand All @@ -350,29 +376,72 @@ export const NetworkFee = memo(function NetworkFee() {
<Trans>Base fee required: {MIN_BASE_FEE} Gwei</Trans>
</Typography>
</Box>
<MaskTextField
placeholder="0.1-50"
type="number"
value={weiToGwei(baseFee)}
onChange={(e) => {
setBaseFee(gweiToWei(e.target.value))
}}
InputProps={{
endAdornment: <Typography className={classes.gwei}>Gwei</Typography>,
<Controller
control={control}
name="baseFee"
render={({ field, fieldState }) => {
return (
<>
<MaskTextField
{...field}
placeholder="0.1-50"
type="number"
value={weiToGwei(baseFee)}
onChange={(e) => {
const value = gweiToWei(e.target.value) || ''
setBaseFee(value)
setValue('baseFee', value)
field.onChange(e)
}}
InputProps={{
endAdornment: (
<Typography className={classes.gwei}>Gwei</Typography>
),
}}
/>
{fieldState.error ?
<Typography className={classes.error}>
{fieldState.error.message}
</Typography>
: null}
</>
)
}}
/>
<Typography className={classes.fieldName}>
<Trans>Priority fee</Trans>
</Typography>
<MaskTextField
placeholder="0.1-50"
type="number"
value={weiToGwei(priorityFee)}
onChange={(e) => {
setPriorityFee(gweiToWei(e.target.value))
}}
InputProps={{
endAdornment: <Typography className={classes.gwei}>Gwei</Typography>,

<Controller
control={control}
name="priorityFee"
render={({ field, fieldState }) => {
return (
<>
<MaskTextField
{...field}
placeholder="0.1-50"
type="number"
value={weiToGwei(priorityFee)}
onChange={(e) => {
const value = gweiToWei(e.target.value) || ''
setPriorityFee(value)
setValue('priorityFee', value)
field.onChange(e)
}}
InputProps={{
endAdornment: (
<Typography className={classes.gwei}>Gwei</Typography>
),
}}
/>
{fieldState.error ?
<Typography className={classes.error}>
{fieldState.error.message}
</Typography>
: null}
</>
)
}}
/>
</>
Expand All @@ -382,15 +451,36 @@ export const NetworkFee = memo(function NetworkFee() {
<Trans>Gas Price</Trans>
</Typography>
</Box>
<MaskTextField
placeholder="0.1-50"
type="number"
value={weiToGwei(gasPrice)}
onChange={(e) => {
setGasPrice(gweiToWei(e.target.value || '0'))
}}
InputProps={{
endAdornment: <Typography className={classes.gwei}>Gwei</Typography>,
<Controller
control={control}
name="gasPrice"
render={({ field, fieldState }) => {
return (
<>
<MaskTextField
{...field}
placeholder="0.1-50"
type="number"
value={weiToGwei(gasPrice)}
onChange={(e) => {
const value = gweiToWei(e.target.value) || ''
setGasPrice(value)
setValue('gasPrice', value)
field.onChange(e)
}}
InputProps={{
endAdornment: (
<Typography className={classes.gwei}>Gwei</Typography>
),
}}
/>
{fieldState.error ?
<Typography className={classes.error}>
{fieldState.error.message}
</Typography>
: null}
</>
)
}}
/>
</>
Expand All @@ -407,7 +497,7 @@ export const NetworkFee = memo(function NetworkFee() {
<Button
variant="roundedContained"
fullWidth
disabled={disabled}
disabled={disabled || !isEmpty(errors)}
onClick={() => {
if (isSupport1559) {
const maxFeePerGas = plus(baseFee ?? '0', priorityFee ?? '0').toFixed()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { t } from '@lingui/macro'
import { isGreaterThan, isLessThan } from '@masknet/web3-shared-base'
import { useMemo } from 'react'
import { z as zod } from 'zod'

const gtZero = (v: string) => isGreaterThan(v, 0)
export function useSchema(supported1559: boolean, minGasLimit = 21000) {
const gasLimit = zod
.string()
.min(1, t`Enter gas limit`)
.refine(
(gasLimit) => isGreaterThan(gasLimit, minGasLimit) && isLessThan(gasLimit, 150_000),
t`Gas limit should be between ${minGasLimit} and 15.00M`,
)
return useMemo(() => {
if (supported1559) {
return zod.object({
gasLimit,
priorityFee: zod.string().refine(gtZero, t`Max base fee should be greater than 0`),
baseFee: zod.string().refine(gtZero, t`Max base fee should be greater than 0`),
})
}
return zod.object({
gasLimit,
gasPrice: zod.string().refine(gtZero, t`Gas price should be greater than 0`),
})
}, [supported1559, minGasLimit])
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import {
} from '@masknet/web3-shared-base'
import { isNativeTokenAddress, type ChainId } from '@masknet/web3-shared-evm'
import { Box, Button, Typography } from '@mui/material'
import { BigNumber } from 'bignumber.js'
import { useMemo, useState } from 'react'
import { useNavigate } from 'react-router-dom'
import urlcat from 'urlcat'
Expand Down Expand Up @@ -256,6 +257,7 @@ export function TradeView() {
)
if (picked) {
setInputAmount('')
setIsMax(false)
setFromToken(picked)
if (toChainId !== picked.chainId && isSwap) setToToken(undefined)
}
Expand Down Expand Up @@ -296,7 +298,9 @@ export function TradeView() {
if (!fromToken?.address) return
const isNative = isNativeTokenAddress(fromToken.address)
const balance =
isNative ? minus(fromTokenBalance, gasFee) : fromTokenBalance
isNative ?
BigNumber.max(minus(fromTokenBalance, gasFee), 0)
: fromTokenBalance
setInputAmount(trimZero(leftShift(balance, fromToken.decimals).toFixed()))
setIsMax(true)
}}>
Expand Down
Loading

0 comments on commit fb8c8f6

Please sign in to comment.