Merge pull request #1487 from oceanprotocol/fix/issue-1069-c2d-unsupported-networks

allow price calculation when users are on unsupported network / not connected
This commit is contained in:
EnzoVezzaro 2022-11-15 05:58:40 -04:00 committed by GitHub
commit 8225775828
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 117 additions and 59 deletions

View File

@ -2,23 +2,9 @@ import { gql, OperationResult, TypedDocumentNode, OperationContext } from 'urql'
import { LoggerInstance } from '@oceanprotocol/lib' import { LoggerInstance } from '@oceanprotocol/lib'
import { getUrqlClientInstance } from '@context/UrqlProvider' import { getUrqlClientInstance } from '@context/UrqlProvider'
import { getOceanConfig } from './ocean' import { getOceanConfig } from './ocean'
import { AssetPreviousOrder } from '../@types/subgraph/AssetPreviousOrder'
import { OrdersData_orders as OrdersData } from '../@types/subgraph/OrdersData' import { OrdersData_orders as OrdersData } from '../@types/subgraph/OrdersData'
import { OpcFeesQuery as OpcFeesData } from '../@types/subgraph/OpcFeesQuery' import { OpcFeesQuery as OpcFeesData } from '../@types/subgraph/OpcFeesQuery'
import appConfig from '../../app.config'
const PreviousOrderQuery = gql`
query AssetPreviousOrder($id: String!, $account: String!) {
orders(
first: 1
where: { datatoken: $id, payer: $account }
orderBy: createdTimestamp
orderDirection: desc
) {
createdTimestamp
tx
}
}
`
const UserTokenOrders = gql` const UserTokenOrders = gql`
query OrdersData($user: String!) { query OrdersData($user: String!) {
@ -76,6 +62,11 @@ export function getSubgraphUri(chainId: number): string {
export function getQueryContext(chainId: number): OperationContext { export function getQueryContext(chainId: number): OperationContext {
try { try {
if (!appConfig.chainIdsSupported.includes(chainId))
throw Object.assign(
new Error('network not supported, query context cancelled')
)
const queryContext: OperationContext = { const queryContext: OperationContext = {
url: `${getSubgraphUri( url: `${getSubgraphUri(
Number(chainId) Number(chainId)

View File

@ -2,6 +2,8 @@ import React, { FormEvent, ReactElement } from 'react'
import Button from '../../../@shared/atoms/Button' import Button from '../../../@shared/atoms/Button'
import styles from './index.module.css' import styles from './index.module.css'
import Loader from '../../../@shared/atoms/Loader' import Loader from '../../../@shared/atoms/Loader'
import { useWeb3 } from '@context/Web3'
import Web3 from 'web3'
export interface ButtonBuyProps { export interface ButtonBuyProps {
action: 'download' | 'compute' action: 'download' | 'compute'
@ -28,12 +30,11 @@ export interface ButtonBuyProps {
priceType?: string priceType?: string
algorithmPriceType?: string algorithmPriceType?: string
isAlgorithmConsumable?: boolean isAlgorithmConsumable?: boolean
isSupportedOceanNetwork?: boolean
hasProviderFee?: boolean hasProviderFee?: boolean
retry?: boolean retry?: boolean
} }
// TODO: we need to take a look at these messages
function getConsumeHelpText( function getConsumeHelpText(
btSymbol: string, btSymbol: string,
dtBalance: string, dtBalance: string,
@ -43,12 +44,14 @@ function getConsumeHelpText(
assetType: string, assetType: string,
isConsumable: boolean, isConsumable: boolean,
isBalanceSufficient: boolean, isBalanceSufficient: boolean,
consumableFeedback: string consumableFeedback: string,
isSupportedOceanNetwork: boolean,
web3: Web3
) { ) {
const text = const text =
isConsumable === false isConsumable === false
? consumableFeedback ? consumableFeedback
: hasPreviousOrder : hasPreviousOrder && web3 && isSupportedOceanNetwork
? `You bought this ${assetType} already allowing you to use it without paying again.` ? `You bought this ${assetType} already allowing you to use it without paying again.`
: hasDatatoken : hasDatatoken
? `You own ${dtBalance} ${dtSymbol} allowing you to use this dataset by spending 1 ${dtSymbol}, but without paying ${btSymbol} again.` ? `You own ${dtBalance} ${dtSymbol} allowing you to use this dataset by spending 1 ${dtSymbol}, but without paying ${btSymbol} again.`
@ -58,6 +61,35 @@ function getConsumeHelpText(
return text return text
} }
function getAlgoHelpText(
dtSymbolSelectedComputeAsset: string,
dtBalanceSelectedComputeAsset: string,
isConsumable: boolean,
isAlgorithmConsumable: boolean,
hasPreviousOrderSelectedComputeAsset: boolean,
selectedComputeAssetType: string,
hasDatatokenSelectedComputeAsset: boolean,
isBalanceSufficient: boolean,
isSupportedOceanNetwork: boolean,
web3: Web3
) {
const text =
(!dtSymbolSelectedComputeAsset && !dtBalanceSelectedComputeAsset) ||
isConsumable === false ||
isAlgorithmConsumable === false
? ''
: hasPreviousOrderSelectedComputeAsset && web3 && isSupportedOceanNetwork
? `You already bought the selected ${selectedComputeAssetType}, allowing you to use it without paying again.`
: hasDatatokenSelectedComputeAsset
? `You own ${dtBalanceSelectedComputeAsset} ${dtSymbolSelectedComputeAsset} allowing you to use the selected ${selectedComputeAssetType} by spending 1 ${dtSymbolSelectedComputeAsset}, but without paying OCEAN again.`
: web3 && !isSupportedOceanNetwork
? `Connect to the correct network to interact with this asset.`
: isBalanceSufficient === false
? ''
: `Additionally, you will buy 1 ${dtSymbolSelectedComputeAsset} for the ${selectedComputeAssetType} and spend it back to its publisher and pool.`
return text
}
function getComputeAssetHelpText( function getComputeAssetHelpText(
hasPreviousOrder: boolean, hasPreviousOrder: boolean,
hasDatatoken: boolean, hasDatatoken: boolean,
@ -74,6 +106,8 @@ function getComputeAssetHelpText(
dtBalanceSelectedComputeAsset?: string, dtBalanceSelectedComputeAsset?: string,
selectedComputeAssetType?: string, selectedComputeAssetType?: string,
isAlgorithmConsumable?: boolean, isAlgorithmConsumable?: boolean,
isSupportedOceanNetwork?: boolean,
web3?: Web3,
hasProviderFee?: boolean hasProviderFee?: boolean
) { ) {
const computeAssetHelpText = getConsumeHelpText( const computeAssetHelpText = getConsumeHelpText(
@ -85,21 +119,24 @@ function getComputeAssetHelpText(
assetType, assetType,
isConsumable, isConsumable,
isBalanceSufficient, isBalanceSufficient,
consumableFeedback consumableFeedback,
isSupportedOceanNetwork,
web3
)
const computeAlgoHelpText = getAlgoHelpText(
dtSymbolSelectedComputeAsset,
dtBalanceSelectedComputeAsset,
isConsumable,
isAlgorithmConsumable,
hasPreviousOrderSelectedComputeAsset,
selectedComputeAssetType,
hasDatatokenSelectedComputeAsset,
isBalanceSufficient,
isSupportedOceanNetwork,
web3
) )
const computeAlgoHelpText =
(!dtSymbolSelectedComputeAsset && !dtBalanceSelectedComputeAsset) ||
isConsumable === false ||
isAlgorithmConsumable === false
? ''
: hasPreviousOrderSelectedComputeAsset
? `You already bought the selected ${selectedComputeAssetType}, allowing you to use it without paying again.`
: hasDatatokenSelectedComputeAsset
? `You own ${dtBalanceSelectedComputeAsset} ${dtSymbolSelectedComputeAsset} allowing you to use the selected ${selectedComputeAssetType} by spending 1 ${dtSymbolSelectedComputeAsset}, but without paying ${btSymbol} again.`
: isBalanceSufficient === false
? ''
: `Additionally, you will buy 1 ${dtSymbolSelectedComputeAsset} for the ${selectedComputeAssetType} and spend it back to its publisher.`
const providerFeeHelpText = hasProviderFee const providerFeeHelpText = hasProviderFee
? 'In order to start the job you also need to pay the fees for renting the c2d resources.' ? 'In order to start the job you also need to pay the fees for renting the c2d resources.'
: 'C2D resources required to start the job are available, no payment required for those fees.' : 'C2D resources required to start the job are available, no payment required for those fees.'
@ -133,8 +170,10 @@ export default function ButtonBuy({
algorithmPriceType, algorithmPriceType,
isAlgorithmConsumable, isAlgorithmConsumable,
hasProviderFee, hasProviderFee,
retry retry,
isSupportedOceanNetwork
}: ButtonBuyProps): ReactElement { }: ButtonBuyProps): ReactElement {
const { web3 } = useWeb3()
const buttonText = retry const buttonText = retry
? 'Retry' ? 'Retry'
: action === 'download' : action === 'download'
@ -177,7 +216,9 @@ export default function ButtonBuy({
assetType, assetType,
isConsumable, isConsumable,
isBalanceSufficient, isBalanceSufficient,
consumableFeedback consumableFeedback,
isSupportedOceanNetwork,
web3
) )
: getComputeAssetHelpText( : getComputeAssetHelpText(
hasPreviousOrder, hasPreviousOrder,
@ -195,6 +236,8 @@ export default function ButtonBuy({
dtBalanceSelectedComputeAsset, dtBalanceSelectedComputeAsset,
selectedComputeAssetType, selectedComputeAssetType,
isAlgorithmConsumable, isAlgorithmConsumable,
isSupportedOceanNetwork,
web3,
hasProviderFee hasProviderFee
)} )}
</div> </div>

View File

@ -9,7 +9,7 @@ import PriceOutput from './PriceOutput'
import { useAsset } from '@context/Asset' import { useAsset } from '@context/Asset'
import { useWeb3 } from '@context/Web3' import { useWeb3 } from '@context/Web3'
import content from '../../../../../content/pages/startComputeDataset.json' import content from '../../../../../content/pages/startComputeDataset.json'
import { Asset } from '@oceanprotocol/lib' import { Asset, ZERO_ADDRESS } from '@oceanprotocol/lib'
import { getAccessDetails } from '@utils/accessDetailsAndPricing' import { getAccessDetails } from '@utils/accessDetailsAndPricing'
import { useMarketMetadata } from '@context/MarketMetadata' import { useMarketMetadata } from '@context/MarketMetadata'
import Alert from '@shared/atoms/Alert' import Alert from '@shared/atoms/Alert'
@ -75,7 +75,7 @@ export default function FormStartCompute({
retry: boolean retry: boolean
}): ReactElement { }): ReactElement {
const { siteContent } = useMarketMetadata() const { siteContent } = useMarketMetadata()
const { accountId, balance } = useWeb3() const { accountId, balance, isSupportedOceanNetwork } = useWeb3()
const { isValid, values }: FormikContextType<{ algorithm: string }> = const { isValid, values }: FormikContextType<{ algorithm: string }> =
useFormikContext() useFormikContext()
const { asset, isAssetNetwork } = useAsset() const { asset, isAssetNetwork } = useAsset()
@ -98,7 +98,7 @@ export default function FormStartCompute({
} }
useEffect(() => { useEffect(() => {
if (!values.algorithm || !accountId || !isConsumable) return if (!values.algorithm || !isConsumable) return
async function fetchAlgorithmAssetExtended() { async function fetchAlgorithmAssetExtended() {
const algorithmAsset = getAlgorithmAsset(values.algorithm) const algorithmAsset = getAlgorithmAsset(values.algorithm)
@ -106,7 +106,7 @@ export default function FormStartCompute({
algorithmAsset.chainId, algorithmAsset.chainId,
algorithmAsset.services[0].datatokenAddress, algorithmAsset.services[0].datatokenAddress,
algorithmAsset.services[0].timeout, algorithmAsset.services[0].timeout,
accountId accountId || ZERO_ADDRESS // if user is not connected, use ZERO_ADDRESS as accountId
) )
const extendedAlgoAsset: AssetExtended = { const extendedAlgoAsset: AssetExtended = {
...algorithmAsset, ...algorithmAsset,
@ -198,15 +198,20 @@ export default function FormStartCompute({
} }
setTotalPrices(totalPrices) setTotalPrices(totalPrices)
}, [ }, [
asset?.accessDetails, asset,
selectedAlgorithmAsset?.accessDetails,
hasPreviousOrder, hasPreviousOrder,
hasDatatoken, hasDatatoken,
hasPreviousOrderSelectedComputeAsset, hasPreviousOrderSelectedComputeAsset,
hasDatatokenSelectedComputeAsset, hasDatatokenSelectedComputeAsset,
datasetOrderPriceAndFees, datasetOrderPriceAndFees,
algoOrderPriceAndFees, algoOrderPriceAndFees,
providerFeeAmount providerFeeAmount,
isAssetNetwork,
selectedAlgorithmAsset?.accessDetails,
datasetOrderPrice,
algoOrderPrice,
algorithmSymbol,
datasetSymbol
]) ])
useEffect(() => { useEffect(() => {
@ -216,12 +221,13 @@ export default function FormStartCompute({
setIsBalanceSufficient(false) setIsBalanceSufficient(false)
return return
} }
// if one comparison of baseTokenBalance and token price comparison is false then the state will be false // if one comparison of baseTokenBalance and token price comparison is false then the state will be false
setIsBalanceSufficient( setIsBalanceSufficient(
isBalanceSufficient && compareAsBN(baseTokenBalance, `${price.value}`) baseTokenBalance && compareAsBN(baseTokenBalance, `${price.value}`)
) )
}) })
}, [balance, dtBalance, datasetSymbol, algorithmSymbol]) }, [balance, dtBalance, datasetSymbol, algorithmSymbol, totalPrices])
return ( return (
<Form className={styles.form}> <Form className={styles.form}>
@ -295,6 +301,7 @@ export default function FormStartCompute({
isAlgorithmConsumable={ isAlgorithmConsumable={
selectedAlgorithmAsset?.accessDetails?.isPurchasable selectedAlgorithmAsset?.accessDetails?.isPurchasable
} }
isSupportedOceanNetwork={isSupportedOceanNetwork}
hasProviderFee={providerFeeAmount && providerFeeAmount !== '0'} hasProviderFee={providerFeeAmount && providerFeeAmount !== '0'}
retry={retry} retry={retry}
/> />

View File

@ -5,6 +5,7 @@ import Tooltip from '@shared/atoms/Tooltip'
import styles from './PriceOutput.module.css' import styles from './PriceOutput.module.css'
import { MAX_DECIMALS } from '@utils/constants' import { MAX_DECIMALS } from '@utils/constants'
import Decimal from 'decimal.js' import Decimal from 'decimal.js'
import { useWeb3 } from '@context/Web3'
interface PriceOutputProps { interface PriceOutputProps {
hasPreviousOrder: boolean hasPreviousOrder: boolean
@ -40,13 +41,21 @@ function Row({
sign?: string sign?: string
type?: string type?: string
}) { }) {
const { isSupportedOceanNetwork } = useWeb3()
return ( return (
<div className={styles.priceRow}> <div className={styles.priceRow}>
<div className={styles.sign}>{sign}</div> <div className={styles.sign}>{sign}</div>
<div className={styles.type}>{type}</div> <div className={styles.type}>{type}</div>
<div> <div>
<PriceUnit <PriceUnit
price={hasPreviousOrder || hasDatatoken ? 0 : Number(price)} price={
!isSupportedOceanNetwork
? hasPreviousOrder || hasDatatoken
? 0
: Number(price)
: Number(price)
}
symbol={symbol} symbol={symbol}
size="small" size="small"
className={styles.price} className={styles.price}

View File

@ -45,6 +45,7 @@ import { getComputeFeedback } from '@utils/feedback'
import { getDummyWeb3 } from '@utils/web3' import { getDummyWeb3 } from '@utils/web3'
import { initializeProviderForCompute } from '@utils/provider' import { initializeProviderForCompute } from '@utils/provider'
import { useUserPreferences } from '@context/UserPreferences' import { useUserPreferences } from '@context/UserPreferences'
import { useAsset } from '@context/Asset'
const refreshInterval = 10000 // 10 sec. const refreshInterval = 10000 // 10 sec.
export default function Compute({ export default function Compute({
@ -60,8 +61,10 @@ export default function Compute({
fileIsLoading?: boolean fileIsLoading?: boolean
consumableFeedback?: string consumableFeedback?: string
}): ReactElement { }): ReactElement {
const { accountId, web3 } = useWeb3() const { accountId, web3, isSupportedOceanNetwork } = useWeb3()
const { chainIds } = useUserPreferences() const { chainIds } = useUserPreferences()
const { isAssetNetwork } = useAsset()
const newAbortController = useAbortController() const newAbortController = useAbortController()
const newCancelToken = useCancelToken() const newCancelToken = useCancelToken()
@ -116,7 +119,7 @@ export default function Compute({
const datatokenInstance = new Datatoken(web3) const datatokenInstance = new Datatoken(web3)
const dtBalance = await datatokenInstance.balance( const dtBalance = await datatokenInstance.balance(
asset?.services[0].datatokenAddress, asset?.services[0].datatokenAddress,
accountId accountId || ZERO_ADDRESS // if the user is not connected, we use ZERO_ADDRESS as accountId
) )
setAlgorithmDTBalance(new Decimal(dtBalance).toString()) setAlgorithmDTBalance(new Decimal(dtBalance).toString())
const hasAlgoDt = Number(dtBalance) >= 1 const hasAlgoDt = Number(dtBalance) >= 1
@ -134,9 +137,10 @@ export default function Compute({
const initializedProvider = await initializeProviderForCompute( const initializedProvider = await initializeProviderForCompute(
asset, asset,
selectedAlgorithmAsset, selectedAlgorithmAsset,
accountId, accountId || ZERO_ADDRESS, // if the user is not connected, we use ZERO_ADDRESS as accountId
computeEnv computeEnv
) )
if ( if (
!initializedProvider || !initializedProvider ||
!initializedProvider?.datasets || !initializedProvider?.datasets ||
@ -145,13 +149,17 @@ export default function Compute({
throw new Error(`Error initializing provider for the compute job!`) throw new Error(`Error initializing provider for the compute job!`)
setInitializedProviderResponse(initializedProvider) setInitializedProviderResponse(initializedProvider)
setProviderFeeAmount(
await unitsToAmount( const feeAmount = await unitsToAmount(
web3, !isSupportedOceanNetwork || !isAssetNetwork
initializedProvider?.datasets?.[0]?.providerFee?.providerFeeToken, ? await getDummyWeb3(asset?.chainId)
initializedProvider?.datasets?.[0]?.providerFee?.providerFeeAmount : web3,
) initializedProvider?.datasets?.[0]?.providerFee?.providerFeeToken,
initializedProvider?.datasets?.[0]?.providerFee?.providerFeeAmount
) )
setProviderFeeAmount(feeAmount)
const computeDuration = ( const computeDuration = (
parseInt(initializedProvider?.datasets?.[0]?.providerFee?.validUntil) - parseInt(initializedProvider?.datasets?.[0]?.providerFee?.validUntil) -
Math.floor(Date.now() / 1000) Math.floor(Date.now() / 1000)
@ -217,7 +225,7 @@ export default function Compute({
}, [asset?.accessDetails, accountId, isUnsupportedPricing]) }, [asset?.accessDetails, accountId, isUnsupportedPricing])
useEffect(() => { useEffect(() => {
if (!selectedAlgorithmAsset?.accessDetails || !accountId) return if (!selectedAlgorithmAsset?.accessDetails) return
setIsRequestingAlgoOrderPrice(true) setIsRequestingAlgoOrderPrice(true)
setIsConsumableAlgorithmPrice( setIsConsumableAlgorithmPrice(
@ -306,6 +314,7 @@ export default function Compute({
documentId: selectedAlgorithmAsset.id, documentId: selectedAlgorithmAsset.id,
serviceId: selectedAlgorithmAsset.services[0].id serviceId: selectedAlgorithmAsset.services[0].id
} }
const allowed = await isOrderable( const allowed = await isOrderable(
asset, asset,
computeService.id, computeService.id,
@ -450,14 +459,12 @@ export default function Compute({
setSelectedAlgorithm={setSelectedAlgorithmAsset} setSelectedAlgorithm={setSelectedAlgorithmAsset}
isLoading={isOrdering || isRequestingAlgoOrderPrice} isLoading={isOrdering || isRequestingAlgoOrderPrice}
isComputeButtonDisabled={isComputeButtonDisabled} isComputeButtonDisabled={isComputeButtonDisabled}
hasPreviousOrder={validOrderTx !== undefined} hasPreviousOrder={!!validOrderTx}
hasDatatoken={hasDatatoken} hasDatatoken={hasDatatoken}
dtBalance={dtBalance} dtBalance={dtBalance}
assetType={asset?.metadata.type} assetType={asset?.metadata.type}
assetTimeout={secondsToString(asset?.services[0].timeout)} assetTimeout={secondsToString(asset?.services[0].timeout)}
hasPreviousOrderSelectedComputeAsset={ hasPreviousOrderSelectedComputeAsset={!!validAlgorithmOrderTx}
validAlgorithmOrderTx !== undefined
}
hasDatatokenSelectedComputeAsset={hasAlgoAssetDatatoken} hasDatatokenSelectedComputeAsset={hasAlgoAssetDatatoken}
datasetSymbol={asset?.accessDetails?.baseToken?.symbol || 'OCEAN'} datasetSymbol={asset?.accessDetails?.baseToken?.symbol || 'OCEAN'}
algorithmSymbol={ algorithmSymbol={

View File

@ -33,7 +33,7 @@ export default function Download({
fileIsLoading?: boolean fileIsLoading?: boolean
consumableFeedback?: string consumableFeedback?: string
}): ReactElement { }): ReactElement {
const { accountId, web3 } = useWeb3() const { accountId, web3, isSupportedOceanNetwork } = useWeb3()
const { getOpcFeeForToken } = useMarketMetadata() const { getOpcFeeForToken } = useMarketMetadata()
const { isInPurgatory, isAssetNetwork } = useAsset() const { isInPurgatory, isAssetNetwork } = useAsset()
const isMounted = useIsMounted() const isMounted = useIsMounted()
@ -184,6 +184,7 @@ export default function Download({
isBalanceSufficient={isBalanceSufficient} isBalanceSufficient={isBalanceSufficient}
consumableFeedback={consumableFeedback} consumableFeedback={consumableFeedback}
retry={retry} retry={retry}
isSupportedOceanNetwork={isSupportedOceanNetwork}
/> />
) )