mirror of
https://github.com/oceanprotocol/market.git
synced 2024-12-02 05:57:29 +01:00
[EPIC] Free Pricing (#681)
* Free Pricing Option at create Pricing (#621) * Free Pricing Option + env var toggle * Create Pricing step msg * Default 'allowFreePricing' to true temp for review * Fix price 0 on free tab * Attempt fix useSiteMetadata * Fix linting * Feature/free price support consume compute (#654) * Update fetch free price * Feedback change UI remove 0's * update button msg && fix * compute algorithm list show 'Free' instead of '0' * updateMetadata() v3 workaround solution for free pricing (#677) * compute algorithm list show 'Free' instead of '0' * workaround editMetaData free price * utils function for compute & download * `allowFreePricing` default to false
This commit is contained in:
parent
eb8c6afb62
commit
e02babf2c2
@ -11,5 +11,6 @@ GATSBY_NETWORK="rinkeby"
|
|||||||
#GATSBY_PORTIS_ID="xxx"
|
#GATSBY_PORTIS_ID="xxx"
|
||||||
#GATSBY_ALLOW_FIXED_PRICING="true"
|
#GATSBY_ALLOW_FIXED_PRICING="true"
|
||||||
#GATSBY_ALLOW_DYNAMIC_PRICING="true"
|
#GATSBY_ALLOW_DYNAMIC_PRICING="true"
|
||||||
|
#GATSBY_ALLOW_FREE_PRICING="true"
|
||||||
#GATSBY_ALLOW_ADVANCED_SETTINGS="true"
|
#GATSBY_ALLOW_ADVANCED_SETTINGS="true"
|
||||||
#GATSBY_CREDENTIAL_TYPE="address"
|
#GATSBY_CREDENTIAL_TYPE="address"
|
||||||
|
@ -2,8 +2,7 @@ module.exports = {
|
|||||||
client: {
|
client: {
|
||||||
service: {
|
service: {
|
||||||
name: 'ocean',
|
name: 'ocean',
|
||||||
url:
|
url: 'https://subgraph.rinkeby.oceanprotocol.com/subgraphs/name/oceanprotocol/ocean-subgraph',
|
||||||
'https://subgraph.rinkeby.oceanprotocol.com/subgraphs/name/oceanprotocol/ocean-subgraph',
|
|
||||||
// optional disable SSL validation check
|
// optional disable SSL validation check
|
||||||
skipSSLValidation: true
|
skipSSLValidation: true
|
||||||
}
|
}
|
||||||
|
@ -41,10 +41,11 @@ module.exports = {
|
|||||||
// Wallets
|
// Wallets
|
||||||
portisId: process.env.GATSBY_PORTIS_ID || 'xxx',
|
portisId: process.env.GATSBY_PORTIS_ID || 'xxx',
|
||||||
|
|
||||||
// Used to show or hide the fixed and dynamic price options
|
// Used to show or hide the fixed, dynamic or free price options
|
||||||
// tab to publishers during the price creation.
|
// tab to publishers during the price creation.
|
||||||
allowFixedPricing: process.env.GATSBY_ALLOW_FIXED_PRICING || 'true',
|
allowFixedPricing: process.env.GATSBY_ALLOW_FIXED_PRICING || 'true',
|
||||||
allowDynamicPricing: process.env.GATSBY_ALLOW_DYNAMIC_PRICING || 'true',
|
allowDynamicPricing: process.env.GATSBY_ALLOW_DYNAMIC_PRICING || 'true',
|
||||||
|
allowFreePricing: process.env.GATSBY_ALLOW_FREE_PRICING || 'false',
|
||||||
|
|
||||||
// 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',
|
||||||
|
@ -21,6 +21,10 @@
|
|||||||
"communityFee": "Explain community fee...",
|
"communityFee": "Explain community fee...",
|
||||||
"marketplaceFee": "Explain marketplace fee..."
|
"marketplaceFee": "Explain marketplace fee..."
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"free": {
|
||||||
|
"title": "Free",
|
||||||
|
"info": "Set your data set as free. The datatoken for this data set will be given for free via creating a faucet."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"pool": {
|
"pool": {
|
||||||
|
@ -21,6 +21,8 @@ interface ButtonBuyProps {
|
|||||||
onClick?: (e: FormEvent<HTMLButtonElement>) => void
|
onClick?: (e: FormEvent<HTMLButtonElement>) => void
|
||||||
stepText?: string
|
stepText?: string
|
||||||
type?: 'submit'
|
type?: 'submit'
|
||||||
|
priceType?: string
|
||||||
|
algorithmPriceType?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
function getConsumeHelpText(
|
function getConsumeHelpText(
|
||||||
@ -87,15 +89,21 @@ export default function ButtonBuy({
|
|||||||
onClick,
|
onClick,
|
||||||
stepText,
|
stepText,
|
||||||
isLoading,
|
isLoading,
|
||||||
type
|
type,
|
||||||
|
priceType,
|
||||||
|
algorithmPriceType
|
||||||
}: ButtonBuyProps): ReactElement {
|
}: ButtonBuyProps): ReactElement {
|
||||||
const buttonText =
|
const buttonText =
|
||||||
action === 'download'
|
action === 'download'
|
||||||
? hasPreviousOrder
|
? hasPreviousOrder
|
||||||
? 'Download'
|
? 'Download'
|
||||||
|
: priceType === 'free'
|
||||||
|
? 'Get'
|
||||||
: `Buy ${assetTimeout === 'Forever' ? '' : ` for ${assetTimeout}`}`
|
: `Buy ${assetTimeout === 'Forever' ? '' : ` for ${assetTimeout}`}`
|
||||||
: hasPreviousOrder && hasPreviousOrderSelectedComputeAsset
|
: hasPreviousOrder && hasPreviousOrderSelectedComputeAsset
|
||||||
? 'Start Compute Job'
|
? 'Start Compute Job'
|
||||||
|
: priceType === 'free' && algorithmPriceType === 'free'
|
||||||
|
? 'Order Compute Job'
|
||||||
: `Buy Compute Job`
|
: `Buy Compute Job`
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -42,15 +42,20 @@ export default function PriceUnit({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styleClasses}>
|
<div className={styleClasses}>
|
||||||
<div>
|
{type && type === 'free' ? (
|
||||||
{Number.isNaN(Number(price)) ? '-' : formatPrice(price, locale)}{' '}
|
<div> Free </div>
|
||||||
<span className={styles.symbol}>{symbol || 'OCEAN'}</span>
|
) : (
|
||||||
{type && type === 'pool' && (
|
<>
|
||||||
<Badge label="pool" className={styles.badge} />
|
<div>
|
||||||
)}
|
{Number.isNaN(Number(price)) ? '-' : formatPrice(price, locale)}{' '}
|
||||||
</div>
|
<span className={styles.symbol}>{symbol || 'OCEAN'}</span>
|
||||||
|
{type && type === 'pool' && (
|
||||||
{conversion && <Conversion price={price} />}
|
<Badge label="pool" className={styles.badge} />
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
{conversion && <Conversion price={price} />}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,7 @@ export default function Price({
|
|||||||
small?: boolean
|
small?: boolean
|
||||||
conversion?: boolean
|
conversion?: boolean
|
||||||
}): ReactElement {
|
}): ReactElement {
|
||||||
return price?.value ? (
|
return price?.value || price?.type === 'free' ? (
|
||||||
<PriceUnit
|
<PriceUnit
|
||||||
price={`${price.value}`}
|
price={`${price.value}`}
|
||||||
className={className}
|
className={className}
|
||||||
|
@ -107,7 +107,12 @@ export default function AssetSelection({
|
|||||||
</Dotdotdot>
|
</Dotdotdot>
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
<PriceUnit price={asset.price} small className={styles.price} />
|
<PriceUnit
|
||||||
|
price={asset.price}
|
||||||
|
type={asset.price === '0' ? 'free' : undefined}
|
||||||
|
small
|
||||||
|
className={styles.price}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
))
|
))
|
||||||
)}
|
)}
|
||||||
|
@ -166,6 +166,8 @@ export default function FormStartCompute({
|
|||||||
stepText={stepText}
|
stepText={stepText}
|
||||||
isLoading={isLoading}
|
isLoading={isLoading}
|
||||||
type="submit"
|
type="submit"
|
||||||
|
priceType={price?.type}
|
||||||
|
algorithmPriceType={algorithmPrice?.type}
|
||||||
/>
|
/>
|
||||||
</Form>
|
</Form>
|
||||||
)
|
)
|
||||||
|
@ -160,6 +160,7 @@ export default function Consume({
|
|||||||
assetType={type}
|
assetType={type}
|
||||||
stepText={consumeStepText || pricingStepText}
|
stepText={consumeStepText || pricingStepText}
|
||||||
isLoading={pricingIsLoading || isLoading}
|
isLoading={pricingIsLoading || isLoading}
|
||||||
|
priceType={price?.type}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -16,6 +16,10 @@ import { useUserPreferences } from '../../../../providers/UserPreferences'
|
|||||||
import DebugEditCompute from './DebugEditCompute'
|
import DebugEditCompute from './DebugEditCompute'
|
||||||
import styles from './index.module.css'
|
import styles from './index.module.css'
|
||||||
import { transformComputeFormToServiceComputePrivacy } from '../../../../utils/compute'
|
import { transformComputeFormToServiceComputePrivacy } from '../../../../utils/compute'
|
||||||
|
import {
|
||||||
|
setMinterToDispenser,
|
||||||
|
setMinterToPublisher
|
||||||
|
} from '../../../../utils/freePrice'
|
||||||
|
|
||||||
const contentQuery = graphql`
|
const contentQuery = graphql`
|
||||||
query EditComputeDataQuery {
|
query EditComputeDataQuery {
|
||||||
@ -62,7 +66,7 @@ export default function EditComputeDataset({
|
|||||||
const { debug } = useUserPreferences()
|
const { debug } = useUserPreferences()
|
||||||
const { ocean } = useOcean()
|
const { ocean } = useOcean()
|
||||||
const { accountId } = useWeb3()
|
const { accountId } = useWeb3()
|
||||||
const { ddo, refreshDdo } = useAsset()
|
const { ddo, refreshDdo, price } = useAsset()
|
||||||
const [success, setSuccess] = useState<string>()
|
const [success, setSuccess] = useState<string>()
|
||||||
const [error, setError] = useState<string>()
|
const [error, setError] = useState<string>()
|
||||||
|
|
||||||
@ -73,6 +77,15 @@ export default function EditComputeDataset({
|
|||||||
resetForm: () => void
|
resetForm: () => void
|
||||||
) {
|
) {
|
||||||
try {
|
try {
|
||||||
|
if (price.type === 'free') {
|
||||||
|
const tx = await setMinterToPublisher(
|
||||||
|
ocean,
|
||||||
|
ddo.dataToken,
|
||||||
|
accountId,
|
||||||
|
setError
|
||||||
|
)
|
||||||
|
if (!tx) return
|
||||||
|
}
|
||||||
const privacy = await transformComputeFormToServiceComputePrivacy(
|
const privacy = await transformComputeFormToServiceComputePrivacy(
|
||||||
values,
|
values,
|
||||||
ocean
|
ocean
|
||||||
@ -99,6 +112,15 @@ export default function EditComputeDataset({
|
|||||||
Logger.error(content.form.error)
|
Logger.error(content.form.error)
|
||||||
return
|
return
|
||||||
} else {
|
} else {
|
||||||
|
if (price.type === 'free') {
|
||||||
|
const tx = await setMinterToDispenser(
|
||||||
|
ocean,
|
||||||
|
ddo.dataToken,
|
||||||
|
accountId,
|
||||||
|
setError
|
||||||
|
)
|
||||||
|
if (!tx) return
|
||||||
|
}
|
||||||
// Edit succeeded
|
// Edit succeeded
|
||||||
setSuccess(content.form.success)
|
setSuccess(content.form.success)
|
||||||
resetForm()
|
resetForm()
|
||||||
|
@ -18,6 +18,10 @@ import MetadataFeedback from '../../../molecules/MetadataFeedback'
|
|||||||
import { graphql, useStaticQuery } from 'gatsby'
|
import { graphql, useStaticQuery } from 'gatsby'
|
||||||
import { useWeb3 } from '../../../../providers/Web3'
|
import { useWeb3 } from '../../../../providers/Web3'
|
||||||
import { useOcean } from '../../../../providers/Ocean'
|
import { useOcean } from '../../../../providers/Ocean'
|
||||||
|
import {
|
||||||
|
setMinterToDispenser,
|
||||||
|
setMinterToPublisher
|
||||||
|
} from '../../../../utils/freePrice'
|
||||||
|
|
||||||
const contentQuery = graphql`
|
const contentQuery = graphql`
|
||||||
query EditMetadataQuery {
|
query EditMetadataQuery {
|
||||||
@ -88,6 +92,15 @@ export default function Edit({
|
|||||||
resetForm: () => void
|
resetForm: () => void
|
||||||
) {
|
) {
|
||||||
try {
|
try {
|
||||||
|
if (price.type === 'free') {
|
||||||
|
const tx = await setMinterToPublisher(
|
||||||
|
ocean,
|
||||||
|
ddo.dataToken,
|
||||||
|
accountId,
|
||||||
|
setError
|
||||||
|
)
|
||||||
|
if (!tx) return
|
||||||
|
}
|
||||||
// Construct new DDO with new values
|
// Construct new DDO with new values
|
||||||
const ddoEditedMetdata = await ocean.assets.editMetadata(ddo, {
|
const ddoEditedMetdata = await ocean.assets.editMetadata(ddo, {
|
||||||
title: values.name,
|
title: values.name,
|
||||||
@ -132,6 +145,15 @@ export default function Edit({
|
|||||||
Logger.error(content.form.error)
|
Logger.error(content.form.error)
|
||||||
return
|
return
|
||||||
} else {
|
} else {
|
||||||
|
if (price.type === 'free') {
|
||||||
|
const tx = await setMinterToDispenser(
|
||||||
|
ocean,
|
||||||
|
ddo.dataToken,
|
||||||
|
accountId,
|
||||||
|
setError
|
||||||
|
)
|
||||||
|
if (!tx) return
|
||||||
|
}
|
||||||
// Edit succeeded
|
// Edit succeeded
|
||||||
setSuccess(content.form.success)
|
setSuccess(content.form.success)
|
||||||
resetForm()
|
resetForm()
|
||||||
|
@ -65,6 +65,7 @@ export default function AssetActions(): ReactElement {
|
|||||||
|
|
||||||
// Check user balance against price
|
// Check user balance against price
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
if (price?.type === 'free') setIsBalanceSufficient(true)
|
||||||
if (!price?.value || !account || !balance?.ocean || !dtBalance) return
|
if (!price?.value || !account || !balance?.ocean || !dtBalance) return
|
||||||
|
|
||||||
setIsBalanceSufficient(
|
setIsBalanceSufficient(
|
||||||
|
@ -0,0 +1,3 @@
|
|||||||
|
.free {
|
||||||
|
composes: content from './index.module.css';
|
||||||
|
}
|
@ -0,0 +1,21 @@
|
|||||||
|
import React, { ReactElement } from 'react'
|
||||||
|
import stylesIndex from './index.module.css'
|
||||||
|
import styles from './Free.module.css'
|
||||||
|
import FormHelp from '../../../../atoms/Input/Help'
|
||||||
|
import { DDO } from '@oceanprotocol/lib'
|
||||||
|
import Price from './Price'
|
||||||
|
|
||||||
|
export default function Free({
|
||||||
|
ddo,
|
||||||
|
content
|
||||||
|
}: {
|
||||||
|
ddo: DDO
|
||||||
|
content: any
|
||||||
|
}): ReactElement {
|
||||||
|
return (
|
||||||
|
<div className={styles.free}>
|
||||||
|
<FormHelp className={stylesIndex.help}>{content.info}</FormHelp>
|
||||||
|
<Price ddo={ddo} free />
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
@ -10,10 +10,12 @@ import usePricing from '../../../../../hooks/usePricing'
|
|||||||
|
|
||||||
export default function Price({
|
export default function Price({
|
||||||
ddo,
|
ddo,
|
||||||
firstPrice
|
firstPrice,
|
||||||
|
free
|
||||||
}: {
|
}: {
|
||||||
ddo: DDO
|
ddo: DDO
|
||||||
firstPrice?: string
|
firstPrice?: string
|
||||||
|
free?: boolean
|
||||||
}): ReactElement {
|
}): ReactElement {
|
||||||
const [field, meta] = useField('price')
|
const [field, meta] = useField('price')
|
||||||
const { getDTName, getDTSymbol } = usePricing()
|
const { getDTName, getDTSymbol } = usePricing()
|
||||||
@ -38,17 +40,27 @@ export default function Price({
|
|||||||
<div className={styles.price}>
|
<div className={styles.price}>
|
||||||
<div className={styles.grid}>
|
<div className={styles.grid}>
|
||||||
<div className={styles.form}>
|
<div className={styles.form}>
|
||||||
<Input
|
{free ? (
|
||||||
value={field.value}
|
<Input
|
||||||
name="price"
|
value="0"
|
||||||
type="number"
|
name="price"
|
||||||
prefix="OCEAN"
|
type="number"
|
||||||
min="1"
|
prefix="OCEAN"
|
||||||
{...field}
|
readOnly
|
||||||
additionalComponent={
|
/>
|
||||||
<Conversion price={field.value} className={styles.conversion} />
|
) : (
|
||||||
}
|
<Input
|
||||||
/>
|
value={field.value}
|
||||||
|
name="price"
|
||||||
|
type="number"
|
||||||
|
prefix="OCEAN"
|
||||||
|
min="1"
|
||||||
|
{...field}
|
||||||
|
additionalComponent={
|
||||||
|
<Conversion price={field.value} className={styles.conversion} />
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
<Error meta={meta} />
|
<Error meta={meta} />
|
||||||
</div>
|
</div>
|
||||||
<div className={styles.datatoken}>
|
<div className={styles.datatoken}>
|
||||||
|
@ -45,3 +45,8 @@
|
|||||||
padding-left: var(--spacer);
|
padding-left: var(--spacer);
|
||||||
padding-right: var(--spacer);
|
padding-right: var(--spacer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.free {
|
||||||
|
text-align: center;
|
||||||
|
margin-bottom: calc(var(--spacer) / 1.5);
|
||||||
|
}
|
||||||
|
@ -3,6 +3,7 @@ import styles from './index.module.css'
|
|||||||
import Tabs from '../../../../atoms/Tabs'
|
import Tabs from '../../../../atoms/Tabs'
|
||||||
import Fixed from './Fixed'
|
import Fixed from './Fixed'
|
||||||
import Dynamic from './Dynamic'
|
import Dynamic from './Dynamic'
|
||||||
|
import Free from './Free'
|
||||||
import { useFormikContext } from 'formik'
|
import { useFormikContext } from 'formik'
|
||||||
import { useUserPreferences } from '../../../../../providers/UserPreferences'
|
import { useUserPreferences } from '../../../../../providers/UserPreferences'
|
||||||
import { PriceOptionsMarket } from '../../../../../@types/MetaData'
|
import { PriceOptionsMarket } from '../../../../../@types/MetaData'
|
||||||
@ -33,6 +34,7 @@ export default function FormPricing({
|
|||||||
const type = tabName.toLowerCase()
|
const type = tabName.toLowerCase()
|
||||||
setFieldValue('type', type)
|
setFieldValue('type', type)
|
||||||
type === 'fixed' && setFieldValue('dtAmount', 1000)
|
type === 'fixed' && setFieldValue('dtAmount', 1000)
|
||||||
|
type === 'free' && price < 1 && setFieldValue('price', 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Always update everything when price value changes
|
// Always update everything when price value changes
|
||||||
@ -57,6 +59,12 @@ export default function FormPricing({
|
|||||||
title: content.dynamic.title,
|
title: content.dynamic.title,
|
||||||
content: <Dynamic content={content.dynamic} ddo={ddo} />
|
content: <Dynamic content={content.dynamic} ddo={ddo} />
|
||||||
}
|
}
|
||||||
|
: undefined,
|
||||||
|
appConfig.allowFreePricing === 'true'
|
||||||
|
? {
|
||||||
|
title: content.free.title,
|
||||||
|
content: <Free content={content.free} ddo={ddo} />
|
||||||
|
}
|
||||||
: undefined
|
: undefined
|
||||||
].filter((tab) => tab !== undefined)
|
].filter((tab) => tab !== undefined)
|
||||||
|
|
||||||
|
@ -40,6 +40,10 @@ const query = graphql`
|
|||||||
marketplaceFee
|
marketplaceFee
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
free {
|
||||||
|
title
|
||||||
|
info
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,9 @@ import { Decimal } from 'decimal.js'
|
|||||||
import {
|
import {
|
||||||
getCreatePricingPoolFeedback,
|
getCreatePricingPoolFeedback,
|
||||||
getCreatePricingExchangeFeedback,
|
getCreatePricingExchangeFeedback,
|
||||||
getBuyDTFeedback
|
getBuyDTFeedback,
|
||||||
|
getCreateFreePricingFeedback,
|
||||||
|
getDispenseFeedback
|
||||||
} from '../utils/feedback'
|
} from '../utils/feedback'
|
||||||
import { sleep } from '../utils'
|
import { sleep } from '../utils'
|
||||||
|
|
||||||
@ -16,7 +18,7 @@ interface PriceOptions {
|
|||||||
price: number
|
price: number
|
||||||
dtAmount: number
|
dtAmount: number
|
||||||
oceanAmount: number
|
oceanAmount: number
|
||||||
type: 'fixed' | 'dynamic' | string
|
type: 'fixed' | 'dynamic' | 'free' | string
|
||||||
weightOnDataToken: string
|
weightOnDataToken: string
|
||||||
swapFee: string
|
swapFee: string
|
||||||
}
|
}
|
||||||
@ -68,7 +70,7 @@ function usePricing(): UsePricing {
|
|||||||
// Helper for setting steps & feedback for all flows
|
// Helper for setting steps & feedback for all flows
|
||||||
async function setStep(
|
async function setStep(
|
||||||
index: number,
|
index: number,
|
||||||
type: 'pool' | 'exchange' | 'buy',
|
type: 'pool' | 'exchange' | 'free' | 'buy' | 'dispense',
|
||||||
ddo: DDO
|
ddo: DDO
|
||||||
) {
|
) {
|
||||||
const dtSymbol = await getDTSymbol(ddo)
|
const dtSymbol = await getDTSymbol(ddo)
|
||||||
@ -84,9 +86,15 @@ function usePricing(): UsePricing {
|
|||||||
case 'exchange':
|
case 'exchange':
|
||||||
messages = getCreatePricingExchangeFeedback(dtSymbol)
|
messages = getCreatePricingExchangeFeedback(dtSymbol)
|
||||||
break
|
break
|
||||||
|
case 'free':
|
||||||
|
messages = getCreateFreePricingFeedback(dtSymbol)
|
||||||
|
break
|
||||||
case 'buy':
|
case 'buy':
|
||||||
messages = getBuyDTFeedback(dtSymbol)
|
messages = getBuyDTFeedback(dtSymbol)
|
||||||
break
|
break
|
||||||
|
case 'dispense':
|
||||||
|
messages = getDispenseFeedback(dtSymbol)
|
||||||
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
setPricingStepText(messages[index])
|
setPricingStepText(messages[index])
|
||||||
@ -180,6 +188,28 @@ function usePricing(): UsePricing {
|
|||||||
Logger.log('DT exchange buy response', tx)
|
Logger.log('DT exchange buy response', tx)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
case 'free': {
|
||||||
|
setStep(1, 'dispense', ddo)
|
||||||
|
const isDispensable = await ocean.OceanDispenser.isDispensable(
|
||||||
|
ddo.dataToken,
|
||||||
|
accountId,
|
||||||
|
'1'
|
||||||
|
)
|
||||||
|
|
||||||
|
if (!isDispensable) {
|
||||||
|
Logger.error(`Dispenser for ${ddo.dataToken} failed to dispense`)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
tx = await ocean.OceanDispenser.dispense(
|
||||||
|
ddo.dataToken,
|
||||||
|
accountId,
|
||||||
|
'1'
|
||||||
|
)
|
||||||
|
setStep(2, 'dispense', ddo)
|
||||||
|
Logger.log('DT dispense response', tx)
|
||||||
|
break
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
setPricingError(error.message)
|
setPricingError(error.message)
|
||||||
@ -219,9 +249,14 @@ function usePricing(): UsePricing {
|
|||||||
setStep(99, 'pool', ddo)
|
setStep(99, 'pool', ddo)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// if fixedPrice set dt to max amount
|
if (type === 'free') {
|
||||||
if (!isPool) dtAmount = 1000
|
setStep(99, 'free', ddo)
|
||||||
await mint(`${dtAmount}`, ddo)
|
await ocean.OceanDispenser.activate(dataToken, '1', '1', accountId)
|
||||||
|
} else {
|
||||||
|
// if fixedPrice set dt to max amount
|
||||||
|
if (!isPool) dtAmount = 1000
|
||||||
|
await mint(`${dtAmount}`, ddo)
|
||||||
|
}
|
||||||
|
|
||||||
// dtAmount for fixed price is set to max
|
// dtAmount for fixed price is set to max
|
||||||
const tx = isPool
|
const tx = isPool
|
||||||
@ -235,9 +270,13 @@ function usePricing(): UsePricing {
|
|||||||
swapFee
|
swapFee
|
||||||
)
|
)
|
||||||
.next((step: number) => setStep(step, 'pool', ddo))
|
.next((step: number) => setStep(step, 'pool', ddo))
|
||||||
: await ocean.fixedRateExchange
|
: type === 'fixed'
|
||||||
|
? await ocean.fixedRateExchange
|
||||||
.create(dataToken, `${price}`, accountId, `${dtAmount}`)
|
.create(dataToken, `${price}`, accountId, `${dtAmount}`)
|
||||||
.next((step: number) => setStep(step, 'exchange', ddo))
|
.next((step: number) => setStep(step, 'exchange', ddo))
|
||||||
|
: await ocean.OceanDispenser.makeMinter(dataToken, accountId).next(
|
||||||
|
(step: number) => setStep(step, 'free', ddo)
|
||||||
|
)
|
||||||
await sleep(20000)
|
await sleep(20000)
|
||||||
return tx
|
return tx
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
@ -27,6 +27,7 @@ interface UseSiteMetadata {
|
|||||||
portisId: string
|
portisId: string
|
||||||
allowFixedPricing: string
|
allowFixedPricing: string
|
||||||
allowDynamicPricing: string
|
allowDynamicPricing: string
|
||||||
|
allowFreePricing: string
|
||||||
allowAdvancedSettings: string
|
allowAdvancedSettings: string
|
||||||
credentialType: string
|
credentialType: string
|
||||||
}
|
}
|
||||||
@ -61,6 +62,7 @@ const query = graphql`
|
|||||||
portisId
|
portisId
|
||||||
allowFixedPricing
|
allowFixedPricing
|
||||||
allowDynamicPricing
|
allowDynamicPricing
|
||||||
|
allowFreePricing
|
||||||
allowAdvancedSettings
|
allowAdvancedSettings
|
||||||
credentialType
|
credentialType
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,7 @@ export const validationSchema: Yup.SchemaOf<PriceOptionsMarket> =
|
|||||||
.min(21, (param) => `Must be more or equal to ${param.min}`)
|
.min(21, (param) => `Must be more or equal to ${param.min}`)
|
||||||
.required('Required'),
|
.required('Required'),
|
||||||
type: Yup.string()
|
type: Yup.string()
|
||||||
.matches(/fixed|dynamic/g, { excludeEmptyString: true })
|
.matches(/fixed|dynamic|free/g, { excludeEmptyString: true })
|
||||||
.required('Required'),
|
.required('Required'),
|
||||||
weightOnDataToken: Yup.string().required('Required'),
|
weightOnDataToken: Yup.string().required('Required'),
|
||||||
weightOnOcean: Yup.string().required('Required'),
|
weightOnOcean: Yup.string().required('Required'),
|
||||||
|
@ -52,6 +52,17 @@ export function getCreatePricingExchangeFeedback(dtSymbol: string): {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getCreateFreePricingFeedback(dtSymbol: string): {
|
||||||
|
[key: number]: string
|
||||||
|
} {
|
||||||
|
return {
|
||||||
|
99: `Creating ${dtSymbol} faucet...`,
|
||||||
|
0: 'Setting faucet as minter ...',
|
||||||
|
1: 'Approving minter...',
|
||||||
|
2: 'Faucet created.'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export function getBuyDTFeedback(dtSymbol: string): { [key: number]: string } {
|
export function getBuyDTFeedback(dtSymbol: string): { [key: number]: string } {
|
||||||
return {
|
return {
|
||||||
1: '1/3 Approving OCEAN ...',
|
1: '1/3 Approving OCEAN ...',
|
||||||
@ -67,3 +78,12 @@ export function getSellDTFeedback(dtSymbol: string): { [key: number]: string } {
|
|||||||
3: `3/3 ${dtSymbol} sold.`
|
3: `3/3 ${dtSymbol} sold.`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getDispenseFeedback(dtSymbol: string): {
|
||||||
|
[key: number]: string
|
||||||
|
} {
|
||||||
|
return {
|
||||||
|
1: `1/2 Requesting ${dtSymbol}...`,
|
||||||
|
2: `2/2 Received ${dtSymbol}.`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
37
src/utils/freePrice.ts
Normal file
37
src/utils/freePrice.ts
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
import { Logger, Ocean } from '@oceanprotocol/lib'
|
||||||
|
|
||||||
|
export async function setMinterToPublisher(
|
||||||
|
ocean: Ocean,
|
||||||
|
dataTokenAddress: string,
|
||||||
|
accountId: string,
|
||||||
|
setError: (msg: string) => void
|
||||||
|
): Promise<any> {
|
||||||
|
// free pricing v3 workaround part1
|
||||||
|
const response = await ocean.OceanDispenser.cancelMinter(
|
||||||
|
dataTokenAddress,
|
||||||
|
accountId
|
||||||
|
)
|
||||||
|
if (!response) {
|
||||||
|
setError('Updating DDO failed.')
|
||||||
|
Logger.error('Failed at cancelMinter')
|
||||||
|
}
|
||||||
|
return response
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function setMinterToDispenser(
|
||||||
|
ocean: Ocean,
|
||||||
|
dataTokenAddress: string,
|
||||||
|
accountId: string,
|
||||||
|
setError: (msg: string) => void
|
||||||
|
): Promise<any> {
|
||||||
|
// free pricing v3 workaround part2
|
||||||
|
const response = await ocean.OceanDispenser.makeMinter(
|
||||||
|
dataTokenAddress,
|
||||||
|
accountId
|
||||||
|
)
|
||||||
|
if (!response) {
|
||||||
|
setError('Updating DDO failed.')
|
||||||
|
Logger.error('Failed at makeMinter')
|
||||||
|
}
|
||||||
|
return response
|
||||||
|
}
|
@ -10,6 +10,10 @@ import {
|
|||||||
AssetsFrePrice_fixedRateExchanges as AssetsFrePriceFixedRateExchanges
|
AssetsFrePrice_fixedRateExchanges as AssetsFrePriceFixedRateExchanges
|
||||||
} from '../@types/apollo/AssetsFrePrice'
|
} from '../@types/apollo/AssetsFrePrice'
|
||||||
import { AssetPreviousOrder } from '../@types/apollo/AssetPreviousOrder'
|
import { AssetPreviousOrder } from '../@types/apollo/AssetPreviousOrder'
|
||||||
|
import {
|
||||||
|
AssetsFreePrice,
|
||||||
|
AssetsFreePrice_dispensers as AssetFreePriceDispenser
|
||||||
|
} from '../@types/apollo/AssetsFreePrice'
|
||||||
import web3 from 'web3'
|
import web3 from 'web3'
|
||||||
|
|
||||||
export interface PriceList {
|
export interface PriceList {
|
||||||
@ -25,6 +29,36 @@ interface DidAndDatatokenMap {
|
|||||||
[name: string]: string
|
[name: string]: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const FreeQuery = gql`
|
||||||
|
query AssetsFreePrice($datatoken_in: [String!]) {
|
||||||
|
dispensers(orderBy: id, where: { datatoken_in: $datatoken_in }) {
|
||||||
|
datatoken {
|
||||||
|
id
|
||||||
|
address
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
const AssetFreeQuery = gql`
|
||||||
|
query AssetFreePrice($datatoken: String) {
|
||||||
|
dispensers(orderBy: id, where: { datatoken: $datatoken }) {
|
||||||
|
active
|
||||||
|
owner {
|
||||||
|
id
|
||||||
|
}
|
||||||
|
minterApproved
|
||||||
|
isTrueMinter
|
||||||
|
maxTokens
|
||||||
|
maxBalance
|
||||||
|
balance
|
||||||
|
datatoken {
|
||||||
|
id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
const FreQuery = gql`
|
const FreQuery = gql`
|
||||||
query AssetsFrePrice($datatoken_in: [String!]) {
|
query AssetsFrePrice($datatoken_in: [String!]) {
|
||||||
fixedRateExchanges(orderBy: id, where: { datatoken_in: $datatoken_in }) {
|
fixedRateExchanges(orderBy: id, where: { datatoken_in: $datatoken_in }) {
|
||||||
@ -146,7 +180,8 @@ export async function getPreviousOrders(
|
|||||||
|
|
||||||
function transformPriceToBestPrice(
|
function transformPriceToBestPrice(
|
||||||
frePrice: AssetsFrePriceFixedRateExchanges[],
|
frePrice: AssetsFrePriceFixedRateExchanges[],
|
||||||
poolPrice: AssetsPoolPricePools[]
|
poolPrice: AssetsPoolPricePools[],
|
||||||
|
freePrice: AssetFreePriceDispenser[]
|
||||||
) {
|
) {
|
||||||
if (poolPrice?.length > 0) {
|
if (poolPrice?.length > 0) {
|
||||||
const price: BestPrice = {
|
const price: BestPrice = {
|
||||||
@ -176,6 +211,18 @@ function transformPriceToBestPrice(
|
|||||||
isConsumable: 'true'
|
isConsumable: 'true'
|
||||||
}
|
}
|
||||||
return price
|
return price
|
||||||
|
} else if (freePrice?.length > 0) {
|
||||||
|
const price: BestPrice = {
|
||||||
|
type: 'free',
|
||||||
|
value: 0,
|
||||||
|
address: freePrice[0]?.datatoken.id,
|
||||||
|
exchange_id: '',
|
||||||
|
ocean: 0,
|
||||||
|
datatoken: 0,
|
||||||
|
pools: [],
|
||||||
|
isConsumable: 'true'
|
||||||
|
}
|
||||||
|
return price
|
||||||
} else {
|
} else {
|
||||||
const price: BestPrice = {
|
const price: BestPrice = {
|
||||||
type: '',
|
type: '',
|
||||||
@ -197,6 +244,7 @@ async function getAssetsPoolsExchangesAndDatatokenMap(
|
|||||||
[
|
[
|
||||||
ApolloQueryResult<AssetsPoolPrice>,
|
ApolloQueryResult<AssetsPoolPrice>,
|
||||||
ApolloQueryResult<AssetsFrePrice>,
|
ApolloQueryResult<AssetsFrePrice>,
|
||||||
|
ApolloQueryResult<AssetsFreePrice>,
|
||||||
DidAndDatatokenMap
|
DidAndDatatokenMap
|
||||||
]
|
]
|
||||||
> {
|
> {
|
||||||
@ -214,6 +262,10 @@ async function getAssetsPoolsExchangesAndDatatokenMap(
|
|||||||
datatokenAddress_in: dataTokenList
|
datatokenAddress_in: dataTokenList
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const freeVariables = {
|
||||||
|
datatoken_in: dataTokenList
|
||||||
|
}
|
||||||
|
|
||||||
const poolPriceResponse: ApolloQueryResult<AssetsPoolPrice> = await fetchData(
|
const poolPriceResponse: ApolloQueryResult<AssetsPoolPrice> = await fetchData(
|
||||||
PoolQuery,
|
PoolQuery,
|
||||||
poolVariables
|
poolVariables
|
||||||
@ -223,7 +275,12 @@ async function getAssetsPoolsExchangesAndDatatokenMap(
|
|||||||
freVariables
|
freVariables
|
||||||
)
|
)
|
||||||
|
|
||||||
return [poolPriceResponse, frePriceResponse, didDTMap]
|
const freePriceResponse: ApolloQueryResult<AssetsFreePrice> = await fetchData(
|
||||||
|
FreeQuery,
|
||||||
|
freeVariables
|
||||||
|
)
|
||||||
|
|
||||||
|
return [poolPriceResponse, frePriceResponse, freePriceResponse, didDTMap]
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getAssetsPriceList(assets: DDO[]): Promise<PriceList> {
|
export async function getAssetsPriceList(assets: DDO[]): Promise<PriceList> {
|
||||||
@ -232,11 +289,13 @@ export async function getAssetsPriceList(assets: DDO[]): Promise<PriceList> {
|
|||||||
const values: [
|
const values: [
|
||||||
ApolloQueryResult<AssetsPoolPrice>,
|
ApolloQueryResult<AssetsPoolPrice>,
|
||||||
ApolloQueryResult<AssetsFrePrice>,
|
ApolloQueryResult<AssetsFrePrice>,
|
||||||
|
ApolloQueryResult<AssetsFreePrice>,
|
||||||
DidAndDatatokenMap
|
DidAndDatatokenMap
|
||||||
] = await getAssetsPoolsExchangesAndDatatokenMap(assets)
|
] = await getAssetsPoolsExchangesAndDatatokenMap(assets)
|
||||||
const poolPriceResponse = values[0]
|
const poolPriceResponse = values[0]
|
||||||
const frePriceResponse = values[1]
|
const frePriceResponse = values[1]
|
||||||
const didDTMap: DidAndDatatokenMap = values[2]
|
const freePriceResponse = values[2]
|
||||||
|
const didDTMap: DidAndDatatokenMap = values[3]
|
||||||
|
|
||||||
for (const poolPrice of poolPriceResponse.data?.pools) {
|
for (const poolPrice of poolPriceResponse.data?.pools) {
|
||||||
priceList[didDTMap[poolPrice.datatokenAddress]] =
|
priceList[didDTMap[poolPrice.datatokenAddress]] =
|
||||||
@ -247,6 +306,9 @@ export async function getAssetsPriceList(assets: DDO[]): Promise<PriceList> {
|
|||||||
for (const frePrice of frePriceResponse.data?.fixedRateExchanges) {
|
for (const frePrice of frePriceResponse.data?.fixedRateExchanges) {
|
||||||
priceList[didDTMap[frePrice.datatoken?.address]] = frePrice.rate
|
priceList[didDTMap[frePrice.datatoken?.address]] = frePrice.rate
|
||||||
}
|
}
|
||||||
|
for (const freePrice of freePriceResponse.data?.dispensers) {
|
||||||
|
priceList[didDTMap[freePrice.datatoken?.address]] = '0'
|
||||||
|
}
|
||||||
return priceList
|
return priceList
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -259,6 +321,10 @@ export async function getPrice(asset: DDO): Promise<BestPrice> {
|
|||||||
datatokenAddress: asset?.dataToken.toLowerCase()
|
datatokenAddress: asset?.dataToken.toLowerCase()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const freeVariables = {
|
||||||
|
datatoken: asset?.dataToken.toLowerCase()
|
||||||
|
}
|
||||||
|
|
||||||
const poolPriceResponse: ApolloQueryResult<AssetsPoolPrice> = await fetchData(
|
const poolPriceResponse: ApolloQueryResult<AssetsPoolPrice> = await fetchData(
|
||||||
AssetPoolPriceQuerry,
|
AssetPoolPriceQuerry,
|
||||||
poolVariables
|
poolVariables
|
||||||
@ -267,10 +333,15 @@ export async function getPrice(asset: DDO): Promise<BestPrice> {
|
|||||||
AssetFreQuery,
|
AssetFreQuery,
|
||||||
freVariables
|
freVariables
|
||||||
)
|
)
|
||||||
|
const freePriceResponse: ApolloQueryResult<AssetsFreePrice> = await fetchData(
|
||||||
|
AssetFreeQuery,
|
||||||
|
freeVariables
|
||||||
|
)
|
||||||
|
|
||||||
const bestPrice: BestPrice = transformPriceToBestPrice(
|
const bestPrice: BestPrice = transformPriceToBestPrice(
|
||||||
frePriceResponse.data.fixedRateExchanges,
|
frePriceResponse.data.fixedRateExchanges,
|
||||||
poolPriceResponse.data.pools
|
poolPriceResponse.data.pools,
|
||||||
|
freePriceResponse.data.dispensers
|
||||||
)
|
)
|
||||||
|
|
||||||
return bestPrice
|
return bestPrice
|
||||||
@ -284,15 +355,18 @@ export async function getAssetsBestPrices(
|
|||||||
const values: [
|
const values: [
|
||||||
ApolloQueryResult<AssetsPoolPrice>,
|
ApolloQueryResult<AssetsPoolPrice>,
|
||||||
ApolloQueryResult<AssetsFrePrice>,
|
ApolloQueryResult<AssetsFrePrice>,
|
||||||
|
ApolloQueryResult<AssetsFreePrice>,
|
||||||
DidAndDatatokenMap
|
DidAndDatatokenMap
|
||||||
] = await getAssetsPoolsExchangesAndDatatokenMap(assets)
|
] = await getAssetsPoolsExchangesAndDatatokenMap(assets)
|
||||||
const poolPriceResponse = values[0]
|
const poolPriceResponse = values[0]
|
||||||
const frePriceResponse = values[1]
|
const frePriceResponse = values[1]
|
||||||
|
const freePriceResponse = values[2]
|
||||||
|
|
||||||
for (const ddo of assets) {
|
for (const ddo of assets) {
|
||||||
const dataToken = ddo.dataToken.toLowerCase()
|
const dataToken = ddo.dataToken.toLowerCase()
|
||||||
const poolPrice: AssetsPoolPricePools[] = []
|
const poolPrice: AssetsPoolPricePools[] = []
|
||||||
const frePrice: AssetsFrePriceFixedRateExchanges[] = []
|
const frePrice: AssetsFrePriceFixedRateExchanges[] = []
|
||||||
|
const freePrice: AssetFreePriceDispenser[] = []
|
||||||
const pool = poolPriceResponse.data?.pools.find(
|
const pool = poolPriceResponse.data?.pools.find(
|
||||||
(pool: any) => pool.datatokenAddress === dataToken
|
(pool: any) => pool.datatokenAddress === dataToken
|
||||||
)
|
)
|
||||||
@ -301,7 +375,11 @@ export async function getAssetsBestPrices(
|
|||||||
(fre: any) => fre.datatoken.address === dataToken
|
(fre: any) => fre.datatoken.address === dataToken
|
||||||
)
|
)
|
||||||
fre && frePrice.push(fre)
|
fre && frePrice.push(fre)
|
||||||
const bestPrice = transformPriceToBestPrice(frePrice, poolPrice)
|
const free = freePriceResponse.data?.dispensers.find(
|
||||||
|
(free: any) => free.datatoken.address === dataToken
|
||||||
|
)
|
||||||
|
free && freePrice.push(free)
|
||||||
|
const bestPrice = transformPriceToBestPrice(frePrice, poolPrice, freePrice)
|
||||||
assetsWithPrice.push({
|
assetsWithPrice.push({
|
||||||
ddo: ddo,
|
ddo: ddo,
|
||||||
price: bestPrice
|
price: bestPrice
|
||||||
|
Loading…
Reference in New Issue
Block a user