mirror of
https://github.com/oceanprotocol/market.git
synced 2024-12-02 05:57:29 +01:00
merge branch main into feature/account-page and fixed merge conflicts
This commit is contained in:
commit
69f02afd59
@ -18,6 +18,7 @@
|
|||||||
|
|
||||||
# Enables another asset editing button holder further advanced settings
|
# Enables another asset editing button holder further advanced settings
|
||||||
#GATSBY_ALLOW_ADVANCED_SETTINGS="true"
|
#GATSBY_ALLOW_ADVANCED_SETTINGS="true"
|
||||||
|
#GATSBY_ALLOW_ADVANCED_PUBLISH_SETTINGS="true"
|
||||||
|
|
||||||
# Allow/Deny Lists
|
# Allow/Deny Lists
|
||||||
#GATSBY_CREDENTIAL_TYPE="address"
|
#GATSBY_CREDENTIAL_TYPE="address"
|
||||||
|
@ -81,7 +81,7 @@ npm start
|
|||||||
|
|
||||||
To use the app together with MetaMask, importing one of the accounts auto-generated by the Ganache container is the easiest way to have test ETH available. All of them have 100 ETH by default. Upon start, the `ocean_ganache_1` container will print out the private keys of multiple accounts in its logs. Pick one of them and import into MetaMask.
|
To use the app together with MetaMask, importing one of the accounts auto-generated by the Ganache container is the easiest way to have test ETH available. All of them have 100 ETH by default. Upon start, the `ocean_ganache_1` container will print out the private keys of multiple accounts in its logs. Pick one of them and import into MetaMask.
|
||||||
|
|
||||||
To fully test all [The Graph](https://thegraph.com) integrations, you have to run your own local Graph node with our [`ocean-subgraph`](https://github.com/oceanprotocol/ocean-subgraph) deployed to it. Barge does not include a local subgraph so by default, the `config.subgraphUri` is hardcoded to the Rinkeby subgraph in our [`NetworkMonitor` component](https://github.com/oceanprotocol/market/blob/main/src/helpers/NetworkMonitor.tsx).
|
To fully test all [The Graph](https://thegraph.com) integrations, you have to run your own local Graph node with our [`ocean-subgraph`](https://github.com/oceanprotocol/ocean-subgraph) deployed to it. Barge does not include a local subgraph so by default, the `subgraphUri` is hardcoded to the Rinkeby subgraph in our [`getDevelopmentConfig` function](https://github.com/oceanprotocol/market/blob/d0b1534d105e5dcb3790c65d4bb04ff1d2dbc575/src/utils/ocean.ts#L31).
|
||||||
|
|
||||||
> Cleaning all Docker images so they are fetched freshly is often a good idea to make sure no issues are caused by old or stale images: `docker system prune --all --volumes`
|
> Cleaning all Docker images so they are fetched freshly is often a good idea to make sure no issues are caused by old or stale images: `docker system prune --all --volumes`
|
||||||
|
|
||||||
|
@ -60,5 +60,7 @@ module.exports = {
|
|||||||
|
|
||||||
// Used to show or hide advanced settings button in asset details page
|
// Used to show or hide advanced settings button in asset details page
|
||||||
allowAdvancedSettings: process.env.GATSBY_ALLOW_ADVANCED_SETTINGS || 'false',
|
allowAdvancedSettings: process.env.GATSBY_ALLOW_ADVANCED_SETTINGS || 'false',
|
||||||
|
allowAdvancedPublishSettings:
|
||||||
|
process.env.GATSBY_ALLOW_ADVANCED_PUBLISH_SETTINGS || 'false',
|
||||||
credentialType: process.env.GATSBY_CREDENTIAL_TYPE || 'address'
|
credentialType: process.env.GATSBY_CREDENTIAL_TYPE || 'address'
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,7 @@ documents:
|
|||||||
- './src/components/pages/History/PoolShares.tsx'
|
- './src/components/pages/History/PoolShares.tsx'
|
||||||
- './src/components/pages/History/Downloads.tsx'
|
- './src/components/pages/History/Downloads.tsx'
|
||||||
- './src/components/pages/History/ComputeJobs/index.tsx'
|
- './src/components/pages/History/ComputeJobs/index.tsx'
|
||||||
- './src/ //Users/bogdanfazakas/Sites/ocean-market/src/components/organisms/AssetContent/EditHistory.tsx'
|
- './src/components/organisms/AssetContent/EditHistory.tsx'
|
||||||
# - './src/components/organisms/AssetActions/Pool/index.tsx'
|
# - './src/components/organisms/AssetActions/Pool/index.tsx'
|
||||||
- './src/components/organisms/AssetActions/Pool/Graph.tsx'
|
- './src/components/organisms/AssetActions/Pool/Graph.tsx'
|
||||||
- './src/components/organisms/AssetActions/Consume.tsx'
|
- './src/components/organisms/AssetActions/Consume.tsx'
|
||||||
|
@ -91,6 +91,14 @@
|
|||||||
"placeholder": "e.g. logistics, ai",
|
"placeholder": "e.g. logistics, ai",
|
||||||
"help": "Separate tags with comma."
|
"help": "Separate tags with comma."
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "providerUri",
|
||||||
|
"label": "Custom Provider URL",
|
||||||
|
"type": "providerUri",
|
||||||
|
"help": "Enter the URL for your custom provider or leave blank to use the default provider. [Learn more](https://github.com/oceanprotocol/provider/).",
|
||||||
|
"placeholder": "https://provider.polygon.oceanprotocol.com/",
|
||||||
|
"advanced": true
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "termsAndConditions",
|
"name": "termsAndConditions",
|
||||||
"label": "Terms & Conditions",
|
"label": "Terms & Conditions",
|
||||||
|
@ -38,6 +38,14 @@
|
|||||||
"options": ["Download", "Compute"],
|
"options": ["Download", "Compute"],
|
||||||
"required": true
|
"required": true
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "providerUri",
|
||||||
|
"label": "Custom Provider URL",
|
||||||
|
"type": "providerUri",
|
||||||
|
"help": "Enter the URL for your custom provider or leave blank to use the default provider. [Learn more](https://github.com/oceanprotocol/provider/).",
|
||||||
|
"placeholder": "https://provider.polygon.oceanprotocol.com/",
|
||||||
|
"advanced": true
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "timeout",
|
"name": "timeout",
|
||||||
"label": "Timeout",
|
"label": "Timeout",
|
||||||
|
@ -12,18 +12,18 @@
|
|||||||
"title": "Fixed",
|
"title": "Fixed",
|
||||||
"info": "Set your price for accessing this data set. The datatoken for this data set will be worth the entered amount of OCEAN.",
|
"info": "Set your price for accessing this data set. The datatoken for this data set will be worth the entered amount of OCEAN.",
|
||||||
"tooltips": {
|
"tooltips": {
|
||||||
"communityFee": "Explain community fee...",
|
"communityFee": "Goes to Ocean DAO for teams to improve the tools, build apps, do outreach, and more. A small fraction is used to burn OCEAN. This fee is collected when downloading or using an asset in a compute job.",
|
||||||
"marketplaceFee": "Explain marketplace fee..."
|
"marketplaceFee": "Goes to the marketplace owner that is hosting and providing the marketplace and is collected when downloading or using an asset in a compute job. In Ocean Market, it is treated as network revenue that goes to the Ocean community."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"dynamic": {
|
"dynamic": {
|
||||||
"title": "Dynamic",
|
"title": "Dynamic",
|
||||||
"info": "Let's create a decentralized, automated market for your data set. The datatoken for this data set will be worth the entered amount of OCEAN. Additionally, you will provide liquidity into a Datatoken/OCEAN liquidity pool with Balancer.",
|
"info": "Let's create a decentralized, automated market for your data set. The datatoken for this data set will be worth the entered amount of OCEAN. Additionally, you will provide liquidity into a Datatoken/OCEAN liquidity pool with Balancer.",
|
||||||
"tooltips": {
|
"tooltips": {
|
||||||
"poolInfo": "Explain what is going on here...",
|
"poolInfo": "The liquidity pool provides the funds for traders to trade against. The price of the asset is determined by the ratio of OCEAN to datatokens.",
|
||||||
"swapFee": "Explain liquidity provider fee...",
|
"swapFee": "Liquidity providers earn this fee on all pool trades, proportionally to their share of the pool. The fee is set by the creator of the pool and is used to incentivize liquidity providers to join the pool.",
|
||||||
"communityFee": "Explain community fee...",
|
"communityFee": "Goes to Ocean DAO for teams to improve the tools, build apps, do outreach, and more. A small fraction is used to burn OCEAN. This fee is collected when downloading or using an asset in a compute job.",
|
||||||
"marketplaceFee": "Explain marketplace fee..."
|
"marketplaceFee": "Goes to the marketplace owner that is hosting and providing the marketplace and is collected when downloading or using an asset in a compute job. In Ocean Market, it is treated as network revenue that goes to the Ocean community."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"free": {
|
"free": {
|
||||||
@ -33,7 +33,7 @@
|
|||||||
},
|
},
|
||||||
"pool": {
|
"pool": {
|
||||||
"tooltips": {
|
"tooltips": {
|
||||||
"price": "Explain how this price is determined...",
|
"price": "The price is determined by an automated market maker, which is a type of decentralized exchange protocol that relies on a mathematical formula. It is an alternative to a traditional order book.",
|
||||||
"liquidity": "Providing liquidity will earn you SWAPFEE% on every transaction in this pool, proportionally to your share of the pool."
|
"liquidity": "Providing liquidity will earn you SWAPFEE% on every transaction in this pool, proportionally to your share of the pool."
|
||||||
},
|
},
|
||||||
"add": {
|
"add": {
|
||||||
|
1
src/@types/Form.d.ts
vendored
1
src/@types/Form.d.ts
vendored
@ -13,6 +13,7 @@ export interface FormFieldProps {
|
|||||||
placeholder?: string
|
placeholder?: string
|
||||||
pattern?: string
|
pattern?: string
|
||||||
min?: string
|
min?: string
|
||||||
|
advanced?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface FormContent {
|
export interface FormContent {
|
||||||
|
2
src/@types/MetaData.d.ts
vendored
2
src/@types/MetaData.d.ts
vendored
@ -38,6 +38,7 @@ export interface MetadataPublishFormDataset {
|
|||||||
// ---- optional fields ----
|
// ---- optional fields ----
|
||||||
tags?: string
|
tags?: string
|
||||||
links?: string | EditableMetadataLinks[]
|
links?: string | EditableMetadataLinks[]
|
||||||
|
providerUri?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface MetadataPublishFormAlgorithm {
|
export interface MetadataPublishFormAlgorithm {
|
||||||
@ -56,6 +57,7 @@ export interface MetadataPublishFormAlgorithm {
|
|||||||
containerTag: string
|
containerTag: string
|
||||||
entrypoint: string
|
entrypoint: string
|
||||||
tags?: string
|
tags?: string
|
||||||
|
providerUri?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface MetadataEditForm {
|
export interface MetadataEditForm {
|
||||||
|
4
src/@types/TokenBalance.d.ts
vendored
4
src/@types/TokenBalance.d.ts
vendored
@ -1,6 +1,6 @@
|
|||||||
export interface PoolBalance {
|
export interface PoolBalance {
|
||||||
ocean: number
|
ocean: string
|
||||||
datatoken: number
|
datatoken: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface UserBalance {
|
export interface UserBalance {
|
||||||
|
@ -8,7 +8,6 @@ import { useWeb3 } from '../providers/Web3'
|
|||||||
import { useSiteMetadata } from '../hooks/useSiteMetadata'
|
import { useSiteMetadata } from '../hooks/useSiteMetadata'
|
||||||
import { useAccountPurgatory } from '../hooks/useAccountPurgatory'
|
import { useAccountPurgatory } from '../hooks/useAccountPurgatory'
|
||||||
import AnnouncementBanner from './atoms/AnnouncementBanner'
|
import AnnouncementBanner from './atoms/AnnouncementBanner'
|
||||||
import { useGraphSyncStatus } from '../hooks/useGraphSyncStatus'
|
|
||||||
import styles from './App.module.css'
|
import styles from './App.module.css'
|
||||||
|
|
||||||
const contentQuery = graphql`
|
const contentQuery = graphql`
|
||||||
@ -40,7 +39,6 @@ export default function App({
|
|||||||
const { warning } = useSiteMetadata()
|
const { warning } = useSiteMetadata()
|
||||||
const { accountId } = useWeb3()
|
const { accountId } = useWeb3()
|
||||||
const { isInPurgatory, purgatoryData } = useAccountPurgatory(accountId)
|
const { isInPurgatory, purgatoryData } = useAccountPurgatory(accountId)
|
||||||
// const { isGraphSynced, blockHead, blockGraph } = useGraphSyncStatus()
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Styles>
|
<Styles>
|
||||||
|
@ -3,6 +3,7 @@ import slugify from '@sindresorhus/slugify'
|
|||||||
import styles from './InputElement.module.css'
|
import styles from './InputElement.module.css'
|
||||||
import { InputProps } from '.'
|
import { InputProps } from '.'
|
||||||
import FilesInput from '../../molecules/FormFields/FilesInput'
|
import FilesInput from '../../molecules/FormFields/FilesInput'
|
||||||
|
import CustomProvider from '../../molecules/FormFields/CustomProvider'
|
||||||
import Terms from '../../molecules/FormFields/Terms'
|
import Terms from '../../molecules/FormFields/Terms'
|
||||||
import BoxSelection, {
|
import BoxSelection, {
|
||||||
BoxSelectionOption
|
BoxSelectionOption
|
||||||
@ -125,6 +126,8 @@ export default function InputElement({
|
|||||||
)
|
)
|
||||||
case 'files':
|
case 'files':
|
||||||
return <FilesInput name={name} {...field} {...props} />
|
return <FilesInput name={name} {...field} {...props} />
|
||||||
|
case 'providerUri':
|
||||||
|
return <CustomProvider name={name} {...field} {...props} />
|
||||||
case 'datatoken':
|
case 'datatoken':
|
||||||
return <Datatoken name={name} {...field} {...props} />
|
return <Datatoken name={name} {...field} {...props} />
|
||||||
case 'terms':
|
case 'terms':
|
||||||
|
@ -63,7 +63,7 @@ export default function Publisher({
|
|||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
<Link
|
<Link
|
||||||
to={`/search/?owner=${account}&sort=created&sortOrder=desc`}
|
to={`/search?sort=created&sortOrder=desc&text=${account}`}
|
||||||
title="Show all data sets created by this account."
|
title="Show all data sets created by this account."
|
||||||
>
|
>
|
||||||
{name}
|
{name}
|
||||||
|
@ -0,0 +1,3 @@
|
|||||||
|
.advancedBtn {
|
||||||
|
margin-bottom: 2rem;
|
||||||
|
}
|
53
src/components/molecules/FormFields/AdvancedSettings.tsx
Normal file
53
src/components/molecules/FormFields/AdvancedSettings.tsx
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
import React, { ReactElement, useState, FormEvent, ChangeEvent } from 'react'
|
||||||
|
import { useSiteMetadata } from '../../../hooks/useSiteMetadata'
|
||||||
|
import Input from '../../atoms/Input'
|
||||||
|
import Button from '../../atoms/Button'
|
||||||
|
import { FormContent, FormFieldProps } from '../../../@types/Form'
|
||||||
|
import { Field } from 'formik'
|
||||||
|
import styles from './AdvancedSettings.module.css'
|
||||||
|
|
||||||
|
export default function AdvancedSettings(prop: {
|
||||||
|
content: FormContent
|
||||||
|
handleFieldChange: (
|
||||||
|
e: ChangeEvent<HTMLInputElement>,
|
||||||
|
field: FormFieldProps
|
||||||
|
) => void
|
||||||
|
}): ReactElement {
|
||||||
|
const { appConfig } = useSiteMetadata()
|
||||||
|
const [advancedSettings, setAdvancedSettings] = useState<boolean>(false)
|
||||||
|
function toggleAdvancedSettings(e: FormEvent<Element>) {
|
||||||
|
e.preventDefault()
|
||||||
|
advancedSettings === true
|
||||||
|
? setAdvancedSettings(false)
|
||||||
|
: setAdvancedSettings(true)
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{appConfig.allowAdvancedPublishSettings === 'true' && (
|
||||||
|
<Button
|
||||||
|
className={styles.advancedBtn}
|
||||||
|
style="text"
|
||||||
|
size="small"
|
||||||
|
onClick={toggleAdvancedSettings}
|
||||||
|
>
|
||||||
|
Advanced Settings
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
{prop.content.data.map(
|
||||||
|
(field: FormFieldProps) =>
|
||||||
|
advancedSettings === true &&
|
||||||
|
field.advanced === true && (
|
||||||
|
<Field
|
||||||
|
key={field.name}
|
||||||
|
{...field}
|
||||||
|
options={field.options}
|
||||||
|
component={Input}
|
||||||
|
onChange={(e: ChangeEvent<HTMLInputElement>) =>
|
||||||
|
prop.handleFieldChange(e, field)
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
60
src/components/molecules/FormFields/CustomProvider.tsx
Normal file
60
src/components/molecules/FormFields/CustomProvider.tsx
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
import React, { ReactElement, useState, useEffect } from 'react'
|
||||||
|
import { useField } from 'formik'
|
||||||
|
import { toast } from 'react-toastify'
|
||||||
|
import CustomInput from './URLInput/Input'
|
||||||
|
import { useOcean } from '../../../providers/Ocean'
|
||||||
|
import { InputProps } from '../../atoms/Input'
|
||||||
|
|
||||||
|
export default function CustomProvider(props: InputProps): ReactElement {
|
||||||
|
const [field, meta, helpers] = useField(props.name)
|
||||||
|
const [isLoading, setIsLoading] = useState(false)
|
||||||
|
const [providerUrl, setProviderUrl] = useState<string>()
|
||||||
|
const { ocean, config } = useOcean()
|
||||||
|
|
||||||
|
function loadProvider() {
|
||||||
|
if (!providerUrl) return
|
||||||
|
async function validateProvider() {
|
||||||
|
let valid: boolean
|
||||||
|
try {
|
||||||
|
setIsLoading(true)
|
||||||
|
valid = await ocean.provider.isValidProvider(providerUrl)
|
||||||
|
} catch (error) {
|
||||||
|
valid = false
|
||||||
|
console.error(error.message)
|
||||||
|
} finally {
|
||||||
|
valid
|
||||||
|
? toast.success('Perfect! That provider URL looks good 🐳')
|
||||||
|
: toast.error(
|
||||||
|
'Could not validate provider. Please check URL and try again'
|
||||||
|
)
|
||||||
|
|
||||||
|
setIsLoading(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
validateProvider()
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
loadProvider()
|
||||||
|
}, [providerUrl, config.providerUri])
|
||||||
|
|
||||||
|
async function handleButtonClick(e: React.SyntheticEvent, url: string) {
|
||||||
|
helpers.setTouched(false)
|
||||||
|
e.preventDefault()
|
||||||
|
if (providerUrl === url) {
|
||||||
|
loadProvider()
|
||||||
|
}
|
||||||
|
|
||||||
|
setProviderUrl(url)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<CustomInput
|
||||||
|
submitText="Validate"
|
||||||
|
{...props}
|
||||||
|
{...field}
|
||||||
|
isLoading={isLoading}
|
||||||
|
handleButtonClick={handleButtonClick}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
@ -3,7 +3,7 @@ import axios from 'axios'
|
|||||||
import { useField } from 'formik'
|
import { useField } from 'formik'
|
||||||
import { toast } from 'react-toastify'
|
import { toast } from 'react-toastify'
|
||||||
import FileInfo from './Info'
|
import FileInfo from './Info'
|
||||||
import FileInput from './Input'
|
import CustomInput from '../URLInput/Input'
|
||||||
import { InputProps } from '../../../atoms/Input'
|
import { InputProps } from '../../../atoms/Input'
|
||||||
import { fileinfo } from '../../../../utils/provider'
|
import { fileinfo } from '../../../../utils/provider'
|
||||||
import { useWeb3 } from '../../../../providers/Web3'
|
import { useWeb3 } from '../../../../providers/Web3'
|
||||||
@ -68,7 +68,8 @@ export default function FilesInput(props: InputProps): ReactElement {
|
|||||||
{field?.value && field.value[0] && typeof field.value === 'object' ? (
|
{field?.value && field.value[0] && typeof field.value === 'object' ? (
|
||||||
<FileInfo name={props.name} file={field.value[0]} />
|
<FileInfo name={props.name} file={field.value[0]} />
|
||||||
) : (
|
) : (
|
||||||
<FileInput
|
<CustomInput
|
||||||
|
submitText="Add File"
|
||||||
{...props}
|
{...props}
|
||||||
{...field}
|
{...field}
|
||||||
isLoading={isLoading}
|
isLoading={isLoading}
|
||||||
|
@ -5,11 +5,13 @@ import Loader from '../../../atoms/Loader'
|
|||||||
import styles from './Input.module.css'
|
import styles from './Input.module.css'
|
||||||
import InputGroup from '../../../atoms/Input/InputGroup'
|
import InputGroup from '../../../atoms/Input/InputGroup'
|
||||||
|
|
||||||
export default function FileInput({
|
export default function URLInput({
|
||||||
|
submitText,
|
||||||
handleButtonClick,
|
handleButtonClick,
|
||||||
isLoading,
|
isLoading,
|
||||||
...props
|
...props
|
||||||
}: {
|
}: {
|
||||||
|
submitText: string
|
||||||
handleButtonClick(e: React.SyntheticEvent, data: string): void
|
handleButtonClick(e: React.SyntheticEvent, data: string): void
|
||||||
isLoading: boolean
|
isLoading: boolean
|
||||||
}): ReactElement {
|
}): ReactElement {
|
||||||
@ -30,7 +32,7 @@ export default function FileInput({
|
|||||||
onClick={(e: React.SyntheticEvent) => e.preventDefault()}
|
onClick={(e: React.SyntheticEvent) => e.preventDefault()}
|
||||||
disabled={!field.value}
|
disabled={!field.value}
|
||||||
>
|
>
|
||||||
{isLoading ? <Loader /> : 'Add File'}
|
{isLoading ? <Loader /> : submitText}
|
||||||
</Button>
|
</Button>
|
||||||
</InputGroup>
|
</InputGroup>
|
||||||
)
|
)
|
@ -4,7 +4,7 @@ import Conversion from '../atoms/Price/Conversion'
|
|||||||
import PriceUnit from '../atoms/Price/PriceUnit'
|
import PriceUnit from '../atoms/Price/PriceUnit'
|
||||||
import Tooltip from '../atoms/Tooltip'
|
import Tooltip from '../atoms/Tooltip'
|
||||||
import NetworkName from '../atoms/NetworkName'
|
import NetworkName from '../atoms/NetworkName'
|
||||||
import { fetchData, getSubgrahUri } from '../../utils/subgraph'
|
import { fetchData, getSubgraphUri } from '../../utils/subgraph'
|
||||||
import { filterNetworksByType } from './UserPreferences/Networks/index'
|
import { filterNetworksByType } from './UserPreferences/Networks/index'
|
||||||
import { useSiteMetadata } from '../../hooks/useSiteMetadata'
|
import { useSiteMetadata } from '../../hooks/useSiteMetadata'
|
||||||
import useNetworkMetadata from '../../hooks/useNetworkMetadata'
|
import useNetworkMetadata from '../../hooks/useNetworkMetadata'
|
||||||
@ -113,7 +113,7 @@ export default function MarketStats(): ReactElement {
|
|||||||
|
|
||||||
for (const chainId of mainChainIdsList) {
|
for (const chainId of mainChainIdsList) {
|
||||||
const context: OperationContext = {
|
const context: OperationContext = {
|
||||||
url: `${getSubgrahUri(
|
url: `${getSubgraphUri(
|
||||||
chainId
|
chainId
|
||||||
)}/subgraphs/name/oceanprotocol/ocean-subgraph`,
|
)}/subgraphs/name/oceanprotocol/ocean-subgraph`,
|
||||||
requestPolicy: 'network-only'
|
requestPolicy: 'network-only'
|
||||||
|
@ -38,3 +38,6 @@
|
|||||||
.action {
|
.action {
|
||||||
margin-top: calc(var(--spacer) / 1.5);
|
margin-top: calc(var(--spacer) / 1.5);
|
||||||
}
|
}
|
||||||
|
.moreInfo {
|
||||||
|
padding: calc(var(--spacer) / 4) calc(var(--spacer) / 2) !important;
|
||||||
|
}
|
||||||
|
@ -70,7 +70,12 @@ export default function MetadataFeedback({
|
|||||||
<>
|
<>
|
||||||
<p>Sorry, something went wrong. Please try again.</p>
|
<p>Sorry, something went wrong. Please try again.</p>
|
||||||
{moreInfo && <Alert text={error} state="error" />}
|
{moreInfo && <Alert text={error} state="error" />}
|
||||||
<Button style="text" size="small" onClick={toggleMoreInfo}>
|
<Button
|
||||||
|
style="text"
|
||||||
|
size="small"
|
||||||
|
onClick={toggleMoreInfo}
|
||||||
|
className={styles.moreInfo}
|
||||||
|
>
|
||||||
{moreInfo === false ? 'More Info' : 'Hide error'}
|
{moreInfo === false ? 'More Info' : 'Hide error'}
|
||||||
</Button>
|
</Button>
|
||||||
<ActionError setError={setError} />
|
<ActionError setError={setError} />
|
||||||
|
@ -129,10 +129,12 @@ const columnsMinimal = [columns[0], columns[3]]
|
|||||||
|
|
||||||
export default function PoolTransactions({
|
export default function PoolTransactions({
|
||||||
poolAddress,
|
poolAddress,
|
||||||
|
poolChainId,
|
||||||
minimal,
|
minimal,
|
||||||
accountId
|
accountId
|
||||||
}: {
|
}: {
|
||||||
poolAddress?: string
|
poolAddress?: string
|
||||||
|
poolChainId?: number[]
|
||||||
minimal?: boolean
|
minimal?: boolean
|
||||||
accountId: string
|
accountId: string
|
||||||
}): ReactElement {
|
}): ReactElement {
|
||||||
@ -144,13 +146,17 @@ export default function PoolTransactions({
|
|||||||
const [data, setData] = useState<PoolTransaction[]>()
|
const [data, setData] = useState<PoolTransaction[]>()
|
||||||
|
|
||||||
async function fetchPoolTransactionData() {
|
async function fetchPoolTransactionData() {
|
||||||
const variables = { user: accountId?.toLowerCase() }
|
const variables = {
|
||||||
|
user: accountId?.toLowerCase(),
|
||||||
|
pool: poolAddress?.toLowerCase()
|
||||||
|
}
|
||||||
const transactions: PoolTransaction[] = []
|
const transactions: PoolTransaction[] = []
|
||||||
const result = await fetchDataForMultipleChains(
|
const result = await fetchDataForMultipleChains(
|
||||||
poolAddress ? txHistoryQueryByPool : txHistoryQuery,
|
poolAddress ? txHistoryQueryByPool : txHistoryQuery,
|
||||||
variables,
|
variables,
|
||||||
chainIds
|
poolAddress ? poolChainId : chainIds
|
||||||
)
|
)
|
||||||
|
|
||||||
for (let i = 0; i < result.length; i++) {
|
for (let i = 0; i < result.length; i++) {
|
||||||
result[i].poolTransactions.forEach((poolTransaction: PoolTransaction) => {
|
result[i].poolTransactions.forEach((poolTransaction: PoolTransaction) => {
|
||||||
transactions.push(poolTransaction)
|
transactions.push(poolTransaction)
|
||||||
|
@ -41,19 +41,20 @@ function handleTimeoutCustomOption(
|
|||||||
data[timeoutInputIndex].options[5] = values.timeout
|
data[timeoutInputIndex].options[5] = values.timeout
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function FormEditMetadata({
|
export default function FormEditMetadata({
|
||||||
data,
|
data,
|
||||||
setShowEdit,
|
setShowEdit,
|
||||||
setTimeoutStringValue,
|
setTimeoutStringValue,
|
||||||
values,
|
values,
|
||||||
showPrice
|
showPrice,
|
||||||
|
isComputeDataset
|
||||||
}: {
|
}: {
|
||||||
data: FormFieldProps[]
|
data: FormFieldProps[]
|
||||||
setShowEdit: (show: boolean) => void
|
setShowEdit: (show: boolean) => void
|
||||||
setTimeoutStringValue: (value: string) => void
|
setTimeoutStringValue: (value: string) => void
|
||||||
values: Partial<MetadataPublishFormDataset>
|
values: Partial<MetadataPublishFormDataset>
|
||||||
showPrice: boolean
|
showPrice: boolean
|
||||||
|
isComputeDataset: boolean
|
||||||
}): ReactElement {
|
}): ReactElement {
|
||||||
const { config } = useOcean()
|
const { config } = useOcean()
|
||||||
const {
|
const {
|
||||||
@ -70,12 +71,22 @@ export default function FormEditMetadata({
|
|||||||
validateField(field.name)
|
validateField(field.name)
|
||||||
setFieldValue(field.name, e.target.value)
|
setFieldValue(field.name, e.target.value)
|
||||||
}
|
}
|
||||||
|
|
||||||
// This component is handled by Formik so it's not rendered like a "normal" react component,
|
// This component is handled by Formik so it's not rendered like a "normal" react component,
|
||||||
// so handleTimeoutCustomOption is called only once.
|
// so handleTimeoutCustomOption is called only once.
|
||||||
// https://github.com/oceanprotocol/market/pull/324#discussion_r561132310
|
// https://github.com/oceanprotocol/market/pull/324#discussion_r561132310
|
||||||
if (data && values) handleTimeoutCustomOption(data, values)
|
if (data && values) handleTimeoutCustomOption(data, values)
|
||||||
|
|
||||||
|
const timeoutOptionsArray = data.filter(
|
||||||
|
(field) => field.name === 'timeout'
|
||||||
|
)[0].options
|
||||||
|
|
||||||
|
if (isComputeDataset && timeoutOptionsArray.includes('Forever')) {
|
||||||
|
const foreverOptionIndex = timeoutOptionsArray.indexOf('Forever')
|
||||||
|
timeoutOptionsArray.splice(foreverOptionIndex, 1)
|
||||||
|
} else if (!isComputeDataset && !timeoutOptionsArray.includes('Forever')) {
|
||||||
|
timeoutOptionsArray.push('Forever')
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Form className={styles.form}>
|
<Form className={styles.form}>
|
||||||
{data.map(
|
{data.map(
|
||||||
@ -83,6 +94,11 @@ export default function FormEditMetadata({
|
|||||||
(!showPrice && field.name === 'price') || (
|
(!showPrice && field.name === 'price') || (
|
||||||
<Field
|
<Field
|
||||||
key={field.name}
|
key={field.name}
|
||||||
|
options={
|
||||||
|
field.name === 'timeout' && isComputeDataset === true
|
||||||
|
? timeoutOptionsArray
|
||||||
|
: field.options
|
||||||
|
}
|
||||||
{...field}
|
{...field}
|
||||||
component={Input}
|
component={Input}
|
||||||
prefix={field.name === 'price' && config.oceanTokenSymbol}
|
prefix={field.name === 'price' && config.oceanTokenSymbol}
|
||||||
|
@ -55,9 +55,11 @@ const contentQuery = graphql`
|
|||||||
`
|
`
|
||||||
|
|
||||||
export default function Edit({
|
export default function Edit({
|
||||||
setShowEdit
|
setShowEdit,
|
||||||
|
isComputeType
|
||||||
}: {
|
}: {
|
||||||
setShowEdit: (show: boolean) => void
|
setShowEdit: (show: boolean) => void
|
||||||
|
isComputeType?: boolean
|
||||||
}): ReactElement {
|
}): ReactElement {
|
||||||
const data = useStaticQuery(contentQuery)
|
const data = useStaticQuery(contentQuery)
|
||||||
const content = data.content.edges[0].node.childPagesJson
|
const content = data.content.edges[0].node.childPagesJson
|
||||||
@ -201,6 +203,7 @@ export default function Edit({
|
|||||||
setTimeoutStringValue={setTimeoutStringValue}
|
setTimeoutStringValue={setTimeoutStringValue}
|
||||||
values={initialValues}
|
values={initialValues}
|
||||||
showPrice={price.type === 'exchange'}
|
showPrice={price.type === 'exchange'}
|
||||||
|
isComputeDataset={isComputeType}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<aside>
|
<aside>
|
||||||
|
@ -15,6 +15,9 @@ import UserLiquidity from '../../../../atoms/UserLiquidity'
|
|||||||
import { useOcean } from '../../../../../providers/Ocean'
|
import { useOcean } from '../../../../../providers/Ocean'
|
||||||
import { useWeb3 } from '../../../../../providers/Web3'
|
import { useWeb3 } from '../../../../../providers/Web3'
|
||||||
|
|
||||||
|
import { isValidNumber } from './../../../../../utils/numberValidations'
|
||||||
|
import Decimal from 'decimal.js'
|
||||||
|
|
||||||
export default function FormAdd({
|
export default function FormAdd({
|
||||||
coin,
|
coin,
|
||||||
dtBalance,
|
dtBalance,
|
||||||
@ -67,6 +70,7 @@ export default function FormAdd({
|
|||||||
setNewPoolShare('0')
|
setNewPoolShare('0')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Number(values.amount) > Number(amountMax)) return
|
if (Number(values.amount) > Number(amountMax)) return
|
||||||
|
|
||||||
const poolTokens = await ocean.pool.calcPoolOutGivenSingleIn(
|
const poolTokens = await ocean.pool.calcPoolOutGivenSingleIn(
|
||||||
@ -74,15 +78,20 @@ export default function FormAdd({
|
|||||||
coin === 'OCEAN' ? ocean.pool.oceanAddress : ocean.pool.dtAddress,
|
coin === 'OCEAN' ? ocean.pool.oceanAddress : ocean.pool.dtAddress,
|
||||||
`${values.amount}`
|
`${values.amount}`
|
||||||
)
|
)
|
||||||
|
|
||||||
setNewPoolTokens(poolTokens)
|
setNewPoolTokens(poolTokens)
|
||||||
totalBalance &&
|
|
||||||
setNewPoolShare(
|
const newPoolShareDecimal =
|
||||||
`${
|
isValidNumber(poolTokens) && isValidNumber(totalPoolTokens)
|
||||||
(Number(poolTokens) /
|
? new Decimal(poolTokens)
|
||||||
(Number(totalPoolTokens) + Number(poolTokens))) *
|
.dividedBy(
|
||||||
100
|
new Decimal(totalPoolTokens).plus(new Decimal(poolTokens))
|
||||||
}`
|
|
||||||
)
|
)
|
||||||
|
.mul(100)
|
||||||
|
.toString()
|
||||||
|
: '0'
|
||||||
|
|
||||||
|
totalBalance && setNewPoolShare(newPoolShareDecimal)
|
||||||
}
|
}
|
||||||
calculatePoolShares()
|
calculatePoolShares()
|
||||||
}, [
|
}, [
|
||||||
|
@ -2,6 +2,7 @@ import Conversion from '../../../atoms/Price/Conversion'
|
|||||||
import React, { ReactElement, ReactNode } from 'react'
|
import React, { ReactElement, ReactNode } from 'react'
|
||||||
import Token from './Token'
|
import Token from './Token'
|
||||||
import styles from './TokenList.module.css'
|
import styles from './TokenList.module.css'
|
||||||
|
import Decimal from 'decimal.js'
|
||||||
|
|
||||||
export default function TokenList({
|
export default function TokenList({
|
||||||
title,
|
title,
|
||||||
@ -20,7 +21,7 @@ export default function TokenList({
|
|||||||
dt: string
|
dt: string
|
||||||
dtSymbol: string
|
dtSymbol: string
|
||||||
poolShares: string
|
poolShares: string
|
||||||
conversion: number
|
conversion: Decimal
|
||||||
highlight?: boolean
|
highlight?: boolean
|
||||||
showTVLLabel?: boolean
|
showTVLLabel?: boolean
|
||||||
}): ReactElement {
|
}): ReactElement {
|
||||||
@ -31,9 +32,9 @@ export default function TokenList({
|
|||||||
<div>
|
<div>
|
||||||
<Token symbol="OCEAN" balance={ocean} />
|
<Token symbol="OCEAN" balance={ocean} />
|
||||||
<Token symbol={dtSymbol} balance={dt} />
|
<Token symbol={dtSymbol} balance={dt} />
|
||||||
{conversion > 0 && (
|
{conversion.greaterThan(0) && (
|
||||||
<Conversion
|
<Conversion
|
||||||
price={`${conversion}`}
|
price={conversion.toString()}
|
||||||
className={styles.totalLiquidity}
|
className={styles.totalLiquidity}
|
||||||
showTVLLabel={showTVLLabel}
|
showTVLLabel={showTVLLabel}
|
||||||
/>
|
/>
|
||||||
|
@ -22,8 +22,13 @@ import { useWeb3 } from '../../../../providers/Web3'
|
|||||||
import PoolTransactions from '../../../molecules/PoolTransactions'
|
import PoolTransactions from '../../../molecules/PoolTransactions'
|
||||||
import { fetchData, getQueryContext } from '../../../../utils/subgraph'
|
import { fetchData, getQueryContext } from '../../../../utils/subgraph'
|
||||||
|
|
||||||
|
import { isValidNumber } from './../../../../utils/numberValidations'
|
||||||
|
import Decimal from 'decimal.js'
|
||||||
|
|
||||||
const REFETCH_INTERVAL = 5000
|
const REFETCH_INTERVAL = 5000
|
||||||
|
|
||||||
|
Decimal.set({ toExpNeg: -18, precision: 18, rounding: 1 })
|
||||||
|
|
||||||
const contentQuery = graphql`
|
const contentQuery = graphql`
|
||||||
query PoolQuery {
|
query PoolQuery {
|
||||||
content: allFile(filter: { relativePath: { eq: "price.json" } }) {
|
content: allFile(filter: { relativePath: { eq: "price.json" } }) {
|
||||||
@ -85,11 +90,15 @@ export default function Pool(): ReactElement {
|
|||||||
|
|
||||||
const [hasAddedLiquidity, setHasAddedLiquidity] = useState(false)
|
const [hasAddedLiquidity, setHasAddedLiquidity] = useState(false)
|
||||||
const [poolShare, setPoolShare] = useState<string>()
|
const [poolShare, setPoolShare] = useState<string>()
|
||||||
const [totalUserLiquidityInOcean, setTotalUserLiquidityInOcean] = useState(0)
|
const [totalUserLiquidityInOcean, setTotalUserLiquidityInOcean] = useState(
|
||||||
const [totalLiquidityInOcean, setTotalLiquidityInOcean] = useState(0)
|
new Decimal(0)
|
||||||
|
)
|
||||||
|
const [totalLiquidityInOcean, setTotalLiquidityInOcean] = useState(
|
||||||
|
new Decimal(0)
|
||||||
|
)
|
||||||
|
|
||||||
const [creatorTotalLiquidityInOcean, setCreatorTotalLiquidityInOcean] =
|
const [creatorTotalLiquidityInOcean, setCreatorTotalLiquidityInOcean] =
|
||||||
useState(0)
|
useState(new Decimal(0))
|
||||||
const [creatorLiquidity, setCreatorLiquidity] = useState<PoolBalance>()
|
const [creatorLiquidity, setCreatorLiquidity] = useState<PoolBalance>()
|
||||||
const [creatorPoolTokens, setCreatorPoolTokens] = useState<string>()
|
const [creatorPoolTokens, setCreatorPoolTokens] = useState<string>()
|
||||||
const [creatorPoolShare, setCreatorPoolShare] = useState<string>()
|
const [creatorPoolShare, setCreatorPoolShare] = useState<string>()
|
||||||
@ -144,15 +153,28 @@ export default function Pool(): ReactElement {
|
|||||||
|
|
||||||
// Get swap fee
|
// Get swap fee
|
||||||
// swapFee is tricky: to get 0.1% you need to convert from 0.001
|
// swapFee is tricky: to get 0.1% you need to convert from 0.001
|
||||||
setSwapFee(`${Number(dataLiquidity.pool.swapFee) * 100}`)
|
const swapFee = isValidNumber(dataLiquidity.pool.swapFee)
|
||||||
|
? new Decimal(dataLiquidity.pool.swapFee).mul(100).toString()
|
||||||
|
: '0'
|
||||||
|
|
||||||
|
setSwapFee(swapFee)
|
||||||
|
|
||||||
// Get weights
|
// Get weights
|
||||||
const weightDt = dataLiquidity.pool.tokens.filter(
|
const weightDt = dataLiquidity.pool.tokens.filter(
|
||||||
(token: any) => token.tokenAddress === ddo.dataToken.toLowerCase()
|
(token: any) => token.tokenAddress === ddo.dataToken.toLowerCase()
|
||||||
)[0].denormWeight
|
)[0].denormWeight
|
||||||
|
|
||||||
setWeightDt(`${Number(weightDt) * 10}`)
|
const weightDtDecimal = isValidNumber(weightDt)
|
||||||
setWeightOcean(`${100 - Number(weightDt) * 10}`)
|
? new Decimal(weightDt).mul(10).toString()
|
||||||
|
: '0'
|
||||||
|
|
||||||
|
setWeightDt(weightDtDecimal)
|
||||||
|
|
||||||
|
const weightOceanDecimal = isValidNumber(weightDt)
|
||||||
|
? new Decimal(100).minus(new Decimal(weightDt).mul(10)).toString()
|
||||||
|
: '0'
|
||||||
|
|
||||||
|
setWeightOcean(weightOceanDecimal)
|
||||||
|
|
||||||
//
|
//
|
||||||
// Get everything the creator put into the pool
|
// Get everything the creator put into the pool
|
||||||
@ -161,12 +183,25 @@ export default function Pool(): ReactElement {
|
|||||||
const creatorPoolTokens = dataLiquidity.pool.shares[0].balance
|
const creatorPoolTokens = dataLiquidity.pool.shares[0].balance
|
||||||
setCreatorPoolTokens(creatorPoolTokens)
|
setCreatorPoolTokens(creatorPoolTokens)
|
||||||
|
|
||||||
// Calculate creator's provided liquidity based on pool tokens
|
|
||||||
const creatorOceanBalance =
|
const creatorOceanBalance =
|
||||||
(Number(creatorPoolTokens) / Number(totalPoolTokens)) * price.ocean
|
isValidNumber(creatorPoolTokens) &&
|
||||||
|
isValidNumber(totalPoolTokens) &&
|
||||||
|
isValidNumber(price.ocean)
|
||||||
|
? new Decimal(creatorPoolTokens)
|
||||||
|
.dividedBy(new Decimal(totalPoolTokens))
|
||||||
|
.mul(price.ocean)
|
||||||
|
.toString()
|
||||||
|
: '0'
|
||||||
|
|
||||||
const creatorDtBalance =
|
const creatorDtBalance =
|
||||||
(Number(creatorPoolTokens) / Number(totalPoolTokens)) * price.datatoken
|
isValidNumber(creatorPoolTokens) &&
|
||||||
|
isValidNumber(totalPoolTokens) &&
|
||||||
|
isValidNumber(price.datatoken)
|
||||||
|
? new Decimal(creatorPoolTokens)
|
||||||
|
.dividedBy(new Decimal(totalPoolTokens))
|
||||||
|
.mul(price.datatoken)
|
||||||
|
.toString()
|
||||||
|
: '0'
|
||||||
|
|
||||||
const creatorLiquidity = {
|
const creatorLiquidity = {
|
||||||
ocean: creatorOceanBalance,
|
ocean: creatorOceanBalance,
|
||||||
@ -175,14 +210,30 @@ export default function Pool(): ReactElement {
|
|||||||
setCreatorLiquidity(creatorLiquidity)
|
setCreatorLiquidity(creatorLiquidity)
|
||||||
|
|
||||||
const totalCreatorLiquidityInOcean =
|
const totalCreatorLiquidityInOcean =
|
||||||
creatorLiquidity?.ocean +
|
isValidNumber(creatorLiquidity?.ocean) &&
|
||||||
creatorLiquidity?.datatoken * dataLiquidity.pool.spotPrice
|
isValidNumber(creatorLiquidity?.datatoken) &&
|
||||||
|
isValidNumber(dataLiquidity.pool.spotPrice)
|
||||||
|
? new Decimal(creatorLiquidity?.ocean).add(
|
||||||
|
new Decimal(creatorLiquidity?.datatoken).mul(
|
||||||
|
new Decimal(dataLiquidity.pool.spotPrice)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
: new Decimal(0)
|
||||||
|
|
||||||
setCreatorTotalLiquidityInOcean(totalCreatorLiquidityInOcean)
|
setCreatorTotalLiquidityInOcean(totalCreatorLiquidityInOcean)
|
||||||
|
|
||||||
const creatorPoolShare =
|
const creatorPoolShare =
|
||||||
price?.ocean &&
|
price?.ocean &&
|
||||||
price?.datatoken &&
|
price?.datatoken &&
|
||||||
creatorLiquidity &&
|
creatorLiquidity &&
|
||||||
((Number(creatorPoolTokens) / Number(totalPoolTokens)) * 100).toFixed(2)
|
isValidNumber(creatorPoolTokens) &&
|
||||||
|
isValidNumber(totalPoolTokens)
|
||||||
|
? new Decimal(creatorPoolTokens)
|
||||||
|
.dividedBy(new Decimal(totalPoolTokens))
|
||||||
|
.mul(100)
|
||||||
|
.toFixed(2)
|
||||||
|
: '0'
|
||||||
|
|
||||||
setCreatorPoolShare(creatorPoolShare)
|
setCreatorPoolShare(creatorPoolShare)
|
||||||
refetchLiquidity()
|
refetchLiquidity()
|
||||||
}
|
}
|
||||||
@ -195,17 +246,38 @@ export default function Pool(): ReactElement {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const poolShare =
|
const poolShare =
|
||||||
|
isValidNumber(poolTokens) &&
|
||||||
|
isValidNumber(totalPoolTokens) &&
|
||||||
price?.ocean &&
|
price?.ocean &&
|
||||||
price?.datatoken &&
|
price?.datatoken &&
|
||||||
((Number(poolTokens) / Number(totalPoolTokens)) * 100).toFixed(5)
|
new Decimal(poolTokens)
|
||||||
|
.dividedBy(new Decimal(totalPoolTokens))
|
||||||
|
.mul(100)
|
||||||
|
.toFixed(5)
|
||||||
|
|
||||||
setPoolShare(poolShare)
|
setPoolShare(poolShare)
|
||||||
setHasAddedLiquidity(Number(poolShare) > 0)
|
setHasAddedLiquidity(Number(poolShare) > 0)
|
||||||
|
|
||||||
const totalUserLiquidityInOcean =
|
const totalUserLiquidityInOcean =
|
||||||
userLiquidity?.ocean + userLiquidity?.datatoken * price?.value
|
isValidNumber(userLiquidity?.ocean) &&
|
||||||
|
isValidNumber(userLiquidity?.datatoken) &&
|
||||||
|
isValidNumber(price?.value)
|
||||||
|
? new Decimal(userLiquidity?.ocean).add(
|
||||||
|
new Decimal(userLiquidity?.datatoken).mul(price?.value)
|
||||||
|
)
|
||||||
|
: new Decimal(0)
|
||||||
|
|
||||||
setTotalUserLiquidityInOcean(totalUserLiquidityInOcean)
|
setTotalUserLiquidityInOcean(totalUserLiquidityInOcean)
|
||||||
|
|
||||||
const totalLiquidityInOcean =
|
const totalLiquidityInOcean =
|
||||||
Number(price?.ocean) + Number(price?.datatoken) * Number(price?.value)
|
isValidNumber(price?.ocean) &&
|
||||||
|
isValidNumber(price?.datatoken) &&
|
||||||
|
isValidNumber(price?.value)
|
||||||
|
? new Decimal(price?.ocean).add(
|
||||||
|
new Decimal(price?.datatoken).mul(price?.value)
|
||||||
|
)
|
||||||
|
: new Decimal(0)
|
||||||
|
|
||||||
setTotalLiquidityInOcean(totalLiquidityInOcean)
|
setTotalLiquidityInOcean(totalLiquidityInOcean)
|
||||||
}, [userLiquidity, price, poolTokens, totalPoolTokens])
|
}, [userLiquidity, price, poolTokens, totalPoolTokens])
|
||||||
|
|
||||||
@ -221,11 +293,28 @@ export default function Pool(): ReactElement {
|
|||||||
price.address
|
price.address
|
||||||
)
|
)
|
||||||
setPoolTokens(poolTokens)
|
setPoolTokens(poolTokens)
|
||||||
|
|
||||||
// calculate user's provided liquidity based on pool tokens
|
// calculate user's provided liquidity based on pool tokens
|
||||||
const userOceanBalance =
|
const userOceanBalance =
|
||||||
(Number(poolTokens) / Number(totalPoolTokens)) * price.ocean
|
isValidNumber(poolTokens) &&
|
||||||
|
isValidNumber(totalPoolTokens) &&
|
||||||
|
isValidNumber(price.ocean)
|
||||||
|
? new Decimal(poolTokens)
|
||||||
|
.dividedBy(new Decimal(totalPoolTokens))
|
||||||
|
.mul(price.ocean)
|
||||||
|
.toString()
|
||||||
|
: '0'
|
||||||
|
|
||||||
const userDtBalance =
|
const userDtBalance =
|
||||||
(Number(poolTokens) / Number(totalPoolTokens)) * price.datatoken
|
isValidNumber(poolTokens) &&
|
||||||
|
isValidNumber(totalPoolTokens) &&
|
||||||
|
isValidNumber(price.datatoken)
|
||||||
|
? new Decimal(poolTokens)
|
||||||
|
.dividedBy(new Decimal(totalPoolTokens))
|
||||||
|
.mul(price.datatoken)
|
||||||
|
.toString()
|
||||||
|
: '0'
|
||||||
|
|
||||||
const userLiquidity = {
|
const userLiquidity = {
|
||||||
ocean: userOceanBalance,
|
ocean: userOceanBalance,
|
||||||
datatoken: userDtBalance
|
datatoken: userDtBalance
|
||||||
@ -255,8 +344,8 @@ export default function Pool(): ReactElement {
|
|||||||
poolAddress={price.address}
|
poolAddress={price.address}
|
||||||
totalPoolTokens={totalPoolTokens}
|
totalPoolTokens={totalPoolTokens}
|
||||||
totalBalance={{
|
totalBalance={{
|
||||||
ocean: price.ocean,
|
ocean: new Decimal(price.ocean).toString(),
|
||||||
datatoken: price.datatoken
|
datatoken: new Decimal(price.datatoken).toString()
|
||||||
}}
|
}}
|
||||||
swapFee={swapFee}
|
swapFee={swapFee}
|
||||||
dtSymbol={dtSymbol}
|
dtSymbol={dtSymbol}
|
||||||
@ -367,7 +456,7 @@ export default function Pool(): ReactElement {
|
|||||||
style="primary"
|
style="primary"
|
||||||
size="small"
|
size="small"
|
||||||
onClick={() => setShowAdd(true)}
|
onClick={() => setShowAdd(true)}
|
||||||
disabled={isInPurgatory || !isAssetNetwork}
|
disabled={isInPurgatory}
|
||||||
>
|
>
|
||||||
Add Liquidity
|
Add Liquidity
|
||||||
</Button>
|
</Button>
|
||||||
@ -389,6 +478,7 @@ export default function Pool(): ReactElement {
|
|||||||
<PoolTransactions
|
<PoolTransactions
|
||||||
accountId={accountId}
|
accountId={accountId}
|
||||||
poolAddress={price?.address}
|
poolAddress={price?.address}
|
||||||
|
poolChainId={[ddo.chainId]}
|
||||||
minimal
|
minimal
|
||||||
/>
|
/>
|
||||||
</AssetActionHistoryTable>
|
</AssetActionHistoryTable>
|
||||||
|
@ -1,5 +1,10 @@
|
|||||||
import { Ocean } from '@oceanprotocol/lib'
|
import { Ocean } from '@oceanprotocol/lib'
|
||||||
|
|
||||||
|
import { isValidNumber } from './../../../../utils/numberValidations'
|
||||||
|
import Decimal from 'decimal.js'
|
||||||
|
|
||||||
|
Decimal.set({ toExpNeg: -18, precision: 18, rounding: 1 })
|
||||||
|
|
||||||
export async function getMaxPercentRemove(
|
export async function getMaxPercentRemove(
|
||||||
ocean: Ocean,
|
ocean: Ocean,
|
||||||
poolAddress: string,
|
poolAddress: string,
|
||||||
@ -15,9 +20,15 @@ export async function getMaxPercentRemove(
|
|||||||
amountMaxOcean
|
amountMaxOcean
|
||||||
)
|
)
|
||||||
|
|
||||||
let amountMaxPercent = `${Math.floor(
|
let amountMaxPercent =
|
||||||
(Number(amountMaxPoolShares) / Number(poolTokens)) * 100
|
isValidNumber(amountMaxPoolShares) && isValidNumber(poolTokens)
|
||||||
)}`
|
? new Decimal(amountMaxPoolShares)
|
||||||
|
.dividedBy(new Decimal(poolTokens))
|
||||||
|
.mul(100)
|
||||||
|
.floor()
|
||||||
|
.toString()
|
||||||
|
: '0'
|
||||||
|
|
||||||
if (Number(amountMaxPercent) > 100) {
|
if (Number(amountMaxPercent) > 100) {
|
||||||
amountMaxPercent = '100'
|
amountMaxPercent = '100'
|
||||||
}
|
}
|
||||||
|
@ -42,8 +42,8 @@ export default function FormTrade({
|
|||||||
}: {
|
}: {
|
||||||
ddo: DDO
|
ddo: DDO
|
||||||
balance: PoolBalance
|
balance: PoolBalance
|
||||||
maxDt: number
|
maxDt: string
|
||||||
maxOcean: number
|
maxOcean: string
|
||||||
price: BestPrice
|
price: BestPrice
|
||||||
}): ReactElement {
|
}): ReactElement {
|
||||||
const data = useStaticQuery(contentQuery)
|
const data = useStaticQuery(contentQuery)
|
||||||
@ -61,12 +61,18 @@ export default function FormTrade({
|
|||||||
const validationSchema: Yup.SchemaOf<FormTradeData> = Yup.object()
|
const validationSchema: Yup.SchemaOf<FormTradeData> = Yup.object()
|
||||||
.shape({
|
.shape({
|
||||||
ocean: Yup.number()
|
ocean: Yup.number()
|
||||||
.max(maximumOcean, (param) => `Must be more or equal to ${param.max}`)
|
.max(
|
||||||
|
Number(maximumOcean),
|
||||||
|
(param) => `Must be more or equal to ${param.max}`
|
||||||
|
)
|
||||||
.min(0.001, (param) => `Must be more or equal to ${param.min}`)
|
.min(0.001, (param) => `Must be more or equal to ${param.min}`)
|
||||||
.required('Required')
|
.required('Required')
|
||||||
.nullable(),
|
.nullable(),
|
||||||
datatoken: Yup.number()
|
datatoken: Yup.number()
|
||||||
.max(maximumDt, (param) => `Must be less or equal than ${param.max}`)
|
.max(
|
||||||
|
Number(maximumDt),
|
||||||
|
(param) => `Must be less or equal than ${param.max}`
|
||||||
|
)
|
||||||
.min(0.00001, (param) => `Must be more or equal to ${param.min}`)
|
.min(0.00001, (param) => `Must be more or equal to ${param.min}`)
|
||||||
.required('Required')
|
.required('Required')
|
||||||
.nullable(),
|
.nullable(),
|
||||||
@ -77,7 +83,9 @@ export default function FormTrade({
|
|||||||
|
|
||||||
async function handleTrade(values: FormTradeData) {
|
async function handleTrade(values: FormTradeData) {
|
||||||
try {
|
try {
|
||||||
const impact = new Decimal(100 - Number(values.slippage)).div(100)
|
const impact = new Decimal(
|
||||||
|
new Decimal(100).sub(new Decimal(values.slippage))
|
||||||
|
).div(100)
|
||||||
const precision = 15
|
const precision = 15
|
||||||
const tx =
|
const tx =
|
||||||
values.type === 'buy'
|
values.type === 'buy'
|
||||||
|
@ -5,6 +5,11 @@ import { useOcean } from '../../../../providers/Ocean'
|
|||||||
import Token from '../Pool/Token'
|
import Token from '../Pool/Token'
|
||||||
import styles from './Output.module.css'
|
import styles from './Output.module.css'
|
||||||
|
|
||||||
|
import { isValidNumber } from './../../../../utils/numberValidations'
|
||||||
|
import Decimal from 'decimal.js'
|
||||||
|
|
||||||
|
Decimal.set({ toExpNeg: -18, precision: 18, rounding: 1 })
|
||||||
|
|
||||||
export default function Output({
|
export default function Output({
|
||||||
dtSymbol,
|
dtSymbol,
|
||||||
poolAddress
|
poolAddress
|
||||||
@ -25,12 +30,20 @@ export default function Output({
|
|||||||
|
|
||||||
async function getSwapFee() {
|
async function getSwapFee() {
|
||||||
const swapFee = await ocean.pool.getSwapFee(poolAddress)
|
const swapFee = await ocean.pool.getSwapFee(poolAddress)
|
||||||
|
|
||||||
// swapFee is tricky: to get 0.1% you need to convert from 0.001
|
// swapFee is tricky: to get 0.1% you need to convert from 0.001
|
||||||
setSwapFee(`${Number(swapFee) * 100}`)
|
setSwapFee(
|
||||||
|
isValidNumber(swapFee) ? new Decimal(swapFee).mul(100).toString() : '0'
|
||||||
|
)
|
||||||
|
|
||||||
const value =
|
const value =
|
||||||
values.type === 'buy'
|
values.type === 'buy'
|
||||||
? Number(swapFee) * values.ocean
|
? isValidNumber(swapFee) && isValidNumber(values.ocean)
|
||||||
: Number(swapFee) * values.datatoken
|
? new Decimal(swapFee).mul(new Decimal(values.ocean))
|
||||||
|
: 0
|
||||||
|
: isValidNumber(swapFee) && isValidNumber(values.datatoken)
|
||||||
|
? new Decimal(swapFee).mul(new Decimal(values.datatoken))
|
||||||
|
: 0
|
||||||
setSwapFeeValue(value.toString())
|
setSwapFeeValue(value.toString())
|
||||||
}
|
}
|
||||||
getSwapFee()
|
getSwapFee()
|
||||||
@ -46,8 +59,14 @@ export default function Output({
|
|||||||
const maxImpact = 1 - Number(values.slippage) / 100
|
const maxImpact = 1 - Number(values.slippage) / 100
|
||||||
const maxPrice =
|
const maxPrice =
|
||||||
values.type === 'buy'
|
values.type === 'buy'
|
||||||
? (values.datatoken * maxImpact).toString()
|
? isValidNumber(values.datatoken) && isValidNumber(maxImpact)
|
||||||
: (values.ocean * maxImpact).toString()
|
? new Decimal(values.datatoken)
|
||||||
|
.mul(new Decimal(maxImpact))
|
||||||
|
.toString()
|
||||||
|
: '0'
|
||||||
|
: isValidNumber(values.ocean) && isValidNumber(maxImpact)
|
||||||
|
? new Decimal(values.ocean).mul(new Decimal(maxImpact)).toString()
|
||||||
|
: '0'
|
||||||
|
|
||||||
setMaxOutput(maxPrice)
|
setMaxOutput(maxPrice)
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,24 @@
|
|||||||
|
.priceImpact {
|
||||||
|
font-size: var(--font-size-small);
|
||||||
|
border-top: 1px solid var(--border-color);
|
||||||
|
margin-left: -2rem;
|
||||||
|
margin-right: -2rem;
|
||||||
|
padding: calc(var(--spacer) / 4) var(--spacer);
|
||||||
|
color: var(--color-secondary);
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr 1fr;
|
||||||
|
gap: calc(var(--spacer) / 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.priceImpact strong {
|
||||||
|
font-weight: var(--font-weight-base);
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.alert {
|
||||||
|
color: var(--brand-alert-red);
|
||||||
|
}
|
||||||
|
|
||||||
|
.number {
|
||||||
|
font-weight: var(--font-weight-bold);
|
||||||
|
}
|
65
src/components/organisms/AssetActions/Trade/PriceImpact.tsx
Normal file
65
src/components/organisms/AssetActions/Trade/PriceImpact.tsx
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
import React, { ReactElement, useEffect, useState } from 'react'
|
||||||
|
import Decimal from 'decimal.js'
|
||||||
|
import Tooltip from '../../../atoms/Tooltip'
|
||||||
|
import styles from './PriceImpact.module.css'
|
||||||
|
|
||||||
|
export default function PriceImpact({
|
||||||
|
totalValue,
|
||||||
|
tokenAmount,
|
||||||
|
spotPrice
|
||||||
|
}: {
|
||||||
|
/// how much the user actually pays (doesn't matter witch token it is)
|
||||||
|
totalValue: string
|
||||||
|
/// how many tokens the user trades (doesn't matter witch token it is)
|
||||||
|
tokenAmount: string
|
||||||
|
/// the spot price of the traded token (doesn't matter witch token it is))
|
||||||
|
spotPrice: string
|
||||||
|
}): ReactElement {
|
||||||
|
const [priceImpact, setPriceImpact] = useState<string>('0')
|
||||||
|
|
||||||
|
async function getPriceImpact(
|
||||||
|
totalValue: string,
|
||||||
|
tokenAmount: string,
|
||||||
|
spotPrice: string
|
||||||
|
) {
|
||||||
|
const dtotalValue = new Decimal(totalValue)
|
||||||
|
const dTokenAmount = new Decimal(tokenAmount)
|
||||||
|
const dSpotPrice = new Decimal(spotPrice)
|
||||||
|
let priceImpact = Decimal.abs(
|
||||||
|
dtotalValue.div(dTokenAmount.times(dSpotPrice)).minus(1)
|
||||||
|
).mul(100)
|
||||||
|
if (priceImpact.isNaN()) priceImpact = new Decimal(0)
|
||||||
|
return priceImpact.toDecimalPlaces(2, Decimal.ROUND_DOWN)
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!totalValue || !tokenAmount || !spotPrice) {
|
||||||
|
setPriceImpact('0')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
async function init() {
|
||||||
|
const newPriceImpact = await getPriceImpact(
|
||||||
|
totalValue,
|
||||||
|
tokenAmount,
|
||||||
|
spotPrice
|
||||||
|
)
|
||||||
|
setPriceImpact(newPriceImpact.toString())
|
||||||
|
}
|
||||||
|
init()
|
||||||
|
}, [totalValue, tokenAmount, spotPrice])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={styles.priceImpact}>
|
||||||
|
<strong>Price impact</strong>
|
||||||
|
<div>
|
||||||
|
<span
|
||||||
|
className={`${styles.number} ${
|
||||||
|
parseInt(priceImpact) > 5 && styles.alert
|
||||||
|
}`}
|
||||||
|
>{`${priceImpact}%`}</span>
|
||||||
|
<Tooltip content="The difference between the market price and estimated price due to trade size." />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
@ -4,13 +4,15 @@
|
|||||||
margin-left: -2rem;
|
margin-left: -2rem;
|
||||||
margin-right: -2rem;
|
margin-right: -2rem;
|
||||||
padding: calc(var(--spacer) / 4) var(--spacer);
|
padding: calc(var(--spacer) / 4) var(--spacer);
|
||||||
text-align: center;
|
|
||||||
color: var(--color-secondary);
|
color: var(--color-secondary);
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr 1fr;
|
||||||
|
gap: calc(var(--spacer) / 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
.slippage strong {
|
.slippage strong {
|
||||||
font-weight: var(--font-weight-base);
|
font-weight: var(--font-weight-base);
|
||||||
color: var(--font-color-heading);
|
text-align: right;
|
||||||
}
|
}
|
||||||
|
|
||||||
.title {
|
.title {
|
||||||
@ -25,6 +27,4 @@
|
|||||||
.slippage select {
|
.slippage select {
|
||||||
width: fit-content;
|
width: fit-content;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
margin-left: calc(var(--spacer) / 4);
|
|
||||||
margin-right: calc(var(--spacer) / 4);
|
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
import { FormikContextType, useFormikContext } from 'formik'
|
import { FormikContextType, useFormikContext } from 'formik'
|
||||||
import React, { ChangeEvent, ReactElement, useEffect, useState } from 'react'
|
import React, { ChangeEvent, ReactElement } from 'react'
|
||||||
import { FormTradeData, slippagePresets } from '../../../../models/FormTrade'
|
import { FormTradeData, slippagePresets } from '../../../../models/FormTrade'
|
||||||
import InputElement from '../../../atoms/Input/InputElement'
|
import InputElement from '../../../atoms/Input/InputElement'
|
||||||
|
import Tooltip from '../../../atoms/Tooltip'
|
||||||
import styles from './Slippage.module.css'
|
import styles from './Slippage.module.css'
|
||||||
|
|
||||||
export default function Slippage(): ReactElement {
|
export default function Slippage(): ReactElement {
|
||||||
@ -14,9 +15,9 @@ export default function Slippage(): ReactElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
|
||||||
<div className={styles.slippage}>
|
<div className={styles.slippage}>
|
||||||
<strong>Expected price impact</strong>
|
<strong>Slippage Tolerance</strong>
|
||||||
|
<div>
|
||||||
<InputElement
|
<InputElement
|
||||||
name="slippage"
|
name="slippage"
|
||||||
type="select"
|
type="select"
|
||||||
@ -27,7 +28,8 @@ export default function Slippage(): ReactElement {
|
|||||||
value={values.slippage}
|
value={values.slippage}
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
/>
|
/>
|
||||||
|
<Tooltip content="Your transaction will revert if the price changes unfavorably by more than this percentage." />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</>
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,11 @@ import Output from './Output'
|
|||||||
import Slippage from './Slippage'
|
import Slippage from './Slippage'
|
||||||
import { FormTradeData, TradeItem } from '../../../../models/FormTrade'
|
import { FormTradeData, TradeItem } from '../../../../models/FormTrade'
|
||||||
import { useOcean } from '../../../../providers/Ocean'
|
import { useOcean } from '../../../../providers/Ocean'
|
||||||
|
import PriceImpact from './PriceImpact'
|
||||||
|
|
||||||
|
import Decimal from 'decimal.js'
|
||||||
|
|
||||||
|
Decimal.set({ toExpNeg: -18, precision: 18, rounding: 1 })
|
||||||
|
|
||||||
export default function Swap({
|
export default function Swap({
|
||||||
ddo,
|
ddo,
|
||||||
@ -21,23 +26,23 @@ export default function Swap({
|
|||||||
setMaximumOcean
|
setMaximumOcean
|
||||||
}: {
|
}: {
|
||||||
ddo: DDO
|
ddo: DDO
|
||||||
maxDt: number
|
maxDt: string
|
||||||
maxOcean: number
|
maxOcean: string
|
||||||
balance: PoolBalance
|
balance: PoolBalance
|
||||||
price: BestPrice
|
price: BestPrice
|
||||||
setMaximumDt: (value: number) => void
|
setMaximumDt: (value: string) => void
|
||||||
setMaximumOcean: (value: number) => void
|
setMaximumOcean: (value: string) => void
|
||||||
}): ReactElement {
|
}): ReactElement {
|
||||||
const { ocean } = useOcean()
|
const { ocean } = useOcean()
|
||||||
const [oceanItem, setOceanItem] = useState<TradeItem>({
|
const [oceanItem, setOceanItem] = useState<TradeItem>({
|
||||||
amount: 0,
|
amount: '0',
|
||||||
token: 'OCEAN',
|
token: 'OCEAN',
|
||||||
maxAmount: 0
|
maxAmount: '0'
|
||||||
})
|
})
|
||||||
const [dtItem, setDtItem] = useState<TradeItem>({
|
const [dtItem, setDtItem] = useState<TradeItem>({
|
||||||
amount: 0,
|
amount: '0',
|
||||||
token: ddo.dataTokenInfo.symbol,
|
token: ddo.dataTokenInfo.symbol,
|
||||||
maxAmount: 0
|
maxAmount: '0'
|
||||||
})
|
})
|
||||||
|
|
||||||
const {
|
const {
|
||||||
@ -47,6 +52,11 @@ export default function Swap({
|
|||||||
validateForm
|
validateForm
|
||||||
}: FormikContextType<FormTradeData> = useFormikContext()
|
}: FormikContextType<FormTradeData> = useFormikContext()
|
||||||
|
|
||||||
|
/// Values used for calculation of price impact
|
||||||
|
const [spotPrice, setSpotPrice] = useState<string>()
|
||||||
|
const [totalValue, setTotalValue] = useState<string>()
|
||||||
|
const [tokenAmount, setTokenAmount] = useState<string>()
|
||||||
|
///
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!ddo || !balance || !values || !price) return
|
if (!ddo || !balance || !values || !price) return
|
||||||
|
|
||||||
@ -66,32 +76,32 @@ export default function Swap({
|
|||||||
const maximumDt =
|
const maximumDt =
|
||||||
values.type === 'buy'
|
values.type === 'buy'
|
||||||
? Number(dtAmount) > Number(maxBuyDt)
|
? Number(dtAmount) > Number(maxBuyDt)
|
||||||
? Number(maxBuyDt)
|
? new Decimal(maxBuyDt)
|
||||||
: Number(dtAmount)
|
: new Decimal(dtAmount)
|
||||||
: Number(dtAmount) > balance.datatoken
|
: Number(dtAmount) > Number(balance.datatoken)
|
||||||
? balance.datatoken
|
? new Decimal(balance.datatoken)
|
||||||
: Number(dtAmount)
|
: new Decimal(dtAmount)
|
||||||
|
|
||||||
const maximumOcean =
|
const maximumOcean =
|
||||||
values.type === 'sell'
|
values.type === 'sell'
|
||||||
? Number(oceanAmount) > Number(maxBuyOcean)
|
? Number(oceanAmount) > Number(maxBuyOcean)
|
||||||
? Number(maxBuyOcean)
|
? new Decimal(maxBuyOcean)
|
||||||
: Number(oceanAmount)
|
: new Decimal(oceanAmount)
|
||||||
: Number(oceanAmount) > balance.ocean
|
: Number(oceanAmount) > Number(balance.ocean)
|
||||||
? balance.ocean
|
? new Decimal(balance.ocean)
|
||||||
: Number(oceanAmount)
|
: new Decimal(oceanAmount)
|
||||||
|
|
||||||
setMaximumDt(maximumDt)
|
setMaximumDt(maximumDt.toString())
|
||||||
setMaximumOcean(maximumOcean)
|
setMaximumOcean(maximumOcean.toString())
|
||||||
setOceanItem({
|
setOceanItem({
|
||||||
...oceanItem,
|
...oceanItem,
|
||||||
amount: oceanAmount,
|
amount: oceanAmount.toString(),
|
||||||
maxAmount: maximumOcean
|
maxAmount: maximumOcean.toString()
|
||||||
})
|
})
|
||||||
setDtItem({
|
setDtItem({
|
||||||
...dtItem,
|
...dtItem,
|
||||||
amount: dtAmount,
|
amount: dtAmount.toString(),
|
||||||
maxAmount: maximumDt
|
maxAmount: maximumDt.toString()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
calculateMaximum()
|
calculateMaximum()
|
||||||
@ -106,16 +116,63 @@ export default function Swap({
|
|||||||
}
|
}
|
||||||
|
|
||||||
const handleValueChange = async (name: string, value: number) => {
|
const handleValueChange = async (name: string, value: number) => {
|
||||||
const newValue =
|
let tokenIn = ''
|
||||||
name === 'ocean'
|
let tokenOut = ''
|
||||||
? values.type === 'sell'
|
let newValue
|
||||||
? await ocean.pool.getDTNeeded(price.address, value.toString())
|
|
||||||
: await ocean.pool.getDTReceived(price.address, value.toString())
|
|
||||||
: values.type === 'sell'
|
|
||||||
? await ocean.pool.getOceanReceived(price.address, value.toString())
|
|
||||||
: await ocean.pool.getOceanNeeded(price.address, value.toString())
|
|
||||||
|
|
||||||
setFieldValue(name === 'ocean' ? 'datatoken' : 'ocean', newValue)
|
if (name === 'ocean') {
|
||||||
|
if (values.type === 'sell') {
|
||||||
|
newValue = await ocean.pool.getDTNeeded(price.address, value.toString())
|
||||||
|
|
||||||
|
setTotalValue(newValue)
|
||||||
|
setTokenAmount(value.toString())
|
||||||
|
|
||||||
|
tokenIn = ddo.dataToken
|
||||||
|
tokenOut = ocean.pool.oceanAddress
|
||||||
|
} else {
|
||||||
|
newValue = await ocean.pool.getDTReceived(
|
||||||
|
price.address,
|
||||||
|
value.toString()
|
||||||
|
)
|
||||||
|
|
||||||
|
setTotalValue(value.toString())
|
||||||
|
setTokenAmount(newValue)
|
||||||
|
tokenIn = ocean.pool.oceanAddress
|
||||||
|
tokenOut = ddo.dataToken
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (values.type === 'sell') {
|
||||||
|
newValue = await ocean.pool.getOceanReceived(
|
||||||
|
price.address,
|
||||||
|
value.toString()
|
||||||
|
)
|
||||||
|
|
||||||
|
setTotalValue(value.toString())
|
||||||
|
setTokenAmount(newValue)
|
||||||
|
tokenIn = ddo.dataToken
|
||||||
|
tokenOut = ocean.pool.oceanAddress
|
||||||
|
} else {
|
||||||
|
newValue = await ocean.pool.getOceanNeeded(
|
||||||
|
price.address,
|
||||||
|
value.toString()
|
||||||
|
)
|
||||||
|
|
||||||
|
setTotalValue(newValue)
|
||||||
|
setTokenAmount(value.toString())
|
||||||
|
tokenIn = ocean.pool.oceanAddress
|
||||||
|
tokenOut = ddo.dataToken
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await setFieldValue(name === 'ocean' ? 'datatoken' : 'ocean', newValue)
|
||||||
|
|
||||||
|
const spotPrice = await ocean.pool.getSpotPrice(
|
||||||
|
price.address,
|
||||||
|
tokenIn,
|
||||||
|
tokenOut
|
||||||
|
)
|
||||||
|
|
||||||
|
setSpotPrice(spotPrice)
|
||||||
validateForm()
|
validateForm()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -139,6 +196,11 @@ export default function Swap({
|
|||||||
|
|
||||||
<Output dtSymbol={dtItem.token} poolAddress={price?.address} />
|
<Output dtSymbol={dtItem.token} poolAddress={price?.address} />
|
||||||
|
|
||||||
|
<PriceImpact
|
||||||
|
totalValue={totalValue}
|
||||||
|
tokenAmount={tokenAmount}
|
||||||
|
spotPrice={spotPrice}
|
||||||
|
/>
|
||||||
<Slippage />
|
<Slippage />
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
@ -73,7 +73,7 @@ export default function TradeInput({
|
|||||||
size="small"
|
size="small"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setFieldValue(name, item?.maxAmount)
|
setFieldValue(name, item?.maxAmount)
|
||||||
handleValueChange(name, item?.maxAmount)
|
handleValueChange(name, Number(item?.maxAmount))
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Use Max
|
Use Max
|
||||||
|
@ -5,13 +5,18 @@ import { useAsset } from '../../../../providers/Asset'
|
|||||||
import { useOcean } from '../../../../providers/Ocean'
|
import { useOcean } from '../../../../providers/Ocean'
|
||||||
import { useWeb3 } from '../../../../providers/Web3'
|
import { useWeb3 } from '../../../../providers/Web3'
|
||||||
|
|
||||||
|
import { isValidNumber } from './../../../../utils/numberValidations'
|
||||||
|
import Decimal from 'decimal.js'
|
||||||
|
|
||||||
|
Decimal.set({ toExpNeg: -18, precision: 18, rounding: 1 })
|
||||||
|
|
||||||
export default function Trade(): ReactElement {
|
export default function Trade(): ReactElement {
|
||||||
const { accountId, balance } = useWeb3()
|
const { accountId, balance } = useWeb3()
|
||||||
const { ocean } = useOcean()
|
const { ocean } = useOcean()
|
||||||
const [tokenBalance, setTokenBalance] = useState<PoolBalance>()
|
const [tokenBalance, setTokenBalance] = useState<PoolBalance>()
|
||||||
const { price, ddo } = useAsset()
|
const { price, ddo } = useAsset()
|
||||||
const [maxDt, setMaxDt] = useState(0)
|
const [maxDt, setMaxDt] = useState('0')
|
||||||
const [maxOcean, setMaxOcean] = useState(0)
|
const [maxOcean, setMaxOcean] = useState('0')
|
||||||
|
|
||||||
// Get datatoken balance, and combine with OCEAN balance from hooks into one object
|
// Get datatoken balance, and combine with OCEAN balance from hooks into one object
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -20,8 +25,8 @@ export default function Trade(): ReactElement {
|
|||||||
async function getTokenBalance() {
|
async function getTokenBalance() {
|
||||||
const dtBalance = await ocean.datatokens.balance(ddo.dataToken, accountId)
|
const dtBalance = await ocean.datatokens.balance(ddo.dataToken, accountId)
|
||||||
setTokenBalance({
|
setTokenBalance({
|
||||||
ocean: Number(balance.ocean),
|
ocean: new Decimal(balance.ocean).toString(),
|
||||||
datatoken: Number(dtBalance)
|
datatoken: new Decimal(dtBalance).toString()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
getTokenBalance()
|
getTokenBalance()
|
||||||
@ -35,12 +40,20 @@ export default function Trade(): ReactElement {
|
|||||||
const maxTokensInPool = await ocean.pool.getDTMaxBuyQuantity(
|
const maxTokensInPool = await ocean.pool.getDTMaxBuyQuantity(
|
||||||
price.address
|
price.address
|
||||||
)
|
)
|
||||||
setMaxDt(Number(maxTokensInPool))
|
setMaxDt(
|
||||||
|
isValidNumber(maxTokensInPool)
|
||||||
|
? new Decimal(maxTokensInPool).toString()
|
||||||
|
: '0'
|
||||||
|
)
|
||||||
|
|
||||||
const maxOceanInPool = await ocean.pool.getOceanMaxBuyQuantity(
|
const maxOceanInPool = await ocean.pool.getOceanMaxBuyQuantity(
|
||||||
price.address
|
price.address
|
||||||
)
|
)
|
||||||
setMaxOcean(Number(maxOceanInPool))
|
setMaxOcean(
|
||||||
|
isValidNumber(maxOceanInPool)
|
||||||
|
? new Decimal(maxOceanInPool).toString()
|
||||||
|
: '0'
|
||||||
|
)
|
||||||
}
|
}
|
||||||
getMaximum()
|
getMaximum()
|
||||||
}, [ocean, balance.ocean, price])
|
}, [ocean, balance.ocean, price])
|
||||||
|
@ -14,10 +14,11 @@ import { useWeb3 } from '../../../providers/Web3'
|
|||||||
import Web3Feedback from '../../molecules/Web3Feedback'
|
import Web3Feedback from '../../molecules/Web3Feedback'
|
||||||
import { getFileInfo } from '../../../utils/provider'
|
import { getFileInfo } from '../../../utils/provider'
|
||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
|
import { getOceanConfig } from '../../../utils/ocean'
|
||||||
|
|
||||||
export default function AssetActions(): ReactElement {
|
export default function AssetActions(): ReactElement {
|
||||||
const { accountId, balance } = useWeb3()
|
const { accountId, balance } = useWeb3()
|
||||||
const { ocean, config, account } = useOcean()
|
const { ocean, account } = useOcean()
|
||||||
const { price, ddo, isAssetNetwork } = useAsset()
|
const { price, ddo, isAssetNetwork } = useAsset()
|
||||||
|
|
||||||
const [isBalanceSufficient, setIsBalanceSufficient] = useState<boolean>()
|
const [isBalanceSufficient, setIsBalanceSufficient] = useState<boolean>()
|
||||||
@ -30,9 +31,10 @@ export default function AssetActions(): ReactElement {
|
|||||||
const [consumableFeedback, setConsumableFeedback] = useState<string>('')
|
const [consumableFeedback, setConsumableFeedback] = useState<string>('')
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!ddo || !accountId) return
|
if (!ddo || !accountId || !ocean || !isAssetNetwork) return
|
||||||
|
|
||||||
async function checkIsConsumable() {
|
async function checkIsConsumable() {
|
||||||
const consumable: any = await ocean.assets.isConsumable(
|
const consumable = await ocean.assets.isConsumable(
|
||||||
ddo,
|
ddo,
|
||||||
accountId.toLowerCase()
|
accountId.toLowerCase()
|
||||||
)
|
)
|
||||||
@ -42,17 +44,20 @@ export default function AssetActions(): ReactElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
checkIsConsumable()
|
checkIsConsumable()
|
||||||
}, [accountId, ddo])
|
}, [accountId, isAssetNetwork, ddo, ocean])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!config) return
|
const oceanConfig = getOceanConfig(ddo.chainId)
|
||||||
|
if (!oceanConfig) return
|
||||||
|
|
||||||
const source = axios.CancelToken.source()
|
const source = axios.CancelToken.source()
|
||||||
|
|
||||||
async function initFileInfo() {
|
async function initFileInfo() {
|
||||||
setFileIsLoading(true)
|
setFileIsLoading(true)
|
||||||
try {
|
try {
|
||||||
const fileInfo = await getFileInfo(
|
const fileInfo = await getFileInfo(
|
||||||
DID.parse(`${ddo.id}`),
|
DID.parse(`${ddo.id}`),
|
||||||
config.providerUri,
|
oceanConfig.providerUri,
|
||||||
source.token
|
source.token
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -60,15 +65,16 @@ export default function AssetActions(): ReactElement {
|
|||||||
} catch (error) {
|
} catch (error) {
|
||||||
Logger.error(error.message)
|
Logger.error(error.message)
|
||||||
} finally {
|
} finally {
|
||||||
// this triggers a memory leak warrning, no idea how to fix
|
// this triggers a memory leak warning, no idea how to fix
|
||||||
setFileIsLoading(false)
|
setFileIsLoading(false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
initFileInfo()
|
initFileInfo()
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
source.cancel()
|
source.cancel()
|
||||||
}
|
}
|
||||||
}, [config, ddo])
|
}, [ddo])
|
||||||
|
|
||||||
// Get and set user DT balance
|
// Get and set user DT balance
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
@ -2,10 +2,10 @@ import React, { ReactElement, useEffect, useState } from 'react'
|
|||||||
import { useAsset } from '../../../providers/Asset'
|
import { useAsset } from '../../../providers/Asset'
|
||||||
import ExplorerLink from '../../atoms/ExplorerLink'
|
import ExplorerLink from '../../atoms/ExplorerLink'
|
||||||
import Time from '../../atoms/Time'
|
import Time from '../../atoms/Time'
|
||||||
import styles from './EditHistory.module.css'
|
import { gql, OperationContext, useQuery } from 'urql'
|
||||||
import { gql, useQuery } from 'urql'
|
|
||||||
import { ReceiptData_datatokens_updates as ReceiptData } from '../../../@types/apollo/ReceiptData'
|
import { ReceiptData_datatokens_updates as ReceiptData } from '../../../@types/apollo/ReceiptData'
|
||||||
import { useWeb3 } from '../../../providers/Web3'
|
import { getQueryContext } from '../../../utils/subgraph'
|
||||||
|
import styles from './EditHistory.module.css'
|
||||||
|
|
||||||
const getReceipts = gql`
|
const getReceipts = gql`
|
||||||
query ReceiptData($address: ID!) {
|
query ReceiptData($address: ID!) {
|
||||||
@ -20,14 +20,32 @@ const getReceipts = gql`
|
|||||||
`
|
`
|
||||||
|
|
||||||
export default function EditHistory(): ReactElement {
|
export default function EditHistory(): ReactElement {
|
||||||
const { networkId } = useWeb3()
|
|
||||||
const { ddo } = useAsset()
|
const { ddo } = useAsset()
|
||||||
|
|
||||||
|
//
|
||||||
|
// 1. Construct subgraph query based on DDO.
|
||||||
|
// Need to wait for it to avoid infinite rerender loop with useQuery.
|
||||||
|
//
|
||||||
|
const [queryContext, setQueryContext] = useState<OperationContext>()
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!ddo) return
|
||||||
|
|
||||||
|
const queryContext = getQueryContext(ddo.chainId)
|
||||||
|
setQueryContext(queryContext)
|
||||||
|
}, [ddo])
|
||||||
|
|
||||||
const [result] = useQuery({
|
const [result] = useQuery({
|
||||||
query: getReceipts,
|
query: getReceipts,
|
||||||
variables: { address: ddo?.dataToken.toLowerCase() }
|
variables: { address: ddo?.dataToken.toLowerCase() },
|
||||||
|
context: queryContext,
|
||||||
|
pause: !ddo || !queryContext
|
||||||
})
|
})
|
||||||
const { data } = result
|
const { data } = result
|
||||||
|
|
||||||
|
//
|
||||||
|
// 2. Construct display data based on fetched data.
|
||||||
|
//
|
||||||
const [receipts, setReceipts] = useState<ReceiptData[]>()
|
const [receipts, setReceipts] = useState<ReceiptData[]>()
|
||||||
const [creationTx, setCreationTx] = useState<string>()
|
const [creationTx, setCreationTx] = useState<string>()
|
||||||
|
|
||||||
@ -51,8 +69,7 @@ export default function EditHistory(): ReactElement {
|
|||||||
{receipts?.map((receipt) => (
|
{receipts?.map((receipt) => (
|
||||||
<li key={receipt.id} className={styles.item}>
|
<li key={receipt.id} className={styles.item}>
|
||||||
<ExplorerLink networkId={ddo.chainId} path={`/tx/${receipt.tx}`}>
|
<ExplorerLink networkId={ddo.chainId} path={`/tx/${receipt.tx}`}>
|
||||||
edited{' '}
|
edited <Time date={`${receipt.timestamp}`} relative isUnix />
|
||||||
<Time date={receipt.timestamp.toString()} relative isUnix />
|
|
||||||
</ExplorerLink>
|
</ExplorerLink>
|
||||||
</li>
|
</li>
|
||||||
))}
|
))}
|
||||||
|
@ -12,6 +12,11 @@ import { DDO } from '@oceanprotocol/lib'
|
|||||||
import FormHelp from '../../../../atoms/Input/Help'
|
import FormHelp from '../../../../atoms/Input/Help'
|
||||||
import { useSiteMetadata } from '../../../../../hooks/useSiteMetadata'
|
import { useSiteMetadata } from '../../../../../hooks/useSiteMetadata'
|
||||||
|
|
||||||
|
import { isValidNumber } from './../../../../../utils/numberValidations'
|
||||||
|
import Decimal from 'decimal.js'
|
||||||
|
|
||||||
|
Decimal.set({ toExpNeg: -18, precision: 18, rounding: 1 })
|
||||||
|
|
||||||
export default function FormPricing({
|
export default function FormPricing({
|
||||||
ddo,
|
ddo,
|
||||||
setShowPricing,
|
setShowPricing,
|
||||||
@ -41,8 +46,15 @@ export default function FormPricing({
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (type === 'fixed') return
|
if (type === 'fixed') return
|
||||||
const dtAmount =
|
const dtAmount =
|
||||||
(Number(oceanAmount) / Number(weightOnOcean) / price) *
|
isValidNumber(oceanAmount) &&
|
||||||
Number(weightOnDataToken)
|
isValidNumber(weightOnOcean) &&
|
||||||
|
isValidNumber(price) &&
|
||||||
|
isValidNumber(weightOnDataToken)
|
||||||
|
? new Decimal(oceanAmount)
|
||||||
|
.dividedBy(new Decimal(weightOnOcean))
|
||||||
|
.dividedBy(new Decimal(price))
|
||||||
|
.mul(new Decimal(weightOnDataToken))
|
||||||
|
: 0
|
||||||
|
|
||||||
setFieldValue('dtAmount', dtAmount)
|
setFieldValue('dtAmount', dtAmount)
|
||||||
}, [price, oceanAmount, weightOnOcean, weightOnDataToken, type])
|
}, [price, oceanAmount, weightOnOcean, weightOnDataToken, type])
|
||||||
|
@ -50,6 +50,7 @@ export default function AssetContent(props: AssetContentProps): ReactElement {
|
|||||||
const { owner, isInPurgatory, purgatoryData, isAssetNetwork } = useAsset()
|
const { owner, isInPurgatory, purgatoryData, isAssetNetwork } = useAsset()
|
||||||
const [showPricing, setShowPricing] = useState(false)
|
const [showPricing, setShowPricing] = useState(false)
|
||||||
const [showEdit, setShowEdit] = useState<boolean>()
|
const [showEdit, setShowEdit] = useState<boolean>()
|
||||||
|
const [isComputeType, setIsComputeType] = useState<boolean>(false)
|
||||||
const [showEditCompute, setShowEditCompute] = useState<boolean>()
|
const [showEditCompute, setShowEditCompute] = useState<boolean>()
|
||||||
const [showEditAdvancedSettings, setShowEditAdvancedSettings] =
|
const [showEditAdvancedSettings, setShowEditAdvancedSettings] =
|
||||||
useState<boolean>()
|
useState<boolean>()
|
||||||
@ -63,7 +64,8 @@ export default function AssetContent(props: AssetContentProps): ReactElement {
|
|||||||
const isOwner = accountId.toLowerCase() === owner.toLowerCase()
|
const isOwner = accountId.toLowerCase() === owner.toLowerCase()
|
||||||
setIsOwner(isOwner)
|
setIsOwner(isOwner)
|
||||||
setShowPricing(isOwner && price.type === '')
|
setShowPricing(isOwner && price.type === '')
|
||||||
}, [accountId, price, owner])
|
setIsComputeType(Boolean(ddo.findServiceByType('compute')))
|
||||||
|
}, [accountId, price, owner, ddo])
|
||||||
|
|
||||||
function handleEditButton() {
|
function handleEditButton() {
|
||||||
// move user's focus to top of screen
|
// move user's focus to top of screen
|
||||||
@ -82,7 +84,7 @@ export default function AssetContent(props: AssetContentProps): ReactElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return showEdit ? (
|
return showEdit ? (
|
||||||
<Edit setShowEdit={setShowEdit} />
|
<Edit setShowEdit={setShowEdit} isComputeType={isComputeType} />
|
||||||
) : showEditCompute ? (
|
) : showEditCompute ? (
|
||||||
<EditComputeDataset setShowEdit={setShowEditCompute} />
|
<EditComputeDataset setShowEdit={setShowEditCompute} />
|
||||||
) : showEditAdvancedSettings ? (
|
) : showEditAdvancedSettings ? (
|
||||||
|
@ -6,6 +6,7 @@ import { DDO } from '@oceanprotocol/lib'
|
|||||||
import classNames from 'classnames/bind'
|
import classNames from 'classnames/bind'
|
||||||
import { getAssetsBestPrices, AssetListPrices } from '../../utils/subgraph'
|
import { getAssetsBestPrices, AssetListPrices } from '../../utils/subgraph'
|
||||||
import Loader from '../atoms/Loader'
|
import Loader from '../atoms/Loader'
|
||||||
|
import { useUserPreferences } from '../../providers/UserPreferences'
|
||||||
|
|
||||||
const cx = classNames.bind(styles)
|
const cx = classNames.bind(styles)
|
||||||
|
|
||||||
@ -36,6 +37,7 @@ const AssetList: React.FC<AssetListProps> = ({
|
|||||||
onPageChange,
|
onPageChange,
|
||||||
className
|
className
|
||||||
}) => {
|
}) => {
|
||||||
|
const { chainIds } = useUserPreferences()
|
||||||
const [assetsWithPrices, setAssetWithPrices] = useState<AssetListPrices[]>()
|
const [assetsWithPrices, setAssetWithPrices] = useState<AssetListPrices[]>()
|
||||||
const [loading, setLoading] = useState<boolean>(true)
|
const [loading, setLoading] = useState<boolean>(true)
|
||||||
|
|
||||||
@ -71,6 +73,8 @@ const AssetList: React.FC<AssetListProps> = ({
|
|||||||
key={assetWithPrice.ddo.id}
|
key={assetWithPrice.ddo.id}
|
||||||
/>
|
/>
|
||||||
))
|
))
|
||||||
|
) : chainIds.length === 0 ? (
|
||||||
|
<div className={styles.empty}>No network selected.</div>
|
||||||
) : (
|
) : (
|
||||||
<div className={styles.empty}>No results found.</div>
|
<div className={styles.empty}>No results found.</div>
|
||||||
)}
|
)}
|
||||||
|
@ -17,6 +17,10 @@ import { fetchDataForMultipleChains } from '../../../../utils/subgraph'
|
|||||||
import NetworkName from '../../../atoms/NetworkName'
|
import NetworkName from '../../../atoms/NetworkName'
|
||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
import { retrieveDDO } from '../../../../utils/aquarius'
|
import { retrieveDDO } from '../../../../utils/aquarius'
|
||||||
|
import { isValidNumber } from '../../../../utils/numberValidations'
|
||||||
|
import Decimal from 'decimal.js'
|
||||||
|
|
||||||
|
Decimal.set({ toExpNeg: -18, precision: 18, rounding: 1 })
|
||||||
|
|
||||||
const REFETCH_INTERVAL = 20000
|
const REFETCH_INTERVAL = 20000
|
||||||
|
|
||||||
@ -90,11 +94,16 @@ function Liquidity({ row, type }: { row: Asset; type: string }) {
|
|||||||
).toString()
|
).toString()
|
||||||
}
|
}
|
||||||
if (type === 'pool') {
|
if (type === 'pool') {
|
||||||
price = `${
|
price =
|
||||||
Number(row.poolShare.poolId.oceanReserve) +
|
isValidNumber(row.poolShare.poolId.oceanReserve) &&
|
||||||
Number(row.poolShare.poolId.datatokenReserve) *
|
isValidNumber(row.poolShare.poolId.datatokenReserve) &&
|
||||||
row.poolShare.poolId.consumePrice
|
isValidNumber(row.poolShare.poolId.consumePrice)
|
||||||
}`
|
? new Decimal(row.poolShare.poolId.datatokenReserve)
|
||||||
|
.mul(new Decimal(row.poolShare.poolId.consumePrice))
|
||||||
|
.plus(row.poolShare.poolId.oceanReserve)
|
||||||
|
.toString()
|
||||||
|
: '0'
|
||||||
|
|
||||||
oceanTokenBalance = row.poolShare.poolId.oceanReserve.toString()
|
oceanTokenBalance = row.poolShare.poolId.oceanReserve.toString()
|
||||||
dataTokenBalance = row.poolShare.poolId.datatokenReserve.toString()
|
dataTokenBalance = row.poolShare.poolId.datatokenReserve.toString()
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,9 @@
|
|||||||
import React, { ReactElement, useEffect, useState } from 'react'
|
import React, { ReactElement, useEffect, useState } from 'react'
|
||||||
import SearchBar from '../molecules/SearchBar'
|
|
||||||
import styles from './Home.module.css'
|
|
||||||
import AssetList from '../organisms/AssetList'
|
import AssetList from '../organisms/AssetList'
|
||||||
import {
|
import {
|
||||||
QueryResult,
|
QueryResult,
|
||||||
SearchQuery
|
SearchQuery
|
||||||
} from '@oceanprotocol/lib/dist/node/metadatacache/MetadataCache'
|
} from '@oceanprotocol/lib/dist/node/metadatacache/MetadataCache'
|
||||||
import Container from '../atoms/Container'
|
|
||||||
import Button from '../atoms/Button'
|
import Button from '../atoms/Button'
|
||||||
import Bookmarks from '../molecules/Bookmarks'
|
import Bookmarks from '../molecules/Bookmarks'
|
||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
@ -19,14 +16,15 @@ import { getHighestLiquidityDIDs } from '../../utils/subgraph'
|
|||||||
import { DDO, Logger } from '@oceanprotocol/lib'
|
import { DDO, Logger } from '@oceanprotocol/lib'
|
||||||
import { useSiteMetadata } from '../../hooks/useSiteMetadata'
|
import { useSiteMetadata } from '../../hooks/useSiteMetadata'
|
||||||
import { useUserPreferences } from '../../providers/UserPreferences'
|
import { useUserPreferences } from '../../providers/UserPreferences'
|
||||||
|
import styles from './Home.module.css'
|
||||||
|
|
||||||
async function getQueryHighest(
|
async function getQueryHighest(
|
||||||
chainIds: number[]
|
chainIds: number[]
|
||||||
): Promise<[SearchQuery, string]> {
|
): Promise<[SearchQuery, string]> {
|
||||||
const dids = await getHighestLiquidityDIDs(chainIds)
|
const [dids, didsLength] = await getHighestLiquidityDIDs(chainIds)
|
||||||
const queryHighest = {
|
const queryHighest = {
|
||||||
page: 1,
|
page: 1,
|
||||||
offset: dids.length,
|
offset: didsLength,
|
||||||
query: {
|
query: {
|
||||||
query_string: {
|
query_string: {
|
||||||
query: `(${dids}) AND (${transformChainIdsListToQuery(
|
query: `(${dids}) AND (${transformChainIdsListToQuery(
|
||||||
@ -74,15 +72,25 @@ function SectionQueryResult({
|
|||||||
queryData?: string
|
queryData?: string
|
||||||
}) {
|
}) {
|
||||||
const { appConfig } = useSiteMetadata()
|
const { appConfig } = useSiteMetadata()
|
||||||
|
const { chainIds } = useUserPreferences()
|
||||||
const [result, setResult] = useState<QueryResult>()
|
const [result, setResult] = useState<QueryResult>()
|
||||||
const [loading, setLoading] = useState<boolean>()
|
const [loading, setLoading] = useState<boolean>()
|
||||||
const { chainIds } = useUserPreferences()
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!appConfig.metadataCacheUri) return
|
if (!appConfig.metadataCacheUri) return
|
||||||
const source = axios.CancelToken.source()
|
const source = axios.CancelToken.source()
|
||||||
|
|
||||||
async function init() {
|
async function init() {
|
||||||
|
if (chainIds.length === 0) {
|
||||||
|
const result: QueryResult = {
|
||||||
|
results: [],
|
||||||
|
page: 0,
|
||||||
|
totalPages: 0,
|
||||||
|
totalResults: 0
|
||||||
|
}
|
||||||
|
setResult(result)
|
||||||
|
setLoading(false)
|
||||||
|
} else {
|
||||||
try {
|
try {
|
||||||
setLoading(true)
|
setLoading(true)
|
||||||
const result = await queryMetadata(query, source.token)
|
const result = await queryMetadata(query, source.token)
|
||||||
@ -96,7 +104,8 @@ function SectionQueryResult({
|
|||||||
setResult(result)
|
setResult(result)
|
||||||
setLoading(false)
|
setLoading(false)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
Logger.log(error.message)
|
Logger.error(error.message)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
init()
|
init()
|
||||||
|
@ -23,6 +23,7 @@ export default function Debug({
|
|||||||
{
|
{
|
||||||
index: 1,
|
index: 1,
|
||||||
type: values.access,
|
type: values.access,
|
||||||
|
serviceEndpoint: values.providerUri,
|
||||||
attributes: {}
|
attributes: {}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
@ -11,6 +11,7 @@ import Input from '../../atoms/Input'
|
|||||||
import { FormContent, FormFieldProps } from '../../../@types/Form'
|
import { FormContent, FormFieldProps } from '../../../@types/Form'
|
||||||
import { MetadataPublishFormAlgorithm } from '../../../@types/MetaData'
|
import { MetadataPublishFormAlgorithm } from '../../../@types/MetaData'
|
||||||
import { initialValues as initialValuesAlgorithm } from '../../../models/FormAlgoPublish'
|
import { initialValues as initialValuesAlgorithm } from '../../../models/FormAlgoPublish'
|
||||||
|
import AdvancedSettings from '../../molecules/FormFields/AdvancedSettings'
|
||||||
import FormTitle from './FormTitle'
|
import FormTitle from './FormTitle'
|
||||||
import FormActions from './FormActions'
|
import FormActions from './FormActions'
|
||||||
import styles from './FormPublish.module.css'
|
import styles from './FormPublish.module.css'
|
||||||
@ -33,6 +34,7 @@ const query = graphql`
|
|||||||
required
|
required
|
||||||
sortOptions
|
sortOptions
|
||||||
options
|
options
|
||||||
|
advanced
|
||||||
}
|
}
|
||||||
warning
|
warning
|
||||||
}
|
}
|
||||||
@ -145,6 +147,7 @@ export default function FormPublish(): ReactElement {
|
|||||||
|
|
||||||
{content.data.map(
|
{content.data.map(
|
||||||
(field: FormFieldProps) =>
|
(field: FormFieldProps) =>
|
||||||
|
field.advanced !== true &&
|
||||||
((field.name !== 'entrypoint' &&
|
((field.name !== 'entrypoint' &&
|
||||||
field.name !== 'image' &&
|
field.name !== 'image' &&
|
||||||
field.name !== 'containerTag') ||
|
field.name !== 'containerTag') ||
|
||||||
@ -164,7 +167,10 @@ export default function FormPublish(): ReactElement {
|
|||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
)}
|
)}
|
||||||
|
<AdvancedSettings
|
||||||
|
content={content}
|
||||||
|
handleFieldChange={handleFieldChange}
|
||||||
|
/>
|
||||||
<FormActions
|
<FormActions
|
||||||
isValid={isValid}
|
isValid={isValid}
|
||||||
resetFormAndClearStorage={resetFormAndClearStorage}
|
resetFormAndClearStorage={resetFormAndClearStorage}
|
||||||
|
@ -1,16 +1,22 @@
|
|||||||
import React, { ReactElement, useEffect, FormEvent, ChangeEvent } from 'react'
|
import React, {
|
||||||
|
ReactElement,
|
||||||
|
useEffect,
|
||||||
|
FormEvent,
|
||||||
|
ChangeEvent,
|
||||||
|
useState
|
||||||
|
} from 'react'
|
||||||
import { useStaticQuery, graphql } from 'gatsby'
|
import { useStaticQuery, graphql } from 'gatsby'
|
||||||
import { useFormikContext, Field, Form, FormikContextType } from 'formik'
|
import { useFormikContext, Field, Form, FormikContextType } from 'formik'
|
||||||
import Input from '../../atoms/Input'
|
import Input from '../../atoms/Input'
|
||||||
import { FormContent, FormFieldProps } from '../../../@types/Form'
|
import { FormContent, FormFieldProps } from '../../../@types/Form'
|
||||||
import { MetadataPublishFormDataset } from '../../../@types/MetaData'
|
import { MetadataPublishFormDataset } from '../../../@types/MetaData'
|
||||||
import { initialValues as initialValuesDataset } from '../../../models/FormAlgoPublish'
|
import { initialValues as initialValuesDataset } from '../../../models/FormAlgoPublish'
|
||||||
import { useOcean } from '../../../providers/Ocean'
|
|
||||||
import { ReactComponent as Download } from '../../../images/download.svg'
|
import { ReactComponent as Download } from '../../../images/download.svg'
|
||||||
import { ReactComponent as Compute } from '../../../images/compute.svg'
|
import { ReactComponent as Compute } from '../../../images/compute.svg'
|
||||||
import FormTitle from './FormTitle'
|
import FormTitle from './FormTitle'
|
||||||
import FormActions from './FormActions'
|
import FormActions from './FormActions'
|
||||||
import styles from './FormPublish.module.css'
|
import styles from './FormPublish.module.css'
|
||||||
|
import AdvancedSettings from '../../molecules/FormFields/AdvancedSettings'
|
||||||
|
|
||||||
const query = graphql`
|
const query = graphql`
|
||||||
query {
|
query {
|
||||||
@ -30,6 +36,7 @@ const query = graphql`
|
|||||||
required
|
required
|
||||||
sortOptions
|
sortOptions
|
||||||
options
|
options
|
||||||
|
advanced
|
||||||
}
|
}
|
||||||
warning
|
warning
|
||||||
}
|
}
|
||||||
@ -47,6 +54,7 @@ export default function FormPublish(): ReactElement {
|
|||||||
status,
|
status,
|
||||||
setStatus,
|
setStatus,
|
||||||
isValid,
|
isValid,
|
||||||
|
values,
|
||||||
setErrors,
|
setErrors,
|
||||||
setTouched,
|
setTouched,
|
||||||
resetForm,
|
resetForm,
|
||||||
@ -54,6 +62,8 @@ export default function FormPublish(): ReactElement {
|
|||||||
setFieldValue
|
setFieldValue
|
||||||
}: FormikContextType<MetadataPublishFormDataset> = useFormikContext()
|
}: FormikContextType<MetadataPublishFormDataset> = useFormikContext()
|
||||||
|
|
||||||
|
const [computeTypeSelected, setComputeTypeSelected] = useState<boolean>(false)
|
||||||
|
|
||||||
// reset form validation on every mount
|
// reset form validation on every mount
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setErrors({})
|
setErrors({})
|
||||||
@ -75,6 +85,8 @@ export default function FormPublish(): ReactElement {
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
|
const computeTypeOptions = ['1 day', '1 week', '1 month', '1 year']
|
||||||
|
|
||||||
// Manually handle change events instead of using `handleChange` from Formik.
|
// Manually handle change events instead of using `handleChange` from Formik.
|
||||||
// Workaround for default `validateOnChange` not kicking in
|
// Workaround for default `validateOnChange` not kicking in
|
||||||
function handleFieldChange(
|
function handleFieldChange(
|
||||||
@ -84,6 +96,16 @@ export default function FormPublish(): ReactElement {
|
|||||||
const value =
|
const value =
|
||||||
field.type === 'terms' ? !JSON.parse(e.target.value) : e.target.value
|
field.type === 'terms' ? !JSON.parse(e.target.value) : e.target.value
|
||||||
|
|
||||||
|
if (field.name === 'access' && value === 'Compute') {
|
||||||
|
setComputeTypeSelected(true)
|
||||||
|
if (values.timeout === 'Forever')
|
||||||
|
setFieldValue('timeout', computeTypeOptions[0])
|
||||||
|
} else {
|
||||||
|
if (field.name === 'access' && value === 'Download') {
|
||||||
|
setComputeTypeSelected(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
validateField(field.name)
|
validateField(field.name)
|
||||||
setFieldValue(field.name, value)
|
setFieldValue(field.name, value)
|
||||||
}
|
}
|
||||||
@ -105,19 +127,30 @@ export default function FormPublish(): ReactElement {
|
|||||||
>
|
>
|
||||||
<FormTitle title={content.title} />
|
<FormTitle title={content.title} />
|
||||||
|
|
||||||
{content.data.map((field: FormFieldProps) => (
|
{content.data.map(
|
||||||
|
(field: FormFieldProps) =>
|
||||||
|
field.advanced !== true && (
|
||||||
<Field
|
<Field
|
||||||
key={field.name}
|
key={field.name}
|
||||||
{...field}
|
{...field}
|
||||||
options={
|
options={
|
||||||
field.type === 'boxSelection' ? accessTypeOptions : field.options
|
field.type === 'boxSelection'
|
||||||
|
? accessTypeOptions
|
||||||
|
: field.name === 'timeout' && computeTypeSelected === true
|
||||||
|
? computeTypeOptions
|
||||||
|
: field.options
|
||||||
}
|
}
|
||||||
component={Input}
|
component={Input}
|
||||||
onChange={(e: ChangeEvent<HTMLInputElement>) =>
|
onChange={(e: ChangeEvent<HTMLInputElement>) =>
|
||||||
handleFieldChange(e, field)
|
handleFieldChange(e, field)
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
))}
|
)
|
||||||
|
)}
|
||||||
|
<AdvancedSettings
|
||||||
|
content={content}
|
||||||
|
handleFieldChange={handleFieldChange}
|
||||||
|
/>
|
||||||
|
|
||||||
<FormActions
|
<FormActions
|
||||||
isValid={isValid}
|
isValid={isValid}
|
||||||
|
@ -132,14 +132,16 @@ export default function PublishPage({
|
|||||||
'Publish with ',
|
'Publish with ',
|
||||||
metadata,
|
metadata,
|
||||||
serviceType,
|
serviceType,
|
||||||
values.dataTokenOptions
|
values.dataTokenOptions,
|
||||||
|
values.providerUri
|
||||||
)
|
)
|
||||||
|
|
||||||
const ddo = await publish(
|
const ddo = await publish(
|
||||||
metadata as unknown as Metadata,
|
metadata as unknown as Metadata,
|
||||||
serviceType,
|
serviceType,
|
||||||
values.dataTokenOptions,
|
values.dataTokenOptions,
|
||||||
timeout
|
timeout,
|
||||||
|
values.providerUri
|
||||||
)
|
)
|
||||||
|
|
||||||
// Publish failed
|
// Publish failed
|
||||||
|
@ -32,6 +32,7 @@ interface UseSiteMetadata {
|
|||||||
allowFreePricing: string
|
allowFreePricing: string
|
||||||
allowAdvancedSettings: string
|
allowAdvancedSettings: string
|
||||||
credentialType: string
|
credentialType: string
|
||||||
|
allowAdvancedPublishSettings: string
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -68,6 +69,7 @@ const query = graphql`
|
|||||||
allowDynamicPricing
|
allowDynamicPricing
|
||||||
allowFreePricing
|
allowFreePricing
|
||||||
allowAdvancedSettings
|
allowAdvancedSettings
|
||||||
|
allowAdvancedPublishSettings
|
||||||
credentialType
|
credentialType
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -51,5 +51,6 @@ export const initialValues: Partial<MetadataPublishFormAlgorithm> = {
|
|||||||
algorithmPrivacy: false,
|
algorithmPrivacy: false,
|
||||||
termsAndConditions: false,
|
termsAndConditions: false,
|
||||||
tags: '',
|
tags: '',
|
||||||
timeout: 'Forever'
|
timeout: 'Forever',
|
||||||
|
providerUri: ''
|
||||||
}
|
}
|
||||||
|
@ -25,10 +25,10 @@ export const validationSchema: Yup.SchemaOf<MetadataPublishFormDataset> =
|
|||||||
.matches(/Compute|Download/g, { excludeEmptyString: true })
|
.matches(/Compute|Download/g, { excludeEmptyString: true })
|
||||||
.required('Required'),
|
.required('Required'),
|
||||||
termsAndConditions: Yup.boolean().required('Required'),
|
termsAndConditions: Yup.boolean().required('Required'),
|
||||||
|
|
||||||
// ---- optional fields ----
|
// ---- optional fields ----
|
||||||
tags: Yup.string().nullable(),
|
tags: Yup.string().nullable(),
|
||||||
links: Yup.array<FileMetadata[]>().nullable()
|
links: Yup.array<FileMetadata[]>().nullable(),
|
||||||
|
providerUri: Yup.string().url().nullable()
|
||||||
})
|
})
|
||||||
.defined()
|
.defined()
|
||||||
|
|
||||||
@ -44,5 +44,6 @@ export const initialValues: Partial<MetadataPublishFormDataset> = {
|
|||||||
timeout: 'Forever',
|
timeout: 'Forever',
|
||||||
access: '',
|
access: '',
|
||||||
termsAndConditions: false,
|
termsAndConditions: false,
|
||||||
tags: ''
|
tags: '',
|
||||||
|
providerUri: ''
|
||||||
}
|
}
|
||||||
|
@ -7,9 +7,9 @@ export interface FormTradeData extends PoolBalance {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface TradeItem {
|
export interface TradeItem {
|
||||||
amount: number
|
amount: string
|
||||||
token: string
|
token: string
|
||||||
maxAmount: number
|
maxAmount: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export const initialValues: FormTradeData = {
|
export const initialValues: FormTradeData = {
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
import { createClient, Provider, Client } from 'urql'
|
import { createClient, Provider, Client } from 'urql'
|
||||||
import React, { useState, useEffect, ReactNode, ReactElement } from 'react'
|
import React, { useState, useEffect, ReactNode, ReactElement } from 'react'
|
||||||
import { useWeb3 } from './Web3'
|
|
||||||
import { Logger } from '@oceanprotocol/lib'
|
import { Logger } from '@oceanprotocol/lib'
|
||||||
import { getOceanConfig } from '../utils/ocean'
|
import { getOceanConfig } from '../utils/ocean'
|
||||||
|
|
||||||
@ -22,11 +21,16 @@ export default function UrqlClientProvider({
|
|||||||
}: {
|
}: {
|
||||||
children: ReactNode
|
children: ReactNode
|
||||||
}): ReactElement {
|
}): ReactElement {
|
||||||
const { networkId } = useWeb3()
|
//
|
||||||
|
// Set a default client here based on ETH Mainnet, as that's required for
|
||||||
|
// urql to work.
|
||||||
|
// Throughout code base this client is then used and altered by passing
|
||||||
|
// a new queryContext holding different subgraph URLs.
|
||||||
|
//
|
||||||
const [client, setClient] = useState<Client>()
|
const [client, setClient] = useState<Client>()
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const oceanConfig = getOceanConfig(networkId || 1)
|
const oceanConfig = getOceanConfig(1)
|
||||||
|
|
||||||
if (!oceanConfig?.subgraphUri) {
|
if (!oceanConfig?.subgraphUri) {
|
||||||
Logger.error(
|
Logger.error(
|
||||||
@ -39,8 +43,9 @@ export default function UrqlClientProvider({
|
|||||||
urqlClient = newClient
|
urqlClient = newClient
|
||||||
setClient(newClient)
|
setClient(newClient)
|
||||||
Logger.log(`[URQL] Client connected to ${oceanConfig.subgraphUri}`)
|
Logger.log(`[URQL] Client connected to ${oceanConfig.subgraphUri}`)
|
||||||
}, [networkId])
|
}, [])
|
||||||
|
|
||||||
return client ? <Provider value={client}>{children}</Provider> : <></>
|
return client ? <Provider value={client}>{children}</Provider> : <></>
|
||||||
}
|
}
|
||||||
|
|
||||||
export { UrqlClientProvider }
|
export { UrqlClientProvider }
|
||||||
|
@ -8,7 +8,8 @@ export default function compareAsBN(balance: string, price: string): boolean {
|
|||||||
const compare = aBN.comparedTo(bBN)
|
const compare = aBN.comparedTo(bBN)
|
||||||
|
|
||||||
switch (compare) {
|
switch (compare) {
|
||||||
case 1 || 0: // balance is greater or equal to price
|
case 1: // balance is greater than price
|
||||||
|
case 0: // balance is equal to price
|
||||||
return true
|
return true
|
||||||
default:
|
default:
|
||||||
return false
|
return false
|
||||||
|
@ -42,6 +42,7 @@ export function secondsToString(numberOfSeconds: number): string {
|
|||||||
if (numberOfSeconds === 0) return 'Forever'
|
if (numberOfSeconds === 0) return 'Forever'
|
||||||
|
|
||||||
const years = Math.floor(numberOfSeconds / 31536000)
|
const years = Math.floor(numberOfSeconds / 31536000)
|
||||||
|
const months = Math.floor((numberOfSeconds %= 31536000) / 2630000)
|
||||||
const weeks = Math.floor((numberOfSeconds %= 31536000) / 604800)
|
const weeks = Math.floor((numberOfSeconds %= 31536000) / 604800)
|
||||||
const days = Math.floor((numberOfSeconds %= 604800) / 86400)
|
const days = Math.floor((numberOfSeconds %= 604800) / 86400)
|
||||||
const hours = Math.floor((numberOfSeconds %= 86400) / 3600)
|
const hours = Math.floor((numberOfSeconds %= 86400) / 3600)
|
||||||
@ -50,6 +51,8 @@ export function secondsToString(numberOfSeconds: number): string {
|
|||||||
|
|
||||||
return years
|
return years
|
||||||
? `${years} year${numberEnding(years)}`
|
? `${years} year${numberEnding(years)}`
|
||||||
|
: months
|
||||||
|
? `${months} month${numberEnding(months)}`
|
||||||
: weeks
|
: weeks
|
||||||
? `${weeks} week${numberEnding(weeks)}`
|
? `${weeks} week${numberEnding(weeks)}`
|
||||||
: days
|
: days
|
||||||
|
8
src/utils/numberValidations.ts
Normal file
8
src/utils/numberValidations.ts
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
export function isValidNumber(value: any): boolean {
|
||||||
|
const isUndefinedValue = typeof value === 'undefined'
|
||||||
|
const isNullValue = value === null
|
||||||
|
const isNaNValue = isNaN(Number(value))
|
||||||
|
const isEmptyString = value === ''
|
||||||
|
|
||||||
|
return !isUndefinedValue && !isNullValue && !isNaNValue && !isEmptyString
|
||||||
|
}
|
@ -141,17 +141,17 @@ const HighestLiquidityAssets = gql`
|
|||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
export function getSubgrahUri(chainId: number): string {
|
export function getSubgraphUri(chainId: number): string {
|
||||||
const config = getOceanConfig(chainId)
|
const config = getOceanConfig(chainId)
|
||||||
return config.subgraphUri
|
return config.subgraphUri
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getQueryContext(chainId: number): OperationContext {
|
export function getQueryContext(chainId: number): OperationContext {
|
||||||
const queryContext: OperationContext = {
|
const queryContext: OperationContext = {
|
||||||
url: `${getSubgrahUri(
|
url: `${getSubgraphUri(
|
||||||
Number(chainId)
|
Number(chainId)
|
||||||
)}/subgraphs/name/oceanprotocol/ocean-subgraph`,
|
)}/subgraphs/name/oceanprotocol/ocean-subgraph`,
|
||||||
requestPolicy: 'network-only'
|
requestPolicy: 'cache-and-network'
|
||||||
}
|
}
|
||||||
|
|
||||||
return queryContext
|
return queryContext
|
||||||
@ -180,7 +180,7 @@ export async function fetchDataForMultipleChains(
|
|||||||
let datas: any[] = []
|
let datas: any[] = []
|
||||||
for (const chainId of chainIds) {
|
for (const chainId of chainIds) {
|
||||||
const context: OperationContext = {
|
const context: OperationContext = {
|
||||||
url: `${getSubgrahUri(
|
url: `${getSubgraphUri(
|
||||||
chainId
|
chainId
|
||||||
)}/subgraphs/name/oceanprotocol/ocean-subgraph`,
|
)}/subgraphs/name/oceanprotocol/ocean-subgraph`,
|
||||||
requestPolicy: 'network-only'
|
requestPolicy: 'network-only'
|
||||||
@ -410,6 +410,21 @@ export async function getPrice(asset: DDO): Promise<BestPrice> {
|
|||||||
return bestPrice
|
return bestPrice
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function getSpotPrice(asset: DDO): Promise<number> {
|
||||||
|
const poolVariables = {
|
||||||
|
datatokenAddress: asset?.dataToken.toLowerCase()
|
||||||
|
}
|
||||||
|
const queryContext = getQueryContext(Number(asset.chainId))
|
||||||
|
|
||||||
|
const poolPriceResponse: OperationResult<AssetsPoolPrice> = await fetchData(
|
||||||
|
AssetPoolPriceQuerry,
|
||||||
|
poolVariables,
|
||||||
|
queryContext
|
||||||
|
)
|
||||||
|
|
||||||
|
return poolPriceResponse.data.pools[0].spotPrice
|
||||||
|
}
|
||||||
|
|
||||||
export async function getAssetsBestPrices(
|
export async function getAssetsBestPrices(
|
||||||
assets: DDO[]
|
assets: DDO[]
|
||||||
): Promise<AssetListPrices[]> {
|
): Promise<AssetListPrices[]> {
|
||||||
@ -454,7 +469,7 @@ export async function getAssetsBestPrices(
|
|||||||
|
|
||||||
export async function getHighestLiquidityDIDs(
|
export async function getHighestLiquidityDIDs(
|
||||||
chainIds: number[]
|
chainIds: number[]
|
||||||
): Promise<string> {
|
): Promise<[string, number]> {
|
||||||
const didList: string[] = []
|
const didList: string[] = []
|
||||||
let highestLiquidiyAssets: HighestLiquidityAssetsPools[] = []
|
let highestLiquidiyAssets: HighestLiquidityAssetsPools[] = []
|
||||||
for (const chain of chainIds) {
|
for (const chain of chainIds) {
|
||||||
@ -480,5 +495,5 @@ export async function getHighestLiquidityDIDs(
|
|||||||
.replace(/"/g, '')
|
.replace(/"/g, '')
|
||||||
.replace(/(\[|\])/g, '')
|
.replace(/(\[|\])/g, '')
|
||||||
.replace(/(did:op:)/g, '0x')
|
.replace(/(did:op:)/g, '0x')
|
||||||
return searchDids
|
return [searchDids, didList.length]
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user