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

Merge pull request #73 from oceanprotocol/feature/dt-name-output

handle generated dt names during publish
This commit is contained in:
Matthias Kretschmann 2020-09-11 16:50:15 +02:00 committed by GitHub
commit b70fa86273
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 213 additions and 105 deletions

View File

@ -100,11 +100,11 @@
"price": {
"fixed": {
"title": "Fixed",
"info": "Set your price for accessing this data set. A Data Token contract for this data set, worth the entered amount of OCEAN will be created."
"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."
},
"dynamic": {
"title": "Dynamic",
"info": "Let's create a decentralized, automated market for your data set. A Data Token contract 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 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.",
"tooltips": {
"poolInfo": "Help me",
"liquidityProviderFee": "Help me"

View File

@ -19,6 +19,7 @@ interface ButtonProps {
download?: boolean
target?: string
rel?: string
title?: string
}
export default function Button({

View File

@ -18,14 +18,18 @@
border: 1px solid var(--brand-grey-lighter);
border-radius: 50%;
background-color: var(--brand-white);
margin-bottom: var(--spacer);
margin-bottom: calc(var(--spacer) / 2);
}
.coin:last-child .icon path {
fill: var(--brand-grey-dimmed);
stroke: var(--brand-black);
stroke-width: 5px;
stroke-linejoin: round;
fill: var(--brand-violet);
}
.tokenName {
font-size: var(--font-size-base);
color: var(--brand-grey);
text-align: center;
margin-bottom: calc(var(--spacer) / 6);
}
.data {
@ -47,7 +51,8 @@
.weight {
width: 100%;
margin-top: var(--spacer);
text-align: center;
margin-bottom: calc(var(--spacer) / 2);
text-transform: uppercase;
font-size: var(--font-size-small);
color: var(--color-secondary);
@ -55,5 +60,4 @@
.weight strong {
color: var(--brand-grey);
font-size: var(--font-size-base);
}

View File

@ -4,20 +4,24 @@ import styles from './Coin.module.css'
import InputElement from '../../../atoms/Input/InputElement'
import { ReactComponent as Logo } from '../../../../images/logo.svg'
import Conversion from '../../../atoms/Price/Conversion'
import { DataTokenOptions } from '@oceanprotocol/react'
import RefreshName from './RefreshName'
export default function Coin({
symbol,
datatokenOptions,
name,
value,
weight,
onOceanChange,
generateName,
readOnly
}: {
symbol: string
datatokenOptions: DataTokenOptions
name: string
value: string
weight: string
onOceanChange?: (event: ChangeEvent<HTMLInputElement>) => void
generateName?: () => void
readOnly?: boolean
}): ReactElement {
return (
@ -26,6 +30,17 @@ export default function Coin({
<Logo />
</figure>
<h4 className={styles.tokenName}>
{datatokenOptions?.name || 'Data Token'}
{datatokenOptions?.name && generateName && (
<RefreshName generateName={generateName} />
)}
</h4>
<div className={styles.weight}>
Weight <strong>{weight}</strong>
</div>
<div className={styles.data}>
<InputElement
value={value}
@ -33,13 +48,11 @@ export default function Coin({
type="number"
onChange={onOceanChange}
readOnly={readOnly}
prefix={symbol}
prefix={datatokenOptions?.symbol || 'DT'}
/>
<Conversion price={value} className={stylesIndex.conversion} />
<div className={styles.weight}>
Weight <strong>{weight}</strong>
</div>
{datatokenOptions?.symbol === 'OCEAN' && (
<Conversion price={value} className={stylesIndex.conversion} />
)}
</div>
</div>
)

View File

@ -1,4 +1,5 @@
.advanced {
.dynamic {
composes: content from './index.module.css';
}
.wallet {
@ -36,8 +37,8 @@
.tokens {
display: grid;
margin-left: -3rem;
margin-right: -3rem;
margin-left: -2rem;
margin-right: -2rem;
border-bottom: 1px solid var(--brand-grey-lighter);
}
@ -50,7 +51,6 @@
.summary {
text-align: center;
margin-top: var(--spacer);
margin-bottom: -2rem;
}
.summary input {
@ -58,8 +58,8 @@
}
.alertArea {
margin-left: -3rem;
margin-right: -3rem;
margin-left: -2rem;
margin-right: -2rem;
padding: var(--spacer) calc(var(--spacer) / 2);
padding-bottom: 0;
margin-top: var(--spacer);

View File

@ -1,10 +1,9 @@
import React, { ReactElement, useState, ChangeEvent, useEffect } from 'react'
import { graphql, useStaticQuery } from 'gatsby'
import stylesIndex from './index.module.css'
import styles from './Dynamic.module.css'
import FormHelp from '../../../atoms/Input/Help'
import Wallet from '../../Wallet'
import { useOcean } from '@oceanprotocol/react'
import { DataTokenOptions, PriceOptions, useOcean } from '@oceanprotocol/react'
import Alert from '../../../atoms/Alert'
import Coin from './Coin'
import { isCorrectNetwork } from '../../../../utils/wallet'
@ -15,21 +14,22 @@ import Tooltip from '../../../atoms/Tooltip'
export default function Dynamic({
ocean,
tokensToMint,
weightOnDataToken,
liquidityProviderFee,
priceOptions,
datatokenOptions,
onOceanChange,
generateName,
content
}: {
ocean: string
tokensToMint: number
weightOnDataToken: string
liquidityProviderFee: string
priceOptions: PriceOptions
datatokenOptions: DataTokenOptions
onOceanChange: (event: ChangeEvent<HTMLInputElement>) => void
generateName: () => void
content: any
}): ReactElement {
const { appConfig } = useSiteMetadata()
const { account, balance, chainId, refreshBalance } = useOcean()
const { weightOnDataToken, tokensToMint, liquidityProviderFee } = priceOptions
const [error, setError] = useState<string>()
const correctNetwork = isCorrectNetwork(chainId)
@ -63,60 +63,59 @@ export default function Dynamic({
}, [ocean, chainId, account])
return (
<div className={stylesIndex.content}>
<div className={styles.advanced}>
<FormHelp className={stylesIndex.help}>{content.info}</FormHelp>
<div className={styles.dynamic}>
<FormHelp className={stylesIndex.help}>{content.info}</FormHelp>
<aside className={styles.wallet}>
{balance?.ocean && (
<div className={styles.balance}>
OCEAN <strong>{balance.ocean}</strong>
</div>
)}
<Wallet />
</aside>
<h4 className={styles.title}>
Data Token Liquidity Pool{' '}
<Tooltip content={content.tooltips.poolInfo} />
</h4>
<div className={styles.tokens}>
<Coin
name="ocean"
symbol="OCEAN"
value={ocean}
weight={`${100 - Number(Number(weightOnDataToken) * 10)}%`}
onOceanChange={onOceanChange}
/>
<Coin
name="tokensToMint"
symbol="OCEAN-CAV"
value={tokensToMint.toString()}
weight={`${Number(weightOnDataToken) * 10}%`}
readOnly
/>
</div>
<footer className={styles.summary}>
<Label htmlFor="liquidityProviderFee">
Liquidity Provider Fee{' '}
<Tooltip content={content.tooltips.liquidityProviderFee} />
</Label>
<InputElement
value={liquidityProviderFee}
name="liquidityProviderFee"
readOnly
postfix="%"
/>
</footer>
{error && (
<div className={styles.alertArea}>
<Alert text={error} state="error" />
<aside className={styles.wallet}>
{balance?.ocean && (
<div className={styles.balance}>
OCEAN <strong>{balance.ocean}</strong>
</div>
)}
<Wallet />
</aside>
<h4 className={styles.title}>
Data Token Liquidity Pool{' '}
<Tooltip content={content.tooltips.poolInfo} />
</h4>
<div className={styles.tokens}>
<Coin
name="ocean"
datatokenOptions={{ symbol: 'OCEAN', name: 'Ocean Token' }}
value={ocean}
weight={`${100 - Number(Number(weightOnDataToken) * 10)}%`}
onOceanChange={onOceanChange}
/>
<Coin
name="tokensToMint"
datatokenOptions={datatokenOptions}
value={tokensToMint.toString()}
weight={`${Number(weightOnDataToken) * 10}%`}
generateName={generateName}
readOnly
/>
</div>
<footer className={styles.summary}>
<Label htmlFor="liquidityProviderFee">
Liquidity Provider Fee{' '}
<Tooltip content={content.tooltips.liquidityProviderFee} />
</Label>
<InputElement
value={liquidityProviderFee}
name="liquidityProviderFee"
readOnly
postfix="%"
/>
</footer>
{error && (
<div className={styles.alertArea}>
<Alert text={error} state="error" />
</div>
)}
</div>
)
}

View File

@ -1,8 +1,32 @@
.fixed {
composes: content from './index.module.css';
}
.form {
max-width: 12rem;
margin: 0 auto;
margin-left: auto;
margin-right: auto;
}
.grid {
margin-top: var(--spacer);
display: grid;
gap: var(--spacer);
grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
justify-content: center;
}
.fixed label {
display: none;
}
.datatoken {
color: var(--color-secondary);
font-size: var(--font-size-small);
font-weight: var(--font-weight-bold);
white-space: nowrap;
}
.datatoken strong {
color: var(--brand-grey);
}

View File

@ -5,24 +5,29 @@ 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 { DataTokenOptions } from '@oceanprotocol/react'
import RefreshName from './RefreshName'
export default function Fixed({
ocean,
datatokenOptions,
onChange,
generateName,
content
}: {
ocean: string
datatokenOptions: DataTokenOptions
onChange: (event: ChangeEvent<HTMLInputElement>) => void
generateName: () => void
content: any
}): ReactElement {
return (
<div className={stylesIndex.content}>
<div className={styles.fixed}>
<FormHelp className={stylesIndex.help}>{content.info}</FormHelp>
<div className={styles.fixed}>
<FormHelp className={stylesIndex.help}>{content.info}</FormHelp>
<div className={styles.grid}>
<div className={styles.form}>
<Label htmlFor="ocean">Ocean Tokens</Label>
<Label htmlFor="ocean">Ocean Token</Label>
<InputElement
value={ocean}
name="ocean"
@ -30,9 +35,16 @@ export default function Fixed({
prefix="OCEAN"
onChange={onChange}
/>
<Conversion price={ocean} className={stylesIndex.conversion} />
</div>
{datatokenOptions && (
<div className={styles.datatoken}>
<strong>Data Token</strong>
<RefreshName generateName={generateName} />
<br />
{datatokenOptions?.name} | {datatokenOptions?.symbol}
</div>
)}
</div>
</div>
)

View File

@ -0,0 +1,9 @@
.refresh {
margin-left: calc(var(--spacer) / 4) !important;
}
.refresh svg {
fill: var(--brand-pink);
width: var(--font-size-mini);
height: var(--font-size-mini);
}

View File

@ -0,0 +1,25 @@
import React, { ReactElement } from 'react'
import styles from './RefreshName.module.css'
import Button from '../../../atoms/Button'
import { ReactComponent as Refresh } from '../../../../images/refresh.svg'
export default function RefreshName({
generateName
}: {
generateName: () => void
}): ReactElement {
return (
<Button
style="text"
size="small"
className={styles.refresh}
title="Generate new name & symbol"
onClick={(e) => {
e.preventDefault()
generateName()
}}
>
<Refresh />
</Button>
)
}

View File

@ -5,7 +5,7 @@
}
.content {
padding: 0 calc(var(--spacer) / 2);
padding: 0;
}
.content label {

View File

@ -7,6 +7,7 @@ import Fixed from './Fixed'
import Dynamic from './Dynamic'
import { useField } from 'formik'
import { useUserPreferences } from '../../../../providers/UserPreferences'
import { DataTokenOptions, PriceOptions, useOcean } from '@oceanprotocol/react'
const query = graphql`
query PriceFieldQuery {
@ -39,15 +40,17 @@ export default function Price(props: InputProps): ReactElement {
const { debug } = useUserPreferences()
const data = useStaticQuery(query)
const content = data.content.edges[0].node.childPagesJson.price
const { ocean } = useOcean()
const [field, meta, helpers] = useField(props)
const { weightOnDataToken, liquidityProviderFee } = field.value
const priceOptions: PriceOptions = field.value
const [ocean, setOcean] = useState('1')
const [amountOcean, setAmountOcean] = useState('1')
const [tokensToMint, setTokensToMint] = useState<number>()
const [datatokenOptions, setDatatokenOptions] = useState<DataTokenOptions>()
function handleOceanChange(event: ChangeEvent<HTMLInputElement>) {
setOcean(event.target.value)
setAmountOcean(event.target.value)
}
function handleTabChange(tabName: string) {
@ -55,11 +58,23 @@ export default function Price(props: InputProps): ReactElement {
helpers.setValue({ ...field.value, type })
}
// Always update everything when ocean changes
function generateName() {
if (!ocean) return
const newDatatokenOptions = ocean.datatokens.generateDtName()
setDatatokenOptions(newDatatokenOptions)
}
// Always update everything when amountOcean changes
useEffect(() => {
const tokensToMint = Number(ocean) * Number(weightOnDataToken)
const tokensToMint =
Number(amountOcean) * Number(priceOptions.weightOnDataToken)
setTokensToMint(tokensToMint)
helpers.setValue({ ...field.value, tokensToMint })
}, [amountOcean])
// Generate new DT name & symbol
useEffect(() => {
generateName()
}, [ocean])
const tabs = [
@ -67,8 +82,10 @@ export default function Price(props: InputProps): ReactElement {
title: content.fixed.title,
content: (
<Fixed
ocean={ocean}
ocean={amountOcean}
datatokenOptions={datatokenOptions}
onChange={handleOceanChange}
generateName={generateName}
content={content.fixed}
/>
)
@ -77,11 +94,11 @@ export default function Price(props: InputProps): ReactElement {
title: content.dynamic.title,
content: (
<Dynamic
ocean={ocean}
tokensToMint={tokensToMint}
weightOnDataToken={weightOnDataToken}
ocean={amountOcean}
priceOptions={{ ...priceOptions, tokensToMint }}
datatokenOptions={datatokenOptions}
onOceanChange={handleOceanChange}
liquidityProviderFee={liquidityProviderFee}
generateName={generateName}
content={content.dynamic}
/>
)

View File

@ -2,7 +2,7 @@ import React, { ReactElement } from 'react'
import { useNavigate } from '@reach/router'
import { toast } from 'react-toastify'
import { Formik } from 'formik'
import { usePublish, useOcean, PriceOptions } from '@oceanprotocol/react'
import { usePublish, DataTokenOptions } from '@oceanprotocol/react'
import styles from './index.module.css'
import PublishForm from './PublishForm'
import Web3Feedback from '../../molecules/Wallet/Feedback'
@ -11,7 +11,7 @@ import { initialValues, validationSchema } from '../../../models/FormPublish'
import { transformPublishFormToMetadata } from './utils'
import Preview from './Preview'
import { MetadataPublishForm } from '../../../@types/MetaData'
import { useSiteMetadata } from '../../../hooks/useSiteMetadata'
// import { useSiteMetadata } from '../../../hooks/useSiteMetadata'
import { useUserPreferences } from '../../../providers/UserPreferences'
export default function PublishPage({
@ -19,7 +19,8 @@ export default function PublishPage({
}: {
content: { form: FormContent }
}): ReactElement {
const { marketFeeAddress, marketFeeAmount } = useSiteMetadata()
// TODO: implement marketFee
// const { marketFeeAddress, marketFeeAmount } = useSiteMetadata()
const { debug } = useUserPreferences()
const { publish, publishError, isLoading, publishStepText } = usePublish()
const navigate = useNavigate()
@ -31,15 +32,15 @@ export default function PublishPage({
const metadata = transformPublishFormToMetadata(values)
const priceOptions = values.price
const serviceType = values.access === 'Download' ? 'access' : 'compute'
let datatokenOptions: DataTokenOptions
try {
// mpAddress and mpFee are not yet implemented in ocean js so are not used
const ddo = await publish(
metadata as any,
priceOptions,
serviceType
// marketFeeAddress,
// marketFeeAmount
serviceType,
datatokenOptions
)
if (publishError) {

3
src/images/refresh.svg Normal file
View File

@ -0,0 +1,3 @@
<svg width="16" height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
<path d="M13.64 2.35C12.19 0.9 10.2 0 7.99 0C3.57 0 0 3.58 0 8C0 12.42 3.57 16 7.99 16C11.72 16 14.83 13.45 15.72 10H13.64C12.82 12.33 10.6 14 7.99 14C4.68 14 1.99 11.31 1.99 8C1.99 4.69 4.68 2 7.99 2C9.65 2 11.13 2.69 12.21 3.78L8.99 7H15.99V0L13.64 2.35Z" />
</svg>

After

Width:  |  Height:  |  Size: 353 B