mirror of
https://github.com/oceanprotocol/market.git
synced 2024-09-28 03:58:59 +02:00
Merge pull request #81 from oceanprotocol/feature/fees
Fees input and output
This commit is contained in:
commit
8de48d88e6
@ -100,14 +100,16 @@
|
|||||||
"price": {
|
"price": {
|
||||||
"fixed": {
|
"fixed": {
|
||||||
"title": "Fixed",
|
"title": "Fixed",
|
||||||
"info": "Set your price for accessing this data set. A Data Token for this data set, worth the entered amount of OCEAN, will be created."
|
"info": "Set your price for accessing this data set. A Datatoken for this data set, worth the entered amount of OCEAN, will be created."
|
||||||
},
|
},
|
||||||
"dynamic": {
|
"dynamic": {
|
||||||
"title": "Dynamic",
|
"title": "Dynamic",
|
||||||
"info": "Let's create a decentralized, automated market for your data set. A Data Token for this data set, worth the entered amount of OCEAN, will be created. Additionally, you will provide liquidity into a Data Token/OCEAN liquidity pool with Balancer.",
|
"info": "Let's create a decentralized, automated market for your data set. A Datatoken for this data set, worth the entered amount of OCEAN, will be created. Additionally, you will provide liquidity into a OCEAN/Datatoken liquidity pool with Balancer.",
|
||||||
"tooltips": {
|
"tooltips": {
|
||||||
"poolInfo": "Help me",
|
"poolInfo": "Explain what is going on here...",
|
||||||
"liquidityProviderFee": "Help me"
|
"liquidityProviderFee": "Explain liquidity provider fee...",
|
||||||
|
"communityFee": "Explain community fee...",
|
||||||
|
"marketplaceFee": "Explain marketplace fee..."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
16
src/@types/MetaData.d.ts
vendored
16
src/@types/MetaData.d.ts
vendored
@ -4,7 +4,7 @@ import {
|
|||||||
AdditionalInformation,
|
AdditionalInformation,
|
||||||
ServiceMetadata
|
ServiceMetadata
|
||||||
} from '@oceanprotocol/lib'
|
} from '@oceanprotocol/lib'
|
||||||
import { PriceOptions } from '@oceanprotocol/react'
|
import { PriceOptions, DataTokenOptions } from '@oceanprotocol/react'
|
||||||
|
|
||||||
export interface AdditionalInformationMarket extends AdditionalInformation {
|
export interface AdditionalInformationMarket extends AdditionalInformation {
|
||||||
links?: File[]
|
links?: File[]
|
||||||
@ -13,7 +13,17 @@ export interface AdditionalInformationMarket extends AdditionalInformation {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface MetadataMarket extends Metadata {
|
export interface MetadataMarket extends Metadata {
|
||||||
additionalInformation: AdditionalInformationMarket
|
// While required for this market, Aquarius/Plecos will keep this as optional
|
||||||
|
// allowing external pushes of assets without `additionalInformation`.
|
||||||
|
// Making it optional here helps safeguarding against those assets.
|
||||||
|
additionalInformation?: AdditionalInformationMarket
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface PriceOptionsMarket extends PriceOptions {
|
||||||
|
// easier to keep this as number for Yup input validation
|
||||||
|
liquidityProviderFee: number
|
||||||
|
// collect datatoken info for publishing
|
||||||
|
datatoken?: DataTokenOptions
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface MetadataPublishForm {
|
export interface MetadataPublishForm {
|
||||||
@ -23,7 +33,7 @@ export interface MetadataPublishForm {
|
|||||||
files: string | File[]
|
files: string | File[]
|
||||||
author: string
|
author: string
|
||||||
license: string
|
license: string
|
||||||
price: PriceOptions
|
price: PriceOptionsMarket
|
||||||
access: 'Download' | 'Compute' | string
|
access: 'Download' | 'Compute' | string
|
||||||
termsAndConditions: boolean
|
termsAndConditions: boolean
|
||||||
// ---- optional fields ----
|
// ---- optional fields ----
|
||||||
|
@ -38,6 +38,15 @@
|
|||||||
color: var(--brand-grey-light);
|
color: var(--brand-grey-light);
|
||||||
cursor: not-allowed;
|
cursor: not-allowed;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
|
/* for hiding spin buttons in Firefox */
|
||||||
|
-moz-appearance: textfield;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input[readonly]::-webkit-inner-spin-button,
|
||||||
|
.input[disabled]::-webkit-inner-spin-button,
|
||||||
|
.input[readonly]::-webkit-outer-spin-button,
|
||||||
|
.input[disabled]::-webkit-outer-spin-button {
|
||||||
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.select {
|
.select {
|
||||||
@ -207,6 +216,12 @@
|
|||||||
font-size: var(--font-size-small);
|
font-size: var(--font-size-small);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.prefix.small,
|
||||||
|
.postfix.small {
|
||||||
|
min-height: 34px;
|
||||||
|
font-size: var(--font-size-mini);
|
||||||
|
}
|
||||||
|
|
||||||
.selectSmall {
|
.selectSmall {
|
||||||
composes: small;
|
composes: small;
|
||||||
height: 34px;
|
height: 34px;
|
||||||
|
@ -6,8 +6,12 @@ import FilesInput from '../../molecules/FormFields/FilesInput'
|
|||||||
import Terms from '../../molecules/FormFields/Terms'
|
import Terms from '../../molecules/FormFields/Terms'
|
||||||
import Price from '../../molecules/FormFields/Price'
|
import Price from '../../molecules/FormFields/Price'
|
||||||
|
|
||||||
const DefaultInput = (props: InputProps) => (
|
const DefaultInput = ({ small, ...props }: InputProps) => (
|
||||||
<input className={styles.input} id={props.name} {...props} />
|
<input
|
||||||
|
className={`${styles.input} ${small ? styles.small : null}`}
|
||||||
|
id={props.name}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
)
|
)
|
||||||
|
|
||||||
export default function InputElement({
|
export default function InputElement({
|
||||||
@ -18,6 +22,10 @@ export default function InputElement({
|
|||||||
postfix,
|
postfix,
|
||||||
small,
|
small,
|
||||||
field,
|
field,
|
||||||
|
label,
|
||||||
|
help,
|
||||||
|
form,
|
||||||
|
additionalComponent,
|
||||||
...props
|
...props
|
||||||
}: InputProps): ReactElement {
|
}: InputProps): ReactElement {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
@ -75,12 +83,30 @@ export default function InputElement({
|
|||||||
default:
|
default:
|
||||||
return prefix || postfix ? (
|
return prefix || postfix ? (
|
||||||
<div className={`${prefix ? styles.prefixGroup : styles.postfixGroup}`}>
|
<div className={`${prefix ? styles.prefixGroup : styles.postfixGroup}`}>
|
||||||
{prefix && <div className={styles.prefix}>{prefix}</div>}
|
{prefix && (
|
||||||
<DefaultInput name={name} type={type || 'text'} {...props} />
|
<div className={`${styles.prefix} ${small ? styles.small : ''}`}>
|
||||||
{postfix && <div className={styles.postfix}>{postfix}</div>}
|
{prefix}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
<DefaultInput
|
||||||
|
name={name}
|
||||||
|
type={type || 'text'}
|
||||||
|
small={small}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
{postfix && (
|
||||||
|
<div className={`${styles.postfix} ${small ? styles.small : ''}`}>
|
||||||
|
{postfix}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<DefaultInput name={name} type={type || 'text'} {...props} />
|
<DefaultInput
|
||||||
|
name={name}
|
||||||
|
type={type || 'text'}
|
||||||
|
small={small}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,7 @@ const cx = classNames.bind(styles)
|
|||||||
|
|
||||||
export interface InputProps {
|
export interface InputProps {
|
||||||
name: string
|
name: string
|
||||||
label?: string
|
label?: string | ReactNode
|
||||||
placeholder?: string
|
placeholder?: string
|
||||||
required?: boolean
|
required?: boolean
|
||||||
help?: string
|
help?: string
|
||||||
@ -30,6 +30,7 @@ export interface InputProps {
|
|||||||
multiple?: boolean
|
multiple?: boolean
|
||||||
pattern?: string
|
pattern?: string
|
||||||
min?: string
|
min?: string
|
||||||
|
max?: string
|
||||||
disabled?: boolean
|
disabled?: boolean
|
||||||
readOnly?: boolean
|
readOnly?: boolean
|
||||||
field?: any
|
field?: any
|
||||||
@ -53,8 +54,7 @@ export default function Input(props: Partial<InputProps>): ReactElement {
|
|||||||
} = props
|
} = props
|
||||||
|
|
||||||
const hasError =
|
const hasError =
|
||||||
props.form?.touched[field.name] &&
|
props.form?.touched[field.name] && props.form?.errors[field.name]
|
||||||
typeof props.form.errors[field.name] === 'string'
|
|
||||||
|
|
||||||
const styleClasses = cx({
|
const styleClasses = cx({
|
||||||
field: true,
|
field: true,
|
||||||
@ -71,7 +71,7 @@ export default function Input(props: Partial<InputProps>): ReactElement {
|
|||||||
</Label>
|
</Label>
|
||||||
<InputElement small={small} {...field} {...props} />
|
<InputElement small={small} {...field} {...props} />
|
||||||
|
|
||||||
{field && (
|
{field && field.name !== 'price' && (
|
||||||
<div className={styles.error}>
|
<div className={styles.error}>
|
||||||
<ErrorMessage name={field.name} />
|
<ErrorMessage name={field.name} />
|
||||||
</div>
|
</div>
|
||||||
|
@ -6,12 +6,8 @@ import FileInput from './Input'
|
|||||||
import { getFileInfo } from '../../../../utils'
|
import { getFileInfo } from '../../../../utils'
|
||||||
import { InputProps } from '../../../atoms/Input'
|
import { InputProps } from '../../../atoms/Input'
|
||||||
|
|
||||||
interface Values {
|
|
||||||
url: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function FilesInput(props: InputProps): ReactElement {
|
export default function FilesInput(props: InputProps): ReactElement {
|
||||||
const [field, meta, helpers] = useField(props)
|
const [field, meta, helpers] = useField(props.name)
|
||||||
const [isLoading, setIsLoading] = useState(false)
|
const [isLoading, setIsLoading] = useState(false)
|
||||||
|
|
||||||
async function handleButtonClick(e: React.SyntheticEvent, url: string) {
|
async function handleButtonClick(e: React.SyntheticEvent, url: string) {
|
||||||
@ -36,7 +32,7 @@ export default function FilesInput(props: InputProps): ReactElement {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{field && typeof field.value === 'object' ? (
|
{field?.value && field.value[0] && typeof field.value === 'object' ? (
|
||||||
<FileInfo file={field.value[0]} removeItem={removeItem} />
|
<FileInfo file={field.value[0]} removeItem={removeItem} />
|
||||||
) : (
|
) : (
|
||||||
<FileInput
|
<FileInput
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import React, { ReactElement, ChangeEvent } from 'react'
|
import React, { ReactElement } from 'react'
|
||||||
import stylesIndex from './index.module.css'
|
import stylesIndex from './index.module.css'
|
||||||
import styles from './Coin.module.css'
|
import styles from './Coin.module.css'
|
||||||
import InputElement from '../../../atoms/Input/InputElement'
|
import InputElement from '../../../atoms/Input/InputElement'
|
||||||
@ -6,24 +6,24 @@ import { ReactComponent as Logo } from '../../../../images/logo.svg'
|
|||||||
import Conversion from '../../../atoms/Price/Conversion'
|
import Conversion from '../../../atoms/Price/Conversion'
|
||||||
import { DataTokenOptions } from '@oceanprotocol/react'
|
import { DataTokenOptions } from '@oceanprotocol/react'
|
||||||
import RefreshName from './RefreshName'
|
import RefreshName from './RefreshName'
|
||||||
|
import { useField } from 'formik'
|
||||||
|
import Error from './Error'
|
||||||
|
|
||||||
export default function Coin({
|
export default function Coin({
|
||||||
datatokenOptions,
|
datatokenOptions,
|
||||||
name,
|
name,
|
||||||
value,
|
|
||||||
weight,
|
weight,
|
||||||
onOceanChange,
|
|
||||||
generateName,
|
generateName,
|
||||||
readOnly
|
readOnly
|
||||||
}: {
|
}: {
|
||||||
datatokenOptions: DataTokenOptions
|
datatokenOptions: DataTokenOptions
|
||||||
name: string
|
name: string
|
||||||
value: string
|
|
||||||
weight: string
|
weight: string
|
||||||
onOceanChange?: (event: ChangeEvent<HTMLInputElement>) => void
|
|
||||||
generateName?: () => void
|
generateName?: () => void
|
||||||
readOnly?: boolean
|
readOnly?: boolean
|
||||||
}): ReactElement {
|
}): ReactElement {
|
||||||
|
const [field, meta] = useField(name)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.coin}>
|
<div className={styles.coin}>
|
||||||
<figure className={styles.icon}>
|
<figure className={styles.icon}>
|
||||||
@ -43,16 +43,16 @@ export default function Coin({
|
|||||||
|
|
||||||
<div className={styles.data}>
|
<div className={styles.data}>
|
||||||
<InputElement
|
<InputElement
|
||||||
value={value}
|
|
||||||
name={name}
|
|
||||||
type="number"
|
type="number"
|
||||||
onChange={onOceanChange}
|
|
||||||
readOnly={readOnly}
|
readOnly={readOnly}
|
||||||
prefix={datatokenOptions?.symbol || 'DT'}
|
prefix={datatokenOptions?.symbol || 'DT'}
|
||||||
|
min="1"
|
||||||
|
{...field}
|
||||||
/>
|
/>
|
||||||
{datatokenOptions?.symbol === 'OCEAN' && (
|
{datatokenOptions?.symbol === 'OCEAN' && (
|
||||||
<Conversion price={value} className={stylesIndex.conversion} />
|
<Conversion price={field.value} className={stylesIndex.conversion} />
|
||||||
)}
|
)}
|
||||||
|
<Error meta={meta} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
@ -49,14 +49,9 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.summary {
|
.summary {
|
||||||
text-align: center;
|
|
||||||
margin-top: var(--spacer);
|
margin-top: var(--spacer);
|
||||||
}
|
}
|
||||||
|
|
||||||
.summary input {
|
|
||||||
max-width: 5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.alertArea {
|
.alertArea {
|
||||||
margin-left: -2rem;
|
margin-left: -2rem;
|
||||||
margin-right: -2rem;
|
margin-right: -2rem;
|
||||||
|
@ -1,35 +1,33 @@
|
|||||||
import React, { ReactElement, useState, ChangeEvent, useEffect } from 'react'
|
import React, { ReactElement, useState, useEffect } from 'react'
|
||||||
import stylesIndex from './index.module.css'
|
import stylesIndex from './index.module.css'
|
||||||
import styles from './Dynamic.module.css'
|
import styles from './Dynamic.module.css'
|
||||||
import FormHelp from '../../../atoms/Input/Help'
|
import FormHelp from '../../../atoms/Input/Help'
|
||||||
import Wallet from '../../Wallet'
|
import Wallet from '../../Wallet'
|
||||||
import { DataTokenOptions, PriceOptions, useOcean } from '@oceanprotocol/react'
|
import { DataTokenOptions, useOcean } from '@oceanprotocol/react'
|
||||||
import Alert from '../../../atoms/Alert'
|
import Alert from '../../../atoms/Alert'
|
||||||
import Coin from './Coin'
|
import Coin from './Coin'
|
||||||
import { isCorrectNetwork } from '../../../../utils/wallet'
|
import { isCorrectNetwork } from '../../../../utils/wallet'
|
||||||
import { useSiteMetadata } from '../../../../hooks/useSiteMetadata'
|
import { useSiteMetadata } from '../../../../hooks/useSiteMetadata'
|
||||||
import InputElement from '../../../atoms/Input/InputElement'
|
|
||||||
import Label from '../../../atoms/Input/Label'
|
|
||||||
import Tooltip from '../../../atoms/Tooltip'
|
import Tooltip from '../../../atoms/Tooltip'
|
||||||
|
import Fees from './Fees'
|
||||||
|
import { PriceOptionsMarket } from '../../../../@types/MetaData'
|
||||||
|
|
||||||
export default function Dynamic({
|
export default function Dynamic({
|
||||||
ocean,
|
ocean,
|
||||||
priceOptions,
|
priceOptions,
|
||||||
datatokenOptions,
|
datatokenOptions,
|
||||||
onOceanChange,
|
|
||||||
generateName,
|
generateName,
|
||||||
content
|
content
|
||||||
}: {
|
}: {
|
||||||
ocean: string
|
ocean: number
|
||||||
priceOptions: PriceOptions
|
priceOptions: PriceOptionsMarket
|
||||||
datatokenOptions: DataTokenOptions
|
datatokenOptions: DataTokenOptions
|
||||||
onOceanChange: (event: ChangeEvent<HTMLInputElement>) => void
|
|
||||||
generateName: () => void
|
generateName: () => void
|
||||||
content: any
|
content: any
|
||||||
}): ReactElement {
|
}): ReactElement {
|
||||||
const { appConfig } = useSiteMetadata()
|
const { appConfig } = useSiteMetadata()
|
||||||
const { account, balance, chainId, refreshBalance } = useOcean()
|
const { account, balance, chainId, refreshBalance } = useOcean()
|
||||||
const { weightOnDataToken, tokensToMint, liquidityProviderFee } = priceOptions
|
const { weightOnDataToken } = priceOptions
|
||||||
|
|
||||||
const [error, setError] = useState<string>()
|
const [error, setError] = useState<string>()
|
||||||
const correctNetwork = isCorrectNetwork(chainId)
|
const correctNetwork = isCorrectNetwork(chainId)
|
||||||
@ -37,14 +35,14 @@ export default function Dynamic({
|
|||||||
c.toUpperCase()
|
c.toUpperCase()
|
||||||
)
|
)
|
||||||
|
|
||||||
// Check: account, network & insuffciant balance
|
// Check: account, network & insufficient balance
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!account) {
|
if (!account) {
|
||||||
setError(`No account connected. Please connect your Web3 wallet.`)
|
setError(`No account connected. Please connect your Web3 wallet.`)
|
||||||
} else if (!correctNetwork) {
|
} else if (!correctNetwork) {
|
||||||
setError(`Wrong Network. Please connect to ${desiredNetworkName}.`)
|
setError(`Wrong Network. Please connect to ${desiredNetworkName}.`)
|
||||||
} else if (Number(balance.ocean) < Number(ocean)) {
|
} else if (Number(balance.ocean) < Number(ocean)) {
|
||||||
setError(`Insufficiant balance. You need at least ${ocean} OCEAN`)
|
setError(`Insufficient balance. You need at least ${ocean} OCEAN`)
|
||||||
} else {
|
} else {
|
||||||
setError(undefined)
|
setError(undefined)
|
||||||
}
|
}
|
||||||
@ -76,39 +74,29 @@ export default function Dynamic({
|
|||||||
</aside>
|
</aside>
|
||||||
|
|
||||||
<h4 className={styles.title}>
|
<h4 className={styles.title}>
|
||||||
Data Token Liquidity Pool{' '}
|
Datatoken Liquidity Pool <Tooltip content={content.tooltips.poolInfo} />
|
||||||
<Tooltip content={content.tooltips.poolInfo} />
|
|
||||||
</h4>
|
</h4>
|
||||||
|
|
||||||
<div className={styles.tokens}>
|
<div className={styles.tokens}>
|
||||||
<Coin
|
<Coin
|
||||||
name="ocean"
|
name="price.price"
|
||||||
datatokenOptions={{ symbol: 'OCEAN', name: 'Ocean Token' }}
|
datatokenOptions={{ symbol: 'OCEAN', name: 'Ocean Token' }}
|
||||||
value={ocean}
|
|
||||||
weight={`${100 - Number(Number(weightOnDataToken) * 10)}%`}
|
weight={`${100 - Number(Number(weightOnDataToken) * 10)}%`}
|
||||||
onOceanChange={onOceanChange}
|
|
||||||
/>
|
/>
|
||||||
<Coin
|
<Coin
|
||||||
name="tokensToMint"
|
name="price.tokensToMint"
|
||||||
datatokenOptions={datatokenOptions}
|
datatokenOptions={datatokenOptions}
|
||||||
value={tokensToMint.toString()}
|
|
||||||
weight={`${Number(weightOnDataToken) * 10}%`}
|
weight={`${Number(weightOnDataToken) * 10}%`}
|
||||||
generateName={generateName}
|
generateName={generateName}
|
||||||
readOnly
|
readOnly
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<Fees tooltips={content.tooltips} />
|
||||||
|
|
||||||
<footer className={styles.summary}>
|
<footer className={styles.summary}>
|
||||||
<Label htmlFor="liquidityProviderFee">
|
You will get: <br />
|
||||||
Liquidity Provider Fee{' '}
|
100% share of pool
|
||||||
<Tooltip content={content.tooltips.liquidityProviderFee} />
|
|
||||||
</Label>
|
|
||||||
<InputElement
|
|
||||||
value={liquidityProviderFee}
|
|
||||||
name="liquidityProviderFee"
|
|
||||||
readOnly
|
|
||||||
postfix="%"
|
|
||||||
/>
|
|
||||||
</footer>
|
</footer>
|
||||||
|
|
||||||
{error && (
|
{error && (
|
||||||
|
13
src/components/molecules/FormFields/Price/Error.tsx
Normal file
13
src/components/molecules/FormFields/Price/Error.tsx
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
import { FieldMetaProps } from 'formik'
|
||||||
|
import React, { ReactElement } from 'react'
|
||||||
|
import stylesInput from '../../../atoms/Input/index.module.css'
|
||||||
|
|
||||||
|
export default function Error({
|
||||||
|
meta
|
||||||
|
}: {
|
||||||
|
meta: FieldMetaProps<any>
|
||||||
|
}): ReactElement {
|
||||||
|
return meta.error ? (
|
||||||
|
<div className={stylesInput.error}>{meta.error}</div>
|
||||||
|
) : null
|
||||||
|
}
|
22
src/components/molecules/FormFields/Price/Fees.module.css
Normal file
22
src/components/molecules/FormFields/Price/Fees.module.css
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
.fees {
|
||||||
|
display: grid;
|
||||||
|
gap: var(--spacer);
|
||||||
|
grid-template-columns: repeat(auto-fit, minmax(10rem, 1fr));
|
||||||
|
margin-left: -2rem;
|
||||||
|
margin-right: -2rem;
|
||||||
|
border-bottom: 1px solid var(--brand-grey-lighter);
|
||||||
|
margin-top: var(--spacer);
|
||||||
|
padding: 0 var(--spacer) calc(var(--spacer) / 2) var(--spacer);
|
||||||
|
|
||||||
|
justify-content: center;
|
||||||
|
text-align: center;
|
||||||
|
border-bottom: 1px solid var(--brand-grey-lighter);
|
||||||
|
}
|
||||||
|
|
||||||
|
.fees label {
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fees input {
|
||||||
|
max-width: 5rem;
|
||||||
|
}
|
67
src/components/molecules/FormFields/Price/Fees.tsx
Normal file
67
src/components/molecules/FormFields/Price/Fees.tsx
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
import React, { ReactElement } from 'react'
|
||||||
|
import Tooltip from '../../../atoms/Tooltip'
|
||||||
|
import styles from './Fees.module.css'
|
||||||
|
import { useSiteMetadata } from '../../../../hooks/useSiteMetadata'
|
||||||
|
import { useField } from 'formik'
|
||||||
|
import Input from '../../../atoms/Input'
|
||||||
|
import Error from './Error'
|
||||||
|
|
||||||
|
export default function Fees({
|
||||||
|
tooltips
|
||||||
|
}: {
|
||||||
|
tooltips: { [key: string]: string }
|
||||||
|
}): ReactElement {
|
||||||
|
const { appConfig } = useSiteMetadata()
|
||||||
|
const [field, meta] = useField('price.liquidityProviderFee')
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div className={styles.fees}>
|
||||||
|
<Input
|
||||||
|
label={
|
||||||
|
<>
|
||||||
|
Liquidity Provider Fee
|
||||||
|
<Tooltip content={tooltips.liquidityProviderFee} />
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
type="number"
|
||||||
|
postfix="%"
|
||||||
|
min="0.1"
|
||||||
|
max="0.9"
|
||||||
|
step="0.1"
|
||||||
|
small
|
||||||
|
{...field}
|
||||||
|
additionalComponent={<Error meta={meta} />}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Input
|
||||||
|
label={
|
||||||
|
<>
|
||||||
|
Community Fee
|
||||||
|
<Tooltip content={tooltips.communityFee} />
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
value="0.1"
|
||||||
|
name="communityFee"
|
||||||
|
postfix="%"
|
||||||
|
readOnly
|
||||||
|
small
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Input
|
||||||
|
label={
|
||||||
|
<>
|
||||||
|
Marketplace Fee
|
||||||
|
<Tooltip content={tooltips.marketplaceFee} />
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
value={appConfig.marketFeeAmount}
|
||||||
|
name="marketplaceFee"
|
||||||
|
postfix="%"
|
||||||
|
readOnly
|
||||||
|
small
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
@ -2,6 +2,10 @@
|
|||||||
composes: content from './index.module.css';
|
composes: content from './index.module.css';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.form {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
@media (min-width: 55rem) {
|
@media (min-width: 55rem) {
|
||||||
.form {
|
.form {
|
||||||
max-width: 12rem;
|
max-width: 12rem;
|
||||||
|
@ -1,42 +1,49 @@
|
|||||||
import React, { ReactElement, ChangeEvent } from 'react'
|
import React, { ReactElement } from 'react'
|
||||||
import stylesIndex from './index.module.css'
|
import stylesIndex from './index.module.css'
|
||||||
import styles from './Fixed.module.css'
|
import styles from './Fixed.module.css'
|
||||||
import FormHelp from '../../../atoms/Input/Help'
|
import FormHelp from '../../../atoms/Input/Help'
|
||||||
import Label from '../../../atoms/Input/Label'
|
|
||||||
import InputElement from '../../../atoms/Input/InputElement'
|
|
||||||
import Conversion from '../../../atoms/Price/Conversion'
|
import Conversion from '../../../atoms/Price/Conversion'
|
||||||
import { DataTokenOptions } from '@oceanprotocol/react'
|
import { DataTokenOptions } from '@oceanprotocol/react'
|
||||||
import RefreshName from './RefreshName'
|
import RefreshName from './RefreshName'
|
||||||
|
import { useField } from 'formik'
|
||||||
|
import Input from '../../../atoms/Input'
|
||||||
|
import Error from './Error'
|
||||||
|
|
||||||
export default function Fixed({
|
export default function Fixed({
|
||||||
ocean,
|
|
||||||
datatokenOptions,
|
datatokenOptions,
|
||||||
onChange,
|
|
||||||
generateName,
|
generateName,
|
||||||
content
|
content
|
||||||
}: {
|
}: {
|
||||||
ocean: string
|
|
||||||
datatokenOptions: DataTokenOptions
|
datatokenOptions: DataTokenOptions
|
||||||
onChange: (event: ChangeEvent<HTMLInputElement>) => void
|
|
||||||
generateName: () => void
|
generateName: () => void
|
||||||
content: any
|
content: any
|
||||||
}): ReactElement {
|
}): ReactElement {
|
||||||
|
const [field, meta] = useField('price.price')
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.fixed}>
|
<div className={styles.fixed}>
|
||||||
<FormHelp className={stylesIndex.help}>{content.info}</FormHelp>
|
<FormHelp className={stylesIndex.help}>{content.info}</FormHelp>
|
||||||
|
|
||||||
<div className={styles.grid}>
|
<div className={styles.grid}>
|
||||||
<div className={styles.form}>
|
<div className={styles.form}>
|
||||||
<Label htmlFor="ocean">Ocean Token</Label>
|
<Input
|
||||||
<InputElement
|
label="Ocean Token"
|
||||||
value={ocean}
|
value={field.value}
|
||||||
name="ocean"
|
name="price.price"
|
||||||
type="number"
|
type="number"
|
||||||
prefix="OCEAN"
|
prefix="OCEAN"
|
||||||
onChange={onChange}
|
min="1"
|
||||||
|
{...field}
|
||||||
|
additionalComponent={
|
||||||
|
<Conversion
|
||||||
|
price={field.value}
|
||||||
|
className={stylesIndex.conversion}
|
||||||
/>
|
/>
|
||||||
<Conversion price={ocean} className={stylesIndex.conversion} />
|
}
|
||||||
|
/>
|
||||||
|
<Error meta={meta} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{datatokenOptions && (
|
{datatokenOptions && (
|
||||||
<div className={styles.datatoken}>
|
<div className={styles.datatoken}>
|
||||||
<h4>
|
<h4>
|
||||||
|
@ -20,6 +20,11 @@
|
|||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.content [class*='error'] {
|
||||||
|
text-align: left;
|
||||||
|
top: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
.conversion {
|
.conversion {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
display: block;
|
display: block;
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import React, { ReactElement, useState, ChangeEvent, useEffect } from 'react'
|
import React, { ReactElement, useState, useEffect } from 'react'
|
||||||
import { graphql, useStaticQuery } from 'gatsby'
|
import { graphql, useStaticQuery } from 'gatsby'
|
||||||
import { InputProps } from '../../../atoms/Input'
|
import { InputProps } from '../../../atoms/Input'
|
||||||
import styles from './index.module.css'
|
import styles from './index.module.css'
|
||||||
@ -7,7 +7,8 @@ import Fixed from './Fixed'
|
|||||||
import Dynamic from './Dynamic'
|
import Dynamic from './Dynamic'
|
||||||
import { useField } from 'formik'
|
import { useField } from 'formik'
|
||||||
import { useUserPreferences } from '../../../../providers/UserPreferences'
|
import { useUserPreferences } from '../../../../providers/UserPreferences'
|
||||||
import { DataTokenOptions, PriceOptions, useOcean } from '@oceanprotocol/react'
|
import { useOcean } from '@oceanprotocol/react'
|
||||||
|
import { PriceOptionsMarket } from '../../../../@types/MetaData'
|
||||||
|
|
||||||
const query = graphql`
|
const query = graphql`
|
||||||
query PriceFieldQuery {
|
query PriceFieldQuery {
|
||||||
@ -26,6 +27,8 @@ const query = graphql`
|
|||||||
tooltips {
|
tooltips {
|
||||||
poolInfo
|
poolInfo
|
||||||
liquidityProviderFee
|
liquidityProviderFee
|
||||||
|
communityFee
|
||||||
|
marketplaceFee
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -42,17 +45,10 @@ export default function Price(props: InputProps): ReactElement {
|
|||||||
const content = data.content.edges[0].node.childPagesJson.price
|
const content = data.content.edges[0].node.childPagesJson.price
|
||||||
const { ocean } = useOcean()
|
const { ocean } = useOcean()
|
||||||
|
|
||||||
const [field, meta, helpers] = useField(props)
|
const [field, meta, helpers] = useField(props.name)
|
||||||
const priceOptions: PriceOptions = field.value
|
const { price }: PriceOptionsMarket = field.value
|
||||||
|
|
||||||
const [amountOcean, setAmountOcean] = useState('1')
|
|
||||||
const [tokensToMint, setTokensToMint] = useState<number>()
|
const [tokensToMint, setTokensToMint] = useState<number>()
|
||||||
const [datatokenOptions, setDatatokenOptions] = useState<DataTokenOptions>()
|
|
||||||
|
|
||||||
function handleOceanChange(event: ChangeEvent<HTMLInputElement>) {
|
|
||||||
setAmountOcean(event.target.value)
|
|
||||||
helpers.setValue({ ...field.value, price: event.target.value })
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleTabChange(tabName: string) {
|
function handleTabChange(tabName: string) {
|
||||||
const type = tabName.toLowerCase()
|
const type = tabName.toLowerCase()
|
||||||
@ -61,17 +57,16 @@ export default function Price(props: InputProps): ReactElement {
|
|||||||
|
|
||||||
function generateName() {
|
function generateName() {
|
||||||
if (!ocean) return
|
if (!ocean) return
|
||||||
const newDatatokenOptions = ocean.datatokens.generateDtName()
|
const datatoken = ocean.datatokens.generateDtName()
|
||||||
setDatatokenOptions(newDatatokenOptions)
|
helpers.setValue({ ...field.value, datatoken })
|
||||||
}
|
}
|
||||||
|
|
||||||
// Always update everything when amountOcean changes
|
// Always update everything when amountOcean changes
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const tokensToMint =
|
const tokensToMint = Number(price) * Number(field.value.weightOnDataToken)
|
||||||
Number(amountOcean) * Number(priceOptions.weightOnDataToken)
|
|
||||||
setTokensToMint(tokensToMint)
|
setTokensToMint(tokensToMint)
|
||||||
helpers.setValue({ ...field.value, tokensToMint })
|
helpers.setValue({ ...field.value, tokensToMint })
|
||||||
}, [amountOcean])
|
}, [price])
|
||||||
|
|
||||||
// Generate new DT name & symbol
|
// Generate new DT name & symbol
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -83,9 +78,7 @@ export default function Price(props: InputProps): ReactElement {
|
|||||||
title: content.fixed.title,
|
title: content.fixed.title,
|
||||||
content: (
|
content: (
|
||||||
<Fixed
|
<Fixed
|
||||||
ocean={amountOcean}
|
datatokenOptions={field.value.datatoken}
|
||||||
datatokenOptions={datatokenOptions}
|
|
||||||
onChange={handleOceanChange}
|
|
||||||
generateName={generateName}
|
generateName={generateName}
|
||||||
content={content.fixed}
|
content={content.fixed}
|
||||||
/>
|
/>
|
||||||
@ -95,10 +88,9 @@ export default function Price(props: InputProps): ReactElement {
|
|||||||
title: content.dynamic.title,
|
title: content.dynamic.title,
|
||||||
content: (
|
content: (
|
||||||
<Dynamic
|
<Dynamic
|
||||||
ocean={amountOcean}
|
ocean={price}
|
||||||
priceOptions={{ ...priceOptions, tokensToMint }}
|
priceOptions={{ ...field.value, tokensToMint }}
|
||||||
datatokenOptions={datatokenOptions}
|
datatokenOptions={field.value.datatoken}
|
||||||
onOceanChange={handleOceanChange}
|
|
||||||
generateName={generateName}
|
generateName={generateName}
|
||||||
content={content.dynamic}
|
content={content.dynamic}
|
||||||
/>
|
/>
|
||||||
@ -111,7 +103,7 @@ export default function Price(props: InputProps): ReactElement {
|
|||||||
<Tabs items={tabs} handleTabChange={handleTabChange} />
|
<Tabs items={tabs} handleTabChange={handleTabChange} />
|
||||||
{debug === true && (
|
{debug === true && (
|
||||||
<pre>
|
<pre>
|
||||||
<code>{JSON.stringify(field.value)}</code>
|
<code>{JSON.stringify(field.value, null, 2)}</code>
|
||||||
</pre>
|
</pre>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
@ -16,17 +16,18 @@ export default function Add({
|
|||||||
setShowAdd,
|
setShowAdd,
|
||||||
poolAddress,
|
poolAddress,
|
||||||
totalPoolTokens,
|
totalPoolTokens,
|
||||||
totalBalance
|
totalBalance,
|
||||||
|
liquidityProviderFee
|
||||||
}: {
|
}: {
|
||||||
setShowAdd: (show: boolean) => void
|
setShowAdd: (show: boolean) => void
|
||||||
poolAddress: string
|
poolAddress: string
|
||||||
totalPoolTokens: string
|
totalPoolTokens: string
|
||||||
totalBalance: Balance
|
totalBalance: Balance
|
||||||
|
liquidityProviderFee: string
|
||||||
}): ReactElement {
|
}): ReactElement {
|
||||||
const { debug } = useUserPreferences()
|
const { debug } = useUserPreferences()
|
||||||
const { ocean, accountId, balance } = useOcean()
|
const { ocean, accountId, balance } = useOcean()
|
||||||
const [amount, setAmount] = useState('')
|
const [amount, setAmount] = useState('')
|
||||||
const [swapFee, setSwapFee] = useState<string>()
|
|
||||||
const [txId, setTxId] = useState<string>('')
|
const [txId, setTxId] = useState<string>('')
|
||||||
const [isLoading, setIsLoading] = useState<boolean>()
|
const [isLoading, setIsLoading] = useState<boolean>()
|
||||||
|
|
||||||
@ -38,14 +39,6 @@ export default function Add({
|
|||||||
totalBalance &&
|
totalBalance &&
|
||||||
((Number(newPoolTokens) / Number(totalPoolTokens)) * 100).toFixed(2)
|
((Number(newPoolTokens) / Number(totalPoolTokens)) * 100).toFixed(2)
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
async function getFee() {
|
|
||||||
const swapFee = await ocean.pool.getSwapFee(accountId, poolAddress)
|
|
||||||
setSwapFee(swapFee)
|
|
||||||
}
|
|
||||||
getFee()
|
|
||||||
}, [])
|
|
||||||
|
|
||||||
async function handleAddLiquidity() {
|
async function handleAddLiquidity() {
|
||||||
setIsLoading(true)
|
setIsLoading(true)
|
||||||
|
|
||||||
@ -96,7 +89,7 @@ export default function Add({
|
|||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<p>You will earn</p>
|
<p>You will earn</p>
|
||||||
<Token symbol="%" balance={swapFee} />
|
<Token symbol="%" balance={liquidityProviderFee} />
|
||||||
of each pool transaction
|
of each pool transaction
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -33,6 +33,7 @@ export default function Pool({ ddo }: { ddo: DDO }): ReactElement {
|
|||||||
const [totalBalance, setTotalBalance] = useState<Balance>()
|
const [totalBalance, setTotalBalance] = useState<Balance>()
|
||||||
const [dtSymbol, setDtSymbol] = useState<string>()
|
const [dtSymbol, setDtSymbol] = useState<string>()
|
||||||
const [userBalance, setUserBalance] = useState<Balance>()
|
const [userBalance, setUserBalance] = useState<Balance>()
|
||||||
|
const [liquidityProviderFee, setLiquidityProviderFee] = useState<string>()
|
||||||
|
|
||||||
const [showAdd, setShowAdd] = useState(false)
|
const [showAdd, setShowAdd] = useState(false)
|
||||||
const [showRemove, setShowRemove] = useState(false)
|
const [showRemove, setShowRemove] = useState(false)
|
||||||
@ -103,6 +104,13 @@ export default function Pool({ ddo }: { ddo: DDO }): ReactElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
setUserBalance(userBalance)
|
setUserBalance(userBalance)
|
||||||
|
|
||||||
|
// Get liquidity provider fee
|
||||||
|
const liquidityProviderFee = await ocean.pool.getSwapFee(
|
||||||
|
accountId,
|
||||||
|
price.address
|
||||||
|
)
|
||||||
|
setLiquidityProviderFee(liquidityProviderFee)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error.message)
|
console.error(error.message)
|
||||||
} finally {
|
} finally {
|
||||||
@ -122,6 +130,7 @@ export default function Pool({ ddo }: { ddo: DDO }): ReactElement {
|
|||||||
poolAddress={price.address}
|
poolAddress={price.address}
|
||||||
totalPoolTokens={totalPoolTokens}
|
totalPoolTokens={totalPoolTokens}
|
||||||
totalBalance={totalBalance}
|
totalBalance={totalBalance}
|
||||||
|
liquidityProviderFee={liquidityProviderFee}
|
||||||
/>
|
/>
|
||||||
) : showRemove ? (
|
) : showRemove ? (
|
||||||
<Remove
|
<Remove
|
||||||
@ -144,7 +153,7 @@ export default function Pool({ ddo }: { ddo: DDO }): ReactElement {
|
|||||||
Pool
|
Pool
|
||||||
</EtherscanLink>
|
</EtherscanLink>
|
||||||
<EtherscanLink network="rinkeby" path={`token/${ddo.dataToken}`}>
|
<EtherscanLink network="rinkeby" path={`token/${ddo.dataToken}`}>
|
||||||
Data Token
|
Datatoken
|
||||||
</EtherscanLink>
|
</EtherscanLink>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -168,6 +177,10 @@ export default function Pool({ ddo }: { ddo: DDO }): ReactElement {
|
|||||||
{debug === true && (
|
{debug === true && (
|
||||||
<Token symbol="BPT" balance={totalPoolTokens} />
|
<Token symbol="BPT" balance={totalPoolTokens} />
|
||||||
)}
|
)}
|
||||||
|
<Token
|
||||||
|
symbol="% liquidity provider fee"
|
||||||
|
balance={liquidityProviderFee}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -56,7 +56,7 @@ export default function MetaFull({
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
<MetaItem
|
<MetaItem
|
||||||
title="Data Token"
|
title="Datatoken"
|
||||||
content={
|
content={
|
||||||
<EtherscanLink network="rinkeby" path={`token/${dataToken}`}>
|
<EtherscanLink network="rinkeby" path={`token/${dataToken}`}>
|
||||||
{dtName ? `${dtName} - ${dtSymbol}` : <code>{dataToken}</code>}
|
{dtName ? `${dtName} - ${dtSymbol}` : <code>{dataToken}</code>}
|
||||||
|
@ -10,7 +10,6 @@ export default function MetaSecondary({
|
|||||||
}: {
|
}: {
|
||||||
metadata: MetadataMarket
|
metadata: MetadataMarket
|
||||||
}): ReactElement {
|
}): ReactElement {
|
||||||
console.log(metadata)
|
|
||||||
return (
|
return (
|
||||||
<aside className={styles.metaSecondary}>
|
<aside className={styles.metaSecondary}>
|
||||||
{metadata?.additionalInformation?.tags?.length > 0 && (
|
{metadata?.additionalInformation?.tags?.length > 0 && (
|
||||||
|
@ -11,7 +11,7 @@ import Button from '../../atoms/Button'
|
|||||||
export default function Preview({
|
export default function Preview({
|
||||||
values
|
values
|
||||||
}: {
|
}: {
|
||||||
values: MetadataPublishForm
|
values: Partial<MetadataPublishForm>
|
||||||
}): ReactElement {
|
}): ReactElement {
|
||||||
return (
|
return (
|
||||||
<div className={styles.preview}>
|
<div className={styles.preview}>
|
||||||
|
@ -2,7 +2,7 @@ import React, { ReactElement } from 'react'
|
|||||||
import { useNavigate } from '@reach/router'
|
import { useNavigate } from '@reach/router'
|
||||||
import { toast } from 'react-toastify'
|
import { toast } from 'react-toastify'
|
||||||
import { Formik } from 'formik'
|
import { Formik } from 'formik'
|
||||||
import { usePublish, DataTokenOptions } from '@oceanprotocol/react'
|
import { usePublish } from '@oceanprotocol/react'
|
||||||
import styles from './index.module.css'
|
import styles from './index.module.css'
|
||||||
import PublishForm from './PublishForm'
|
import PublishForm from './PublishForm'
|
||||||
import Web3Feedback from '../../molecules/Wallet/Feedback'
|
import Web3Feedback from '../../molecules/Wallet/Feedback'
|
||||||
@ -11,7 +11,6 @@ import { initialValues, validationSchema } from '../../../models/FormPublish'
|
|||||||
import { transformPublishFormToMetadata } from './utils'
|
import { transformPublishFormToMetadata } from './utils'
|
||||||
import Preview from './Preview'
|
import Preview from './Preview'
|
||||||
import { MetadataPublishForm } from '../../../@types/MetaData'
|
import { MetadataPublishForm } from '../../../@types/MetaData'
|
||||||
// import { useSiteMetadata } from '../../../hooks/useSiteMetadata'
|
|
||||||
import { useUserPreferences } from '../../../providers/UserPreferences'
|
import { useUserPreferences } from '../../../providers/UserPreferences'
|
||||||
import { Logger } from '@oceanprotocol/lib'
|
import { Logger } from '@oceanprotocol/lib'
|
||||||
|
|
||||||
@ -20,44 +19,38 @@ export default function PublishPage({
|
|||||||
}: {
|
}: {
|
||||||
content: { form: FormContent }
|
content: { form: FormContent }
|
||||||
}): ReactElement {
|
}): ReactElement {
|
||||||
// TODO: implement marketFee
|
|
||||||
// const { marketFeeAddress, marketFeeAmount } = useSiteMetadata()
|
|
||||||
const { debug } = useUserPreferences()
|
const { debug } = useUserPreferences()
|
||||||
const { publish, publishError, isLoading, publishStepText } = usePublish()
|
const { publish, publishError, isLoading, publishStepText } = usePublish()
|
||||||
const navigate = useNavigate()
|
const navigate = useNavigate()
|
||||||
|
|
||||||
async function handleSubmit(
|
async function handleSubmit(
|
||||||
values: MetadataPublishForm,
|
values: Partial<MetadataPublishForm>,
|
||||||
resetForm: () => void
|
resetForm: () => void
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const metadata = transformPublishFormToMetadata(values)
|
const metadata = transformPublishFormToMetadata(values)
|
||||||
const priceOptions = values.price
|
const { price } = values
|
||||||
const serviceType = values.access === 'Download' ? 'access' : 'compute'
|
const serviceType = values.access === 'Download' ? 'access' : 'compute'
|
||||||
let datatokenOptions: DataTokenOptions
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Logger.log('Publish with ', priceOptions, serviceType, datatokenOptions)
|
Logger.log('Publish with ', price, serviceType, price.datatoken)
|
||||||
|
|
||||||
const ddo = await publish(
|
const ddo = await publish(
|
||||||
metadata as any,
|
metadata as any,
|
||||||
priceOptions,
|
{
|
||||||
|
...price,
|
||||||
|
liquidityProviderFee: `${price.liquidityProviderFee}`
|
||||||
|
},
|
||||||
serviceType,
|
serviceType,
|
||||||
datatokenOptions
|
price.datatoken
|
||||||
)
|
)
|
||||||
|
|
||||||
if (publishError) {
|
if (publishError) {
|
||||||
toast.error(publishError)
|
toast.error(publishError) && console.error(publishError)
|
||||||
console.error(publishError)
|
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
// User feedback and redirect to new asset detail page
|
// User feedback and redirect to new asset detail page
|
||||||
ddo && toast.success('Asset created successfully.')
|
ddo && toast.success('Asset created successfully.') && resetForm()
|
||||||
|
|
||||||
// reset form state
|
|
||||||
// TODO: verify persistant form in localStorage is cleared with it too
|
|
||||||
resetForm()
|
|
||||||
|
|
||||||
// Go to new asset detail page
|
// Go to new asset detail page
|
||||||
navigate(`/asset/${ddo.id}`)
|
navigate(`/asset/${ddo.id}`)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
@ -3,7 +3,7 @@ import { toStringNoMS } from '../../../utils'
|
|||||||
import AssetModel from '../../../models/Asset'
|
import AssetModel from '../../../models/Asset'
|
||||||
|
|
||||||
export function transformPublishFormToMetadata(
|
export function transformPublishFormToMetadata(
|
||||||
data: MetadataPublishForm
|
data: Partial<MetadataPublishForm>
|
||||||
): MetadataMarket {
|
): MetadataMarket {
|
||||||
const currentTime = toStringNoMS(new Date())
|
const currentTime = toStringNoMS(new Date())
|
||||||
|
|
||||||
|
@ -6,14 +6,28 @@ export const validationSchema = Yup.object().shape<MetadataPublishForm>({
|
|||||||
// ---- required fields ----
|
// ---- required fields ----
|
||||||
name: Yup.string().required('Required'),
|
name: Yup.string().required('Required'),
|
||||||
author: Yup.string().required('Required'),
|
author: Yup.string().required('Required'),
|
||||||
price: Yup.object().shape({
|
price: Yup.object()
|
||||||
tokensToMint: Yup.number().required('Required'),
|
.shape({
|
||||||
|
price: Yup.number().min(1, 'Must be greater than 0').required('Required'),
|
||||||
|
tokensToMint: Yup.number()
|
||||||
|
.min(1, 'Must be greater than 0')
|
||||||
|
.required('Required'),
|
||||||
type: Yup.string()
|
type: Yup.string()
|
||||||
.matches(/fixed|dynamic/g)
|
.matches(/fixed|dynamic/g)
|
||||||
.required('Required'),
|
.required('Required'),
|
||||||
weightOnDataToken: Yup.string().required('Required'),
|
weightOnDataToken: Yup.string().required('Required'),
|
||||||
liquidityProviderFee: Yup.string()
|
liquidityProviderFee: Yup.number()
|
||||||
}),
|
.min(0.1, 'Must be more or equal to 0.1')
|
||||||
|
.max(0.9, 'Must be less or equal to 0.9')
|
||||||
|
.required('Required'),
|
||||||
|
datatoken: Yup.object()
|
||||||
|
.shape({
|
||||||
|
name: Yup.string(),
|
||||||
|
symbol: Yup.string()
|
||||||
|
})
|
||||||
|
.nullable()
|
||||||
|
})
|
||||||
|
.required('Required'),
|
||||||
files: Yup.array<FileMetadata>().required('Required').nullable(),
|
files: Yup.array<FileMetadata>().required('Required').nullable(),
|
||||||
description: Yup.string().required('Required'),
|
description: Yup.string().required('Required'),
|
||||||
license: Yup.string().required('Required'),
|
license: Yup.string().required('Required'),
|
||||||
@ -23,27 +37,24 @@ export const validationSchema = Yup.object().shape<MetadataPublishForm>({
|
|||||||
termsAndConditions: Yup.boolean().required('Required'),
|
termsAndConditions: Yup.boolean().required('Required'),
|
||||||
|
|
||||||
// ---- optional fields ----
|
// ---- optional fields ----
|
||||||
copyrightHolder: Yup.string(),
|
copyrightHolder: Yup.string().nullable(),
|
||||||
tags: Yup.string(),
|
tags: Yup.string().nullable(),
|
||||||
links: Yup.object<FileMetadata[]>().nullable()
|
links: Yup.object<FileMetadata[]>().nullable()
|
||||||
})
|
})
|
||||||
|
|
||||||
export const initialValues: MetadataPublishForm = {
|
export const initialValues: Partial<MetadataPublishForm> = {
|
||||||
name: '',
|
name: '',
|
||||||
author: '',
|
author: '',
|
||||||
price: {
|
price: {
|
||||||
|
price: 1,
|
||||||
type: 'fixed',
|
type: 'fixed',
|
||||||
tokensToMint: 1,
|
tokensToMint: 1,
|
||||||
weightOnDataToken: '9', // 90% on data token
|
weightOnDataToken: '9', // 90% on data token
|
||||||
liquidityProviderFee: '0.1', // in %
|
liquidityProviderFee: 0.1 // in %
|
||||||
price: 1
|
|
||||||
},
|
},
|
||||||
files: '',
|
files: '',
|
||||||
description: '',
|
description: '',
|
||||||
license: '',
|
license: '',
|
||||||
access: '',
|
access: '',
|
||||||
termsAndConditions: false,
|
termsAndConditions: false
|
||||||
copyrightHolder: '',
|
|
||||||
tags: '',
|
|
||||||
links: ''
|
|
||||||
}
|
}
|
||||||
|
@ -5,10 +5,11 @@ const testFormData: MetadataPublishForm = {
|
|||||||
files: [],
|
files: [],
|
||||||
license: '',
|
license: '',
|
||||||
price: {
|
price: {
|
||||||
tokensToMint: 1,
|
price: 1,
|
||||||
type: 'simple',
|
tokensToMint: 9,
|
||||||
|
type: 'fixed',
|
||||||
weightOnDataToken: '1',
|
weightOnDataToken: '1',
|
||||||
liquidityProviderFee: '0.1'
|
liquidityProviderFee: 0.1
|
||||||
},
|
},
|
||||||
name: '',
|
name: '',
|
||||||
description: 'description',
|
description: 'description',
|
||||||
|
Loading…
Reference in New Issue
Block a user