import React, { ReactElement, useEffect, useState } from 'react' import styles from './FormComputeDataset.module.css' import { Field, Form, FormikContextType, useFormikContext } from 'formik' import Input from '@shared/FormInput' import { AssetSelectionAsset } from '@shared/FormInput/InputElement/AssetSelection' import { compareAsBN } from '@utils/numbers' import ButtonBuy from '../ButtonBuy' import PriceOutput from './PriceOutput' import { useAsset } from '@context/Asset' import { useWeb3 } from '@context/Web3' import content from '../../../../../content/pages/startComputeDataset.json' import { Asset, ZERO_ADDRESS } from '@oceanprotocol/lib' import { getAccessDetails } from '@utils/accessDetailsAndPricing' import { useMarketMetadata } from '@context/MarketMetadata' import Alert from '@shared/atoms/Alert' import { getTokenBalanceFromSymbol } from '@utils/web3' import { MAX_DECIMALS } from '@utils/constants' import Decimal from 'decimal.js' export default function FormStartCompute({ algorithms, ddoListAlgorithms, selectedAlgorithmAsset, setSelectedAlgorithm, isLoading, isComputeButtonDisabled, hasPreviousOrder, hasDatatoken, dtBalance, assetType, assetTimeout, hasPreviousOrderSelectedComputeAsset, hasDatatokenSelectedComputeAsset, datasetSymbol, algorithmSymbol, dtSymbolSelectedComputeAsset, dtBalanceSelectedComputeAsset, selectedComputeAssetType, selectedComputeAssetTimeout, stepText, isConsumable, consumableFeedback, datasetOrderPriceAndFees, algoOrderPriceAndFees, providerFeeAmount, validUntil, retry }: { algorithms: AssetSelectionAsset[] ddoListAlgorithms: Asset[] selectedAlgorithmAsset: AssetExtended setSelectedAlgorithm: React.Dispatch> isLoading: boolean isComputeButtonDisabled: boolean hasPreviousOrder: boolean hasDatatoken: boolean dtBalance: string assetType: string assetTimeout: string hasPreviousOrderSelectedComputeAsset?: boolean hasDatatokenSelectedComputeAsset?: boolean datasetSymbol?: string algorithmSymbol?: string dtSymbolSelectedComputeAsset?: string dtBalanceSelectedComputeAsset?: string selectedComputeAssetType?: string selectedComputeAssetTimeout?: string stepText: string isConsumable: boolean consumableFeedback: string datasetOrderPriceAndFees?: OrderPriceAndFees algoOrderPriceAndFees?: OrderPriceAndFees providerFeeAmount?: string validUntil?: string retry: boolean }): ReactElement { const { siteContent } = useMarketMetadata() const { accountId, balance, isSupportedOceanNetwork } = useWeb3() const { isValid, values }: FormikContextType<{ algorithm: string }> = useFormikContext() const { asset, isAssetNetwork } = useAsset() const [datasetOrderPrice, setDatasetOrderPrice] = useState( asset?.accessDetails?.price ) const [algoOrderPrice, setAlgoOrderPrice] = useState( selectedAlgorithmAsset?.accessDetails?.price ) const [totalPrices, setTotalPrices] = useState([]) const [isBalanceSufficient, setIsBalanceSufficient] = useState(true) function getAlgorithmAsset(algorithmId: string): Asset { let assetDdo = null ddoListAlgorithms.forEach((ddo: Asset) => { if (ddo.id === algorithmId) assetDdo = ddo }) return assetDdo } useEffect(() => { if (!values.algorithm || !isConsumable) return async function fetchAlgorithmAssetExtended() { const algorithmAsset = getAlgorithmAsset(values.algorithm) const accessDetails = await getAccessDetails( algorithmAsset.chainId, algorithmAsset.services[0].datatokenAddress, algorithmAsset.services[0].timeout, accountId || ZERO_ADDRESS // if user is not connected, use ZERO_ADDRESS as accountId ) const extendedAlgoAsset: AssetExtended = { ...algorithmAsset, accessDetails } setSelectedAlgorithm(extendedAlgoAsset) } fetchAlgorithmAssetExtended() }, [values.algorithm, accountId, isConsumable]) // // Set price for calculation output // useEffect(() => { if (!asset?.accessDetails || !selectedAlgorithmAsset?.accessDetails) return setDatasetOrderPrice( datasetOrderPriceAndFees?.price || asset.accessDetails.price ) setAlgoOrderPrice( algoOrderPriceAndFees?.price || selectedAlgorithmAsset?.accessDetails.price ) const totalPrices: totalPriceMap[] = [] const priceDataset = !datasetOrderPrice || hasPreviousOrder || hasDatatoken ? new Decimal(0) : new Decimal(datasetOrderPrice).toDecimalPlaces(MAX_DECIMALS) const priceAlgo = !algoOrderPrice || hasPreviousOrderSelectedComputeAsset || hasDatatokenSelectedComputeAsset ? new Decimal(0) : new Decimal(algoOrderPrice).toDecimalPlaces(MAX_DECIMALS) const providerFees = providerFeeAmount ? new Decimal(providerFeeAmount).toDecimalPlaces(MAX_DECIMALS) : new Decimal(0) if (algorithmSymbol === 'OCEAN') { let sum = providerFees.add(priceAlgo) totalPrices.push({ value: sum.toDecimalPlaces(MAX_DECIMALS).toString(), symbol: algorithmSymbol }) if (algorithmSymbol === datasetSymbol) { sum = sum.add(priceDataset) totalPrices[0].value = sum.toDecimalPlaces(MAX_DECIMALS).toString() } else { totalPrices.push({ value: priceDataset.toDecimalPlaces(MAX_DECIMALS).toString(), symbol: datasetSymbol }) } } else { if (datasetSymbol === 'OCEAN') { const sum = providerFees.add(priceDataset) totalPrices.push({ value: sum.toDecimalPlaces(MAX_DECIMALS).toString(), symbol: datasetSymbol }) totalPrices.push({ value: priceAlgo.toDecimalPlaces(MAX_DECIMALS).toString(), symbol: algorithmSymbol }) } else if (datasetSymbol === algorithmSymbol) { const sum = priceAlgo.add(priceDataset) totalPrices.push({ value: sum.toDecimalPlaces(MAX_DECIMALS).toString(), symbol: algorithmSymbol }) totalPrices.push({ value: providerFees.toDecimalPlaces(MAX_DECIMALS).toString(), symbol: 'OCEAN' }) } else { totalPrices.push({ value: priceDataset.toDecimalPlaces(MAX_DECIMALS).toString(), symbol: datasetSymbol }) totalPrices.push({ value: providerFees.toDecimalPlaces(MAX_DECIMALS).toString(), symbol: 'OCEAN' }) totalPrices.push({ value: priceAlgo.toDecimalPlaces(MAX_DECIMALS).toString(), symbol: algorithmSymbol }) } } setTotalPrices(totalPrices) }, [ asset, hasPreviousOrder, hasDatatoken, hasPreviousOrderSelectedComputeAsset, hasDatatokenSelectedComputeAsset, datasetOrderPriceAndFees, algoOrderPriceAndFees, providerFeeAmount, isAssetNetwork, selectedAlgorithmAsset?.accessDetails, datasetOrderPrice, algoOrderPrice, algorithmSymbol, datasetSymbol ]) useEffect(() => { totalPrices.forEach((price) => { const baseTokenBalance = getTokenBalanceFromSymbol(balance, price.symbol) if (!baseTokenBalance) { setIsBalanceSufficient(false) return } // if one comparison of baseTokenBalance and token price comparison is false then the state will be false setIsBalanceSufficient( baseTokenBalance && compareAsBN(baseTokenBalance, `${price.value}`) ) }) }, [balance, dtBalance, datasetSymbol, algorithmSymbol, totalPrices]) return (
{content.form.data.map((field: FormFieldContent) => { return ( ) })} ) }