1
0
mirror of https://github.com/oceanprotocol/market.git synced 2024-12-02 05:57:29 +01:00

merge branch v4 into v4-c2d fixed conflicts

This commit is contained in:
Bogdan Fazakas 2022-03-17 11:29:02 +02:00
commit 08b90b3635
28 changed files with 1765 additions and 885 deletions

View File

@ -141,15 +141,6 @@
"options": ["Forever", "1 day", "1 week", "1 month", "1 year"],
"sortOptions": false,
"required": true
},
{
"name": "computeOptions",
"label": "Compute Environment",
"type": "radio",
"options": [
"populated from computeEnvironmentDefaults in Publish/_constants & computeEnvironmentOptions in Publish/Services/"
],
"required": true
}
]
},

1902
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -21,20 +21,20 @@
"@coingecko/cryptoformat": "^0.4.4",
"@loadable/component": "^5.15.2",
"@oceanprotocol/art": "^3.2.0",
"@oceanprotocol/lib": "^1.0.0-next.27",
"@oceanprotocol/lib": "^1.0.0-next.28",
"@oceanprotocol/typographies": "^0.1.0",
"@portis/web3": "^4.0.6",
"@portis/web3": "^4.0.7",
"@tippyjs/react": "^4.2.6",
"@walletconnect/web3-provider": "^1.7.1",
"axios": "^0.25.0",
"@walletconnect/web3-provider": "^1.7.5",
"axios": "^0.26.1",
"bignumber.js": "^9.0.2",
"chart.js": "^3.7.0",
"chart.js": "^3.7.1",
"classnames": "^2.3.1",
"date-fns": "^2.28.0",
"decimal.js": "^10.3.1",
"dom-confetti": "^0.2.2",
"dotenv": "^15.0.0",
"filesize": "^8.0.6",
"dotenv": "^16.0.0",
"filesize": "^8.0.7",
"formik": "^2.2.9",
"gray-matter": "^4.0.3",
"is-url-superb": "^6.1.0",
@ -44,7 +44,7 @@
"lodash.omit": "^4.5.0",
"myetherwallet-blockies": "^0.1.1",
"next": "^12.1.0",
"query-string": "^7.1.0",
"query-string": "^7.1.1",
"react": "^17.0.2",
"react-chartjs-2": "^4.0.1",
"react-clipboard.js": "^2.0.16",
@ -52,8 +52,8 @@
"react-dom": "^17.0.2",
"react-dotdotdot": "^1.3.1",
"react-modal": "^3.14.4",
"react-paginate": "^8.1.0",
"react-spring": "^9.4.2",
"react-paginate": "^8.1.2",
"react-spring": "^9.4.4",
"react-tabs": "^3.2.3",
"react-toastify": "^8.1.0",
"remark": "^13.0.0",
@ -61,10 +61,10 @@
"remark-html": "^13.0.1",
"remove-markdown": "^0.3.0",
"slugify": "^1.6.5",
"swr": "^1.2.0",
"urql": "^2.1.1",
"swr": "^1.2.2",
"urql": "^2.2.0",
"use-dark-mode": "^2.3.1",
"web3": "^1.6.1",
"web3": "^1.7.1",
"web3modal": "^1.9.5",
"yup": "^0.32.11"
},
@ -84,8 +84,8 @@
"@types/react-tabs": "^2.3.4",
"@types/remove-markdown": "^0.3.1",
"@types/yup": "^0.29.11",
"@typescript-eslint/eslint-plugin": "^5.9.1",
"@typescript-eslint/parser": "^5.9.1",
"@typescript-eslint/eslint-plugin": "^5.15.0",
"@typescript-eslint/parser": "^5.15.0",
"apollo": "^2.33.9",
"eslint": "^7.27.0",
"eslint-config-oceanprotocol": "^1.5.0",
@ -96,11 +96,11 @@
"file-loader": "^6.2.0",
"https-browserify": "^1.0.0",
"husky": "^7.0.4",
"prettier": "^2.5.1",
"prettier": "^2.6.0",
"pretty-quick": "^3.1.3",
"process": "^0.11.10",
"serve": "^13.0.2",
"stream-http": "^2.8.3",
"stream-http": "^3.2.0",
"typescript": "^4.5.4"
},
"repository": {

View File

@ -1,12 +1,13 @@
import { SvgWaves } from './SvgWaves'
import {
Asset,
LoggerInstance,
Asset,
getHash,
Nft,
ProviderInstance,
DDO
DDO,
MetadataAndTokenURI
} from '@oceanprotocol/lib'
import { SvgWaves } from './SvgWaves'
import Web3 from 'web3'
import { TransactionReceipt } from 'web3-core'
@ -45,17 +46,12 @@ function encodeSvg(svgString: string): string {
export function generateNftMetadata(): NftMetadata {
const waves = new SvgWaves()
const svg = waves.generateSvg()
// TODO: figure out if also image URI needs base64 encoding
// e.g. 'data:image/svg+xml;base64,'
// generated SVG embedded as 'data:image/svg+xml' and encoded characters
const imageData = `data:image/svg+xml,${encodeSvg(svg.outerHTML)}`
const newNft: NftMetadata = {
name: 'Ocean Asset NFT',
symbol: 'OCEAN-NFT',
description: `This NFT represents an asset in the Ocean Protocol v4 ecosystem.`,
// TODO: ideally this includes the final DID
external_url: 'https://market.oceanprotocol.com',
background_color: '141414', // dark background
image_data: imageData
@ -64,24 +60,32 @@ export function generateNftMetadata(): NftMetadata {
return newNft
}
export function generateNftCreateData(nftMetadata: NftMetadata): any {
// TODO: figure out if Buffer.from method is working in browser in final build
// as BTOA is deprecated.
// tokenURI: window?.btoa(JSON.stringify(nftMetadata))
const encodedMetadata = Buffer.from(JSON.stringify(nftMetadata)).toString(
'base64'
)
const tokenUriPrefix = 'data:application/json;base64,'
export function generateNftCreateData(nftMetadata: NftMetadata): any {
const nftCreateData = {
name: nftMetadata.name,
symbol: nftMetadata.symbol,
templateIndex: 1,
tokenURI: `data:application/json;base64,${encodedMetadata}`
tokenURI: ''
}
return nftCreateData
}
export function decodeTokenURI(tokenURI: string): NftMetadata {
if (!tokenURI) return undefined
try {
const nftMeta = JSON.parse(
Buffer.from(tokenURI.replace(tokenUriPrefix, ''), 'base64').toString()
) as NftMetadata
return nftMeta
} catch (error) {
LoggerInstance.error(`[NFT] ${error.message}`)
}
}
export async function setNftMetadata(
asset: Asset | DDO,
accountId: string,
@ -125,3 +129,66 @@ export async function setNftMetadata(
return setMetadataTx
}
export async function setNFTMetadataAndTokenURI(
asset: Asset | DDO,
accountId: string,
web3: Web3,
nftMetadata: NftMetadata,
signal: AbortSignal
): Promise<TransactionReceipt> {
const encryptedDdo = await ProviderInstance.encrypt(
asset,
asset.services[0].serviceEndpoint,
signal
)
LoggerInstance.log(
'[setNFTMetadataAndTokenURI] Got encrypted DDO',
encryptedDdo
)
const metadataHash = getHash(JSON.stringify(asset))
// add final did to external_url and asset link to description in nftMetadata before encoding
const externalUrl = `${nftMetadata.external_url}/asset/${asset.id}`
const encodedMetadata = Buffer.from(
JSON.stringify({
...nftMetadata,
description: `${nftMetadata.description}\n\nView on Ocean Market: ${externalUrl}`,
external_url: externalUrl
})
).toString('base64')
const nft = new Nft(web3)
// theoretically used by aquarius or provider, not implemented yet, will remain hardcoded
const flags = '0x02'
const metadataAndTokenURI: MetadataAndTokenURI = {
metaDataState: 0,
metaDataDecryptorUrl: asset.services[0].serviceEndpoint,
metaDataDecryptorAddress: '',
flags,
data: encryptedDdo,
metaDataHash: '0x' + metadataHash,
tokenId: 1,
tokenURI: `data:application/json;base64,${encodedMetadata}`,
metadataProofs: []
}
const estGasSetMetadataAndTokenURI = await nft.estGasSetMetadataAndTokenURI(
asset.nftAddress,
accountId,
metadataAndTokenURI
)
LoggerInstance.log(
'[setNFTMetadataAndTokenURI] est Gas set metadata and token uri --',
estGasSetMetadataAndTokenURI
)
const setMetadataAndTokenURITx = await nft.setMetadataAndTokenURI(
asset.nftAddress,
accountId,
metadataAndTokenURI
)
return setMetadataAndTokenURITx
}

View File

@ -1,6 +1,7 @@
import React, { ReactElement, useEffect, useState } from 'react'
import { usePrices } from '@context/Prices'
import { useWeb3 } from '@context/Web3'
import Web3 from 'web3'
import useNftFactory from '@hooks/contracts/useNftFactory'
import { NftFactory } from '@oceanprotocol/lib'
import Conversion from '@shared/Price/Conversion'
@ -20,7 +21,7 @@ const getEstGasFee = async (
const gasPrice = await web3.eth.getGasPrice()
const gasLimit = await nftFactory?.estGasCreateNFT(address, nft)
const gasFeeEth = web3.utils.fromWei(
const gasFeeEth = Web3.utils.fromWei(
(+gasPrice * +gasLimit).toString(),
'ether'
)

View File

@ -6,7 +6,6 @@
background: none;
padding: 0;
cursor: pointer;
position: relative;
}
.icon {
@ -25,11 +24,12 @@
fill: var(--brand-alert-green);
}
.copied::after {
content: 'Copied!';
position: absolute;
top: -150%;
left: -140%;
.action {
display: flex;
gap: 5px;
}
.feedback {
font-size: var(--font-size-mini);
color: var(--brand-alert-green);
}

View File

@ -27,7 +27,10 @@ export default function Copy({ text }: { text: string }): ReactElement {
onSuccess={() => setIsCopied(true)}
className={`${styles.button} ${isCopied ? styles.copied : ''}`}
>
<IconCopy className={styles.icon} />
<div className={styles.action}>
<IconCopy className={styles.icon} />
{isCopied && <span className={styles.feedback}>Copied!</span>}
</div>
</Clipboard>
)
}

View File

@ -85,11 +85,18 @@ export default function Graph({
const newGraphData = {
labels: timestamps,
datasets: [{ ...lineStyle, data, borderColor: `#8b98a9` }]
datasets: [
{
...lineStyle,
data,
borderColor: `#8b98a9`,
backgroundColor: darkMode.value ? '#201f1f' : '#f7f7f7'
}
]
}
setGraphData(newGraphData)
LoggerInstance.log('[pool graph] New graph data created:', newGraphData)
}, [poolSnapshots, graphType, currency, prices, locale])
}, [poolSnapshots, graphType, currency, prices, locale, darkMode.value])
return (
<div className={styles.graphWrap}>

View File

@ -17,6 +17,7 @@ const getReceipts = gql`
id
nft {
address
owner
}
tx
timestamp
@ -25,7 +26,13 @@ const getReceipts = gql`
}
`
export default function EditHistory(): ReactElement {
export default function EditHistory({
receipts,
setReceipts
}: {
receipts: ReceiptData[]
setReceipts: (receipts: ReceiptData[]) => void
}): ReactElement {
const { asset } = useAsset()
function getUpdateType(type: string): string {
@ -72,7 +79,7 @@ export default function EditHistory(): ReactElement {
if (!data || data.nftUpdates.length === 0) return
const receiptCollection = data.nftUpdates
setReceipts(receiptCollection)
}, [data])
}, [data, setReceipts])
return (
<>

View File

@ -1,51 +0,0 @@
.meta {
margin-bottom: calc(var(--spacer) / 1.5);
color: var(--color-secondary);
font-size: var(--font-size-small);
}
.asset {
margin-left: -2rem;
margin-right: -2rem;
padding-left: 2rem;
padding-right: 3rem;
border-bottom: 1px solid var(--border-color);
margin-bottom: calc(var(--spacer) / 1.5);
padding-bottom: calc(var(--spacer) / 1.75);
}
@media (min-width: 40rem) {
.asset {
margin-top: -0.65rem;
}
}
.assetType {
display: inline-block;
border-right: 1px solid var(--border-color);
padding-right: calc(var(--spacer) / 3.5);
margin-right: calc(var(--spacer) / 4);
}
.datatoken {
white-space: pre;
margin-right: calc(var(--spacer) / 3);
}
.byline {
font-size: var(--font-size-small);
}
.updated {
font-size: var(--font-size-mini);
}
.addWrap {
padding-left: calc(var(--spacer) / 5);
border-left: 1px solid var(--border-color);
display: inline-block;
}
.add {
font-size: var(--font-size-mini);
}

View File

@ -1,75 +0,0 @@
import React, { ReactElement } from 'react'
import { useAsset } from '@context/Asset'
import { useWeb3 } from '@context/Web3'
import ExplorerLink from '@shared/ExplorerLink'
import Publisher from '@shared/Publisher'
import AddToken from '@shared/AddToken'
import Time from '@shared/atoms/Time'
import AssetType from '@shared/AssetType'
import styles from './MetaMain.module.css'
import { getServiceByName } from '@utils/ddo'
import { Asset } from '@oceanprotocol/lib'
export default function MetaMain({ ddo }: { ddo: Asset }): ReactElement {
const { isAssetNetwork } = useAsset()
const { web3ProviderInfo } = useWeb3()
const isCompute = Boolean(getServiceByName(ddo, 'compute'))
const accessType = isCompute ? 'compute' : 'access'
const blockscoutNetworks = [1287, 2021000, 2021001, 44787, 246, 1285]
const isBlockscoutExplorer = blockscoutNetworks.includes(ddo?.chainId)
const dataTokenName = ddo?.datatokens[0]?.name
const dataTokenSymbol = ddo?.datatokens[0]?.symbol
return (
<aside className={styles.meta}>
<header className={styles.asset}>
<AssetType
type={ddo?.metadata.type}
accessType={accessType}
className={styles.assetType}
/>
<ExplorerLink
className={styles.datatoken}
networkId={ddo?.chainId}
path={
isBlockscoutExplorer
? `tokens/${ddo?.services[0].datatokenAddress}`
: `token/${ddo?.services[0].datatokenAddress}`
}
>
{`${dataTokenName}${dataTokenSymbol}`}
</ExplorerLink>
{web3ProviderInfo?.name === 'MetaMask' && isAssetNetwork && (
<span className={styles.addWrap}>
<AddToken
address={ddo?.services[0].datatokenAddress}
symbol={(ddo as Asset)?.datatokens[0]?.symbol}
logo="https://raw.githubusercontent.com/oceanprotocol/art/main/logo/datatoken.png"
text={`Add ${(ddo as Asset)?.datatokens[0]?.symbol} to wallet`}
className={styles.add}
minimal
/>
</span>
)}
</header>
<div className={styles.byline}>
Published By <Publisher account={(ddo as Asset)?.nft?.owner} />
<p>
<Time date={ddo?.metadata.created} relative />
{ddo?.metadata.created !== ddo?.metadata.updated && (
<>
{' — '}
<span className={styles.updated}>
updated <Time date={ddo?.metadata.updated} relative />
</span>
</>
)}
</p>
</div>
</aside>
)
}

View File

@ -0,0 +1,26 @@
.wrapper {
display: flex;
flex-direction: column;
height: 100%;
padding-left: calc(var(--spacer) / 2);
justify-content: center;
}
.datatoken {
white-space: pre;
margin-right: calc(var(--spacer) / 3);
}
.owner {
display: block;
}
.addWrap {
padding-left: calc(var(--spacer) / 5);
border-left: 1px solid var(--border-color);
display: inline-block;
}
.add {
font-size: var(--font-size-mini);
}

View File

@ -0,0 +1,54 @@
import { useAsset } from '@context/Asset'
import { useWeb3 } from '@context/Web3'
import { Asset } from '@oceanprotocol/lib'
import AddToken from '@shared/AddToken'
import ExplorerLink from '@shared/ExplorerLink'
import Publisher from '@shared/Publisher'
import React, { ReactElement } from 'react'
import styles from './MetaAsset.module.css'
export default function MetaAsset({
asset,
isBlockscoutExplorer
}: {
asset: Asset
isBlockscoutExplorer: boolean
}): ReactElement {
const { isAssetNetwork } = useAsset()
const { web3ProviderInfo } = useWeb3()
const dataTokenSymbol = asset?.datatokens[0]?.symbol
return (
<div className={styles.wrapper}>
<span className={styles.owner}>
Owned by <Publisher account={asset?.nft?.owner} />
</span>
<span>
<ExplorerLink
className={styles.datatoken}
networkId={asset?.chainId}
path={
isBlockscoutExplorer
? `tokens/${asset?.services[0].datatokenAddress}`
: `token/${asset?.services[0].datatokenAddress}`
}
>
{`Accessed with ${dataTokenSymbol}`}
</ExplorerLink>
{web3ProviderInfo?.name === 'MetaMask' && isAssetNetwork && (
<span className={styles.addWrap}>
<AddToken
address={asset?.services[0].datatokenAddress}
symbol={(asset as Asset)?.datatokens[0]?.symbol}
logo="https://raw.githubusercontent.com/oceanprotocol/art/main/logo/datatoken.png"
text={`Add ${(asset as Asset)?.datatokens[0]?.symbol} to wallet`}
className={styles.add}
minimal
/>
</span>
)}
</span>
</div>
)
}

View File

@ -0,0 +1,19 @@
.wrapper {
padding: calc(var(--spacer) / 2);
}
.assetType {
display: inline-block;
border-right: 1px solid var(--border-color);
padding-right: calc(var(--spacer) / 3.5);
margin-right: calc(var(--spacer) / 4);
}
.byline {
display: inline-block;
font-size: var(--font-size-small);
}
.updated {
font-size: var(--font-size-mini);
}

View File

@ -0,0 +1,47 @@
import { Asset } from '@oceanprotocol/lib'
import AssetType from '@shared/AssetType'
import Time from '@shared/atoms/Time'
import Publisher from '@shared/Publisher'
import { getServiceByName } from '@utils/ddo'
import React, { ReactElement } from 'react'
import styles from './MetaInfo.module.css'
export default function MetaInfo({
asset,
nftPublisher
}: {
asset: Asset
nftPublisher: string
}): ReactElement {
const isCompute = Boolean(getServiceByName(asset, 'compute'))
const accessType = isCompute ? 'compute' : 'access'
const nftOwner = asset?.nft?.owner
return (
<div className={styles.wrapper}>
<AssetType
type={asset?.metadata.type}
accessType={accessType}
className={styles.assetType}
/>
<div className={styles.byline}>
<p>
Published <Time date={asset?.metadata.created} relative />
{nftPublisher && nftPublisher !== nftOwner && (
<span>
{' by '} <Publisher account={nftPublisher} />
</span>
)}
{asset?.metadata.created !== asset?.metadata.updated && (
<>
{' — '}
<span className={styles.updated}>
updated <Time date={asset?.metadata.updated} relative />
</span>
</>
)}
</p>
</div>
</div>
)
}

View File

@ -0,0 +1,41 @@
.wrapper {
display: flex;
justify-content: flex-start;
align-items: center;
}
.wrapper img {
margin: 0;
width: 128px;
height: 128px;
}
.info {
padding: calc(var(--spacer) / 2);
color: var(--color-secondary);
}
.info h5 {
margin-bottom: 0;
}
.address {
word-break: break-all;
}
.address button::after {
word-break: normal;
}
.links {
margin-top: calc(var(--spacer) / 3);
}
.links a {
display: block;
}
.fallback {
padding-top: calc(var(--spacer) / 3);
font-style: italic;
}

View File

@ -0,0 +1,79 @@
import Copy from '@shared/atoms/Copy'
import External from '@images/external.svg'
import ExplorerLink from '@shared/ExplorerLink'
import { NftMetadata } from '@utils/nft'
import React, { ReactElement } from 'react'
import styles from './NftTooltip.module.css'
import explorerLinkStyles from '@shared/ExplorerLink/index.module.css'
import { accountTruncate } from '@utils/web3'
export default function NftTooltip({
nft,
address,
chainId,
isBlockscoutExplorer
}: {
nft: NftMetadata
address: string
chainId: number
isBlockscoutExplorer: boolean
}): ReactElement {
// Currently Ocean NFTs are not displayed correctly on OpenSea
// Code prepared to easily integrate this feature once this is fixed
//
// Supported OpeanSea networks:
// https://support.opensea.io/hc/en-us/articles/4404027708051-Which-blockchains-does-OpenSea-support-
const openseaNetworks = [1, 137]
const openseaTestNetworks = [4]
const openSeaSupported = openseaNetworks
.concat(openseaTestNetworks)
.includes(chainId)
const openSeaBaseUri = openSeaSupported
? openseaTestNetworks.includes(chainId)
? 'https://testnets.opensea.io'
: 'https://opensea.io'
: undefined
return (
<div className={styles.wrapper}>
{nft && <img src={nft.image_data} alt={nft?.name} />}
<div className={styles.info}>
{nft && <h5>{nft.name}</h5>}
{address && (
<span title={address} className={styles.address}>
{accountTruncate(address)} <Copy text={address} />
</span>
)}
<div className={styles.links}>
{address && (
<ExplorerLink
networkId={chainId}
path={
isBlockscoutExplorer ? `tokens/${address}` : `token/${address}`
}
>
View on explorer
</ExplorerLink>
)}
{openSeaSupported && nft && address && (
<a
href={`${openSeaBaseUri}/assets/${address}/1`}
target="_blank"
rel="noreferrer"
className={explorerLinkStyles.link}
>
View on OpeanSea <External />
</a>
)}
</div>
{!nft?.image_data && (
<p className={styles.fallback}>
This Data NFT was not created on Ocean Market
</p>
)}
</div>
</div>
)
}

View File

@ -0,0 +1,44 @@
.meta {
margin-left: calc(var(--spacer) * -1);
margin-right: calc(var(--spacer) * -1);
margin-bottom: calc(var(--spacer) / 1.5);
color: var(--color-secondary);
font-size: var(--font-size-small);
}
.asset {
display: flex;
justify-content: flex-start;
align-items: flex-start;
height: calc(var(--spacer) * 2);
border-bottom: 1px solid var(--border-color);
}
.nftImage {
position: relative;
margin: 0;
border-right: 1px solid var(--border-color);
width: calc(var(--spacer) * 2);
height: calc(var(--spacer) * 2);
}
.nftImage img,
.nftImage > svg:first-of-type {
width: 100%;
height: 100%;
}
.nftImage > svg:first-of-type {
transform: scale(0.7);
}
.nftImage .tooltip {
position: absolute;
padding: 0;
left: 0;
bottom: 0;
}
.nftImage .tooltip svg {
fill: var(--font-color-text);
}

View File

@ -0,0 +1,53 @@
import React, { ReactElement } from 'react'
import styles from './index.module.css'
import { Asset } from '@oceanprotocol/lib'
import { decodeTokenURI } from '@utils/nft'
import MetaAsset from './MetaAsset'
import MetaInfo from './MetaInfo'
import Tooltip from '@shared/atoms/Tooltip'
import NftTooltip from './NftTooltip'
import Logo from '@shared/atoms/Logo'
export default function MetaMain({
asset,
nftPublisher
}: {
asset: Asset
nftPublisher: string
}): ReactElement {
const nftMetadata = decodeTokenURI(asset?.nft?.tokenURI)
const blockscoutNetworks = [1287, 2021000, 2021001, 44787, 246, 1285]
const isBlockscoutExplorer = blockscoutNetworks.includes(asset?.chainId)
return (
<aside className={styles.meta}>
<header className={styles.asset}>
<div className={styles.nftImage}>
{nftMetadata?.image_data ? (
<img src={nftMetadata?.image_data} alt={asset?.nft?.name} />
) : (
<Logo noWordmark />
)}
{(nftMetadata || asset?.nftAddress) && (
<Tooltip
className={styles.tooltip}
content={
<NftTooltip
nft={nftMetadata}
address={asset?.nftAddress}
chainId={asset?.chainId}
isBlockscoutExplorer={isBlockscoutExplorer}
/>
}
/>
)}
</div>
<MetaAsset asset={asset} isBlockscoutExplorer={isBlockscoutExplorer} />
</header>
<MetaInfo asset={asset} nftPublisher={nftPublisher} />
</aside>
)
}

View File

@ -16,6 +16,7 @@
.content {
composes: box from '@shared/atoms/Box.module.css';
padding-top: 0;
margin-top: var(--spacer);
position: relative;
}

View File

@ -16,16 +16,27 @@ import NetworkName from '@shared/NetworkName'
import content from '../../../../content/purgatory.json'
import { AssetExtended } from 'src/@types/AssetExtended'
import { useWeb3 } from '@context/Web3'
import Web3 from 'web3'
export default function AssetContent({
asset
}: {
asset: AssetExtended
}): ReactElement {
const { debug } = useUserPreferences()
const [isOwner, setIsOwner] = useState(false)
const { accountId } = useWeb3()
const { isInPurgatory, purgatoryData, owner, isAssetNetwork } = useAsset()
const { debug } = useUserPreferences()
const [receipts, setReceipts] = useState([])
const [nftPublisher, setNftPublisher] = useState<string>()
useEffect(() => {
setNftPublisher(
Web3.utils.toChecksumAddress(
receipts?.find((e) => e.type === 'METADATA_CREATED')?.nft?.owner
)
)
}, [receipts])
useEffect(() => {
if (!accountId || !owner) return
@ -50,11 +61,10 @@ export default function AssetContent({
<article className={styles.grid}>
<div>
<div className={styles.content}>
<MetaMain ddo={asset} />
<MetaMain asset={asset} nftPublisher={nftPublisher} />
{asset?.accessDetails?.datatoken !== null && (
<Bookmark did={asset?.id} />
)}
{isInPurgatory === true ? (
<Alert
title={content.asset.title}
@ -71,9 +81,8 @@ export default function AssetContent({
<MetaSecondary ddo={asset} />
</>
)}
<MetaFull ddo={asset} />
<EditHistory />
<EditHistory receipts={receipts} setReceipts={setReceipts} />
{debug === true && <DebugOutput title="DDO" output={asset} />}
</div>
</div>

View File

@ -1,7 +1,7 @@
import { BoxSelectionOption } from '@shared/FormFields/BoxSelection'
import Input from '@shared/FormInput'
import { Field, useFormikContext } from 'formik'
import React, { ReactElement } from 'react'
import React, { ReactElement, useEffect } from 'react'
import content from '../../../../content/publish/form.json'
import { FormPublishData } from '../_types'
import { getFieldContent } from '../_utils'
@ -17,7 +17,7 @@ const assetTypeOptionsTitles = getFieldContent(
export default function MetadataFields(): ReactElement {
// connect with Form state, use for conditional field rendering
const { values } = useFormikContext<FormPublishData>()
const { values, setFieldValue } = useFormikContext<FormPublishData>()
// BoxSelection component is not a Formik component
// so we need to handle checked state manually.
@ -45,6 +45,17 @@ export default function MetadataFields(): ReactElement {
checked: values.metadata.dockerImage === `${preset.image}:${preset.tag}`
}))
useEffect(() => {
setFieldValue(
'services[0].access',
values.metadata.type === 'algorithm' ? 'compute' : 'access'
)
setFieldValue(
'services[0].algorithmPrivacy',
values.metadata.type === 'algorithm'
)
}, [values.metadata.type])
dockerImageOptions.push({ name: 'custom', title: 'Custom', checked: false })
return (

View File

@ -20,7 +20,8 @@ export default function Navigation(): ReactElement {
const isSuccessMetadata = errors.metadata === undefined
const isSuccessServices = errors.services === undefined
const isSuccessPricing =
errors.pricing === undefined && touched.pricing?.price
errors.pricing === undefined &&
(touched.pricing?.price || touched.pricing?.freeAgreement)
const isSuccessPreview =
isSuccessMetadata && isSuccessServices && isSuccessPricing

View File

@ -43,7 +43,11 @@ export default function ServicesFields(): ReactElement {
// Auto-change access type based on algo privacy boolean.
// Could be also done later in transformPublishFormToDdo().
useEffect(() => {
if (!values.services[0].algorithmPrivacy) return
if (
values.services[0].algorithmPrivacy === null ||
values.services[0].algorithmPrivacy === undefined
)
return
setFieldValue(
'services[0].access',

View File

@ -1,6 +1,6 @@
import { ReactElement, useEffect } from 'react'
import { useFormikContext } from 'formik'
import { wizardSteps } from './_constants'
import { wizardSteps, initialPublishFeedback } from './_constants'
import { useWeb3 } from '@context/Web3'
import { FormPublishData, PublishFeedback } from './_types'
@ -38,7 +38,7 @@ export function Steps({
'a single transaction',
'a single transaction, after an initial approve transaction'
)
: feedback['1'].description
: initialPublishFeedback['1'].description
}
})
}, [values.pricing.type, setFieldValue])

View File

@ -70,7 +70,7 @@ export const initialValues: FormPublishData = {
links: [{ url: '' }],
dataTokenOptions: { name: '', symbol: '' },
timeout: '',
access: '',
access: 'access',
providerUrl: {
url: 'https://provider.mainnet.oceanprotocol.com',
valid: true

View File

@ -181,6 +181,7 @@ export async function transformPublishFormToDdo(
}
],
nft: {
...generateNftCreateData(values?.metadata.nft),
owner: accountId
}
})

View File

@ -24,7 +24,7 @@ import {
import { getOceanConfig } from '@utils/ocean'
import { validationSchema } from './_validation'
import { useAbortController } from '@hooks/useAbortController'
import { setNftMetadata } from '@utils/nft'
import { setNFTMetadataAndTokenURI } from '@utils/nft'
// TODO: restore FormikPersist, add back clear form action
const formName = 'ocean-publish-form'
@ -63,7 +63,15 @@ export default function PublishPage({
...prevState,
'1': {
...prevState['1'],
status: 'active'
status: 'active',
txCount: values.pricing.type === 'dynamic' ? 2 : 1,
description:
values.pricing.type === 'dynamic'
? prevState['1'].description.replace(
'a single transaction',
'a single transaction, after an initial approve transaction'
)
: prevState['1'].description
}
}))
@ -102,7 +110,14 @@ export default function PublishPage({
'1': {
...prevState['1'],
status: 'error',
errorMessage: error.message
errorMessage: error.message,
description:
values.pricing.type === 'dynamic'
? prevState['1'].description.replace(
'a single transaction',
'a single transaction, after an initial approve transaction'
)
: prevState['1'].description
}
}))
}
@ -173,10 +188,11 @@ export default function PublishPage({
if (!_ddo || !_encryptedDdo) throw new Error('No DDO received.')
const res = await setNftMetadata(
const res = await setNFTMetadataAndTokenURI(
_ddo,
accountId,
web3,
values.metadata.nft,
newAbortController()
)