mirror of
https://github.com/oceanprotocol/market.git
synced 2024-12-02 05:57:29 +01:00
Merge branch 'feature/v4-c2d' into 'fix/compute-jobs'
This commit is contained in:
commit
2dc12a2542
@ -56,7 +56,13 @@ function PoolProvider({ children }: { children: ReactNode }): ReactElement {
|
||||
// const [fetchInterval, setFetchInterval] = useState<NodeJS.Timeout>()
|
||||
|
||||
const fetchAllData = useCallback(async () => {
|
||||
if (!asset?.chainId || !asset?.accessDetails?.addressOrId || !owner) return
|
||||
if (
|
||||
!accountId ||
|
||||
!asset?.chainId ||
|
||||
!asset?.accessDetails?.addressOrId ||
|
||||
!owner
|
||||
)
|
||||
return
|
||||
|
||||
const response = await getPoolData(
|
||||
asset.chainId,
|
||||
@ -64,6 +70,7 @@ function PoolProvider({ children }: { children: ReactNode }): ReactElement {
|
||||
owner,
|
||||
accountId || ''
|
||||
)
|
||||
|
||||
if (!response) return
|
||||
|
||||
setPoolData(response.poolData)
|
||||
|
@ -1 +1 @@
|
||||
export const MAX_DECIMALS = 5
|
||||
export const MAX_DECIMALS = 6
|
||||
|
@ -65,7 +65,7 @@ export default function FilesInput(props: InputProps): ReactElement {
|
||||
|
||||
return (
|
||||
<>
|
||||
{field.value[0].valid !== undefined ? (
|
||||
{field?.value && field?.value[0]?.valid !== undefined ? (
|
||||
<FileInfo file={field.value[0]} handleClose={handleClose} />
|
||||
) : (
|
||||
<UrlInput
|
||||
|
@ -23,7 +23,7 @@ const txHistoryQueryByPool = gql`
|
||||
poolTransactions(
|
||||
orderBy: timestamp
|
||||
orderDirection: desc
|
||||
where: { pool: $pool }
|
||||
where: { pool: $pool, user: $user }
|
||||
first: 1000
|
||||
) {
|
||||
baseToken {
|
||||
@ -40,6 +40,9 @@ const txHistoryQueryByPool = gql`
|
||||
tx
|
||||
timestamp
|
||||
pool {
|
||||
datatoken {
|
||||
id
|
||||
}
|
||||
id
|
||||
}
|
||||
}
|
||||
@ -67,6 +70,9 @@ const txHistoryQuery = gql`
|
||||
tx
|
||||
timestamp
|
||||
pool {
|
||||
datatoken {
|
||||
id
|
||||
}
|
||||
id
|
||||
}
|
||||
}
|
||||
@ -124,7 +130,7 @@ export default function PoolTransactions({
|
||||
accountId
|
||||
}: {
|
||||
poolAddress?: string
|
||||
poolChainId?: number[]
|
||||
poolChainId?: number
|
||||
minimal?: boolean
|
||||
accountId: string
|
||||
}): ReactElement {
|
||||
@ -146,7 +152,7 @@ export default function PoolTransactions({
|
||||
const result = await fetchDataForMultipleChains(
|
||||
poolAddress ? txHistoryQueryByPool : txHistoryQuery,
|
||||
variables,
|
||||
poolAddress ? poolChainId : chainIds
|
||||
poolAddress ? [poolChainId] : chainIds
|
||||
)
|
||||
|
||||
for (let i = 0; i < result.length; i++) {
|
||||
@ -166,24 +172,24 @@ export default function PoolTransactions({
|
||||
return
|
||||
}
|
||||
const poolTransactions: PoolTransaction[] = []
|
||||
const dtList: string[] = []
|
||||
|
||||
for (let i = 0; i < data.length; i++) {
|
||||
dtList.push(data[i]?.datatoken?.address)
|
||||
}
|
||||
let dtList: string[] = []
|
||||
|
||||
dtList = [...new Set(data.map((item) => item.pool.datatoken.id))]
|
||||
if (dtList.length === 0) {
|
||||
setTransactions([])
|
||||
setIsLoading(false)
|
||||
return
|
||||
}
|
||||
const ddoList = await getAssetsFromDtList(dtList, chainIds, cancelToken)
|
||||
|
||||
const ddoList = !minimal
|
||||
? await getAssetsFromDtList(dtList, chainIds, cancelToken)
|
||||
: []
|
||||
for (let i = 0; i < data.length; i++) {
|
||||
poolTransactions.push({
|
||||
...data[i],
|
||||
networkId: getAsset(ddoList, data[i].datatoken.address).chainId,
|
||||
asset: getAsset(ddoList, data[i].datatoken.address)
|
||||
networkId: !minimal
|
||||
? getAsset(ddoList, data[i].pool.datatoken.id).chainId
|
||||
: poolChainId,
|
||||
asset: !minimal ? getAsset(ddoList, data[i].pool.datatoken.id) : null
|
||||
})
|
||||
}
|
||||
const sortedTransactions = poolTransactions.sort(
|
||||
|
@ -26,6 +26,7 @@
|
||||
|
||||
.button:last-child {
|
||||
margin-right: 0;
|
||||
min-width: auto;
|
||||
}
|
||||
|
||||
.button:hover,
|
||||
@ -33,8 +34,8 @@
|
||||
color: var(--brand-white);
|
||||
background: var(--brand-grey-light);
|
||||
text-decoration: none;
|
||||
transform: translate3d(0, -0.05rem, 0);
|
||||
box-shadow: 0 12px 30px 0 rgba(0, 0, 0, 0.1);
|
||||
transform: translate3d(0, -0.05rem, 0);
|
||||
}
|
||||
|
||||
.button:active {
|
||||
|
@ -10,7 +10,7 @@ import { useAsset } from '@context/Asset'
|
||||
import { useWeb3 } from '@context/Web3'
|
||||
import content from '../../../../../content/pages/startComputeDataset.json'
|
||||
import { Asset } from '@oceanprotocol/lib'
|
||||
import { AccessDetails } from 'src/@types/Price'
|
||||
import { AccessDetails, OrderPriceAndFees } from 'src/@types/Price'
|
||||
import {
|
||||
getAccessDetailsForAssets,
|
||||
getAccessDetails
|
||||
@ -40,7 +40,9 @@ export default function FormStartCompute({
|
||||
selectedComputeAssetTimeout,
|
||||
stepText,
|
||||
isConsumable,
|
||||
consumableFeedback
|
||||
consumableFeedback,
|
||||
datasetOrderPriceAndFees,
|
||||
algoOrderPriceAndFees
|
||||
}: {
|
||||
algorithms: AssetSelectionAsset[]
|
||||
ddoListAlgorithms: Asset[]
|
||||
@ -65,11 +67,19 @@ export default function FormStartCompute({
|
||||
stepText: string
|
||||
isConsumable: boolean
|
||||
consumableFeedback: string
|
||||
datasetOrderPriceAndFees?: OrderPriceAndFees
|
||||
algoOrderPriceAndFees?: OrderPriceAndFees
|
||||
}): ReactElement {
|
||||
const { isValid, values }: FormikContextType<{ algorithm: string }> =
|
||||
useFormikContext()
|
||||
const { asset, isAssetNetwork } = useAsset()
|
||||
const [totalPrice, setTotalPrice] = useState(asset?.accessDetails?.price)
|
||||
const [datasetOrderPrice, setDatasetOrderPrice] = useState(
|
||||
asset?.accessDetails?.price
|
||||
)
|
||||
const [algoOrderPrice, setAlgoOrderPrice] = useState(
|
||||
selectedAlgorithmAsset?.accessDetails?.price
|
||||
)
|
||||
const [isBalanceSufficient, setIsBalanceSufficient] = useState<boolean>(false)
|
||||
const { accountId, balance } = useWeb3()
|
||||
|
||||
@ -106,12 +116,24 @@ export default function FormStartCompute({
|
||||
useEffect(() => {
|
||||
if (!asset?.accessDetails || !selectedAlgorithmAsset?.accessDetails) return
|
||||
|
||||
setDatasetOrderPrice(
|
||||
datasetOrderPriceAndFees?.price || asset.accessDetails.price
|
||||
)
|
||||
setAlgoOrderPrice(
|
||||
algoOrderPriceAndFees?.price ||
|
||||
selectedAlgorithmAsset?.accessDetails.price
|
||||
)
|
||||
const priceDataset =
|
||||
hasPreviousOrder || hasDatatoken ? 0 : Number(asset.accessDetails.price)
|
||||
hasPreviousOrder || hasDatatoken
|
||||
? 0
|
||||
: Number(datasetOrderPriceAndFees?.price || asset.accessDetails.price)
|
||||
const priceAlgo =
|
||||
hasPreviousOrderSelectedComputeAsset || hasDatatokenSelectedComputeAsset
|
||||
? 0
|
||||
: Number(selectedAlgorithmAsset?.accessDetails.price)
|
||||
: Number(
|
||||
algoOrderPriceAndFees?.price ||
|
||||
selectedAlgorithmAsset?.accessDetails.price
|
||||
)
|
||||
|
||||
setTotalPrice((priceDataset + priceAlgo).toString())
|
||||
}, [
|
||||
@ -120,7 +142,9 @@ export default function FormStartCompute({
|
||||
hasPreviousOrder,
|
||||
hasDatatoken,
|
||||
hasPreviousOrderSelectedComputeAsset,
|
||||
hasDatatokenSelectedComputeAsset
|
||||
hasDatatokenSelectedComputeAsset,
|
||||
datasetOrderPriceAndFees,
|
||||
algoOrderPriceAndFees
|
||||
])
|
||||
|
||||
useEffect(() => {
|
||||
@ -153,6 +177,8 @@ export default function FormStartCompute({
|
||||
algorithmConsumeDetails={selectedAlgorithmAsset?.accessDetails}
|
||||
symbol={oceanSymbol}
|
||||
totalPrice={Number.parseFloat(totalPrice)}
|
||||
datasetOrderPrice={datasetOrderPrice}
|
||||
algoOrderPrice={algoOrderPrice}
|
||||
/>
|
||||
|
||||
<ButtonBuy
|
||||
|
@ -15,6 +15,8 @@ interface PriceOutputProps {
|
||||
hasDatatokenSelectedComputeAsset: boolean
|
||||
algorithmConsumeDetails: AccessDetails
|
||||
selectedComputeAssetTimeout: string
|
||||
datasetOrderPrice?: number
|
||||
algoOrderPrice?: number
|
||||
}
|
||||
|
||||
function Row({
|
||||
@ -62,7 +64,9 @@ export default function PriceOutput({
|
||||
hasPreviousOrderSelectedComputeAsset,
|
||||
hasDatatokenSelectedComputeAsset,
|
||||
algorithmConsumeDetails,
|
||||
selectedComputeAssetTimeout
|
||||
selectedComputeAssetTimeout,
|
||||
datasetOrderPrice,
|
||||
algoOrderPrice
|
||||
}: PriceOutputProps): ReactElement {
|
||||
const { asset } = useAsset()
|
||||
|
||||
@ -76,14 +80,20 @@ export default function PriceOutput({
|
||||
<Row
|
||||
hasPreviousOrder={hasPreviousOrder}
|
||||
hasDatatoken={hasDatatoken}
|
||||
price={Number.parseFloat(asset?.accessDetails?.price)}
|
||||
price={
|
||||
datasetOrderPrice ||
|
||||
Number.parseFloat(asset?.accessDetails?.price)
|
||||
}
|
||||
timeout={assetTimeout}
|
||||
symbol={symbol}
|
||||
/>
|
||||
<Row
|
||||
hasPreviousOrder={hasPreviousOrderSelectedComputeAsset}
|
||||
hasDatatoken={hasDatatokenSelectedComputeAsset}
|
||||
price={Number.parseFloat(algorithmConsumeDetails?.price)}
|
||||
price={
|
||||
algoOrderPrice ||
|
||||
Number.parseFloat(algorithmConsumeDetails?.price)
|
||||
}
|
||||
timeout={selectedComputeAssetTimeout}
|
||||
symbol={symbol}
|
||||
sign="+"
|
||||
|
@ -83,13 +83,21 @@ export default function Compute({
|
||||
const [isConsumablePrice, setIsConsumablePrice] = useState(true)
|
||||
const [isAlgoConsumablePrice, setIsAlgoConsumablePrice] = useState(true)
|
||||
const [computeStatusText, setComputeStatusText] = useState('')
|
||||
const [datasetOrderPriceAndFees, setDatasetOrderPriceAndFees] =
|
||||
useState<OrderPriceAndFees>()
|
||||
const [isRequestingDataseOrderPrice, setIsRequestingDataseOrderPrice] =
|
||||
useState(false)
|
||||
const [algoOrderPriceAndFees, setAlgoOrderPriceAndFees] =
|
||||
useState<OrderPriceAndFees>()
|
||||
const [isRequestingAlgoOrderPrice, setIsRequestingAlgoOrderPrice] =
|
||||
useState(false)
|
||||
const isComputeButtonDisabled =
|
||||
isJobStarting === true ||
|
||||
file === null ||
|
||||
(!validOrderTx && !hasDatatoken && !isConsumablePrice) ||
|
||||
(!validAlgorithmOrderTx && !hasAlgoAssetDatatoken && !isAlgoConsumablePrice)
|
||||
|
||||
async function checkAssetDTBalance(asset: DDO) {
|
||||
async function checkAssetDTBalance(asset: DDO): Promise<boolean> {
|
||||
if (!asset?.services[0].datatokenAddress) return
|
||||
const datatokenInstance = new Datatoken(web3)
|
||||
const dtBalance = await datatokenInstance.balance(
|
||||
@ -97,7 +105,9 @@ export default function Compute({
|
||||
accountId
|
||||
)
|
||||
setAlgorithmDTBalance(new Decimal(dtBalance).toString())
|
||||
setHasAlgoAssetDatatoken(Number(dtBalance) >= 1)
|
||||
const hasAlgoDt = Number(dtBalance) >= 1
|
||||
setHasAlgoAssetDatatoken(hasAlgoDt)
|
||||
return hasAlgoDt
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
@ -106,16 +116,56 @@ export default function Compute({
|
||||
setIsConsumablePrice(asset?.accessDetails?.isPurchasable)
|
||||
setIsOwned(asset?.accessDetails?.isOwned)
|
||||
setValidOrderTx(asset?.accessDetails?.validOrderTx)
|
||||
|
||||
async function initDatasetPriceAndFees() {
|
||||
if (
|
||||
asset?.accessDetails?.addressOrId === ZERO_ADDRESS ||
|
||||
asset?.accessDetails?.type === 'free'
|
||||
)
|
||||
return
|
||||
|
||||
setIsRequestingDataseOrderPrice(true)
|
||||
setComputeStatusText('Calculating price including fees.')
|
||||
const orderPriceAndFees = await getOrderPriceAndFees(asset, accountId)
|
||||
setDatasetOrderPriceAndFees(orderPriceAndFees)
|
||||
setIsRequestingDataseOrderPrice(false)
|
||||
}
|
||||
|
||||
initDatasetPriceAndFees()
|
||||
}, [asset?.accessDetails])
|
||||
|
||||
useEffect(() => {
|
||||
if (!selectedAlgorithmAsset?.accessDetails || !accountId) return
|
||||
checkAssetDTBalance(selectedAlgorithmAsset)
|
||||
|
||||
setIsConsumablePrice(selectedAlgorithmAsset?.accessDetails?.isPurchasable)
|
||||
setIsAlgorithmOwned(selectedAlgorithmAsset?.accessDetails?.isOwned)
|
||||
setValidAlgorithmOrderTx(
|
||||
selectedAlgorithmAsset?.accessDetails?.validOrderTx
|
||||
)
|
||||
|
||||
async function initAlgoPriceAndFees() {
|
||||
if (
|
||||
selectedAlgorithmAsset?.accessDetails?.addressOrId === ZERO_ADDRESS ||
|
||||
selectedAlgorithmAsset?.accessDetails?.type === 'free'
|
||||
)
|
||||
return
|
||||
|
||||
setIsRequestingAlgoOrderPrice(true)
|
||||
setComputeStatusText('Calculating price including fees.')
|
||||
const orderPriceAndFees = await getOrderPriceAndFees(
|
||||
selectedAlgorithmAsset,
|
||||
accountId
|
||||
)
|
||||
setAlgoOrderPriceAndFees(orderPriceAndFees)
|
||||
setIsRequestingAlgoOrderPrice(false)
|
||||
}
|
||||
|
||||
async function initSelectedAlgo() {
|
||||
const hasAlgoDt = await checkAssetDTBalance(selectedAlgorithmAsset)
|
||||
!hasAlgoDt && (await initAlgoPriceAndFees())
|
||||
}
|
||||
|
||||
initSelectedAlgo()
|
||||
}, [selectedAlgorithmAsset])
|
||||
|
||||
useEffect(() => {
|
||||
@ -406,7 +456,11 @@ export default function Compute({
|
||||
ddoListAlgorithms={ddoAlgorithmList}
|
||||
selectedAlgorithmAsset={selectedAlgorithmAsset}
|
||||
setSelectedAlgorithm={setSelectedAlgorithmAsset}
|
||||
isLoading={isJobStarting}
|
||||
isLoading={
|
||||
isJobStarting ||
|
||||
isRequestingDataseOrderPrice ||
|
||||
isRequestingAlgoOrderPrice
|
||||
}
|
||||
isComputeButtonDisabled={isComputeButtonDisabled}
|
||||
hasPreviousOrder={validOrderTx !== undefined}
|
||||
hasDatatoken={hasDatatoken}
|
||||
@ -436,6 +490,8 @@ export default function Compute({
|
||||
stepText={computeStatusText}
|
||||
isConsumable={isConsumable}
|
||||
consumableFeedback={consumableFeedback}
|
||||
datasetOrderPriceAndFees={datasetOrderPriceAndFees}
|
||||
algoOrderPriceAndFees={algoOrderPriceAndFees}
|
||||
/>
|
||||
</Formik>
|
||||
)}
|
||||
|
@ -25,7 +25,7 @@ export function getOptions(
|
||||
borderColor: isDarkMode ? `#41474e` : `#e2e2e2`,
|
||||
callbacks: {
|
||||
label: (tooltipItem: TooltipItem<any>) =>
|
||||
`${formatPrice(`${tooltipItem.formattedValue}`, locale)} ${symbol}`
|
||||
`${tooltipItem.formattedValue} ${symbol}`
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -31,13 +31,17 @@
|
||||
|
||||
.maximum {
|
||||
position: absolute;
|
||||
right: -2rem;
|
||||
bottom: 2rem;
|
||||
right: 0;
|
||||
bottom: 2.5rem;
|
||||
font-size: var(--font-size-mini);
|
||||
min-width: 5rem;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.maximum:hover {
|
||||
transform: none;
|
||||
}
|
||||
|
||||
.toggle {
|
||||
margin-top: calc(var(--spacer) / 2);
|
||||
margin-bottom: 0;
|
||||
|
@ -67,11 +67,16 @@ export default function Remove({
|
||||
minOceanAmount
|
||||
)
|
||||
setTxId(result?.transactionHash)
|
||||
// fetch new data
|
||||
fetchAllData()
|
||||
} catch (error) {
|
||||
LoggerInstance.error(error.message)
|
||||
toast.error(error.message)
|
||||
} finally {
|
||||
// reset slider after transaction
|
||||
setAmountPercent('0')
|
||||
setAmountOcean('0')
|
||||
setMinOceanAmount('0')
|
||||
setIsLoading(false)
|
||||
}
|
||||
}
|
||||
@ -80,8 +85,10 @@ export default function Remove({
|
||||
if (!accountId || !poolTokens) return
|
||||
|
||||
async function getMax() {
|
||||
const poolTokensAmount =
|
||||
!poolTokens || poolTokens === '0' ? '1' : poolTokens
|
||||
const maxTokensToRemoveFromPool = calcMaxExactOut(totalPoolTokens)
|
||||
const poolTokensDecimal = new Decimal(poolTokens)
|
||||
const poolTokensDecimal = new Decimal(poolTokensAmount)
|
||||
const maxTokensToRemoveForUser = maxTokensToRemoveFromPool.greaterThan(
|
||||
poolTokensDecimal
|
||||
)
|
||||
@ -105,6 +112,7 @@ export default function Remove({
|
||||
tokenOutAddress,
|
||||
newAmountPoolShares
|
||||
)
|
||||
|
||||
setAmountOcean(newAmountOcean)
|
||||
}, 150)
|
||||
)
|
||||
@ -116,6 +124,11 @@ export default function Remove({
|
||||
}, [amountPoolShares, accountId, poolTokens, poolAddress, totalPoolTokens])
|
||||
|
||||
useEffect(() => {
|
||||
if (!amountOcean || amountPercent === '0') {
|
||||
setMinOceanAmount('0')
|
||||
return
|
||||
}
|
||||
|
||||
const minOceanAmount = new Decimal(amountOcean)
|
||||
.mul(new Decimal(100).minus(new Decimal(slippage)))
|
||||
.dividedBy(100)
|
||||
@ -220,7 +233,12 @@ export default function Remove({
|
||||
actionName={content.pool.remove.action}
|
||||
action={handleRemoveLiquidity}
|
||||
successMessage="Successfully removed liquidity."
|
||||
isDisabled={!isAssetNetwork || amountOcean === '0'}
|
||||
isDisabled={
|
||||
!isAssetNetwork ||
|
||||
amountPercent === '0' ||
|
||||
amountOcean === '0' ||
|
||||
poolTokens === '0'
|
||||
}
|
||||
txId={txId}
|
||||
tokenAddress={tokenOutAddress}
|
||||
tokenSymbol={tokenOutSymbol}
|
||||
|
@ -208,7 +208,7 @@ export default function Pool(): ReactElement {
|
||||
<PoolTransactions
|
||||
accountId={accountId}
|
||||
poolAddress={asset?.accessDetails?.addressOrId}
|
||||
poolChainId={[asset?.chainId]}
|
||||
poolChainId={asset?.chainId}
|
||||
minimal
|
||||
/>
|
||||
</AssetActionHistoryTable>
|
||||
|
@ -34,7 +34,13 @@ export default function Price({
|
||||
<>
|
||||
<div className={styles.grid}>
|
||||
<div className={styles.form}>
|
||||
<Input type="number" prefix="OCEAN" {...field} />
|
||||
<Input
|
||||
type="number"
|
||||
min="1"
|
||||
placeholder="0"
|
||||
prefix="OCEAN"
|
||||
{...field}
|
||||
/>
|
||||
<Error meta={meta} />
|
||||
</div>
|
||||
<div className={styles.datatoken}>
|
||||
|
@ -1,8 +1,10 @@
|
||||
import { MAX_DECIMALS } from '@utils/constants'
|
||||
import * as Yup from 'yup'
|
||||
|
||||
// TODO: conditional validation
|
||||
// e.g. when algo is selected, Docker image is required
|
||||
// hint, hint: https://github.com/jquense/yup#mixedwhenkeys-string--arraystring-builder-object--value-schema-schema-schema
|
||||
|
||||
const validationMetadata = {
|
||||
type: Yup.string()
|
||||
.matches(/dataset|algorithm/g, { excludeEmptyString: true })
|
||||
@ -54,25 +56,53 @@ const validationService = {
|
||||
})
|
||||
}
|
||||
|
||||
const maxDecimalsValidation = new RegExp(
|
||||
'^\\d+(\\.\\d{1,' + MAX_DECIMALS + '})?$'
|
||||
)
|
||||
|
||||
const validationPricing = {
|
||||
type: Yup.string()
|
||||
.matches(/fixed|dynamic|free/g, { excludeEmptyString: true })
|
||||
.required('Required'),
|
||||
// https://github.com/jquense/yup#mixedwhenkeys-string--arraystring-builder-object--value-schema-schema-schema
|
||||
|
||||
price: Yup.number()
|
||||
.min(1, (param: { min: number }) => `Must be more or equal to ${param.min}`)
|
||||
.max(
|
||||
1000000,
|
||||
(param: { max: number }) => `Must be less than or equal to ${param.max}`
|
||||
)
|
||||
.test(
|
||||
'maxDigitsAfterDecimal',
|
||||
`Must have maximum ${MAX_DECIMALS} decimal digits`,
|
||||
(param) => maxDecimalsValidation.test(param?.toString())
|
||||
)
|
||||
.required('Required'),
|
||||
amountDataToken: Yup.number()
|
||||
.min(50, (param) => `Must be more or equal to ${param.min}`)
|
||||
.required('Required'),
|
||||
amountOcean: Yup.number()
|
||||
.min(50, (param) => `Must be more or equal to ${param.min}`)
|
||||
.max(
|
||||
1000000,
|
||||
(param: { max: number }) => `Must be less than or equal to ${param.max}`
|
||||
)
|
||||
.test(
|
||||
'maxDigitsAfterDecimal',
|
||||
`Must have maximum ${MAX_DECIMALS} decimal digits`,
|
||||
(param) => maxDecimalsValidation.test(param?.toString())
|
||||
)
|
||||
.required('Required'),
|
||||
weightOnDataToken: Yup.string().required('Required'),
|
||||
weightOnOcean: Yup.string().required('Required'),
|
||||
swapFee: Yup.number()
|
||||
.min(0.1, (param) => `Must be more or equal to ${param.min}`)
|
||||
.max(10, 'Maximum is 10%')
|
||||
.test(
|
||||
'maxDigitsAfterDecimal',
|
||||
`Must have maximum ${MAX_DECIMALS} decimal digits`,
|
||||
(param) => maxDecimalsValidation.test(param?.toString())
|
||||
)
|
||||
.required('Required')
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user