1
0
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:
Kris Liew 2021-06-16 09:32:11 +08:00 committed by GitHub
parent eb8c6afb62
commit e02babf2c2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
25 changed files with 341 additions and 41 deletions

View File

@ -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"

View File

@ -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
} }

View File

@ -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',

View File

@ -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": {

View File

@ -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 (

View File

@ -42,6 +42,10 @@ export default function PriceUnit({
return ( return (
<div className={styleClasses}> <div className={styleClasses}>
{type && type === 'free' ? (
<div> Free </div>
) : (
<>
<div> <div>
{Number.isNaN(Number(price)) ? '-' : formatPrice(price, locale)}{' '} {Number.isNaN(Number(price)) ? '-' : formatPrice(price, locale)}{' '}
<span className={styles.symbol}>{symbol || 'OCEAN'}</span> <span className={styles.symbol}>{symbol || 'OCEAN'}</span>
@ -49,8 +53,9 @@ export default function PriceUnit({
<Badge label="pool" className={styles.badge} /> <Badge label="pool" className={styles.badge} />
)} )}
</div> </div>
{conversion && <Conversion price={price} />} {conversion && <Conversion price={price} />}
</>
)}
</div> </div>
) )
} }

View File

@ -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}

View File

@ -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>
)) ))
)} )}

View File

@ -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>
) )

View File

@ -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}
/> />
) )

View File

@ -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()

View File

@ -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()

View File

@ -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(

View File

@ -0,0 +1,3 @@
.free {
composes: content from './index.module.css';
}

View File

@ -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>
)
}

View File

@ -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,6 +40,15 @@ 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}>
{free ? (
<Input
value="0"
name="price"
type="number"
prefix="OCEAN"
readOnly
/>
) : (
<Input <Input
value={field.value} value={field.value}
name="price" name="price"
@ -49,6 +60,7 @@ export default function Price({
<Conversion price={field.value} className={styles.conversion} /> <Conversion price={field.value} className={styles.conversion} />
} }
/> />
)}
<Error meta={meta} /> <Error meta={meta} />
</div> </div>
<div className={styles.datatoken}> <div className={styles.datatoken}>

View File

@ -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);
}

View File

@ -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)

View File

@ -40,6 +40,10 @@ const query = graphql`
marketplaceFee marketplaceFee
} }
} }
free {
title
info
}
} }
} }
} }

View File

@ -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 (type === 'free') {
setStep(99, 'free', ddo)
await ocean.OceanDispenser.activate(dataToken, '1', '1', accountId)
} else {
// if fixedPrice set dt to max amount // if fixedPrice set dt to max amount
if (!isPool) dtAmount = 1000 if (!isPool) dtAmount = 1000
await mint(`${dtAmount}`, ddo) 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) {

View File

@ -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
} }

View File

@ -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'),

View File

@ -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
View 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
}

View File

@ -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