mirror of
https://github.com/oceanprotocol/market.git
synced 2024-12-02 05:57:29 +01:00
Merge branch 'feature/v4-c2d' into fix/issue-1069-c2d-unsupported-networks
This commit is contained in:
commit
56583c5e7a
8
.github/dependabot.yml
vendored
Normal file
8
.github/dependabot.yml
vendored
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
version: 2
|
||||||
|
updates:
|
||||||
|
- package-ecosystem: npm
|
||||||
|
directory: '/'
|
||||||
|
schedule:
|
||||||
|
interval: monthly
|
||||||
|
time: '03:00'
|
||||||
|
timezone: Europe/Berlin
|
9
.github/workflows/ci.yml
vendored
9
.github/workflows/ci.yml
vendored
@ -5,6 +5,7 @@ on:
|
|||||||
branches:
|
branches:
|
||||||
- main
|
- main
|
||||||
- v4
|
- v4
|
||||||
|
- v3
|
||||||
tags:
|
tags:
|
||||||
- '**'
|
- '**'
|
||||||
pull_request:
|
pull_request:
|
||||||
@ -36,7 +37,7 @@ jobs:
|
|||||||
key: ${{ runner.os }}-${{ matrix.node }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }}
|
key: ${{ runner.os }}-${{ matrix.node }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }}
|
||||||
restore-keys: ${{ runner.os }}-${{ matrix.node }}-build-${{ env.cache-name }}-
|
restore-keys: ${{ runner.os }}-${{ matrix.node }}-build-${{ env.cache-name }}-
|
||||||
|
|
||||||
- run: npm ci
|
- run: npm ci --legacy-peer-deps
|
||||||
- run: npm run build
|
- run: npm run build
|
||||||
|
|
||||||
test:
|
test:
|
||||||
@ -63,7 +64,7 @@ jobs:
|
|||||||
key: ${{ runner.os }}-${{ matrix.node }}-test-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }}
|
key: ${{ runner.os }}-${{ matrix.node }}-test-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }}
|
||||||
restore-keys: ${{ runner.os }}-${{ matrix.node }}-test-${{ env.cache-name }}-
|
restore-keys: ${{ runner.os }}-${{ matrix.node }}-test-${{ env.cache-name }}-
|
||||||
|
|
||||||
- run: npm ci
|
- run: npm ci --legacy-peer-deps
|
||||||
- run: npm test
|
- run: npm test
|
||||||
|
|
||||||
- name: Upload coverage artifact
|
- name: Upload coverage artifact
|
||||||
@ -95,7 +96,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
name: coverage-${{ runner.os }}
|
name: coverage-${{ runner.os }}
|
||||||
|
|
||||||
- run: npm ci
|
- run: npm ci --legacy-peer-deps
|
||||||
- run: npm run codegen:apollo
|
- run: npm run codegen:apollo
|
||||||
|
|
||||||
- uses: paambaati/codeclimate-action@v3.0.0
|
- uses: paambaati/codeclimate-action@v3.0.0
|
||||||
@ -126,6 +127,6 @@ jobs:
|
|||||||
key: ${{ runner.os }}-${{ matrix.node }}-storybook-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }}
|
key: ${{ runner.os }}-${{ matrix.node }}-storybook-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }}
|
||||||
restore-keys: ${{ runner.os }}-${{ matrix.node }}-storybook-${{ env.cache-name }}-
|
restore-keys: ${{ runner.os }}-${{ matrix.node }}-storybook-${{ env.cache-name }}-
|
||||||
|
|
||||||
- run: npm ci
|
- run: npm ci --legacy-peer-deps
|
||||||
- run: npm run pregenerate
|
- run: npm run pregenerate
|
||||||
- run: npm run storybook:build
|
- run: npm run storybook:build
|
||||||
|
2
.github/workflows/deploy.yml
vendored
2
.github/workflows/deploy.yml
vendored
@ -12,7 +12,7 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
- uses: actions/setup-node@v2
|
- uses: actions/setup-node@v2
|
||||||
- run: npm ci
|
- run: npm ci --legacy-peer-deps
|
||||||
|
|
||||||
- run: npm run build
|
- run: npm run build
|
||||||
env:
|
env:
|
||||||
|
@ -9,12 +9,20 @@ module.exports = {
|
|||||||
process.env.NEXT_PUBLIC_METADATACACHE_URI ||
|
process.env.NEXT_PUBLIC_METADATACACHE_URI ||
|
||||||
'https://v4.aquarius.oceanprotocol.com',
|
'https://v4.aquarius.oceanprotocol.com',
|
||||||
|
|
||||||
|
v3MetadataCacheUri:
|
||||||
|
process.env.NEXT_PUBLIC_V3_METADATACACHE_URI ||
|
||||||
|
'https://aquarius.oceanprotocol.com',
|
||||||
|
|
||||||
|
v3MarketUri:
|
||||||
|
process.env.NEXT_PUBLIC_V3_MARKET_URI ||
|
||||||
|
'https://v3.market.oceanprotocol.com',
|
||||||
|
|
||||||
// List of chainIds which metadata cache queries will return by default.
|
// List of chainIds which metadata cache queries will return by default.
|
||||||
// This preselects the Chains user preferences.
|
// This preselects the Chains user preferences.
|
||||||
chainIds: [3, 4, 80001, 1287],
|
chainIds: [1, 137, 56, 246, 1285],
|
||||||
|
|
||||||
// List of all supported chainIds. Used to populate the Chains user preferences list.
|
// List of all supported chainIds. Used to populate the Chains user preferences list.
|
||||||
chainIdsSupported: [3, 4, 80001, 1287],
|
chainIdsSupported: [1, 137, 56, 246, 1285, 3, 4, 80001, 1287],
|
||||||
|
|
||||||
infuraProjectId: process.env.NEXT_PUBLIC_INFURA_PROJECT_ID || 'xxx',
|
infuraProjectId: process.env.NEXT_PUBLIC_INFURA_PROJECT_ID || 'xxx',
|
||||||
|
|
||||||
|
@ -12,5 +12,8 @@
|
|||||||
"name": "Discord",
|
"name": "Discord",
|
||||||
"url": "https://discord.gg/TnXjkR5"
|
"url": "https://discord.gg/TnXjkR5"
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
"stats": {
|
||||||
|
"note": "Counted on-chain from our NFT and pool factories. Includes assets in all Ocean Market forks and [purgatory](https://github.com/oceanprotocol/list-purgatory)."
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -30,13 +30,22 @@
|
|||||||
"required": true
|
"required": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "links",
|
"name": "files",
|
||||||
"label": "Sample file",
|
"label": "New file",
|
||||||
"placeholder": "e.g. https://file.com/samplefile.json",
|
"placeholder": "e.g. https://file.com/file.json",
|
||||||
"help": "Please provide a URL to a sample of your data set file. This file should reveal the data structure of your data set, e.g. by including the header and one line of a CSV file. This file URL will be publicly available after publishing. **Please make sure that the endpoint is accessible over the internet and is not protected by a firewall or by credentials.**",
|
"help": "This URL will be stored encrypted after publishing. **Please make sure that the endpoint is accessible over the internet and is not protected by a firewall or by credentials.** For a compute data set, your file should match the file type required by the algorithm, and should not exceed 1 GB in file size. Leaving this field empty will not remove the current value.",
|
||||||
"prominentHelp": true,
|
"prominentHelp": true,
|
||||||
"type": "files"
|
"type": "files"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "links",
|
||||||
|
"label": "New sample file",
|
||||||
|
"placeholder": "e.g. https://file.com/samplefile.json",
|
||||||
|
"help": "Please provide a URL to a sample of your data set file. This file should reveal the data structure of your data set, e.g. by including the header and one line of a CSV file. This file URL will be publicly available after publishing. **Please make sure that the endpoint is accessible over the internet and is not protected by a firewall or by credentials.** Leaving this field empty will not remove the current value.",
|
||||||
|
"prominentHelp": true,
|
||||||
|
"type": "files"
|
||||||
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
"name": "timeout",
|
"name": "timeout",
|
||||||
"label": "Timeout",
|
"label": "Timeout",
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"siteTitle": "Ocean Market",
|
"siteTitle": "Ocean Market",
|
||||||
"siteTagline": "A marketplace to find, publish and trade data sets in the Ocean Network.",
|
"siteTagline": "A marketplace to find, publish and trade data sets in the Ocean Network.",
|
||||||
"siteUrl": "https://v4.market.oceanprotocol.com",
|
"siteUrl": "https://market.oceanprotocol.com",
|
||||||
"siteImage": "/share.png",
|
"siteImage": "/share.png",
|
||||||
"copyright": "All Rights Reserved. Powered by ",
|
"copyright": "All Rights Reserved. Powered by ",
|
||||||
"menu": [
|
"menu": [
|
||||||
@ -14,12 +14,8 @@
|
|||||||
"link": "/profile"
|
"link": "/profile"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"announcement": "Data NFTs, One-Sided Staking and more. [Explore OceanONDA V4](https://blog.oceanprotocol.com/oceanonda-v4-production-has-arrived-cb4fe8faaf39).",
|
||||||
"warning": {
|
"warning": {
|
||||||
"main": "",
|
"ctd": "Compute-to-Data is still in a testing phase, please use it only on test networks."
|
||||||
"polygonPublish": "Only republish data sets with a pool from ETH Mainnet into Polygon/Matic if the liquidity is **less than or equal to 1000 OCEAN in the original pool**. Doing otherwise will lead to [purgatory](https://github.com/oceanprotocol/list-purgatory) for the data set in Polygon/Matic."
|
|
||||||
},
|
|
||||||
"announcement": {
|
|
||||||
"main": "Ocean Market is [available on Polygon](https://blog.oceanprotocol.com/ocean-on-polygon-network-8abad19cbf47).",
|
|
||||||
"polygon": "Polygon/Matic EVM support is in early stages. [Use the Polygon Bridge](https://docs.oceanprotocol.com/tutorials/polygon-bridge/) to get mOCEAN."
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
8221
package-lock.json
generated
8221
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
62
package.json
62
package.json
@ -17,28 +17,28 @@
|
|||||||
"type-check": "tsc --noEmit",
|
"type-check": "tsc --noEmit",
|
||||||
"deploy:s3": "bash scripts/deploy-s3.sh",
|
"deploy:s3": "bash scripts/deploy-s3.sh",
|
||||||
"postinstall": "husky install",
|
"postinstall": "husky install",
|
||||||
"codegen:apollo": "apollo client:codegen --endpoint=https://v4.subgraph.rinkeby.oceanprotocol.com/subgraphs/name/oceanprotocol/ocean-subgraph --target typescript --tsFileExtension=d.ts --outputFlat src/@types/subgraph/",
|
"codegen:apollo": "apollo client:codegen --endpoint=https://v4.subgraph.ropsten.oceanprotocol.com/subgraphs/name/oceanprotocol/ocean-subgraph --target typescript --tsFileExtension=d.ts --outputFlat src/@types/subgraph/",
|
||||||
"storybook": "cross-env NODE_ENV=test start-storybook -p 6006 --quiet",
|
"storybook": "cross-env NODE_ENV=test start-storybook -p 6006 --quiet",
|
||||||
"storybook:build": "cross-env NODE_ENV=test build-storybook"
|
"storybook:build": "cross-env NODE_ENV=test build-storybook"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@coingecko/cryptoformat": "^0.4.4",
|
"@coingecko/cryptoformat": "^0.5.4",
|
||||||
"@loadable/component": "^5.15.2",
|
"@loadable/component": "^5.15.2",
|
||||||
"@oceanprotocol/art": "^3.2.0",
|
"@oceanprotocol/art": "^3.2.0",
|
||||||
"@oceanprotocol/lib": "^1.0.0-next.44",
|
"@oceanprotocol/lib": "^1.1.2",
|
||||||
"@oceanprotocol/typographies": "^0.1.0",
|
"@oceanprotocol/typographies": "^0.1.0",
|
||||||
"@portis/web3": "^4.0.7",
|
"@portis/web3": "^4.0.7",
|
||||||
"@tippyjs/react": "^4.2.6",
|
"@tippyjs/react": "^4.2.6",
|
||||||
"@urql/exchange-refocus": "^0.2.5",
|
"@urql/exchange-refocus": "^0.2.5",
|
||||||
"@walletconnect/web3-provider": "^1.7.8",
|
"@walletconnect/web3-provider": "^1.7.8",
|
||||||
"axios": "^0.27.2",
|
"axios": "^0.27.2",
|
||||||
"chart.js": "^3.7.1",
|
"chart.js": "^3.8.0",
|
||||||
"classnames": "^2.3.1",
|
"classnames": "^2.3.1",
|
||||||
"date-fns": "^2.28.0",
|
"date-fns": "^2.28.0",
|
||||||
"decimal.js": "^10.3.1",
|
"decimal.js": "^10.3.1",
|
||||||
"dom-confetti": "^0.2.2",
|
"dom-confetti": "^0.2.2",
|
||||||
"dotenv": "^16.0.1",
|
"dotenv": "^16.0.1",
|
||||||
"filesize": "^8.0.7",
|
"filesize": "^9.0.1",
|
||||||
"formik": "^2.2.9",
|
"formik": "^2.2.9",
|
||||||
"gray-matter": "^4.0.3",
|
"gray-matter": "^4.0.3",
|
||||||
"is-url-superb": "^6.1.0",
|
"is-url-superb": "^6.1.0",
|
||||||
@ -50,7 +50,7 @@
|
|||||||
"next": "^12.1.6",
|
"next": "^12.1.6",
|
||||||
"query-string": "^7.1.1",
|
"query-string": "^7.1.1",
|
||||||
"react": "^18.1.0",
|
"react": "^18.1.0",
|
||||||
"react-chartjs-2": "^4.1.0",
|
"react-chartjs-2": "^4.2.0",
|
||||||
"react-clipboard.js": "^2.0.16",
|
"react-clipboard.js": "^2.0.16",
|
||||||
"react-data-table-component": "^6.11.7",
|
"react-data-table-component": "^6.11.7",
|
||||||
"react-dom": "^18.1.0",
|
"react-dom": "^18.1.0",
|
||||||
@ -59,66 +59,66 @@
|
|||||||
"react-paginate": "^8.1.3",
|
"react-paginate": "^8.1.3",
|
||||||
"react-spring": "^9.4.5",
|
"react-spring": "^9.4.5",
|
||||||
"react-tabs": "^5.1.0",
|
"react-tabs": "^5.1.0",
|
||||||
"react-toastify": "^8.2.0",
|
"react-toastify": "^9.0.4",
|
||||||
"remark": "^13.0.0",
|
"remark": "^13.0.0",
|
||||||
"remark-gfm": "^1.0.0",
|
"remark-gfm": "^1.0.0",
|
||||||
"remark-html": "^13.0.1",
|
"remark-html": "^13.0.1",
|
||||||
"remove-markdown": "^0.3.0",
|
"remove-markdown": "^0.5.0",
|
||||||
"slugify": "^1.6.5",
|
"slugify": "^1.6.5",
|
||||||
"swr": "^1.3.0",
|
"swr": "^1.3.0",
|
||||||
"urql": "^2.2.0",
|
"urql": "^2.2.1",
|
||||||
"use-dark-mode": "^2.3.1",
|
"use-dark-mode": "^2.3.1",
|
||||||
"web3": "^1.7.3",
|
"web3": "^1.7.3",
|
||||||
"web3modal": "^1.9.7",
|
"web3modal": "^1.9.7",
|
||||||
"yup": "^0.32.11"
|
"yup": "^0.32.11"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@storybook/addon-essentials": "^6.5.4",
|
"@storybook/addon-essentials": "^6.5.7",
|
||||||
"@storybook/addon-storyshots": "^6.5.4",
|
"@storybook/addon-storyshots": "^6.5.7",
|
||||||
"@storybook/builder-webpack5": "^6.5.4",
|
"@storybook/builder-webpack5": "^6.5.7",
|
||||||
"@storybook/manager-webpack5": "^6.5.4",
|
"@storybook/manager-webpack5": "^6.5.7",
|
||||||
"@storybook/react": "^6.5.4",
|
"@storybook/react": "^6.5.7",
|
||||||
"@storybook/testing-library": "^0.0.11",
|
"@storybook/testing-library": "^0.0.11",
|
||||||
"@storybook/testing-react": "^1.3.0",
|
"@storybook/testing-react": "^1.3.0",
|
||||||
"@svgr/webpack": "^6.2.1",
|
"@svgr/webpack": "^6.2.1",
|
||||||
"@testing-library/jest-dom": "^5.16.4",
|
"@testing-library/jest-dom": "^5.16.4",
|
||||||
"@testing-library/react": "^13.2.0",
|
"@testing-library/react": "^13.3.0",
|
||||||
"@types/chart.js": "^2.9.37",
|
"@types/chart.js": "^2.9.37",
|
||||||
"@types/js-cookie": "^3.0.1",
|
"@types/js-cookie": "^3.0.2",
|
||||||
"@types/loadable__component": "^5.13.1",
|
"@types/loadable__component": "^5.13.4",
|
||||||
"@types/lodash.debounce": "^4.0.3",
|
"@types/lodash.debounce": "^4.0.7",
|
||||||
"@types/lodash.omit": "^4.5.6",
|
"@types/lodash.omit": "^4.5.7",
|
||||||
"@types/node": "^17.0.35",
|
"@types/node": "^17.0.41",
|
||||||
"@types/react": "^18.0.9",
|
"@types/react": "^18.0.12",
|
||||||
"@types/react-dom": "^18.0.4",
|
"@types/react-dom": "^18.0.5",
|
||||||
"@types/react-modal": "^3.13.1",
|
"@types/react-modal": "^3.13.1",
|
||||||
"@types/react-paginate": "^7.1.1",
|
"@types/react-paginate": "^7.1.1",
|
||||||
"@types/remove-markdown": "^0.3.1",
|
"@types/remove-markdown": "^0.3.1",
|
||||||
"@types/yup": "^0.29.13",
|
"@types/yup": "^0.29.14",
|
||||||
"@typescript-eslint/eslint-plugin": "^5.25.0",
|
"@typescript-eslint/eslint-plugin": "^5.27.1",
|
||||||
"@typescript-eslint/parser": "^5.25.0",
|
"@typescript-eslint/parser": "^5.27.1",
|
||||||
"apollo": "^2.33.9",
|
"apollo": "^2.34.0",
|
||||||
"cross-env": "^7.0.3",
|
"cross-env": "^7.0.3",
|
||||||
"eslint": "^8.16.0",
|
"eslint": "^8.17.0",
|
||||||
"eslint-config-oceanprotocol": "^2.0.1",
|
"eslint-config-oceanprotocol": "^2.0.1",
|
||||||
"eslint-config-prettier": "^8.5.0",
|
"eslint-config-prettier": "^8.5.0",
|
||||||
"eslint-plugin-jest-dom": "^4.0.2",
|
"eslint-plugin-jest-dom": "^4.0.2",
|
||||||
"eslint-plugin-prettier": "^4.0.0",
|
"eslint-plugin-prettier": "^4.0.0",
|
||||||
"eslint-plugin-react": "^7.30.0",
|
"eslint-plugin-react": "^7.30.0",
|
||||||
"eslint-plugin-react-hooks": "^4.5.0",
|
"eslint-plugin-react-hooks": "^4.5.0",
|
||||||
"eslint-plugin-testing-library": "^5.5.0",
|
"eslint-plugin-testing-library": "^5.5.1",
|
||||||
"file-loader": "^6.2.0",
|
"file-loader": "^6.2.0",
|
||||||
"https-browserify": "^1.0.0",
|
"https-browserify": "^1.0.0",
|
||||||
"husky": "^8.0.1",
|
"husky": "^8.0.1",
|
||||||
"jest": "^28.1.0",
|
"jest": "^28.1.1",
|
||||||
"jest-environment-jsdom": "^28.1.0",
|
"jest-environment-jsdom": "^28.1.1",
|
||||||
"prettier": "^2.6.2",
|
"prettier": "^2.6.2",
|
||||||
"pretty-quick": "^3.1.3",
|
"pretty-quick": "^3.1.3",
|
||||||
"process": "^0.11.10",
|
"process": "^0.11.10",
|
||||||
"serve": "^13.0.2",
|
"serve": "^13.0.2",
|
||||||
"stream-http": "^3.2.0",
|
"stream-http": "^3.2.0",
|
||||||
"tsconfig-paths-webpack-plugin": "^3.5.2",
|
"tsconfig-paths-webpack-plugin": "^3.5.2",
|
||||||
"typescript": "^4.6.4"
|
"typescript": "^4.7.3"
|
||||||
},
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
|
@ -9,7 +9,7 @@ import React, {
|
|||||||
} from 'react'
|
} from 'react'
|
||||||
import { Config, LoggerInstance, Purgatory } from '@oceanprotocol/lib'
|
import { Config, LoggerInstance, Purgatory } from '@oceanprotocol/lib'
|
||||||
import { CancelToken } from 'axios'
|
import { CancelToken } from 'axios'
|
||||||
import { retrieveAsset } from '@utils/aquarius'
|
import { checkV3Asset, retrieveAsset } from '@utils/aquarius'
|
||||||
import { useWeb3 } from './Web3'
|
import { useWeb3 } from './Web3'
|
||||||
import { useCancelToken } from '@hooks/useCancelToken'
|
import { useCancelToken } from '@hooks/useCancelToken'
|
||||||
import { getOceanConfig, getDevelopmentConfig } from '@utils/ocean'
|
import { getOceanConfig, getDevelopmentConfig } from '@utils/ocean'
|
||||||
@ -18,7 +18,7 @@ import { getAccessDetails } from '@utils/accessDetailsAndPricing'
|
|||||||
import { useIsMounted } from '@hooks/useIsMounted'
|
import { useIsMounted } from '@hooks/useIsMounted'
|
||||||
import { useMarketMetadata } from './MarketMetadata'
|
import { useMarketMetadata } from './MarketMetadata'
|
||||||
|
|
||||||
interface AssetProviderValue {
|
export interface AssetProviderValue {
|
||||||
isInPurgatory: boolean
|
isInPurgatory: boolean
|
||||||
purgatoryData: Purgatory
|
purgatoryData: Purgatory
|
||||||
asset: AssetExtended
|
asset: AssetExtended
|
||||||
@ -26,6 +26,7 @@ interface AssetProviderValue {
|
|||||||
owner: string
|
owner: string
|
||||||
error?: string
|
error?: string
|
||||||
isAssetNetwork: boolean
|
isAssetNetwork: boolean
|
||||||
|
isV3Asset: boolean
|
||||||
oceanConfig: Config
|
oceanConfig: Config
|
||||||
loading: boolean
|
loading: boolean
|
||||||
fetchAsset: (token?: CancelToken) => Promise<void>
|
fetchAsset: (token?: CancelToken) => Promise<void>
|
||||||
@ -51,6 +52,7 @@ function AssetProvider({
|
|||||||
const [error, setError] = useState<string>()
|
const [error, setError] = useState<string>()
|
||||||
const [loading, setLoading] = useState(false)
|
const [loading, setLoading] = useState(false)
|
||||||
const [isAssetNetwork, setIsAssetNetwork] = useState<boolean>()
|
const [isAssetNetwork, setIsAssetNetwork] = useState<boolean>()
|
||||||
|
const [isV3Asset, setIsV3Asset] = useState<boolean>()
|
||||||
const [oceanConfig, setOceanConfig] = useState<Config>()
|
const [oceanConfig, setOceanConfig] = useState<Config>()
|
||||||
|
|
||||||
const newCancelToken = useCancelToken()
|
const newCancelToken = useCancelToken()
|
||||||
@ -68,6 +70,7 @@ function AssetProvider({
|
|||||||
const asset = await retrieveAsset(did, token)
|
const asset = await retrieveAsset(did, token)
|
||||||
|
|
||||||
if (!asset) {
|
if (!asset) {
|
||||||
|
setIsV3Asset(await checkV3Asset(did, token))
|
||||||
setError(
|
setError(
|
||||||
`\`${did}\`` +
|
`\`${did}\`` +
|
||||||
'\n\nWe could not find an asset for this DID in the cache. If you just published a new asset, wait some seconds and refresh this page.'
|
'\n\nWe could not find an asset for this DID in the cache. If you just published a new asset, wait some seconds and refresh this page.'
|
||||||
@ -168,6 +171,7 @@ function AssetProvider({
|
|||||||
loading,
|
loading,
|
||||||
fetchAsset,
|
fetchAsset,
|
||||||
isAssetNetwork,
|
isAssetNetwork,
|
||||||
|
isV3Asset,
|
||||||
oceanConfig
|
oceanConfig
|
||||||
} as AssetProviderValue
|
} as AssetProviderValue
|
||||||
}
|
}
|
||||||
|
@ -29,6 +29,8 @@ export interface AppConfig {
|
|||||||
classNameLight: string
|
classNameLight: string
|
||||||
storageKey: string
|
storageKey: string
|
||||||
}
|
}
|
||||||
|
v3MetadataCacheUri: string
|
||||||
|
v3MarketUri: string
|
||||||
}
|
}
|
||||||
export interface SiteContent {
|
export interface SiteContent {
|
||||||
siteTitle: string
|
siteTitle: string
|
||||||
@ -40,13 +42,9 @@ export interface SiteContent {
|
|||||||
name: string
|
name: string
|
||||||
link: string
|
link: string
|
||||||
}[]
|
}[]
|
||||||
|
announcement: string
|
||||||
warning: {
|
warning: {
|
||||||
main: string
|
ctd: string
|
||||||
polygonPublish: string
|
|
||||||
}
|
|
||||||
announcement: {
|
|
||||||
main: string
|
|
||||||
polygon: string
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,7 +36,7 @@ function MarketMetadataProvider({
|
|||||||
|
|
||||||
opcData.push({
|
opcData.push({
|
||||||
chainId: appConfig.chainIdsSupported[i],
|
chainId: appConfig.chainIdsSupported[i],
|
||||||
approvedTokens: response.data?.opc.approvedTokens,
|
approvedTokens: response.data?.opc.approvedTokens?.map((x) => x.id),
|
||||||
swapApprovedFee: response.data?.opc.swapOceanFee,
|
swapApprovedFee: response.data?.opc.swapOceanFee,
|
||||||
swapNotApprovedFee: response.data?.opc.swapNonOceanFee
|
swapNotApprovedFee: response.data?.opc.swapNonOceanFee
|
||||||
} as unknown as OpcFee)
|
} as unknown as OpcFee)
|
||||||
|
@ -31,7 +31,7 @@ interface UserPreferencesValue {
|
|||||||
|
|
||||||
const UserPreferencesContext = createContext(null)
|
const UserPreferencesContext = createContext(null)
|
||||||
|
|
||||||
const localStorageKey = 'ocean-user-preferences'
|
const localStorageKey = 'ocean-user-preferences-v4'
|
||||||
|
|
||||||
function getLocalStorage(): UserPreferencesValue {
|
function getLocalStorage(): UserPreferencesValue {
|
||||||
const storageParsed =
|
const storageParsed =
|
||||||
|
@ -319,15 +319,6 @@ export async function getOrderPriceAndFees(
|
|||||||
orderPriceAndFee.price = new Decimal(+orderPriceAndFee.price || 0)
|
orderPriceAndFee.price = new Decimal(+orderPriceAndFee.price || 0)
|
||||||
.add(new Decimal(+orderPriceAndFee?.consumeMarketOrderFee || 0))
|
.add(new Decimal(+orderPriceAndFee?.consumeMarketOrderFee || 0))
|
||||||
.add(new Decimal(+orderPriceAndFee?.publisherMarketOrderFee || 0))
|
.add(new Decimal(+orderPriceAndFee?.publisherMarketOrderFee || 0))
|
||||||
.add(
|
|
||||||
new Decimal(
|
|
||||||
(await unitsToAmount(
|
|
||||||
web3,
|
|
||||||
orderPriceAndFee?.providerFee?.providerFeeToken,
|
|
||||||
orderPriceAndFee?.providerFee?.providerFeeAmount.toString()
|
|
||||||
)) || 0
|
|
||||||
)
|
|
||||||
)
|
|
||||||
.toString()
|
.toString()
|
||||||
return orderPriceAndFee
|
return orderPriceAndFee
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@ import { Asset, LoggerInstance } from '@oceanprotocol/lib'
|
|||||||
import { AssetSelectionAsset } from '@shared/FormFields/AssetSelection'
|
import { AssetSelectionAsset } from '@shared/FormFields/AssetSelection'
|
||||||
import axios, { CancelToken, AxiosResponse } from 'axios'
|
import axios, { CancelToken, AxiosResponse } from 'axios'
|
||||||
import { OrdersData_orders as OrdersData } from '../@types/subgraph/OrdersData'
|
import { OrdersData_orders as OrdersData } from '../@types/subgraph/OrdersData'
|
||||||
import { metadataCacheUri } from '../../app.config'
|
import { metadataCacheUri, v3MetadataCacheUri } from '../../app.config'
|
||||||
import {
|
import {
|
||||||
SortDirectionOptions,
|
SortDirectionOptions,
|
||||||
SortTermOptions
|
SortTermOptions
|
||||||
@ -133,6 +133,28 @@ export async function retrieveAsset(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function checkV3Asset(
|
||||||
|
did: string,
|
||||||
|
cancelToken: CancelToken
|
||||||
|
): Promise<boolean> {
|
||||||
|
try {
|
||||||
|
const response: AxiosResponse<Asset> = await axios.get(
|
||||||
|
`${v3MetadataCacheUri}/api/v1/aquarius/assets/ddo/${did}`,
|
||||||
|
{ cancelToken }
|
||||||
|
)
|
||||||
|
if (!response || response.status !== 200 || !response.data) return false
|
||||||
|
|
||||||
|
return true
|
||||||
|
} catch (error) {
|
||||||
|
if (axios.isCancel(error)) {
|
||||||
|
LoggerInstance.log(error.message)
|
||||||
|
} else {
|
||||||
|
LoggerInstance.error(error.message)
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export async function getAssetsNames(
|
export async function getAssetsNames(
|
||||||
didList: string[],
|
didList: string[],
|
||||||
cancelToken: CancelToken
|
cancelToken: CancelToken
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
import {
|
import {
|
||||||
approve,
|
approve,
|
||||||
|
approveWei,
|
||||||
Datatoken,
|
Datatoken,
|
||||||
FreOrderParams,
|
FreOrderParams,
|
||||||
LoggerInstance,
|
LoggerInstance,
|
||||||
OrderParams,
|
OrderParams,
|
||||||
ProviderComputeInitialize,
|
ProviderComputeInitialize,
|
||||||
ProviderFees,
|
ProviderFees,
|
||||||
ProviderInstance,
|
ProviderInstance
|
||||||
unitsToAmount
|
|
||||||
} from '@oceanprotocol/lib'
|
} from '@oceanprotocol/lib'
|
||||||
import { AssetExtended } from 'src/@types/AssetExtended'
|
import { AssetExtended } from 'src/@types/AssetExtended'
|
||||||
import Web3 from 'web3'
|
import Web3 from 'web3'
|
||||||
@ -53,17 +53,10 @@ export async function order(
|
|||||||
asset.services[0].serviceEndpoint
|
asset.services[0].serviceEndpoint
|
||||||
))
|
))
|
||||||
|
|
||||||
const providerFeesSanitized = providerFees || initializeData.providerFee
|
|
||||||
providerFeesSanitized.providerFeeAmount = await unitsToAmount(
|
|
||||||
web3,
|
|
||||||
providerFeesSanitized.providerFeeToken,
|
|
||||||
providerFeesSanitized.providerFeeAmount.toString()
|
|
||||||
)
|
|
||||||
|
|
||||||
const orderParams = {
|
const orderParams = {
|
||||||
consumer: computeConsumerAddress || accountId,
|
consumer: computeConsumerAddress || accountId,
|
||||||
serviceIndex: 0,
|
serviceIndex: 0,
|
||||||
_providerFee: providerFeesSanitized,
|
_providerFee: providerFees || initializeData.providerFee,
|
||||||
_consumeMarketFee: {
|
_consumeMarketFee: {
|
||||||
consumeMarketFeeAddress: marketFeeAddress,
|
consumeMarketFeeAddress: marketFeeAddress,
|
||||||
consumeMarketFeeAmount: consumeMarketOrderFee,
|
consumeMarketFeeAmount: consumeMarketOrderFee,
|
||||||
@ -71,7 +64,6 @@ export async function order(
|
|||||||
}
|
}
|
||||||
} as OrderParams
|
} as OrderParams
|
||||||
|
|
||||||
// TODO: we need to approve provider fee
|
|
||||||
switch (asset.accessDetails?.type) {
|
switch (asset.accessDetails?.type) {
|
||||||
case 'fixed': {
|
case 'fixed': {
|
||||||
// this assumes all fees are in ocean
|
// this assumes all fees are in ocean
|
||||||
@ -94,8 +86,6 @@ export async function order(
|
|||||||
swapMarketFee: consumeMarketFixedSwapFee,
|
swapMarketFee: consumeMarketFixedSwapFee,
|
||||||
marketFeeAddress
|
marketFeeAddress
|
||||||
} as FreOrderParams
|
} as FreOrderParams
|
||||||
console.log('freParams', freParams)
|
|
||||||
console.log('orderParams', orderParams)
|
|
||||||
const tx = await datatoken.buyFromFreAndOrder(
|
const tx = await datatoken.buyFromFreAndOrder(
|
||||||
asset.accessDetails.datatoken.address,
|
asset.accessDetails.datatoken.address,
|
||||||
accountId,
|
accountId,
|
||||||
@ -155,30 +145,6 @@ export async function reuseOrder(
|
|||||||
asset.services[0].serviceEndpoint
|
asset.services[0].serviceEndpoint
|
||||||
))
|
))
|
||||||
|
|
||||||
if (
|
|
||||||
providerFees?.providerFeeAmount ||
|
|
||||||
initializeData?.providerFee?.providerFeeAmount
|
|
||||||
) {
|
|
||||||
const txApprove = await approve(
|
|
||||||
web3,
|
|
||||||
accountId,
|
|
||||||
providerFees.providerFeeToken ||
|
|
||||||
initializeData.providerFee.providerFeeToken,
|
|
||||||
asset.accessDetails.datatoken.address,
|
|
||||||
await unitsToAmount(
|
|
||||||
web3,
|
|
||||||
providerFees.providerFeeToken ||
|
|
||||||
initializeData.providerFee.providerFeeToken,
|
|
||||||
providerFees.providerFeeAmount ||
|
|
||||||
initializeData.providerFee.providerFeeAmount
|
|
||||||
),
|
|
||||||
false
|
|
||||||
)
|
|
||||||
if (!txApprove) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const tx = await datatoken.reuseOrder(
|
const tx = await datatoken.reuseOrder(
|
||||||
asset.accessDetails.datatoken.address,
|
asset.accessDetails.datatoken.address,
|
||||||
accountId,
|
accountId,
|
||||||
@ -215,6 +181,23 @@ export async function handleComputeOrder(
|
|||||||
'[compute] Handle compute order for asset type: ',
|
'[compute] Handle compute order for asset type: ',
|
||||||
asset.metadata.type
|
asset.metadata.type
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if (
|
||||||
|
initializeData.providerFee &&
|
||||||
|
initializeData.providerFee.providerFeeAmount !== '0'
|
||||||
|
) {
|
||||||
|
const txApproveWei = await approveWei(
|
||||||
|
web3,
|
||||||
|
accountId,
|
||||||
|
asset.accessDetails.baseToken.address,
|
||||||
|
asset.accessDetails.datatoken.address,
|
||||||
|
initializeData.providerFee.providerFeeAmount
|
||||||
|
)
|
||||||
|
if (!txApproveWei) {
|
||||||
|
toast.error('Failed to approve provider fees!')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
if (initializeData.validOrder && !initializeData.providerFee) {
|
if (initializeData.validOrder && !initializeData.providerFee) {
|
||||||
LoggerInstance.log('[compute] Has valid order: ', initializeData.validOrder)
|
LoggerInstance.log('[compute] Has valid order: ', initializeData.validOrder)
|
||||||
return initializeData.validOrder
|
return initializeData.validOrder
|
||||||
|
@ -3,7 +3,7 @@ import {
|
|||||||
ComputeAsset,
|
ComputeAsset,
|
||||||
ComputeEnvironment,
|
ComputeEnvironment,
|
||||||
downloadFileBrowser,
|
downloadFileBrowser,
|
||||||
FileMetadata,
|
FileInfo,
|
||||||
LoggerInstance,
|
LoggerInstance,
|
||||||
ProviderComputeInitializeResults,
|
ProviderComputeInitializeResults,
|
||||||
ProviderInstance
|
ProviderInstance
|
||||||
@ -53,7 +53,7 @@ export async function initializeProviderForCompute(
|
|||||||
|
|
||||||
// TODO: Why do we have these one line functions ?!?!?!
|
// TODO: Why do we have these one line functions ?!?!?!
|
||||||
export async function getEncryptedFiles(
|
export async function getEncryptedFiles(
|
||||||
files: FileMetadata[],
|
files: any,
|
||||||
providerUrl: string
|
providerUrl: string
|
||||||
): Promise<string> {
|
): Promise<string> {
|
||||||
try {
|
try {
|
||||||
@ -69,7 +69,7 @@ export async function getFileDidInfo(
|
|||||||
did: string,
|
did: string,
|
||||||
serviceId: string,
|
serviceId: string,
|
||||||
providerUrl: string
|
providerUrl: string
|
||||||
): Promise<FileMetadata[]> {
|
): Promise<FileInfo[]> {
|
||||||
try {
|
try {
|
||||||
const response = await ProviderInstance.checkDidFiles(
|
const response = await ProviderInstance.checkDidFiles(
|
||||||
did,
|
did,
|
||||||
@ -85,7 +85,7 @@ export async function getFileDidInfo(
|
|||||||
export async function getFileUrlInfo(
|
export async function getFileUrlInfo(
|
||||||
url: string,
|
url: string,
|
||||||
providerUrl: string
|
providerUrl: string
|
||||||
): Promise<FileMetadata[]> {
|
): Promise<FileInfo[]> {
|
||||||
try {
|
try {
|
||||||
const response = await ProviderInstance.checkFileUrl(url, providerUrl)
|
const response = await ProviderInstance.checkFileUrl(url, providerUrl)
|
||||||
return response
|
return response
|
||||||
|
@ -3,6 +3,11 @@
|
|||||||
margin-top: calc(var(--spacer) / 2);
|
margin-top: calc(var(--spacer) / 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.actionsCenter {
|
||||||
|
margin: auto !important;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
.help {
|
.help {
|
||||||
font-size: var(--font-size-mini);
|
font-size: var(--font-size-mini);
|
||||||
color: var(--color-secondary);
|
color: var(--color-secondary);
|
||||||
|
@ -31,6 +31,7 @@ interface ButtonBuyProps {
|
|||||||
algorithmPriceType?: string
|
algorithmPriceType?: string
|
||||||
isAlgorithmConsumable?: boolean
|
isAlgorithmConsumable?: boolean
|
||||||
isSupportedOceanNetwork?: boolean
|
isSupportedOceanNetwork?: boolean
|
||||||
|
hasProviderFee?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: we need to take a look at these messages
|
// TODO: we need to take a look at these messages
|
||||||
@ -109,7 +110,8 @@ function getComputeAssetHelpText(
|
|||||||
selectedComputeAssetType?: string,
|
selectedComputeAssetType?: string,
|
||||||
isAlgorithmConsumable?: boolean,
|
isAlgorithmConsumable?: boolean,
|
||||||
isSupportedOceanNetwork?: boolean,
|
isSupportedOceanNetwork?: boolean,
|
||||||
web3?: any
|
web3?: any,
|
||||||
|
hasProviderFee?: boolean
|
||||||
) {
|
) {
|
||||||
const computeAssetHelpText = getConsumeHelpText(
|
const computeAssetHelpText = getConsumeHelpText(
|
||||||
dtBalance,
|
dtBalance,
|
||||||
@ -138,11 +140,15 @@ function getComputeAssetHelpText(
|
|||||||
isSupportedOceanNetwork
|
isSupportedOceanNetwork
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const providerFeeHelpText = hasProviderFee
|
||||||
|
? '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.'
|
||||||
|
|
||||||
const computeHelpText = selectedComputeAssettLowPoolLiquidity
|
const computeHelpText = selectedComputeAssettLowPoolLiquidity
|
||||||
? computeAlgoHelpText
|
? computeAlgoHelpText
|
||||||
: lowPoolLiquidity
|
: lowPoolLiquidity
|
||||||
? computeAssetHelpText
|
? computeAssetHelpText
|
||||||
: `${computeAssetHelpText} ${computeAlgoHelpText}`
|
: `${computeAssetHelpText} ${computeAlgoHelpText} ${providerFeeHelpText}`
|
||||||
return computeHelpText
|
return computeHelpText
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -172,7 +178,8 @@ export default function ButtonBuy({
|
|||||||
priceType,
|
priceType,
|
||||||
algorithmPriceType,
|
algorithmPriceType,
|
||||||
isAlgorithmConsumable,
|
isAlgorithmConsumable,
|
||||||
isSupportedOceanNetwork
|
isSupportedOceanNetwork,
|
||||||
|
hasProviderFee
|
||||||
}: ButtonBuyProps): ReactElement {
|
}: ButtonBuyProps): ReactElement {
|
||||||
const { web3 } = useWeb3()
|
const { web3 } = useWeb3()
|
||||||
const buttonText =
|
const buttonText =
|
||||||
@ -182,7 +189,9 @@ export default function ButtonBuy({
|
|||||||
: priceType === 'free'
|
: priceType === 'free'
|
||||||
? 'Get'
|
? 'Get'
|
||||||
: `Buy ${assetTimeout === 'Forever' ? '' : ` for ${assetTimeout}`}`
|
: `Buy ${assetTimeout === 'Forever' ? '' : ` for ${assetTimeout}`}`
|
||||||
: hasPreviousOrder && hasPreviousOrderSelectedComputeAsset
|
: hasPreviousOrder &&
|
||||||
|
hasPreviousOrderSelectedComputeAsset &&
|
||||||
|
!hasProviderFee
|
||||||
? 'Start Compute Job'
|
? 'Start Compute Job'
|
||||||
: priceType === 'free' && algorithmPriceType === 'free'
|
: priceType === 'free' && algorithmPriceType === 'free'
|
||||||
? 'Order Compute Job'
|
? 'Order Compute Job'
|
||||||
@ -199,7 +208,7 @@ export default function ButtonBuy({
|
|||||||
type={type}
|
type={type}
|
||||||
onClick={onClick}
|
onClick={onClick}
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
className="center"
|
className={action === 'compute' ? styles.actionsCenter : ''}
|
||||||
>
|
>
|
||||||
{buttonText}
|
{buttonText}
|
||||||
</Button>
|
</Button>
|
||||||
@ -236,7 +245,8 @@ export default function ButtonBuy({
|
|||||||
selectedComputeAssetType,
|
selectedComputeAssetType,
|
||||||
isAlgorithmConsumable,
|
isAlgorithmConsumable,
|
||||||
isSupportedOceanNetwork,
|
isSupportedOceanNetwork,
|
||||||
web3
|
web3,
|
||||||
|
hasProviderFee
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
|
@ -4,7 +4,7 @@ import classNames from 'classnames/bind'
|
|||||||
import cleanupContentType from '@utils/cleanupContentType'
|
import cleanupContentType from '@utils/cleanupContentType'
|
||||||
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 { FileMetadata } from '@oceanprotocol/lib'
|
import { FileInfo } from '@oceanprotocol/lib'
|
||||||
|
|
||||||
const cx = classNames.bind(styles)
|
const cx = classNames.bind(styles)
|
||||||
|
|
||||||
@ -22,7 +22,7 @@ export default function FileIcon({
|
|||||||
small,
|
small,
|
||||||
isLoading
|
isLoading
|
||||||
}: {
|
}: {
|
||||||
file: FileMetadata
|
file: FileInfo
|
||||||
className?: string
|
className?: string
|
||||||
small?: boolean
|
small?: boolean
|
||||||
isLoading?: boolean
|
isLoading?: boolean
|
||||||
|
@ -2,13 +2,13 @@ import React, { ReactElement } from 'react'
|
|||||||
import { prettySize } from './utils'
|
import { prettySize } from './utils'
|
||||||
import cleanupContentType from '@utils/cleanupContentType'
|
import cleanupContentType from '@utils/cleanupContentType'
|
||||||
import styles from './Info.module.css'
|
import styles from './Info.module.css'
|
||||||
import { FileMetadata } from '@oceanprotocol/lib'
|
import { FileInfo as FileInfoData } from '@oceanprotocol/lib'
|
||||||
|
|
||||||
export default function FileInfo({
|
export default function FileInfo({
|
||||||
file,
|
file,
|
||||||
handleClose
|
handleClose
|
||||||
}: {
|
}: {
|
||||||
file: FileMetadata
|
file: FileInfoData
|
||||||
handleClose(): void
|
handleClose(): void
|
||||||
}): ReactElement {
|
}): ReactElement {
|
||||||
const contentTypeCleaned = file.contentType
|
const contentTypeCleaned = file.contentType
|
||||||
|
@ -39,15 +39,10 @@ function getTitle(row: PoolTransaction, locale: string) {
|
|||||||
case 'SETUP': {
|
case 'SETUP': {
|
||||||
const firstToken = row.baseToken
|
const firstToken = row.baseToken
|
||||||
const firstTokenSymbol = firstToken?.symbol
|
const firstTokenSymbol = firstToken?.symbol
|
||||||
const secondToken = row.datatoken
|
|
||||||
const secondTokenSymbol = secondToken?.symbol
|
|
||||||
title += `Create pool with ${formatPrice(
|
title += `Create pool with ${formatPrice(
|
||||||
Math.abs(row.baseTokenValue).toString(),
|
Math.abs(row.baseTokenValue).toString(),
|
||||||
locale
|
locale
|
||||||
)}${firstTokenSymbol} and ${formatPrice(
|
)}${firstTokenSymbol}`
|
||||||
Math.abs(row.datatokenValue).toString(),
|
|
||||||
locale
|
|
||||||
)}${secondTokenSymbol}`
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
case 'JOIN':
|
case 'JOIN':
|
||||||
|
@ -187,7 +187,7 @@ export default function PoolTransactions({
|
|||||||
poolTransactions.push({
|
poolTransactions.push({
|
||||||
...data[i],
|
...data[i],
|
||||||
networkId: !minimal
|
networkId: !minimal
|
||||||
? getAsset(ddoList, data[i].pool.datatoken.id).chainId
|
? getAsset(ddoList, data[i].pool.datatoken.id)?.chainId
|
||||||
: poolChainId,
|
: poolChainId,
|
||||||
asset: !minimal ? getAsset(ddoList, data[i].pool.datatoken.id) : null
|
asset: !minimal ? getAsset(ddoList, data[i].pool.datatoken.id) : null
|
||||||
})
|
})
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
import React, { ReactElement } from 'react'
|
import React, { ReactElement, ReactNode } from 'react'
|
||||||
import styles from './index.module.css'
|
import styles from './index.module.css'
|
||||||
import classNames from 'classnames/bind'
|
import classNames from 'classnames/bind'
|
||||||
|
|
||||||
const cx = classNames.bind(styles)
|
const cx = classNames.bind(styles)
|
||||||
|
|
||||||
export interface BadgeProps {
|
export interface BadgeProps {
|
||||||
label: string
|
label: string | ReactNode
|
||||||
className?: string
|
className?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,15 +20,6 @@
|
|||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.button:first-child {
|
|
||||||
margin-left: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.button:last-child {
|
|
||||||
margin-right: 0;
|
|
||||||
min-width: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.button:hover,
|
.button:hover,
|
||||||
.button:focus {
|
.button:focus {
|
||||||
color: var(--brand-white);
|
color: var(--brand-white);
|
||||||
@ -82,11 +73,6 @@
|
|||||||
min-width: auto;
|
min-width: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.center {
|
|
||||||
margin: auto !important;
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Size Modifiers */
|
/* Size Modifiers */
|
||||||
.small {
|
.small {
|
||||||
font-size: var(--font-size-small);
|
font-size: var(--font-size-small);
|
||||||
|
@ -23,6 +23,11 @@
|
|||||||
margin-left: calc(var(--spacer) / 4);
|
margin-left: calc(var(--spacer) / 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.loader.white {
|
||||||
|
border-color: rgba(255 255 255 / 0.3);
|
||||||
|
border-top-color: var(--brand-white);
|
||||||
|
}
|
||||||
|
|
||||||
@keyframes loader {
|
@keyframes loader {
|
||||||
to {
|
to {
|
||||||
transform: rotate(360deg);
|
transform: rotate(360deg);
|
||||||
|
@ -3,12 +3,13 @@ import styles from './index.module.css'
|
|||||||
|
|
||||||
export interface LoaderProps {
|
export interface LoaderProps {
|
||||||
message?: string
|
message?: string
|
||||||
|
white?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function Loader({ message }: LoaderProps): ReactElement {
|
export default function Loader({ message, white }: LoaderProps): ReactElement {
|
||||||
return (
|
return (
|
||||||
<div className={styles.loaderWrap}>
|
<div className={styles.loaderWrap}>
|
||||||
<span className={styles.loader} />
|
<span className={`${styles.loader} ${white ? styles.white : ''}`} />
|
||||||
{message && <span className={styles.message}>{message}</span>}
|
{message && <span className={styles.message}>{message}</span>}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
@ -8,8 +8,7 @@ import AnnouncementBanner from '@shared/AnnouncementBanner'
|
|||||||
import PrivacyPreferenceCenter from '../Privacy/PrivacyPreferenceCenter'
|
import PrivacyPreferenceCenter from '../Privacy/PrivacyPreferenceCenter'
|
||||||
import styles from './index.module.css'
|
import styles from './index.module.css'
|
||||||
import { ToastContainer } from 'react-toastify'
|
import { ToastContainer } from 'react-toastify'
|
||||||
import { useRouter } from 'next/router'
|
import contentPurgatory from '../../../content/purgatory.json'
|
||||||
import content from '../../../content/purgatory.json'
|
|
||||||
import { useMarketMetadata } from '@context/MarketMetadata'
|
import { useMarketMetadata } from '@context/MarketMetadata'
|
||||||
|
|
||||||
export default function App({
|
export default function App({
|
||||||
@ -17,24 +16,22 @@ export default function App({
|
|||||||
}: {
|
}: {
|
||||||
children: ReactElement
|
children: ReactElement
|
||||||
}): ReactElement {
|
}): ReactElement {
|
||||||
const router = useRouter()
|
|
||||||
|
|
||||||
const { siteContent, appConfig } = useMarketMetadata()
|
const { siteContent, appConfig } = useMarketMetadata()
|
||||||
const { accountId } = useWeb3()
|
const { accountId } = useWeb3()
|
||||||
const { isInPurgatory, purgatoryData } = useAccountPurgatory(accountId)
|
const { isInPurgatory, purgatoryData } = useAccountPurgatory(accountId)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.app}>
|
<div className={styles.app}>
|
||||||
{router.pathname === '/' && siteContent?.warning.main !== '' && (
|
{siteContent?.announcement !== '' && (
|
||||||
<AnnouncementBanner text={siteContent?.warning.main} />
|
<AnnouncementBanner text={siteContent?.announcement} />
|
||||||
)}
|
)}
|
||||||
<Header />
|
<Header />
|
||||||
|
|
||||||
{isInPurgatory && (
|
{isInPurgatory && (
|
||||||
<Alert
|
<Alert
|
||||||
title={content.account.title}
|
title={contentPurgatory.account.title}
|
||||||
badge={`Reason: ${purgatoryData?.reason}`}
|
badge={`Reason: ${purgatoryData?.reason}`}
|
||||||
text={content.account.description}
|
text={contentPurgatory.account.description}
|
||||||
state="error"
|
state="error"
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
@ -22,3 +22,7 @@
|
|||||||
border-right: 0;
|
border-right: 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.warning {
|
||||||
|
margin-bottom: var(--spacer);
|
||||||
|
}
|
||||||
|
@ -18,6 +18,8 @@ import {
|
|||||||
import { AssetExtended } from 'src/@types/AssetExtended'
|
import { AssetExtended } from 'src/@types/AssetExtended'
|
||||||
import Decimal from 'decimal.js'
|
import Decimal from 'decimal.js'
|
||||||
import { MAX_DECIMALS } from '@utils/constants'
|
import { MAX_DECIMALS } from '@utils/constants'
|
||||||
|
import { useMarketMetadata } from '@context/MarketMetadata'
|
||||||
|
import Alert from '@shared/atoms/Alert'
|
||||||
import { getDummyWeb3 } from '@utils/web3'
|
import { getDummyWeb3 } from '@utils/web3'
|
||||||
|
|
||||||
export default function FormStartCompute({
|
export default function FormStartCompute({
|
||||||
@ -45,7 +47,9 @@ export default function FormStartCompute({
|
|||||||
isConsumable,
|
isConsumable,
|
||||||
consumableFeedback,
|
consumableFeedback,
|
||||||
datasetOrderPriceAndFees,
|
datasetOrderPriceAndFees,
|
||||||
algoOrderPriceAndFees
|
algoOrderPriceAndFees,
|
||||||
|
providerFeeAmount,
|
||||||
|
validUntil
|
||||||
}: {
|
}: {
|
||||||
algorithms: AssetSelectionAsset[]
|
algorithms: AssetSelectionAsset[]
|
||||||
ddoListAlgorithms: Asset[]
|
ddoListAlgorithms: Asset[]
|
||||||
@ -72,7 +76,10 @@ export default function FormStartCompute({
|
|||||||
consumableFeedback: string
|
consumableFeedback: string
|
||||||
datasetOrderPriceAndFees?: OrderPriceAndFees
|
datasetOrderPriceAndFees?: OrderPriceAndFees
|
||||||
algoOrderPriceAndFees?: OrderPriceAndFees
|
algoOrderPriceAndFees?: OrderPriceAndFees
|
||||||
|
providerFeeAmount?: string
|
||||||
|
validUntil?: string
|
||||||
}): ReactElement {
|
}): ReactElement {
|
||||||
|
const { siteContent } = useMarketMetadata()
|
||||||
const { isValid, values }: FormikContextType<{ algorithm: string }> =
|
const { isValid, values }: FormikContextType<{ algorithm: string }> =
|
||||||
useFormikContext()
|
useFormikContext()
|
||||||
const { asset, isAssetNetwork } = useAsset()
|
const { asset, isAssetNetwork } = useAsset()
|
||||||
@ -140,8 +147,12 @@ export default function FormStartCompute({
|
|||||||
algoOrderPriceAndFees?.price ||
|
algoOrderPriceAndFees?.price ||
|
||||||
selectedAlgorithmAsset.accessDetails.price
|
selectedAlgorithmAsset.accessDetails.price
|
||||||
).toDecimalPlaces(MAX_DECIMALS)
|
).toDecimalPlaces(MAX_DECIMALS)
|
||||||
|
const providerFees = providerFeeAmount
|
||||||
|
? new Decimal(providerFeeAmount).toDecimalPlaces(MAX_DECIMALS)
|
||||||
|
: new Decimal(0)
|
||||||
const totalPrice = priceDataset
|
const totalPrice = priceDataset
|
||||||
.plus(priceAlgo)
|
.plus(priceAlgo)
|
||||||
|
.plus(providerFees)
|
||||||
.toDecimalPlaces(MAX_DECIMALS)
|
.toDecimalPlaces(MAX_DECIMALS)
|
||||||
.toString()
|
.toString()
|
||||||
|
|
||||||
@ -166,6 +177,11 @@ export default function FormStartCompute({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Form className={styles.form}>
|
<Form className={styles.form}>
|
||||||
|
<Alert
|
||||||
|
className={styles.warning}
|
||||||
|
state="info"
|
||||||
|
text={siteContent.warning.ctd}
|
||||||
|
/>
|
||||||
{content.form.data.map((field: FormFieldContent) => (
|
{content.form.data.map((field: FormFieldContent) => (
|
||||||
<Field
|
<Field
|
||||||
key={field.name}
|
key={field.name}
|
||||||
@ -190,6 +206,8 @@ export default function FormStartCompute({
|
|||||||
totalPrice={totalPrice}
|
totalPrice={totalPrice}
|
||||||
datasetOrderPrice={datasetOrderPrice}
|
datasetOrderPrice={datasetOrderPrice}
|
||||||
algoOrderPrice={algoOrderPrice}
|
algoOrderPrice={algoOrderPrice}
|
||||||
|
providerFeeAmount={providerFeeAmount}
|
||||||
|
validUntil={validUntil}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<ButtonBuy
|
<ButtonBuy
|
||||||
@ -230,6 +248,7 @@ export default function FormStartCompute({
|
|||||||
selectedAlgorithmAsset?.accessDetails?.isPurchasable
|
selectedAlgorithmAsset?.accessDetails?.isPurchasable
|
||||||
}
|
}
|
||||||
isSupportedOceanNetwork={isSupportedOceanNetwork}
|
isSupportedOceanNetwork={isSupportedOceanNetwork}
|
||||||
|
hasProviderFee={providerFeeAmount && providerFeeAmount !== '0'}
|
||||||
/>
|
/>
|
||||||
</Form>
|
</Form>
|
||||||
)
|
)
|
||||||
|
@ -36,8 +36,10 @@
|
|||||||
border-bottom: 1px solid var(--border-color);
|
border-bottom: 1px solid var(--border-color);
|
||||||
padding-top: calc(var(--spacer) / 7);
|
padding-top: calc(var(--spacer) / 7);
|
||||||
padding-bottom: calc(var(--spacer) / 7);
|
padding-bottom: calc(var(--spacer) / 7);
|
||||||
display: flex;
|
display: grid;
|
||||||
justify-content: space-between;
|
grid-template-columns: 5% 1fr auto;
|
||||||
|
column-gap: calc(var(--spacer) / 10);
|
||||||
|
/* justify-content: space-between; */
|
||||||
}
|
}
|
||||||
|
|
||||||
.priceRow:last-child {
|
.priceRow:last-child {
|
||||||
@ -47,8 +49,14 @@
|
|||||||
|
|
||||||
.sign {
|
.sign {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
width: 5%;
|
|
||||||
text-align: left;
|
text-align: left;
|
||||||
color: var(--color-secondary);
|
color: var(--color-secondary);
|
||||||
font-size: var(--font-size-base);
|
font-size: var(--font-size-base);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.type {
|
||||||
|
display: inline-block;
|
||||||
|
text-align: left;
|
||||||
|
color: var(--color-secondary);
|
||||||
|
font-size: var(--font-size-mini);
|
||||||
|
}
|
||||||
|
@ -19,6 +19,8 @@ interface PriceOutputProps {
|
|||||||
selectedComputeAssetTimeout: string
|
selectedComputeAssetTimeout: string
|
||||||
datasetOrderPrice?: number
|
datasetOrderPrice?: number
|
||||||
algoOrderPrice?: number
|
algoOrderPrice?: number
|
||||||
|
providerFeeAmount?: string
|
||||||
|
validUntil?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
function Row({
|
function Row({
|
||||||
@ -27,7 +29,8 @@ function Row({
|
|||||||
hasDatatoken,
|
hasDatatoken,
|
||||||
symbol,
|
symbol,
|
||||||
timeout,
|
timeout,
|
||||||
sign
|
sign,
|
||||||
|
type
|
||||||
}: {
|
}: {
|
||||||
price: string
|
price: string
|
||||||
hasPreviousOrder?: boolean
|
hasPreviousOrder?: boolean
|
||||||
@ -35,10 +38,12 @@ function Row({
|
|||||||
symbol?: string
|
symbol?: string
|
||||||
timeout?: string
|
timeout?: string
|
||||||
sign?: string
|
sign?: string
|
||||||
|
type?: string
|
||||||
}) {
|
}) {
|
||||||
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>
|
<div>
|
||||||
<PriceUnit
|
<PriceUnit
|
||||||
price={hasPreviousOrder || hasDatatoken ? '0' : `${price}`}
|
price={hasPreviousOrder || hasDatatoken ? '0' : `${price}`}
|
||||||
@ -68,7 +73,9 @@ export default function PriceOutput({
|
|||||||
algorithmConsumeDetails,
|
algorithmConsumeDetails,
|
||||||
selectedComputeAssetTimeout,
|
selectedComputeAssetTimeout,
|
||||||
datasetOrderPrice,
|
datasetOrderPrice,
|
||||||
algoOrderPrice
|
algoOrderPrice,
|
||||||
|
providerFeeAmount,
|
||||||
|
validUntil
|
||||||
}: PriceOutputProps): ReactElement {
|
}: PriceOutputProps): ReactElement {
|
||||||
const { asset } = useAsset()
|
const { asset } = useAsset()
|
||||||
|
|
||||||
@ -89,6 +96,7 @@ export default function PriceOutput({
|
|||||||
.toString()}
|
.toString()}
|
||||||
timeout={assetTimeout}
|
timeout={assetTimeout}
|
||||||
symbol={symbol}
|
symbol={symbol}
|
||||||
|
type="DATASET"
|
||||||
/>
|
/>
|
||||||
<Row
|
<Row
|
||||||
hasPreviousOrder={hasPreviousOrderSelectedComputeAsset}
|
hasPreviousOrder={hasPreviousOrderSelectedComputeAsset}
|
||||||
@ -101,6 +109,14 @@ export default function PriceOutput({
|
|||||||
timeout={selectedComputeAssetTimeout}
|
timeout={selectedComputeAssetTimeout}
|
||||||
symbol={symbol}
|
symbol={symbol}
|
||||||
sign="+"
|
sign="+"
|
||||||
|
type="ALGORITHM"
|
||||||
|
/>
|
||||||
|
<Row
|
||||||
|
price={providerFeeAmount} // initializeCompute.provider fee amount
|
||||||
|
timeout={`${validUntil} seconds`} // valid until value
|
||||||
|
symbol={symbol}
|
||||||
|
sign="+"
|
||||||
|
type="C2D RESOURCES"
|
||||||
/>
|
/>
|
||||||
<Row price={totalPrice} symbol={symbol} sign="=" />
|
<Row price={totalPrice} symbol={symbol} sign="=" />
|
||||||
</div>
|
</div>
|
||||||
|
@ -2,7 +2,7 @@ import React, { useState, ReactElement, useEffect, useCallback } from 'react'
|
|||||||
import {
|
import {
|
||||||
Asset,
|
Asset,
|
||||||
DDO,
|
DDO,
|
||||||
FileMetadata,
|
FileInfo,
|
||||||
Datatoken,
|
Datatoken,
|
||||||
ProviderInstance,
|
ProviderInstance,
|
||||||
ComputeAsset,
|
ComputeAsset,
|
||||||
@ -11,7 +11,8 @@ import {
|
|||||||
LoggerInstance,
|
LoggerInstance,
|
||||||
ComputeAlgorithm,
|
ComputeAlgorithm,
|
||||||
ComputeOutput,
|
ComputeOutput,
|
||||||
ProviderComputeInitializeResults
|
ProviderComputeInitializeResults,
|
||||||
|
unitsToAmount
|
||||||
} from '@oceanprotocol/lib'
|
} from '@oceanprotocol/lib'
|
||||||
import { toast } from 'react-toastify'
|
import { toast } from 'react-toastify'
|
||||||
import Price from '@shared/Price'
|
import Price from '@shared/Price'
|
||||||
@ -59,7 +60,7 @@ export default function Compute({
|
|||||||
}: {
|
}: {
|
||||||
asset: AssetExtended
|
asset: AssetExtended
|
||||||
dtBalance: string
|
dtBalance: string
|
||||||
file: FileMetadata
|
file: FileInfo
|
||||||
fileIsLoading?: boolean
|
fileIsLoading?: boolean
|
||||||
isConsumable?: boolean
|
isConsumable?: boolean
|
||||||
consumableFeedback?: string
|
consumableFeedback?: string
|
||||||
@ -94,7 +95,8 @@ export default function Compute({
|
|||||||
const [computeEnv, setComputeEnv] = useState<ComputeEnvironment>()
|
const [computeEnv, setComputeEnv] = useState<ComputeEnvironment>()
|
||||||
const [initializedProviderResponse, setInitializedProviderResponse] =
|
const [initializedProviderResponse, setInitializedProviderResponse] =
|
||||||
useState<ProviderComputeInitializeResults>()
|
useState<ProviderComputeInitializeResults>()
|
||||||
// const [computeValidUntil, setComputeValidUntil] = useState<number>()
|
const [providerFeeAmount, setProviderFeeAmount] = useState<string>('0')
|
||||||
|
const [computeValidUntil, setComputeValidUntil] = useState<string>('0')
|
||||||
const [datasetOrderPriceAndFees, setDatasetOrderPriceAndFees] =
|
const [datasetOrderPriceAndFees, setDatasetOrderPriceAndFees] =
|
||||||
useState<OrderPriceAndFees>()
|
useState<OrderPriceAndFees>()
|
||||||
const [isRequestingDataseOrderPrice, setIsRequestingDataseOrderPrice] =
|
const [isRequestingDataseOrderPrice, setIsRequestingDataseOrderPrice] =
|
||||||
@ -147,7 +149,18 @@ export default function Compute({
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
setInitializedProviderResponse(initializedProvider)
|
setInitializedProviderResponse(initializedProvider)
|
||||||
|
setProviderFeeAmount(
|
||||||
|
await unitsToAmount(
|
||||||
|
web3,
|
||||||
|
initializedProvider?.datasets?.[0]?.providerFee?.providerFeeToken,
|
||||||
|
initializedProvider?.datasets?.[0]?.providerFee?.providerFeeAmount
|
||||||
|
)
|
||||||
|
)
|
||||||
|
const computeDuration = (
|
||||||
|
parseInt(initializedProvider?.datasets?.[0]?.providerFee?.validUntil) -
|
||||||
|
Math.floor(Date.now() / 1000)
|
||||||
|
).toString()
|
||||||
|
setComputeValidUntil(computeDuration)
|
||||||
if (
|
if (
|
||||||
asset?.accessDetails?.addressOrId !== ZERO_ADDRESS &&
|
asset?.accessDetails?.addressOrId !== ZERO_ADDRESS &&
|
||||||
asset?.accessDetails?.type !== 'free' &&
|
asset?.accessDetails?.type !== 'free' &&
|
||||||
@ -258,6 +271,7 @@ export default function Compute({
|
|||||||
setValidAlgorithmOrderTx(
|
setValidAlgorithmOrderTx(
|
||||||
selectedAlgorithmAsset?.accessDetails?.validOrderTx
|
selectedAlgorithmAsset?.accessDetails?.validOrderTx
|
||||||
)
|
)
|
||||||
|
setAlgoOrderPriceAndFees(null)
|
||||||
|
|
||||||
async function initSelectedAlgo() {
|
async function initSelectedAlgo() {
|
||||||
await checkAssetDTBalance(selectedAlgorithmAsset)
|
await checkAssetDTBalance(selectedAlgorithmAsset)
|
||||||
@ -479,6 +493,8 @@ export default function Compute({
|
|||||||
consumableFeedback={consumableFeedback}
|
consumableFeedback={consumableFeedback}
|
||||||
datasetOrderPriceAndFees={datasetOrderPriceAndFees}
|
datasetOrderPriceAndFees={datasetOrderPriceAndFees}
|
||||||
algoOrderPriceAndFees={algoOrderPriceAndFees}
|
algoOrderPriceAndFees={algoOrderPriceAndFees}
|
||||||
|
providerFeeAmount={providerFeeAmount}
|
||||||
|
validUntil={computeValidUntil}
|
||||||
/>
|
/>
|
||||||
</Formik>
|
</Formik>
|
||||||
)}
|
)}
|
||||||
|
@ -7,7 +7,7 @@ import ButtonBuy from '@shared/ButtonBuy'
|
|||||||
import { secondsToString } from '@utils/ddo'
|
import { secondsToString } from '@utils/ddo'
|
||||||
import AlgorithmDatasetsListForCompute from './Compute/AlgorithmDatasetsListForCompute'
|
import AlgorithmDatasetsListForCompute from './Compute/AlgorithmDatasetsListForCompute'
|
||||||
import styles from './Download.module.css'
|
import styles from './Download.module.css'
|
||||||
import { FileMetadata, LoggerInstance, ZERO_ADDRESS } from '@oceanprotocol/lib'
|
import { FileInfo, LoggerInstance, ZERO_ADDRESS } from '@oceanprotocol/lib'
|
||||||
import { order } from '@utils/order'
|
import { order } from '@utils/order'
|
||||||
import { AssetExtended } from 'src/@types/AssetExtended'
|
import { AssetExtended } from 'src/@types/AssetExtended'
|
||||||
import { buyDtFromPool } from '@utils/pool'
|
import { buyDtFromPool } from '@utils/pool'
|
||||||
@ -29,7 +29,7 @@ export default function Download({
|
|||||||
consumableFeedback
|
consumableFeedback
|
||||||
}: {
|
}: {
|
||||||
asset: AssetExtended
|
asset: AssetExtended
|
||||||
file: FileMetadata
|
file: FileInfo
|
||||||
isBalanceSufficient: boolean
|
isBalanceSufficient: boolean
|
||||||
dtBalance: string
|
dtBalance: string
|
||||||
fileIsLoading?: boolean
|
fileIsLoading?: boolean
|
||||||
|
@ -149,7 +149,7 @@ export default function Add({
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Output newPoolTokens={newPoolTokens} newPoolShare={newPoolShare} />
|
{/* TODO: will be fixed in #1481 <Output newPoolTokens={newPoolTokens} newPoolShare={newPoolShare} /> */}
|
||||||
|
|
||||||
<Actions
|
<Actions
|
||||||
isDisabled={!isValid || !values.amount || values.amount === 0}
|
isDisabled={!isValid || !values.amount || values.amount === 0}
|
||||||
|
@ -4,8 +4,8 @@
|
|||||||
font-size: var(--font-size-mini);
|
font-size: var(--font-size-mini);
|
||||||
color: var(--color-secondary);
|
color: var(--color-secondary);
|
||||||
text-align: center;
|
text-align: center;
|
||||||
padding-top: calc(var(--spacer) / 4);
|
padding-top: calc(var(--spacer) / 2);
|
||||||
padding-bottom: calc(var(--spacer) / 3);
|
padding-bottom: calc(var(--spacer) / 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
.update:before {
|
.update:before {
|
||||||
|
@ -18,3 +18,18 @@
|
|||||||
margin-left: calc(var(--spacer) / 3);
|
margin-left: calc(var(--spacer) / 3);
|
||||||
margin-right: calc(var(--spacer) / 3);
|
margin-right: calc(var(--spacer) / 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.fees {
|
||||||
|
border-top: none;
|
||||||
|
padding-top: 0;
|
||||||
|
margin-top: -0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fees > div {
|
||||||
|
grid-template-columns: repeat(auto-fit, minmax(5rem, 1fr));
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fees figure {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
@ -110,17 +110,9 @@ export default function PoolSections() {
|
|||||||
titlePostfixTitle={`Weight of ${poolInfo?.weightBaseToken}% ${poolInfo?.baseTokenSymbol} & ${poolInfo?.weightDt}% ${poolInfo?.datatokenSymbol}`}
|
titlePostfixTitle={`Weight of ${poolInfo?.weightBaseToken}% ${poolInfo?.baseTokenSymbol} & ${poolInfo?.weightDt}% ${poolInfo?.datatokenSymbol}`}
|
||||||
>
|
>
|
||||||
<Graph />
|
<Graph />
|
||||||
<Token
|
</PoolSection>
|
||||||
symbol={poolInfo?.baseTokenSymbol}
|
|
||||||
balance={`${poolData?.baseTokenLiquidity}`}
|
|
||||||
size="mini"
|
|
||||||
/>
|
|
||||||
<Token
|
|
||||||
symbol={poolInfo?.datatokenSymbol}
|
|
||||||
balance={`${poolData?.datatokenLiquidity}`}
|
|
||||||
size="mini"
|
|
||||||
/>
|
|
||||||
|
|
||||||
|
<PoolSection className={styles.fees}>
|
||||||
<Token
|
<Token
|
||||||
symbol="% swap fee"
|
symbol="% swap fee"
|
||||||
balance={poolInfo?.liquidityProviderSwapFee}
|
balance={poolInfo?.liquidityProviderSwapFee}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import React, { ReactElement, useState, useEffect } from 'react'
|
import React, { ReactElement, useState, useEffect } from 'react'
|
||||||
import Compute from './Compute'
|
import Compute from './Compute'
|
||||||
import Consume from './Download'
|
import Consume from './Download'
|
||||||
import { FileMetadata, LoggerInstance, Datatoken } from '@oceanprotocol/lib'
|
import { FileInfo, LoggerInstance, Datatoken } from '@oceanprotocol/lib'
|
||||||
import Tabs, { TabsItem } from '@shared/atoms/Tabs'
|
import Tabs, { TabsItem } from '@shared/atoms/Tabs'
|
||||||
import { compareAsBN } from '@utils/numbers'
|
import { compareAsBN } from '@utils/numbers'
|
||||||
import Pool from './Pool'
|
import Pool from './Pool'
|
||||||
@ -37,7 +37,7 @@ export default function AssetActions({
|
|||||||
|
|
||||||
const [isBalanceSufficient, setIsBalanceSufficient] = useState<boolean>()
|
const [isBalanceSufficient, setIsBalanceSufficient] = useState<boolean>()
|
||||||
const [dtBalance, setDtBalance] = useState<string>()
|
const [dtBalance, setDtBalance] = useState<string>()
|
||||||
const [fileMetadata, setFileMetadata] = useState<FileMetadata>()
|
const [fileMetadata, setFileMetadata] = useState<FileInfo>()
|
||||||
const [fileIsLoading, setFileIsLoading] = useState<boolean>(false)
|
const [fileIsLoading, setFileIsLoading] = useState<boolean>(false)
|
||||||
const isCompute = Boolean(
|
const isCompute = Boolean(
|
||||||
asset?.services.filter((service) => service.type === 'compute')[0]
|
asset?.services.filter((service) => service.type === 'compute')[0]
|
||||||
|
@ -5,13 +5,14 @@ import AddToken from '@shared/AddToken'
|
|||||||
import ExplorerLink from '@shared/ExplorerLink'
|
import ExplorerLink from '@shared/ExplorerLink'
|
||||||
import Publisher from '@shared/Publisher'
|
import Publisher from '@shared/Publisher'
|
||||||
import React, { ReactElement } from 'react'
|
import React, { ReactElement } from 'react'
|
||||||
|
import { AssetExtended } from 'src/@types/AssetExtended'
|
||||||
import styles from './MetaAsset.module.css'
|
import styles from './MetaAsset.module.css'
|
||||||
|
|
||||||
export default function MetaAsset({
|
export default function MetaAsset({
|
||||||
asset,
|
asset,
|
||||||
isBlockscoutExplorer
|
isBlockscoutExplorer
|
||||||
}: {
|
}: {
|
||||||
asset: Asset
|
asset: AssetExtended
|
||||||
isBlockscoutExplorer: boolean
|
isBlockscoutExplorer: boolean
|
||||||
}): ReactElement {
|
}): ReactElement {
|
||||||
const { isAssetNetwork } = useAsset()
|
const { isAssetNetwork } = useAsset()
|
||||||
|
@ -1,16 +1,17 @@
|
|||||||
import { Asset } from '@oceanprotocol/lib'
|
import { useAsset } from '@context/Asset'
|
||||||
import AssetType from '@shared/AssetType'
|
import AssetType from '@shared/AssetType'
|
||||||
import Time from '@shared/atoms/Time'
|
import Time from '@shared/atoms/Time'
|
||||||
import Publisher from '@shared/Publisher'
|
import Publisher from '@shared/Publisher'
|
||||||
import { getServiceByName } from '@utils/ddo'
|
import { getServiceByName } from '@utils/ddo'
|
||||||
import React, { ReactElement } from 'react'
|
import React, { ReactElement } from 'react'
|
||||||
|
import { AssetExtended } from 'src/@types/AssetExtended'
|
||||||
import styles from './MetaInfo.module.css'
|
import styles from './MetaInfo.module.css'
|
||||||
|
|
||||||
export default function MetaInfo({
|
export default function MetaInfo({
|
||||||
asset,
|
asset,
|
||||||
nftPublisher
|
nftPublisher
|
||||||
}: {
|
}: {
|
||||||
asset: Asset
|
asset: AssetExtended
|
||||||
nftPublisher: string
|
nftPublisher: string
|
||||||
}): ReactElement {
|
}): ReactElement {
|
||||||
const isCompute = Boolean(getServiceByName(asset, 'compute'))
|
const isCompute = Boolean(getServiceByName(asset, 'compute'))
|
||||||
|
@ -13,32 +13,3 @@
|
|||||||
height: calc(var(--spacer) * 2);
|
height: calc(var(--spacer) * 2);
|
||||||
border-bottom: 1px solid var(--border-color);
|
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);
|
|
||||||
}
|
|
||||||
|
@ -1,14 +1,11 @@
|
|||||||
import React, { ReactElement } from 'react'
|
import React, { ReactElement } from 'react'
|
||||||
import styles from './index.module.css'
|
import styles from './index.module.css'
|
||||||
import { AssetExtended } from 'src/@types/AssetExtended'
|
|
||||||
import { decodeTokenURI } from '@utils/nft'
|
|
||||||
import MetaAsset from './MetaAsset'
|
import MetaAsset from './MetaAsset'
|
||||||
import MetaInfo from './MetaInfo'
|
import MetaInfo from './MetaInfo'
|
||||||
import Tooltip from '@shared/atoms/Tooltip'
|
import Nft from '../Nft'
|
||||||
import NftTooltip from './NftTooltip'
|
import { AssetExtended } from 'src/@types/AssetExtended'
|
||||||
import Logo from '@shared/atoms/Logo'
|
|
||||||
import { FormPublishData } from '../../../Publish/_types'
|
const blockscoutNetworks = [1287, 2021000, 2021001, 44787, 246, 1285]
|
||||||
import { useFormikContext } from 'formik'
|
|
||||||
|
|
||||||
export default function MetaMain({
|
export default function MetaMain({
|
||||||
asset,
|
asset,
|
||||||
@ -17,51 +14,12 @@ export default function MetaMain({
|
|||||||
asset: AssetExtended
|
asset: AssetExtended
|
||||||
nftPublisher: string
|
nftPublisher: string
|
||||||
}): ReactElement {
|
}): ReactElement {
|
||||||
const nftMetadata = decodeTokenURI(asset?.nft?.tokenURI)
|
|
||||||
|
|
||||||
const blockscoutNetworks = [1287, 2021000, 2021001, 44787, 246, 1285]
|
|
||||||
const isBlockscoutExplorer = blockscoutNetworks.includes(asset?.chainId)
|
const isBlockscoutExplorer = blockscoutNetworks.includes(asset?.chainId)
|
||||||
|
|
||||||
// TODO: using this for the publish preview works fine, but produces a console warning
|
|
||||||
// on asset details page as there is no formik context there:
|
|
||||||
// Warning: Formik context is undefined, please verify you are calling useFormikContext()
|
|
||||||
// as child of a <Formik> component.
|
|
||||||
const formikState = useFormikContext<FormPublishData>()
|
|
||||||
|
|
||||||
// checking if the NFT has an image associated (tokenURI)
|
|
||||||
// if tokenURI is undefined, then we are in Preview
|
|
||||||
// for Preview we need to show accessDetails.dataImage
|
|
||||||
// as this is where the NFT's SVG (during publish) is stored
|
|
||||||
const nftImage = nftMetadata?.image_data
|
|
||||||
? nftMetadata.image_data
|
|
||||||
: formikState?.values?.metadata?.nft?.image_data
|
|
||||||
? formikState.values.metadata.nft.image_data
|
|
||||||
: null
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<aside className={styles.meta}>
|
<aside className={styles.meta}>
|
||||||
<header className={styles.asset}>
|
<header className={styles.asset}>
|
||||||
<div className={styles.nftImage}>
|
<Nft isBlockscoutExplorer={isBlockscoutExplorer} />
|
||||||
{nftImage ? (
|
|
||||||
<img src={nftImage} 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} />
|
<MetaAsset asset={asset} isBlockscoutExplorer={isBlockscoutExplorer} />
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
|
@ -7,6 +7,11 @@ import styles from './NftTooltip.module.css'
|
|||||||
import explorerLinkStyles from '@shared/ExplorerLink/index.module.css'
|
import explorerLinkStyles from '@shared/ExplorerLink/index.module.css'
|
||||||
import { accountTruncate } from '@utils/web3'
|
import { accountTruncate } from '@utils/web3'
|
||||||
|
|
||||||
|
// Supported OpenSea networks:
|
||||||
|
// https://support.opensea.io/hc/en-us/articles/4404027708051-Which-blockchains-does-OpenSea-support-
|
||||||
|
const openSeaNetworks = [1, 137]
|
||||||
|
const openSeaTestNetworks = [4]
|
||||||
|
|
||||||
export default function NftTooltip({
|
export default function NftTooltip({
|
||||||
nft,
|
nft,
|
||||||
address,
|
address,
|
||||||
@ -18,26 +23,23 @@ export default function NftTooltip({
|
|||||||
chainId: number
|
chainId: number
|
||||||
isBlockscoutExplorer: boolean
|
isBlockscoutExplorer: boolean
|
||||||
}): ReactElement {
|
}): ReactElement {
|
||||||
// Currently Ocean NFTs are not displayed correctly on OpenSea
|
const openSeaSupported = openSeaNetworks
|
||||||
// Code prepared to easily integrate this feature once this is fixed
|
.concat(openSeaTestNetworks)
|
||||||
//
|
|
||||||
// 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)
|
.includes(chainId)
|
||||||
|
|
||||||
const openSeaBaseUri = openSeaSupported
|
const openSeaBaseUri = openSeaSupported
|
||||||
? openseaTestNetworks.includes(chainId)
|
? openSeaTestNetworks.includes(chainId)
|
||||||
? 'https://testnets.opensea.io'
|
? 'https://testnets.opensea.io'
|
||||||
: 'https://opensea.io'
|
: 'https://opensea.io'
|
||||||
: undefined
|
: undefined
|
||||||
|
|
||||||
|
const openSeaUrl = `${openSeaBaseUri}/assets/${
|
||||||
|
chainId === 137 ? 'matic' : ''
|
||||||
|
}/${address}/1`
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.wrapper}>
|
<div className={styles.wrapper}>
|
||||||
{nft && <img src={nft.image_data} alt={nft?.name} />}
|
{nft && <img src={nft.image_data || nft.image} alt={nft?.name} />}
|
||||||
<div className={styles.info}>
|
<div className={styles.info}>
|
||||||
{nft && <h5>{nft.name}</h5>}
|
{nft && <h5>{nft.name}</h5>}
|
||||||
{address && (
|
{address && (
|
||||||
@ -53,25 +55,23 @@ export default function NftTooltip({
|
|||||||
isBlockscoutExplorer ? `tokens/${address}` : `token/${address}`
|
isBlockscoutExplorer ? `tokens/${address}` : `token/${address}`
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
View on explorer
|
View on Explorer
|
||||||
</ExplorerLink>
|
</ExplorerLink>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{openSeaSupported && nft && address && (
|
{openSeaSupported && address && (
|
||||||
<a
|
<a
|
||||||
href={`${openSeaBaseUri}/assets/${address}/1`}
|
href={openSeaUrl}
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noreferrer"
|
rel="noreferrer"
|
||||||
className={explorerLinkStyles.link}
|
className={explorerLinkStyles.link}
|
||||||
>
|
>
|
||||||
View on OpeanSea <External />
|
View on OpenSea <External />
|
||||||
</a>
|
</a>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
{!nft?.image_data && (
|
{!nft?.image_data && !nft?.image && (
|
||||||
<p className={styles.fallback}>
|
<p className={styles.fallback}>This Data NFT has no image set.</p>
|
||||||
This Data NFT was not created on Ocean Market
|
|
||||||
</p>
|
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
28
src/components/Asset/AssetContent/Nft/index.module.css
Normal file
28
src/components/Asset/AssetContent/Nft/index.module.css
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
.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);
|
||||||
|
}
|
60
src/components/Asset/AssetContent/Nft/index.tsx
Normal file
60
src/components/Asset/AssetContent/Nft/index.tsx
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
import { useAsset } from '@context/Asset'
|
||||||
|
import Tooltip from '@shared/atoms/Tooltip'
|
||||||
|
import { decodeTokenURI } from '@utils/nft'
|
||||||
|
import { useFormikContext } from 'formik'
|
||||||
|
import React from 'react'
|
||||||
|
import { FormPublishData } from 'src/components/Publish/_types'
|
||||||
|
import Logo from '@shared/atoms/Logo'
|
||||||
|
import NftTooltip from './NftTooltip'
|
||||||
|
import styles from './index.module.css'
|
||||||
|
|
||||||
|
export default function Nft({
|
||||||
|
isBlockscoutExplorer
|
||||||
|
}: {
|
||||||
|
isBlockscoutExplorer: boolean
|
||||||
|
}) {
|
||||||
|
const { asset } = useAsset()
|
||||||
|
const nftMetadata = decodeTokenURI(asset?.nft?.tokenURI)
|
||||||
|
|
||||||
|
// TODO: using this for the publish preview works fine, but produces a console warning
|
||||||
|
// on asset details page as there is no formik context there:
|
||||||
|
// Warning: Formik context is undefined, please verify you are calling useFormikContext()
|
||||||
|
// as child of a <Formik> component.
|
||||||
|
const formikState = useFormikContext<FormPublishData>()
|
||||||
|
|
||||||
|
// checking if the NFT has an image associated (tokenURI)
|
||||||
|
// if tokenURI is undefined, then we are in Preview
|
||||||
|
// for Preview we need to show accessDetails.dataImage
|
||||||
|
// as this is where the NFT's SVG (during publish) is stored
|
||||||
|
const nftImage = nftMetadata?.image_data
|
||||||
|
? nftMetadata.image_data
|
||||||
|
: nftMetadata?.image
|
||||||
|
? nftMetadata.image
|
||||||
|
: formikState?.values?.metadata?.nft?.image_data
|
||||||
|
? formikState.values.metadata.nft.image_data
|
||||||
|
: null
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={styles.nftImage}>
|
||||||
|
{nftImage ? (
|
||||||
|
<img src={nftImage} 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>
|
||||||
|
)
|
||||||
|
}
|
@ -24,6 +24,7 @@ import EditFeedback from './EditFeedback'
|
|||||||
import { useAsset } from '@context/Asset'
|
import { useAsset } from '@context/Asset'
|
||||||
import { setNftMetadata } from '@utils/nft'
|
import { setNftMetadata } from '@utils/nft'
|
||||||
import { sanitizeUrl } from '@utils/url'
|
import { sanitizeUrl } from '@utils/url'
|
||||||
|
import { getEncryptedFiles } from '@utils/provider'
|
||||||
|
|
||||||
export default function Edit({
|
export default function Edit({
|
||||||
asset
|
asset
|
||||||
@ -64,6 +65,7 @@ export default function Edit({
|
|||||||
resetForm: () => void
|
resetForm: () => void
|
||||||
) {
|
) {
|
||||||
try {
|
try {
|
||||||
|
let updatedFiles = asset.services[0].files
|
||||||
const linksTransformed = values.links?.length &&
|
const linksTransformed = values.links?.length &&
|
||||||
values.links[0].valid && [sanitizeUrl(values.links[0].url)]
|
values.links[0].valid && [sanitizeUrl(values.links[0].url)]
|
||||||
const updatedMetadata: Metadata = {
|
const updatedMetadata: Metadata = {
|
||||||
@ -78,17 +80,43 @@ export default function Edit({
|
|||||||
values.price !== asset.accessDetails.price &&
|
values.price !== asset.accessDetails.price &&
|
||||||
(await updateFixedPrice(values.price))
|
(await updateFixedPrice(values.price))
|
||||||
|
|
||||||
|
if (values.files[0]?.url) {
|
||||||
|
const file = {
|
||||||
|
nftAddress: asset.nftAddress,
|
||||||
|
datatokenAddress: asset.services[0].datatokenAddress,
|
||||||
|
files: [
|
||||||
|
{
|
||||||
|
type: 'url',
|
||||||
|
index: 0,
|
||||||
|
url: values.files[0].url,
|
||||||
|
method: 'GET'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
const filesEncrypted = await getEncryptedFiles(
|
||||||
|
file,
|
||||||
|
asset.services[0].serviceEndpoint
|
||||||
|
)
|
||||||
|
updatedFiles = filesEncrypted
|
||||||
|
}
|
||||||
const updatedService: Service = {
|
const updatedService: Service = {
|
||||||
...asset.services[0],
|
...asset.services[0],
|
||||||
timeout: mapTimeoutStringToSeconds(values.timeout)
|
timeout: mapTimeoutStringToSeconds(values.timeout),
|
||||||
|
files: updatedFiles
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: remove version update at a later time
|
||||||
const updatedAsset: Asset = {
|
const updatedAsset: Asset = {
|
||||||
...asset,
|
...(asset as Asset),
|
||||||
|
version: '4.1.0',
|
||||||
metadata: updatedMetadata,
|
metadata: updatedMetadata,
|
||||||
services: [updatedService]
|
services: [updatedService]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// delete custom helper properties injected in the market so we don't write them on chain
|
||||||
|
delete (updatedAsset as AssetExtended).accessDetails
|
||||||
|
delete (updatedAsset as AssetExtended).datatokens
|
||||||
|
delete (updatedAsset as AssetExtended).stats
|
||||||
const setMetadataTx = await setNftMetadata(
|
const setMetadataTx = await setNftMetadata(
|
||||||
updatedAsset,
|
updatedAsset,
|
||||||
accountId,
|
accountId,
|
||||||
|
@ -1,9 +1,8 @@
|
|||||||
import React, { ChangeEvent, ReactElement, useState } from 'react'
|
import React, { ChangeEvent, ReactElement } from 'react'
|
||||||
import { Field, Form, FormikContextType, useFormikContext } from 'formik'
|
import { Field, Form, FormikContextType, useFormikContext } from 'formik'
|
||||||
import Input, { InputProps } from '@shared/FormInput'
|
import Input, { InputProps } from '@shared/FormInput'
|
||||||
import FormActions from './FormActions'
|
import FormActions from './FormActions'
|
||||||
import styles from './FormEdit.module.css'
|
import styles from './FormEdit.module.css'
|
||||||
import { FormPublishData } from '../../Publish/_types'
|
|
||||||
import { useAsset } from '@context/Asset'
|
import { useAsset } from '@context/Asset'
|
||||||
import { MetadataEditForm } from './_types'
|
import { MetadataEditForm } from './_types'
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { Metadata, ServiceComputeOptions } from '@oceanprotocol/lib'
|
import { FileInfo, Metadata, ServiceComputeOptions } from '@oceanprotocol/lib'
|
||||||
import { secondsToString } from '@utils/ddo'
|
import { secondsToString } from '@utils/ddo'
|
||||||
import * as Yup from 'yup'
|
import * as Yup from 'yup'
|
||||||
import { MetadataEditForm } from './_types'
|
import { MetadataEditForm } from './_types'
|
||||||
@ -10,6 +10,7 @@ export const validationSchema = Yup.object().shape({
|
|||||||
description: Yup.string().required('Required').min(10),
|
description: Yup.string().required('Required').min(10),
|
||||||
price: Yup.number().required('Required'),
|
price: Yup.number().required('Required'),
|
||||||
links: Yup.array<any[]>().nullable(),
|
links: Yup.array<any[]>().nullable(),
|
||||||
|
files: Yup.array<FileInfo[]>().nullable(),
|
||||||
timeout: Yup.string().required('Required'),
|
timeout: Yup.string().required('Required'),
|
||||||
author: Yup.string().nullable()
|
author: Yup.string().nullable()
|
||||||
})
|
})
|
||||||
@ -24,6 +25,7 @@ export function getInitialValues(
|
|||||||
description: metadata?.description,
|
description: metadata?.description,
|
||||||
price,
|
price,
|
||||||
links: metadata?.links,
|
links: metadata?.links,
|
||||||
|
files: '',
|
||||||
timeout: secondsToString(timeout),
|
timeout: secondsToString(timeout),
|
||||||
author: metadata?.author
|
author: metadata?.author
|
||||||
}
|
}
|
||||||
|
@ -6,5 +6,6 @@ export interface MetadataEditForm {
|
|||||||
timeout: string
|
timeout: string
|
||||||
price?: string
|
price?: string
|
||||||
links?: string | any[]
|
links?: string | any[]
|
||||||
|
files: string | any[]
|
||||||
author?: string
|
author?: string
|
||||||
}
|
}
|
||||||
|
@ -1,27 +1,33 @@
|
|||||||
import React, { useState, useEffect, ReactElement } from 'react'
|
import React, { useState, useEffect, ReactElement } from 'react'
|
||||||
|
import { useRouter } from 'next/router'
|
||||||
import Page from '@shared/Page'
|
import Page from '@shared/Page'
|
||||||
import Alert from '@shared/atoms/Alert'
|
import Alert from '@shared/atoms/Alert'
|
||||||
import Loader from '@shared/atoms/Loader'
|
import Loader from '@shared/atoms/Loader'
|
||||||
import { useAsset } from '@context/Asset'
|
import { useAsset } from '@context/Asset'
|
||||||
import AssetContent from './AssetContent'
|
import AssetContent from './AssetContent'
|
||||||
|
import { v3MarketUri } from 'app.config'
|
||||||
|
|
||||||
export default function AssetDetails({ uri }: { uri: string }): ReactElement {
|
export default function AssetDetails({ uri }: { uri: string }): ReactElement {
|
||||||
const { asset, title, error, isInPurgatory, loading } = useAsset()
|
const router = useRouter()
|
||||||
|
const { asset, title, error, isInPurgatory, loading, isV3Asset } = useAsset()
|
||||||
const [pageTitle, setPageTitle] = useState<string>()
|
const [pageTitle, setPageTitle] = useState<string>()
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
if (isV3Asset) {
|
||||||
|
router.push(`${v3MarketUri}${uri}`)
|
||||||
|
}
|
||||||
if (!asset || error) {
|
if (!asset || error) {
|
||||||
setPageTitle('Could not retrieve asset')
|
setPageTitle('Could not retrieve asset')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
setPageTitle(isInPurgatory ? '' : title)
|
setPageTitle(isInPurgatory ? '' : title)
|
||||||
}, [asset, error, isInPurgatory, title])
|
}, [asset, error, isInPurgatory, isV3Asset, router, title, uri])
|
||||||
|
|
||||||
return asset && pageTitle !== undefined && !loading ? (
|
return asset && pageTitle !== undefined && !loading ? (
|
||||||
<Page title={pageTitle} uri={uri}>
|
<Page title={pageTitle} uri={uri}>
|
||||||
<AssetContent asset={asset} />
|
<AssetContent asset={asset} />
|
||||||
</Page>
|
</Page>
|
||||||
) : error ? (
|
) : error && isV3Asset === false ? (
|
||||||
<Page title={pageTitle} noPageHeader uri={uri}>
|
<Page title={pageTitle} noPageHeader uri={uri}>
|
||||||
<Alert title={pageTitle} text={error} state="error" />
|
<Alert title={pageTitle} text={error} state="error" />
|
||||||
</Page>
|
</Page>
|
||||||
|
@ -4,6 +4,8 @@ import PriceUnit from '@shared/Price/PriceUnit'
|
|||||||
import NetworkName from '@shared/NetworkName'
|
import NetworkName from '@shared/NetworkName'
|
||||||
import styles from './Tooltip.module.css'
|
import styles from './Tooltip.module.css'
|
||||||
import { StatsValue } from './_types'
|
import { StatsValue } from './_types'
|
||||||
|
import content from '../../../../content/footer.json'
|
||||||
|
import Markdown from '@shared/Markdown'
|
||||||
|
|
||||||
export default function MarketStatsTooltip({
|
export default function MarketStatsTooltip({
|
||||||
totalValueLockedInOcean,
|
totalValueLockedInOcean,
|
||||||
@ -39,13 +41,7 @@ export default function MarketStatsTooltip({
|
|||||||
</li>
|
</li>
|
||||||
))}
|
))}
|
||||||
</ul>
|
</ul>
|
||||||
<p className={styles.note}>
|
<Markdown className={styles.note} text={content.stats.note} />
|
||||||
Counted on-chain from our NFT and pool factories. Does not filter out
|
|
||||||
assets in{' '}
|
|
||||||
<a href="https://github.com/oceanprotocol/list-purgatory">
|
|
||||||
list-purgatory
|
|
||||||
</a>
|
|
||||||
</p>
|
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -61,7 +61,9 @@ export default function MarketStats(): ReactElement {
|
|||||||
//
|
//
|
||||||
const getMarketStats = useCallback(async () => {
|
const getMarketStats = useCallback(async () => {
|
||||||
if (!mainChainIds?.length) return
|
if (!mainChainIds?.length) return
|
||||||
|
const newData: {
|
||||||
|
[chainId: number]: FooterStatsValuesGlobalStatistics
|
||||||
|
} = {}
|
||||||
for (const chainId of mainChainIds) {
|
for (const chainId of mainChainIds) {
|
||||||
const context: OperationContext = {
|
const context: OperationContext = {
|
||||||
url: `${getSubgraphUri(
|
url: `${getSubgraphUri(
|
||||||
@ -73,15 +75,12 @@ export default function MarketStats(): ReactElement {
|
|||||||
try {
|
try {
|
||||||
const response = await fetchData(queryGlobalStatistics, null, context)
|
const response = await fetchData(queryGlobalStatistics, null, context)
|
||||||
if (!response?.data?.globalStatistics) return
|
if (!response?.data?.globalStatistics) return
|
||||||
|
newData[chainId] = response.data.globalStatistics[0]
|
||||||
setData((prevState) => ({
|
|
||||||
...prevState,
|
|
||||||
[chainId]: response.data.globalStatistics[0]
|
|
||||||
}))
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
LoggerInstance.error('Error fetching global stats: ', error.message)
|
LoggerInstance.error('Error fetching global stats: ', error.message)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
setData(newData)
|
||||||
}, [mainChainIds])
|
}, [mainChainIds])
|
||||||
|
|
||||||
//
|
//
|
||||||
@ -96,10 +95,12 @@ export default function MarketStats(): ReactElement {
|
|||||||
//
|
//
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!data || !mainChainIds?.length) return
|
if (!data || !mainChainIds?.length) return
|
||||||
|
|
||||||
const newTotal: StatsTotal = {
|
const newTotal: StatsTotal = {
|
||||||
...initialTotal // always start calculating beginning from initial 0 values
|
...initialTotal // always start calculating beginning from initial 0 values
|
||||||
}
|
}
|
||||||
|
const newTVLInOcean: StatsValue = {}
|
||||||
|
const newTotalLiquidity: StatsValue = {}
|
||||||
|
const newPoolCount: StatsValue = {}
|
||||||
|
|
||||||
for (const chainId of mainChainIds) {
|
for (const chainId of mainChainIds) {
|
||||||
const baseTokenValue = data[chainId]?.totalLiquidity[0]?.value
|
const baseTokenValue = data[chainId]?.totalLiquidity[0]?.value
|
||||||
@ -109,25 +110,15 @@ export default function MarketStats(): ReactElement {
|
|||||||
? new Decimal(baseTokenValue).mul(2)
|
? new Decimal(baseTokenValue).mul(2)
|
||||||
: new Decimal(0)
|
: new Decimal(0)
|
||||||
|
|
||||||
setTotalValueLockedInOcean((prevState) => ({
|
newTVLInOcean[chainId] = `${totalValueLockedInOcean}`
|
||||||
...prevState,
|
|
||||||
[chainId]: `${totalValueLockedInOcean}`
|
|
||||||
}))
|
|
||||||
|
|
||||||
const totalOceanLiquidity = Number(baseTokenValue) || 0
|
const totalOceanLiquidity = Number(baseTokenValue) || 0
|
||||||
|
|
||||||
setTotalOceanLiquidity((prevState) => ({
|
newTotalLiquidity[chainId] = `${totalOceanLiquidity}`
|
||||||
...prevState,
|
|
||||||
[chainId]: `${totalOceanLiquidity}`
|
|
||||||
}))
|
|
||||||
|
|
||||||
const poolCount = data[chainId]?.poolCount || 0
|
const poolCount = data[chainId]?.poolCount || 0
|
||||||
|
|
||||||
setPoolCount((prevState) => ({
|
newPoolCount[chainId] = `${poolCount}`
|
||||||
...prevState,
|
|
||||||
[chainId]: `${poolCount}`
|
|
||||||
}))
|
|
||||||
|
|
||||||
const nftCount = data[chainId]?.nftCount || 0
|
const nftCount = data[chainId]?.nftCount || 0
|
||||||
const datatokenCount = data[chainId]?.datatokenCount || 0
|
const datatokenCount = data[chainId]?.datatokenCount || 0
|
||||||
const orderCount = data[chainId]?.orderCount || 0
|
const orderCount = data[chainId]?.orderCount || 0
|
||||||
@ -142,7 +133,9 @@ export default function MarketStats(): ReactElement {
|
|||||||
LoggerInstance.error('Error data manipulation: ', error.message)
|
LoggerInstance.error('Error data manipulation: ', error.message)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
setTotalValueLockedInOcean(newTVLInOcean)
|
||||||
|
setTotalOceanLiquidity(newTotalLiquidity)
|
||||||
|
setPoolCount(newPoolCount)
|
||||||
setTotal(newTotal)
|
setTotal(newTotal)
|
||||||
}, [data, mainChainIds, prices, currency])
|
}, [data, mainChainIds, prices, currency])
|
||||||
|
|
||||||
|
@ -7,13 +7,24 @@
|
|||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
.logo {
|
.logo,
|
||||||
order: 1;
|
.badge {
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo {
|
||||||
|
order: 0;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.badge {
|
||||||
|
cursor: pointer;
|
||||||
|
margin-top: -0.25rem;
|
||||||
|
position: relative;
|
||||||
|
padding: calc(var(--spacer) / 5) calc(var(--spacer) / 4);
|
||||||
|
}
|
||||||
|
|
||||||
.navigation {
|
.navigation {
|
||||||
order: 3;
|
order: 3;
|
||||||
margin-top: calc(var(--spacer) / 2);
|
margin-top: calc(var(--spacer) / 2);
|
||||||
@ -60,10 +71,10 @@
|
|||||||
|
|
||||||
.title {
|
.title {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
margin-right: var(--spacer);
|
|
||||||
display: block;
|
display: block;
|
||||||
color: var(--color-secondary);
|
color: var(--color-secondary);
|
||||||
font-size: var(--font-size-h4);
|
font-size: var(--font-size-h4);
|
||||||
|
margin-right: calc(var(--spacer) / 6);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -115,6 +126,10 @@
|
|||||||
padding-right: 0;
|
padding-right: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.link[aria-disabled] {
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
.logo svg {
|
.logo svg {
|
||||||
margin-right: calc(var(--spacer) / 3);
|
margin-right: calc(var(--spacer) / 3);
|
||||||
}
|
}
|
||||||
@ -122,3 +137,36 @@
|
|||||||
.actions button {
|
.actions button {
|
||||||
text-transform: none;
|
text-transform: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.tooltip[aria-expanded='true'] svg {
|
||||||
|
transform: rotate(180deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.caret,
|
||||||
|
svg.caret {
|
||||||
|
width: var(--font-size-mini);
|
||||||
|
height: var(--font-size-mini);
|
||||||
|
fill: var(--brand-white);
|
||||||
|
opacity: 0.7;
|
||||||
|
transition: transform 0.2s ease-out;
|
||||||
|
vertical-align: middle;
|
||||||
|
margin-left: calc(var(--spacer) / 12);
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen and (min-width: 42rem) {
|
||||||
|
.caret,
|
||||||
|
svg.caret {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.versions {
|
||||||
|
padding: calc(var(--spacer) / 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
.versions .link {
|
||||||
|
display: inline-block;
|
||||||
|
margin: 0 calc(var(--spacer) / 4);
|
||||||
|
padding: 0;
|
||||||
|
font-size: var(--font-size-small);
|
||||||
|
}
|
||||||
|
@ -9,7 +9,8 @@ import SearchBar from './SearchBar'
|
|||||||
import styles from './Menu.module.css'
|
import styles from './Menu.module.css'
|
||||||
import { useRouter } from 'next/router'
|
import { useRouter } from 'next/router'
|
||||||
import { useMarketMetadata } from '@context/MarketMetadata'
|
import { useMarketMetadata } from '@context/MarketMetadata'
|
||||||
|
import Tooltip from '@shared/atoms/Tooltip'
|
||||||
|
import Caret from '@images/caret.svg'
|
||||||
const Wallet = loadable(() => import('./Wallet'))
|
const Wallet = loadable(() => import('./Wallet'))
|
||||||
|
|
||||||
declare type MenuItem = {
|
declare type MenuItem = {
|
||||||
@ -33,19 +34,41 @@ function MenuLink({ item }: { item: MenuItem }) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default function Menu(): ReactElement {
|
export default function Menu(): ReactElement {
|
||||||
const { siteContent } = useMarketMetadata()
|
const { appConfig, siteContent } = useMarketMetadata()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<nav className={styles.menu}>
|
<nav className={styles.menu}>
|
||||||
<Link href="/">
|
<Link href="/">
|
||||||
<a className={styles.logo}>
|
<a className={styles.logo}>
|
||||||
<Logo noWordmark />
|
<Logo noWordmark />
|
||||||
<h1 className={styles.title}>
|
<h1 className={styles.title}>{siteContent?.siteTitle}</h1>
|
||||||
{siteContent?.siteTitle} <Badge label="v4" />
|
|
||||||
</h1>
|
|
||||||
</a>
|
</a>
|
||||||
</Link>
|
</Link>
|
||||||
|
|
||||||
|
<Tooltip
|
||||||
|
className={styles.tooltip}
|
||||||
|
content={
|
||||||
|
<div className={styles.versions}>
|
||||||
|
<a className={styles.link} href={appConfig.v3MarketUri}>
|
||||||
|
v3
|
||||||
|
</a>
|
||||||
|
<a className={styles.link} href="" aria-current aria-disabled>
|
||||||
|
v4
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
trigger="click focus"
|
||||||
|
placement="bottom"
|
||||||
|
>
|
||||||
|
<Badge
|
||||||
|
className={styles.badge}
|
||||||
|
label={
|
||||||
|
<>
|
||||||
|
v4 <Caret aria-hidden="true" className={styles.caret} />
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</Tooltip>
|
||||||
<ul className={styles.navigation}>
|
<ul className={styles.navigation}>
|
||||||
{siteContent?.menu.map((item: MenuItem) => (
|
{siteContent?.menu.map((item: MenuItem) => (
|
||||||
<li key={item.name}>
|
<li key={item.name}>
|
||||||
|
@ -39,7 +39,7 @@ export async function getAssetsFromPoolShares(
|
|||||||
assetList.push({
|
assetList.push({
|
||||||
poolShare: data[i],
|
poolShare: data[i],
|
||||||
userLiquidity,
|
userLiquidity,
|
||||||
networkId: getAsset(ddoList, data[i].pool.datatoken.address).chainId,
|
networkId: getAsset(ddoList, data[i].pool.datatoken.address)?.chainId,
|
||||||
createTime: data[i].pool.createdTimestamp,
|
createTime: data[i].pool.createdTimestamp,
|
||||||
asset: getAsset(ddoList, data[i].pool.datatoken.address)
|
asset: getAsset(ddoList, data[i].pool.datatoken.address)
|
||||||
})
|
})
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
|
|
||||||
.actions button {
|
.actions button {
|
||||||
margin: 0 calc(var(--spacer) / 2);
|
margin: 0 calc(var(--spacer) / 2);
|
||||||
|
min-height: 40px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.infoIcon {
|
.infoIcon {
|
||||||
|
@ -10,6 +10,7 @@ import { useRouter } from 'next/router'
|
|||||||
import Tooltip from '@shared/atoms/Tooltip'
|
import Tooltip from '@shared/atoms/Tooltip'
|
||||||
import AvailableNetworks from 'src/components/Publish/AvailableNetworks'
|
import AvailableNetworks from 'src/components/Publish/AvailableNetworks'
|
||||||
import Info from '@images/info.svg'
|
import Info from '@images/info.svg'
|
||||||
|
import Loader from '@shared/atoms/Loader'
|
||||||
|
|
||||||
export default function Actions({
|
export default function Actions({
|
||||||
scrollToRef,
|
scrollToRef,
|
||||||
@ -24,8 +25,7 @@ export default function Actions({
|
|||||||
values,
|
values,
|
||||||
errors,
|
errors,
|
||||||
isValid,
|
isValid,
|
||||||
isSubmitting,
|
isSubmitting
|
||||||
setFieldValue
|
|
||||||
}: FormikContextType<FormPublishData> = useFormikContext()
|
}: FormikContextType<FormPublishData> = useFormikContext()
|
||||||
const { connect, accountId } = useWeb3()
|
const { connect, accountId } = useWeb3()
|
||||||
|
|
||||||
@ -60,6 +60,11 @@ export default function Actions({
|
|||||||
(values.user.stepCurrent === 2 && errors.services !== undefined) ||
|
(values.user.stepCurrent === 2 && errors.services !== undefined) ||
|
||||||
(values.user.stepCurrent === 3 && errors.pricing !== undefined)
|
(values.user.stepCurrent === 3 && errors.pricing !== undefined)
|
||||||
|
|
||||||
|
const hasSubmitError =
|
||||||
|
values.feedback?.[1].status === 'error' ||
|
||||||
|
values.feedback?.[2].status === 'error' ||
|
||||||
|
values.feedback?.[3].status === 'error'
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<footer className={styles.actions}>
|
<footer className={styles.actions}>
|
||||||
{did ? (
|
{did ? (
|
||||||
@ -108,7 +113,13 @@ export default function Actions({
|
|||||||
style="primary"
|
style="primary"
|
||||||
disabled={isSubmitting || !isValid}
|
disabled={isSubmitting || !isValid}
|
||||||
>
|
>
|
||||||
Submit
|
{isSubmitting ? (
|
||||||
|
<Loader white />
|
||||||
|
) : hasSubmitError ? (
|
||||||
|
'Retry'
|
||||||
|
) : (
|
||||||
|
'Submit'
|
||||||
|
)}
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
|
@ -4,3 +4,7 @@
|
|||||||
margin-left: 1.75rem;
|
margin-left: 1.75rem;
|
||||||
top: -3.2rem;
|
top: -3.2rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.fieldWarning {
|
||||||
|
composes: fieldWarning from '../index.module.css';
|
||||||
|
}
|
||||||
|
@ -9,6 +9,8 @@ import IconDataset from '@images/dataset.svg'
|
|||||||
import IconAlgorithm from '@images/algorithm.svg'
|
import IconAlgorithm from '@images/algorithm.svg'
|
||||||
import styles from './index.module.css'
|
import styles from './index.module.css'
|
||||||
import { algorithmContainerPresets } from '../_constants'
|
import { algorithmContainerPresets } from '../_constants'
|
||||||
|
import Alert from '@shared/atoms/Alert'
|
||||||
|
import { useMarketMetadata } from '@context/MarketMetadata'
|
||||||
|
|
||||||
const assetTypeOptionsTitles = getFieldContent(
|
const assetTypeOptionsTitles = getFieldContent(
|
||||||
'type',
|
'type',
|
||||||
@ -16,6 +18,8 @@ const assetTypeOptionsTitles = getFieldContent(
|
|||||||
).options
|
).options
|
||||||
|
|
||||||
export default function MetadataFields(): ReactElement {
|
export default function MetadataFields(): ReactElement {
|
||||||
|
const { siteContent } = useMarketMetadata()
|
||||||
|
|
||||||
// connect with Form state, use for conditional field rendering
|
// connect with Form state, use for conditional field rendering
|
||||||
const { values, setFieldValue } = useFormikContext<FormPublishData>()
|
const { values, setFieldValue } = useFormikContext<FormPublishData>()
|
||||||
|
|
||||||
@ -71,6 +75,13 @@ export default function MetadataFields(): ReactElement {
|
|||||||
name="metadata.type"
|
name="metadata.type"
|
||||||
options={assetTypeOptions}
|
options={assetTypeOptions}
|
||||||
/>
|
/>
|
||||||
|
{values.services[0].access === 'compute' && (
|
||||||
|
<Alert
|
||||||
|
className={styles.fieldWarning}
|
||||||
|
state="info"
|
||||||
|
text={siteContent.warning.ctd}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
<Field
|
<Field
|
||||||
{...getFieldContent('name', content.metadata.fields)}
|
{...getFieldContent('name', content.metadata.fields)}
|
||||||
component={Input}
|
component={Input}
|
||||||
|
@ -6,6 +6,9 @@ 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 Alert from '@shared/atoms/Alert'
|
||||||
|
import { useMarketMetadata } from '@context/MarketMetadata'
|
||||||
|
import styles from '../index.module.css'
|
||||||
|
|
||||||
const accessTypeOptionsTitles = getFieldContent(
|
const accessTypeOptionsTitles = getFieldContent(
|
||||||
'access',
|
'access',
|
||||||
@ -13,6 +16,8 @@ const accessTypeOptionsTitles = getFieldContent(
|
|||||||
).options
|
).options
|
||||||
|
|
||||||
export default function ServicesFields(): ReactElement {
|
export default function ServicesFields(): ReactElement {
|
||||||
|
const { siteContent } = useMarketMetadata()
|
||||||
|
|
||||||
// connect with Form state, use for conditional field rendering
|
// connect with Form state, use for conditional field rendering
|
||||||
const { values, setFieldValue } = useFormikContext<FormPublishData>()
|
const { values, setFieldValue } = useFormikContext<FormPublishData>()
|
||||||
|
|
||||||
@ -67,12 +72,21 @@ export default function ServicesFields(): ReactElement {
|
|||||||
name="services[0].algorithmPrivacy"
|
name="services[0].algorithmPrivacy"
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<Field
|
<>
|
||||||
{...getFieldContent('access', content.services.fields)}
|
<Field
|
||||||
component={Input}
|
{...getFieldContent('access', content.services.fields)}
|
||||||
name="services[0].access"
|
component={Input}
|
||||||
options={accessTypeOptions}
|
name="services[0].access"
|
||||||
/>
|
options={accessTypeOptions}
|
||||||
|
/>
|
||||||
|
{values.services[0].access === 'compute' && (
|
||||||
|
<Alert
|
||||||
|
className={styles.fieldWarning}
|
||||||
|
state="info"
|
||||||
|
text={siteContent.warning.ctd}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
)}
|
)}
|
||||||
<Field
|
<Field
|
||||||
{...getFieldContent('providerUrl', content.services.fields)}
|
{...getFieldContent('providerUrl', content.services.fields)}
|
||||||
|
@ -1,12 +1,8 @@
|
|||||||
import React, { ReactElement } from 'react'
|
import React, { ReactElement } from 'react'
|
||||||
import styles from './index.module.css'
|
import styles from './index.module.css'
|
||||||
import { FormPublishData } from '../_types'
|
|
||||||
import { useFormikContext } from 'formik'
|
|
||||||
import { Feedback } from './Feedback'
|
import { Feedback } from './Feedback'
|
||||||
|
|
||||||
export default function Submission(): ReactElement {
|
export default function Submission(): ReactElement {
|
||||||
const { values, handleSubmit } = useFormikContext<FormPublishData>()
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.submission}>
|
<div className={styles.submission}>
|
||||||
<Feedback />
|
<Feedback />
|
||||||
|
@ -3,7 +3,7 @@ import { NftMetadata } from '@utils/nft'
|
|||||||
import { ReactElement } from 'react'
|
import { ReactElement } from 'react'
|
||||||
import { PriceOptions } from 'src/@types/Price'
|
import { PriceOptions } from 'src/@types/Price'
|
||||||
|
|
||||||
interface FileMetadata {
|
interface FileInfo {
|
||||||
url: string
|
url: string
|
||||||
valid?: boolean
|
valid?: boolean
|
||||||
contentLength?: string
|
contentLength?: string
|
||||||
@ -11,8 +11,8 @@ interface FileMetadata {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface FormPublishService {
|
export interface FormPublishService {
|
||||||
files: FileMetadata[]
|
files: FileInfo[]
|
||||||
links?: FileMetadata[]
|
links?: FileInfo[]
|
||||||
timeout: string
|
timeout: string
|
||||||
dataTokenOptions: { name: string; symbol: string }
|
dataTokenOptions: { name: string; symbol: string }
|
||||||
access: 'Download' | 'Compute' | string
|
access: 'Download' | 'Compute' | string
|
||||||
|
@ -144,13 +144,18 @@ export async function transformPublishFormToDdo(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// this is the default format hardcoded
|
// this is the default format hardcoded
|
||||||
const file = [
|
const file = {
|
||||||
{
|
nftAddress,
|
||||||
type: 'url',
|
datatokenAddress,
|
||||||
url: files[0].url,
|
files: [
|
||||||
method: 'GET'
|
{
|
||||||
}
|
type: 'url',
|
||||||
]
|
index: 0,
|
||||||
|
url: files[0].url,
|
||||||
|
method: 'GET'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
const filesEncrypted =
|
const filesEncrypted =
|
||||||
!isPreview &&
|
!isPreview &&
|
||||||
files?.length &&
|
files?.length &&
|
||||||
@ -173,7 +178,7 @@ export async function transformPublishFormToDdo(
|
|||||||
'@context': ['https://w3id.org/did/v1'],
|
'@context': ['https://w3id.org/did/v1'],
|
||||||
id: did,
|
id: did,
|
||||||
nftAddress,
|
nftAddress,
|
||||||
version: '4.0.0',
|
version: '4.1.0',
|
||||||
chainId,
|
chainId,
|
||||||
metadata: newMetadata,
|
metadata: newMetadata,
|
||||||
services: [newService],
|
services: [newService],
|
||||||
|
@ -146,7 +146,7 @@ export const validationSchema: Yup.SchemaOf<any> = Yup.object().shape({
|
|||||||
// .min(4, (param) => `Title must be at least ${param.min} characters`)
|
// .min(4, (param) => `Title must be at least ${param.min} characters`)
|
||||||
// .required('Required'),
|
// .required('Required'),
|
||||||
// description: Yup.string().min(10).required('Required'),
|
// description: Yup.string().min(10).required('Required'),
|
||||||
// files: Yup.array<FileMetadata>().required('Required').nullable(),
|
// files: Yup.array<FileInfo>().required('Required').nullable(),
|
||||||
// timeout: Yup.string().required('Required'),
|
// timeout: Yup.string().required('Required'),
|
||||||
// dataTokenOptions: Yup.object()
|
// dataTokenOptions: Yup.object()
|
||||||
// .shape({
|
// .shape({
|
||||||
@ -167,6 +167,6 @@ export const validationSchema: Yup.SchemaOf<any> = Yup.object().shape({
|
|||||||
// // ---- optional fields ----
|
// // ---- optional fields ----
|
||||||
// algorithmPrivacy: Yup.boolean().nullable(),
|
// algorithmPrivacy: Yup.boolean().nullable(),
|
||||||
// tags: Yup.string().nullable(),
|
// tags: Yup.string().nullable(),
|
||||||
// links: Yup.array<FileMetadata[]>().nullable()
|
// links: Yup.array<FileInfo[]>().nullable()
|
||||||
// })
|
// })
|
||||||
// .defined()
|
// .defined()
|
||||||
|
@ -16,3 +16,8 @@
|
|||||||
padding-right: calc(var(--spacer) * 4);
|
padding-right: calc(var(--spacer) * 4);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.fieldWarning {
|
||||||
|
margin-top: -2rem;
|
||||||
|
margin-bottom: var(--spacer);
|
||||||
|
}
|
||||||
|
@ -11,7 +11,7 @@ import Actions from './Actions'
|
|||||||
import Debug from './Debug'
|
import Debug from './Debug'
|
||||||
import Navigation from './Navigation'
|
import Navigation from './Navigation'
|
||||||
import { Steps } from './Steps'
|
import { Steps } from './Steps'
|
||||||
import { FormPublishData, PublishFeedback } from './_types'
|
import { FormPublishData } 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 { ProviderInstance, LoggerInstance, DDO } from '@oceanprotocol/lib'
|
import { ProviderInstance, LoggerInstance, DDO } from '@oceanprotocol/lib'
|
||||||
@ -35,34 +35,34 @@ export default function PublishPage({
|
|||||||
const nftFactory = useNftFactory()
|
const nftFactory = useNftFactory()
|
||||||
const newAbortController = useAbortController()
|
const newAbortController = useAbortController()
|
||||||
|
|
||||||
const [feedback, setFeedback] = useState<PublishFeedback>(
|
// This `feedback` state is auto-synced into Formik context under `values.feedback`
|
||||||
initialPublishFeedback
|
// for use in other components. Syncing defined in ./Steps.tsx child component.
|
||||||
)
|
const [feedback, setFeedback] = useState(initialPublishFeedback)
|
||||||
|
|
||||||
|
// Collecting output of each publish step, enabling retry of failed steps
|
||||||
|
const [erc721Address, setErc721Address] = useState<string>()
|
||||||
|
const [datatokenAddress, setDatatokenAddress] = useState<string>()
|
||||||
|
const [ddo, setDdo] = useState<DDO>()
|
||||||
|
const [ddoEncrypted, setDdoEncrypted] = useState<string>()
|
||||||
const [did, setDid] = useState<string>()
|
const [did, setDid] = useState<string>()
|
||||||
|
|
||||||
async function handleSubmit(values: FormPublishData) {
|
// --------------------------------------------------
|
||||||
let _erc721Address: string,
|
// 1. Create NFT & datatokens & create pricing schema
|
||||||
_datatokenAddress: string,
|
// --------------------------------------------------
|
||||||
_ddo: DDO,
|
async function create(values: FormPublishData): Promise<{
|
||||||
_encryptedDdo: string
|
erc721Address: string
|
||||||
|
datatokenAddress: string
|
||||||
|
}> {
|
||||||
|
setFeedback((prevState) => ({
|
||||||
|
...prevState,
|
||||||
|
'1': {
|
||||||
|
...prevState['1'],
|
||||||
|
status: 'active',
|
||||||
|
errorMessage: null
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
|
||||||
// reset all feedback state
|
|
||||||
setFeedback(initialPublishFeedback)
|
|
||||||
|
|
||||||
// --------------------------------------------------
|
|
||||||
// 1. Create NFT & datatokens & create pricing schema
|
|
||||||
// --------------------------------------------------
|
|
||||||
try {
|
try {
|
||||||
setFeedback((prevState) => ({
|
|
||||||
...prevState,
|
|
||||||
'1': {
|
|
||||||
...prevState['1'],
|
|
||||||
status: 'active',
|
|
||||||
txCount: values.pricing.type === 'dynamic' ? 2 : 1,
|
|
||||||
description: prevState['1'].description
|
|
||||||
}
|
|
||||||
}))
|
|
||||||
|
|
||||||
const config = getOceanConfig(chainId)
|
const config = getOceanConfig(chainId)
|
||||||
LoggerInstance.log('[publish] using config: ', config)
|
LoggerInstance.log('[publish] using config: ', config)
|
||||||
|
|
||||||
@ -76,8 +76,7 @@ export default function PublishPage({
|
|||||||
)
|
)
|
||||||
|
|
||||||
const isSuccess = Boolean(erc721Address && datatokenAddress && txHash)
|
const isSuccess = Boolean(erc721Address && datatokenAddress && txHash)
|
||||||
_erc721Address = erc721Address
|
if (!isSuccess) throw new Error('No Token created. Please try again.')
|
||||||
_datatokenAddress = datatokenAddress
|
|
||||||
|
|
||||||
LoggerInstance.log('[publish] createTokensAndPricing tx', txHash)
|
LoggerInstance.log('[publish] createTokensAndPricing tx', txHash)
|
||||||
LoggerInstance.log('[publish] erc721Address', erc721Address)
|
LoggerInstance.log('[publish] erc721Address', erc721Address)
|
||||||
@ -87,14 +86,16 @@ export default function PublishPage({
|
|||||||
...prevState,
|
...prevState,
|
||||||
'1': {
|
'1': {
|
||||||
...prevState['1'],
|
...prevState['1'],
|
||||||
status: isSuccess ? 'success' : 'error',
|
status: 'success',
|
||||||
txHash
|
txHash
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
|
|
||||||
|
return { erc721Address, datatokenAddress }
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
LoggerInstance.error('[publish] error', error.message)
|
LoggerInstance.error('[publish] error', error.message)
|
||||||
if (error.message.length > 65) {
|
if (error.message.length > 65) {
|
||||||
error.message = 'No Token created.'
|
error.message = 'No Token created. Please try again.'
|
||||||
}
|
}
|
||||||
|
|
||||||
setFeedback((prevState) => ({
|
setFeedback((prevState) => ({
|
||||||
@ -102,58 +103,65 @@ export default function PublishPage({
|
|||||||
'1': {
|
'1': {
|
||||||
...prevState['1'],
|
...prevState['1'],
|
||||||
status: 'error',
|
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
|
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// --------------------------------------------------
|
||||||
|
// 2. Construct and encrypt DDO
|
||||||
|
// --------------------------------------------------
|
||||||
|
async function encrypt(
|
||||||
|
values: FormPublishData,
|
||||||
|
erc721Address: string,
|
||||||
|
datatokenAddress: string
|
||||||
|
): Promise<{ ddo: DDO; ddoEncrypted: string }> {
|
||||||
|
setFeedback((prevState) => ({
|
||||||
|
...prevState,
|
||||||
|
'2': {
|
||||||
|
...prevState['2'],
|
||||||
|
status: 'active',
|
||||||
|
errorMessage: null
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
|
||||||
// --------------------------------------------------
|
|
||||||
// 2. Construct and encrypt DDO
|
|
||||||
// --------------------------------------------------
|
|
||||||
try {
|
try {
|
||||||
setFeedback((prevState) => ({
|
if (!datatokenAddress || !erc721Address)
|
||||||
...prevState,
|
throw new Error('No NFT or Datatoken received. Please try again.')
|
||||||
'2': {
|
|
||||||
...prevState['2'],
|
|
||||||
status: 'active'
|
|
||||||
}
|
|
||||||
}))
|
|
||||||
|
|
||||||
if (!_datatokenAddress || !_erc721Address)
|
|
||||||
throw new Error('No NFT or Datatoken received.')
|
|
||||||
|
|
||||||
const ddo = await transformPublishFormToDdo(
|
const ddo = await transformPublishFormToDdo(
|
||||||
values,
|
values,
|
||||||
_datatokenAddress,
|
datatokenAddress,
|
||||||
_erc721Address
|
erc721Address
|
||||||
)
|
)
|
||||||
|
|
||||||
_ddo = ddo
|
if (!ddo) throw new Error('No DDO received. Please try again.')
|
||||||
|
|
||||||
|
setDdo(ddo)
|
||||||
LoggerInstance.log('[publish] Got new DDO', ddo)
|
LoggerInstance.log('[publish] Got new DDO', ddo)
|
||||||
|
|
||||||
const encryptedResponse = await ProviderInstance.encrypt(
|
const ddoEncrypted = await ProviderInstance.encrypt(
|
||||||
ddo,
|
ddo,
|
||||||
values.services[0].providerUrl.url,
|
values.services[0].providerUrl.url,
|
||||||
newAbortController()
|
newAbortController()
|
||||||
)
|
)
|
||||||
const encryptedDdo = encryptedResponse
|
|
||||||
_encryptedDdo = encryptedDdo
|
if (!ddoEncrypted)
|
||||||
LoggerInstance.log('[publish] Got encrypted DDO', encryptedDdo)
|
throw new Error('No encrypted DDO received. Please try again.')
|
||||||
|
|
||||||
|
setDdoEncrypted(ddoEncrypted)
|
||||||
|
LoggerInstance.log('[publish] Got encrypted DDO', ddoEncrypted)
|
||||||
|
|
||||||
setFeedback((prevState) => ({
|
setFeedback((prevState) => ({
|
||||||
...prevState,
|
...prevState,
|
||||||
'2': {
|
'2': {
|
||||||
...prevState['2'],
|
...prevState['2'],
|
||||||
status: encryptedDdo ? 'success' : 'error'
|
status: 'success'
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
|
|
||||||
|
return { ddo, ddoEncrypted }
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
LoggerInstance.error('[publish] error', error.message)
|
LoggerInstance.error('[publish] error', error.message)
|
||||||
setFeedback((prevState) => ({
|
setFeedback((prevState) => ({
|
||||||
@ -165,43 +173,53 @@ export default function PublishPage({
|
|||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// --------------------------------------------------
|
||||||
|
// 3. Write DDO into NFT metadata
|
||||||
|
// --------------------------------------------------
|
||||||
|
async function publish(
|
||||||
|
values: FormPublishData,
|
||||||
|
ddo: DDO,
|
||||||
|
ddoEncrypted: string
|
||||||
|
): Promise<{ did: string }> {
|
||||||
|
setFeedback((prevState) => ({
|
||||||
|
...prevState,
|
||||||
|
'3': {
|
||||||
|
...prevState['3'],
|
||||||
|
status: 'active',
|
||||||
|
errorMessage: null
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
|
||||||
// --------------------------------------------------
|
|
||||||
// 3. Write DDO into NFT metadata
|
|
||||||
// --------------------------------------------------
|
|
||||||
try {
|
try {
|
||||||
setFeedback((prevState) => ({
|
if (!ddo || !ddoEncrypted)
|
||||||
...prevState,
|
throw new Error('No DDO received. Please try again.')
|
||||||
'3': {
|
|
||||||
...prevState['3'],
|
|
||||||
status: 'active'
|
|
||||||
}
|
|
||||||
}))
|
|
||||||
|
|
||||||
if (!_ddo || !_encryptedDdo) throw new Error('No DDO received.')
|
|
||||||
|
|
||||||
const res = await setNFTMetadataAndTokenURI(
|
const res = await setNFTMetadataAndTokenURI(
|
||||||
_ddo,
|
ddo,
|
||||||
accountId,
|
accountId,
|
||||||
web3,
|
web3,
|
||||||
values.metadata.nft,
|
values.metadata.nft,
|
||||||
newAbortController()
|
newAbortController()
|
||||||
)
|
)
|
||||||
|
if (!res?.transactionHash)
|
||||||
|
throw new Error(
|
||||||
|
'Metadata could not be written into the NFT. Please try again.'
|
||||||
|
)
|
||||||
|
|
||||||
LoggerInstance.log('[publish] setMetadata result', res)
|
LoggerInstance.log('[publish] setMetadata result', res)
|
||||||
|
|
||||||
const txHash = res.transactionHash
|
|
||||||
|
|
||||||
setFeedback((prevState) => ({
|
setFeedback((prevState) => ({
|
||||||
...prevState,
|
...prevState,
|
||||||
'3': {
|
'3': {
|
||||||
...prevState['3'],
|
...prevState['3'],
|
||||||
status: res ? 'success' : 'error',
|
status: res ? 'success' : 'error',
|
||||||
txHash
|
txHash: res?.transactionHash
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
|
|
||||||
setDid(_ddo.id)
|
return { did: ddo.id }
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
LoggerInstance.error('[publish] error', error.message)
|
LoggerInstance.error('[publish] error', error.message)
|
||||||
setFeedback((prevState) => ({
|
setFeedback((prevState) => ({
|
||||||
@ -215,6 +233,44 @@ export default function PublishPage({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// --------------------------------------------------
|
||||||
|
// Orchestrate publishing
|
||||||
|
// --------------------------------------------------
|
||||||
|
async function handleSubmit(values: FormPublishData) {
|
||||||
|
// Syncing variables with state, enabling retry of failed steps
|
||||||
|
let _erc721Address = erc721Address
|
||||||
|
let _datatokenAddress = datatokenAddress
|
||||||
|
let _ddo = ddo
|
||||||
|
let _ddoEncrypted = ddoEncrypted
|
||||||
|
let _did = did
|
||||||
|
|
||||||
|
if (!_erc721Address || !_datatokenAddress) {
|
||||||
|
const { erc721Address, datatokenAddress } = await create(values)
|
||||||
|
_erc721Address = erc721Address
|
||||||
|
_datatokenAddress = datatokenAddress
|
||||||
|
setErc721Address(erc721Address)
|
||||||
|
setDatatokenAddress(datatokenAddress)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_ddo || !_ddoEncrypted) {
|
||||||
|
const { ddo, ddoEncrypted } = await encrypt(
|
||||||
|
values,
|
||||||
|
_erc721Address,
|
||||||
|
_datatokenAddress
|
||||||
|
)
|
||||||
|
_ddo = ddo
|
||||||
|
_ddoEncrypted = ddoEncrypted
|
||||||
|
setDdo(ddo)
|
||||||
|
setDdoEncrypted(ddoEncrypted)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_did) {
|
||||||
|
const { did } = await publish(values, _ddo, _ddoEncrypted)
|
||||||
|
_did = did
|
||||||
|
setDid(did)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return isInPurgatory && purgatoryData ? null : (
|
return isInPurgatory && purgatoryData ? null : (
|
||||||
<Formik
|
<Formik
|
||||||
initialValues={initialValues}
|
initialValues={initialValues}
|
||||||
@ -224,22 +280,20 @@ export default function PublishPage({
|
|||||||
await handleSubmit(values)
|
await handleSubmit(values)
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{({ values }) => {
|
{({ values }) => (
|
||||||
return (
|
<>
|
||||||
<>
|
<PageHeader
|
||||||
<PageHeader
|
title={<Title networkId={values.user.chainId} />}
|
||||||
title={<Title networkId={values.user.chainId} />}
|
description={content.description}
|
||||||
description={content.description}
|
/>
|
||||||
/>
|
<Form className={styles.form} ref={scrollToRef}>
|
||||||
<Form className={styles.form} ref={scrollToRef}>
|
<Navigation />
|
||||||
<Navigation />
|
<Steps feedback={feedback} />
|
||||||
<Steps feedback={feedback} />
|
<Actions scrollToRef={scrollToRef} did={did} />
|
||||||
<Actions scrollToRef={scrollToRef} did={did} />
|
</Form>
|
||||||
</Form>
|
{debug && <Debug />}
|
||||||
{debug && <Debug />}
|
</>
|
||||||
</>
|
)}
|
||||||
)
|
|
||||||
}}
|
|
||||||
</Formik>
|
</Formik>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user