mirror of
https://github.com/oceanprotocol/market.git
synced 2024-12-02 05:57:29 +01:00
Move auto-changing providerUrl (#1256)
* move auto-changing providerUrl * remove comments * new custom provider → change network interaction * more interaction tweaks for custom provider → change network case * fix adding custom provider * add provider chainId check * initialValues from form context * user chainId fallback
This commit is contained in:
parent
cc0da26740
commit
967b869b02
@ -5,23 +5,29 @@ import { InputProps } from '@shared/FormInput'
|
|||||||
import FileInfo from '../FilesInput/Info'
|
import FileInfo from '../FilesInput/Info'
|
||||||
import styles from './index.module.css'
|
import styles from './index.module.css'
|
||||||
import Button from '@shared/atoms/Button'
|
import Button from '@shared/atoms/Button'
|
||||||
import { initialValues } from 'src/components/Publish/_constants'
|
|
||||||
import { LoggerInstance, ProviderInstance } from '@oceanprotocol/lib'
|
import { LoggerInstance, ProviderInstance } from '@oceanprotocol/lib'
|
||||||
import { FormPublishData } from 'src/components/Publish/_types'
|
import { FormPublishData } from 'src/components/Publish/_types'
|
||||||
|
import { getOceanConfig } from '@utils/ocean'
|
||||||
|
import { useWeb3 } from '@context/Web3'
|
||||||
|
import axios from 'axios'
|
||||||
|
import { useCancelToken } from '@hooks/useCancelToken'
|
||||||
|
|
||||||
export default function CustomProvider(props: InputProps): ReactElement {
|
export default function CustomProvider(props: InputProps): ReactElement {
|
||||||
|
const { chainId } = useWeb3()
|
||||||
|
const newCancelToken = useCancelToken()
|
||||||
|
const { initialValues, setFieldError } = useFormikContext<FormPublishData>()
|
||||||
const [field, meta, helpers] = useField(props.name)
|
const [field, meta, helpers] = useField(props.name)
|
||||||
const [isLoading, setIsLoading] = useState(false)
|
const [isLoading, setIsLoading] = useState(false)
|
||||||
const { setFieldError } = useFormikContext<FormPublishData>()
|
|
||||||
|
|
||||||
async function handleValidation(e: React.SyntheticEvent) {
|
async function handleValidation(e: React.SyntheticEvent) {
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
|
|
||||||
try {
|
try {
|
||||||
setIsLoading(true)
|
setIsLoading(true)
|
||||||
|
|
||||||
|
// Check if provider is a valid provider
|
||||||
const isValid = await ProviderInstance.isValidProvider(field.value.url)
|
const isValid = await ProviderInstance.isValidProvider(field.value.url)
|
||||||
|
|
||||||
// error if something's not right from response
|
|
||||||
// No way to detect a failed request with ProviderInstance.isValidProvider,
|
// No way to detect a failed request with ProviderInstance.isValidProvider,
|
||||||
// making this error show up for multiple cases it shouldn't, like network
|
// making this error show up for multiple cases it shouldn't, like network
|
||||||
// down.
|
// down.
|
||||||
@ -30,8 +36,20 @@ export default function CustomProvider(props: InputProps): ReactElement {
|
|||||||
'✗ No valid provider detected. Check your network, your URL and try again.'
|
'✗ No valid provider detected. Check your network, your URL and try again.'
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Check if valid provider is for same chain user is on
|
||||||
|
const providerResponse = await axios.get(field.value.url, {
|
||||||
|
cancelToken: newCancelToken()
|
||||||
|
})
|
||||||
|
const providerChainId = providerResponse?.data?.chainId
|
||||||
|
const userChainId = chainId || 1
|
||||||
|
|
||||||
|
if (providerChainId !== userChainId)
|
||||||
|
throw Error(
|
||||||
|
'✗ This provider is incompatible with the network your wallet is connected to.'
|
||||||
|
)
|
||||||
|
|
||||||
// if all good, add provider to formik state
|
// if all good, add provider to formik state
|
||||||
helpers.setValue({ url: field.value.url, valid: isValid })
|
helpers.setValue({ url: field.value.url, valid: isValid, custom: true })
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
setFieldError(`${field.name}.url`, error.message)
|
setFieldError(`${field.name}.url`, error.message)
|
||||||
LoggerInstance.error(error.message)
|
LoggerInstance.error(error.message)
|
||||||
@ -41,13 +59,18 @@ export default function CustomProvider(props: InputProps): ReactElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function handleFileInfoClose() {
|
function handleFileInfoClose() {
|
||||||
helpers.setValue({ url: '', valid: false })
|
helpers.setValue({ url: '', valid: false, custom: true })
|
||||||
helpers.setTouched(false)
|
helpers.setTouched(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleDefault(e: React.SyntheticEvent) {
|
function handleDefault(e: React.SyntheticEvent) {
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
helpers.setValue(initialValues.services[0].providerUrl)
|
|
||||||
|
const oceanConfig = getOceanConfig(chainId)
|
||||||
|
const providerUrl =
|
||||||
|
oceanConfig?.providerUri || initialValues.services[0].providerUrl.url
|
||||||
|
|
||||||
|
helpers.setValue({ url: providerUrl, valid: true, custom: false })
|
||||||
}
|
}
|
||||||
|
|
||||||
return field?.value?.valid === true ? (
|
return field?.value?.valid === true ? (
|
||||||
|
@ -6,7 +6,6 @@ import IconCompute from '@images/compute.svg'
|
|||||||
import content from '../../../../content/publish/form.json'
|
import content from '../../../../content/publish/form.json'
|
||||||
import { getFieldContent } from '../_utils'
|
import { getFieldContent } from '../_utils'
|
||||||
import { FormPublishData } from '../_types'
|
import { FormPublishData } from '../_types'
|
||||||
import { getOceanConfig } from '@utils/ocean'
|
|
||||||
|
|
||||||
const accessTypeOptionsTitles = getFieldContent(
|
const accessTypeOptionsTitles = getFieldContent(
|
||||||
'access',
|
'access',
|
||||||
@ -15,8 +14,7 @@ const accessTypeOptionsTitles = getFieldContent(
|
|||||||
|
|
||||||
export default function ServicesFields(): ReactElement {
|
export default function ServicesFields(): ReactElement {
|
||||||
// connect with Form state, use for conditional field rendering
|
// connect with Form state, use for conditional field rendering
|
||||||
const { values, setFieldValue, touched, setTouched } =
|
const { values, setFieldValue } = useFormikContext<FormPublishData>()
|
||||||
useFormikContext<FormPublishData>()
|
|
||||||
|
|
||||||
// name and title should be download, but option value should be access, probably the best way would be to change the component so that option is an object like {name,value}
|
// name and title should be download, but option value should be access, probably the best way would be to change the component so that option is an object like {name,value}
|
||||||
const accessTypeOptions = [
|
const accessTypeOptions = [
|
||||||
@ -55,15 +53,6 @@ export default function ServicesFields(): ReactElement {
|
|||||||
)
|
)
|
||||||
}, [values.services[0].algorithmPrivacy, setFieldValue])
|
}, [values.services[0].algorithmPrivacy, setFieldValue])
|
||||||
|
|
||||||
// Auto-change default providerUrl on user network change
|
|
||||||
useEffect(() => {
|
|
||||||
if (!values?.user?.chainId) return
|
|
||||||
|
|
||||||
const config = getOceanConfig(values.user.chainId)
|
|
||||||
config && setFieldValue('services[0].providerUrl.url', config.providerUri)
|
|
||||||
setTouched({ ...touched, services: [{ providerUrl: { url: true } }] })
|
|
||||||
}, [values.user.chainId, setFieldValue, setTouched])
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Field
|
<Field
|
||||||
|
@ -3,6 +3,7 @@ import { useFormikContext } from 'formik'
|
|||||||
import { wizardSteps, initialPublishFeedback } from './_constants'
|
import { wizardSteps, initialPublishFeedback } from './_constants'
|
||||||
import { useWeb3 } from '@context/Web3'
|
import { useWeb3 } from '@context/Web3'
|
||||||
import { FormPublishData, PublishFeedback } from './_types'
|
import { FormPublishData, PublishFeedback } from './_types'
|
||||||
|
import { getOceanConfig } from '@utils/ocean'
|
||||||
|
|
||||||
export function Steps({
|
export function Steps({
|
||||||
feedback
|
feedback
|
||||||
@ -10,7 +11,8 @@ export function Steps({
|
|||||||
feedback: PublishFeedback
|
feedback: PublishFeedback
|
||||||
}): ReactElement {
|
}): ReactElement {
|
||||||
const { chainId, accountId } = useWeb3()
|
const { chainId, accountId } = useWeb3()
|
||||||
const { values, setFieldValue } = useFormikContext<FormPublishData>()
|
const { values, setFieldValue, touched, setTouched } =
|
||||||
|
useFormikContext<FormPublishData>()
|
||||||
|
|
||||||
// auto-sync user chainId & account into form data values
|
// auto-sync user chainId & account into form data values
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -41,7 +43,32 @@ export function Steps({
|
|||||||
: initialPublishFeedback['1'].description
|
: initialPublishFeedback['1'].description
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}, [values.pricing.type, setFieldValue])
|
}, [values.pricing.type, feedback, setFieldValue])
|
||||||
|
|
||||||
|
// Auto-change default providerUrl on user network change
|
||||||
|
useEffect(() => {
|
||||||
|
if (
|
||||||
|
!values?.user?.chainId ||
|
||||||
|
values?.services[0]?.providerUrl.custom === true
|
||||||
|
)
|
||||||
|
return
|
||||||
|
|
||||||
|
const config = getOceanConfig(values.user.chainId)
|
||||||
|
if (config) {
|
||||||
|
setFieldValue('services[0].providerUrl', {
|
||||||
|
url: config.providerUri,
|
||||||
|
valid: true,
|
||||||
|
custom: false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
setTouched({ ...touched, services: [{ providerUrl: { url: true } }] })
|
||||||
|
}, [
|
||||||
|
values?.user?.chainId,
|
||||||
|
values?.services[0]?.providerUrl.custom,
|
||||||
|
setFieldValue,
|
||||||
|
setTouched
|
||||||
|
])
|
||||||
|
|
||||||
const { component } = wizardSteps.filter(
|
const { component } = wizardSteps.filter(
|
||||||
(stepContent) => stepContent.step === values.user.stepCurrent
|
(stepContent) => stepContent.step === values.user.stepCurrent
|
||||||
|
@ -74,7 +74,8 @@ export const initialValues: FormPublishData = {
|
|||||||
access: 'access',
|
access: 'access',
|
||||||
providerUrl: {
|
providerUrl: {
|
||||||
url: 'https://provider.mainnet.oceanprotocol.com',
|
url: 'https://provider.mainnet.oceanprotocol.com',
|
||||||
valid: true
|
valid: true,
|
||||||
|
custom: false
|
||||||
},
|
},
|
||||||
computeOptions
|
computeOptions
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,7 @@ export interface FormPublishService {
|
|||||||
timeout: string
|
timeout: string
|
||||||
dataTokenOptions: { name: string; symbol: string }
|
dataTokenOptions: { name: string; symbol: string }
|
||||||
access: 'Download' | 'Compute' | string
|
access: 'Download' | 'Compute' | string
|
||||||
providerUrl?: { url: string; valid: boolean }
|
providerUrl: { url: string; valid: boolean; custom: boolean }
|
||||||
algorithmPrivacy?: boolean
|
algorithmPrivacy?: boolean
|
||||||
computeOptions?: ServiceComputeOptions
|
computeOptions?: ServiceComputeOptions
|
||||||
}
|
}
|
||||||
|
@ -58,7 +58,8 @@ const validationService = {
|
|||||||
.required('Required'),
|
.required('Required'),
|
||||||
providerUrl: Yup.object().shape({
|
providerUrl: Yup.object().shape({
|
||||||
url: Yup.string().url('Must be a valid URL.').required('Required'),
|
url: Yup.string().url('Must be a valid URL.').required('Required'),
|
||||||
valid: Yup.boolean().isTrue().required('Valid Provider is required.')
|
valid: Yup.boolean().isTrue().required('Valid Provider is required.'),
|
||||||
|
custom: Yup.boolean()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import React, { ReactElement, useState, useRef, useEffect } from 'react'
|
import React, { ReactElement, useState, useRef } from 'react'
|
||||||
import { Form, Formik } from 'formik'
|
import { Form, Formik } from 'formik'
|
||||||
import { initialPublishFeedback, initialValues } from './_constants'
|
import { initialPublishFeedback, initialValues } from './_constants'
|
||||||
import { useAccountPurgatory } from '@hooks/useAccountPurgatory'
|
import { useAccountPurgatory } from '@hooks/useAccountPurgatory'
|
||||||
@ -14,20 +14,14 @@ import { Steps } from './Steps'
|
|||||||
import { FormPublishData, PublishFeedback } from './_types'
|
import { FormPublishData, PublishFeedback } from './_types'
|
||||||
import { useUserPreferences } from '@context/UserPreferences'
|
import { useUserPreferences } from '@context/UserPreferences'
|
||||||
import useNftFactory from '@hooks/contracts/useNftFactory'
|
import useNftFactory from '@hooks/contracts/useNftFactory'
|
||||||
import {
|
import { ProviderInstance, LoggerInstance, DDO } from '@oceanprotocol/lib'
|
||||||
Nft,
|
|
||||||
getHash,
|
|
||||||
ProviderInstance,
|
|
||||||
LoggerInstance,
|
|
||||||
DDO
|
|
||||||
} from '@oceanprotocol/lib'
|
|
||||||
import { getOceanConfig } from '@utils/ocean'
|
import { getOceanConfig } from '@utils/ocean'
|
||||||
import { validationSchema } from './_validation'
|
import { validationSchema } from './_validation'
|
||||||
import { useAbortController } from '@hooks/useAbortController'
|
import { useAbortController } from '@hooks/useAbortController'
|
||||||
import { setNFTMetadataAndTokenURI } from '@utils/nft'
|
import { setNFTMetadataAndTokenURI } from '@utils/nft'
|
||||||
|
|
||||||
// TODO: restore FormikPersist, add back clear form action
|
// TODO: restore FormikPersist, add back clear form action
|
||||||
const formName = 'ocean-publish-form'
|
// const formName = 'ocean-publish-form'
|
||||||
|
|
||||||
export default function PublishPage({
|
export default function PublishPage({
|
||||||
content
|
content
|
||||||
@ -225,62 +219,13 @@ export default function PublishPage({
|
|||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
// --------------------------------------------------
|
|
||||||
// 3. Integrity check of DDO before & after publishing
|
|
||||||
// --------------------------------------------------
|
|
||||||
|
|
||||||
// TODO: not sure we want to do this at this step, seems overkill
|
|
||||||
|
|
||||||
// if we want to do this we just need to fetch it from aquarius. If we want to fetch from chain and decrypt, we would have more metamask pop-ups (not UX friendly)
|
|
||||||
// decrypt also validates the checksum
|
|
||||||
|
|
||||||
// TODO: remove the commented lines of code until `setSuccess`, didn't remove them yet because maybe i missed something
|
|
||||||
|
|
||||||
// --------------------------------------------------
|
|
||||||
// 1. Mint NFT & datatokens & put in pool
|
|
||||||
// --------------------------------------------------
|
|
||||||
// const nftOptions = values.metadata.nft
|
|
||||||
// const nftCreateData = generateNftCreateData(nftOptions)
|
|
||||||
|
|
||||||
// figure out syntax of ercParams we most likely need to pass
|
|
||||||
// to createNftWithErc() as we need to pass options for the datatoken.
|
|
||||||
// const ercParams = {}
|
|
||||||
// const priceOptions = {
|
|
||||||
// // swapFee is tricky: to get 0.1% you need to send 0.001 as value
|
|
||||||
// swapFee: `${values.pricing.swapFee / 100}`
|
|
||||||
// }
|
|
||||||
// const txMint = await createNftWithErc(accountId, nftCreateData)
|
|
||||||
|
|
||||||
// figure out how to get nftAddress & datatokenAddress from tx log.
|
|
||||||
// const { nftAddress, datatokenAddress } = txMint.logs[0].args
|
|
||||||
// if (!nftAddress || !datatokenAddress) { throw new Error() }
|
|
||||||
//
|
|
||||||
// --------------------------------------------------
|
|
||||||
// 2. Construct and publish DDO
|
|
||||||
// --------------------------------------------------
|
|
||||||
// const did = sha256(`${nftAddress}${chainId}`)
|
|
||||||
// const ddo = transformPublishFormToDdo(values, datatokenAddress, nftAddress)
|
|
||||||
// const txPublish = await publish(ddo)
|
|
||||||
//
|
|
||||||
// --------------------------------------------------
|
|
||||||
// 3. Integrity check of DDO before & after publishing
|
|
||||||
// --------------------------------------------------
|
|
||||||
// const checksumBefore = sha256(ddo)
|
|
||||||
// const ddoFromChain = await getDdoFromChain(ddo.id)
|
|
||||||
// const ddoFromChainDecrypted = await decryptDdo(ddoFromChain)
|
|
||||||
// const checksumAfter = sha256(ddoFromChainDecrypted)
|
|
||||||
|
|
||||||
// if (checksumBefore !== checksumAfter) {
|
|
||||||
// throw new Error('DDO integrity check failed!')
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return isInPurgatory && purgatoryData ? null : (
|
return isInPurgatory && purgatoryData ? null : (
|
||||||
<Formik
|
<Formik
|
||||||
initialValues={initialValues}
|
initialValues={initialValues}
|
||||||
validationSchema={validationSchema}
|
validationSchema={validationSchema}
|
||||||
onSubmit={async (values, { resetForm }) => {
|
onSubmit={async (values) => {
|
||||||
// kick off publishing
|
// kick off publishing
|
||||||
await handleSubmit(values)
|
await handleSubmit(values)
|
||||||
}}
|
}}
|
||||||
|
Loading…
Reference in New Issue
Block a user