1
0
mirror of https://github.com/oceanprotocol/react.git synced 2025-01-03 18:35:18 +01:00

split flows for Publish and Buy

This commit is contained in:
alexcos20 2020-10-14 01:11:49 -07:00
parent 80b1db5176
commit 9d9360230c
15 changed files with 385 additions and 199 deletions

View File

@ -0,0 +1,38 @@
# `useBuy`
Buy datatoken.
## Usage
```tsx
import React from 'react'
import { useOcean, useConsume } from '@oceanprotocol/react'
const did = 'did:op:0x000000000'
export default function MyComponent() {
const { accountId } = useOcean()
// Get metadata for this asset
const { title, price, ddo } = useMetadata(did)
// Consume helpers
const { consume, consumeStep } = useConsume()
async function handleDownload() {
await consume(did, ddo.dataToken, 'access')
}
return (
<div>
<h1>{title}</h1>
<p>Price: {price}</p>
<p>Your account: {accountId}</p>
<button onClick={handleDownload}>
{consumeStep || 'Download Asset'}
</button>
</div>
)
}
```

View File

@ -0,0 +1 @@
export * from './useBuy'

110
src/hooks/useBuy/useBuy.ts Normal file
View File

@ -0,0 +1,110 @@
import { useState } from 'react'
import { useOcean } from 'providers'
import { feedback } from 'utils'
import { DID, Logger, ServiceType } from '@oceanprotocol/lib'
import { getBestDataTokenPrice } from 'utils/dtUtils'
import { TransactionReceipt } from 'web3-core'
import { Decimal } from 'decimal.js'
interface UseBuy {
buyDT: (
dataTokenAddress: string,
dtAmount: number | string,
) => Promise<TransactionReceipt | null>
consumeStep?: number
consumeStepText?: string
consumeError?: string
isLoading: boolean
}
export const buyFeedback: { [key in number]: string } = {
0: '1/2 Approving OCEAN Tokens',
1: '2/3 Buying Datatoken',
2: '3/3 Bought Datatoken'
}
function useBuy(): UseBuy {
const { ocean, account, accountId, config } = useOcean()
const [isLoading, setIsLoading] = useState(false)
const [consumeStep, setConsumeStep] = useState<number | undefined>()
const [consumeStepText, setConsumeStepText] = useState<string | undefined>()
const [consumeError, setConsumeError] = useState<string | undefined>()
function setStep(index: number) {
setConsumeStep(index)
setConsumeStepText(buyFeedback[index])
}
async function buyDT(
dataTokenAddress: string,
dtAmount: number | string,
): Promise<TransactionReceipt | null> {
if (!ocean || !account || !accountId) return
setIsLoading(true)
setConsumeError(undefined)
setStep(0)
try {
const bestPrice = await getBestDataTokenPrice(ocean, dataTokenAddress)
switch (bestPrice?.type) {
case 'pool': {
const price = new Decimal(bestPrice.value).times(1.05).toString()
const maxPrice = new Decimal(bestPrice.value).times(2).toString()
Logger.log('Buying token from pool', bestPrice, account.getId(), price)
const buyResponse = await ocean.pool.buyDT(
account.getId(),
bestPrice.address,
String(dtAmount),
price,
maxPrice
)
setStep(2)
Logger.log('DT buy response', buyResponse)
return buyResponse
}
case 'exchange': {
if (!config.oceanTokenAddress) {
Logger.error(`'oceanTokenAddress' not set in config`)
return
}
if (!config.fixedRateExchangeAddress) {
Logger.error(`'fixedRateExchangeAddress' not set in config`)
return
}
Logger.log('Buying token from exchange', bestPrice, account.getId())
await ocean.datatokens.approve(
config.oceanTokenAddress,
config.fixedRateExchangeAddress,
bestPrice.value.toString(),
account.getId()
)
setStep(1)
const exchange = await ocean.fixedRateExchange.buyDT(
bestPrice.address,
String(dtAmount),
account.getId()
)
setStep(2)
Logger.log('DT exchange buy response', exchange)
return exchange
}
}
} catch (error) {
setConsumeError(error.message)
Logger.error(error)
} finally {
setConsumeStep(undefined)
setConsumeStepText(undefined)
setIsLoading(false)
}
}
return { buyDT, consumeStep, consumeStepText, consumeError, isLoading }
}
export { useBuy, UseBuy }
export default useBuy

View File

@ -4,7 +4,6 @@ import { ComputeValue } from './ComputeOptions'
import { Logger, ServiceCompute } from '@oceanprotocol/lib'
import { MetadataAlgorithm } from '@oceanprotocol/lib/dist/node/ddo/interfaces/MetadataAlgorithm'
import { ComputeJob } from '@oceanprotocol/lib/dist/node/ocean/interfaces/ComputeJob'
import { checkAndBuyDT } from 'utils/dtUtils'
interface UseCompute {
compute: (
@ -13,7 +12,7 @@ interface UseCompute {
dataTokenAddress: string,
algorithmRawCode: string,
computeContainer: ComputeValue,
marketFeeAddress: string
marketFeeAddress?: string
) => Promise<ComputeJob | void>
computeStep?: number
computeStepText?: string
@ -62,7 +61,7 @@ function useCompute(): UseCompute {
dataTokenAddress: string,
algorithmRawCode: string,
computeContainer: ComputeValue,
marketFeeAddress: string
marketFeeAddress?: string
): Promise<ComputeJob | void> {
if (!ocean || !account) return
@ -72,50 +71,47 @@ function useCompute(): UseCompute {
setIsLoading(true)
setStep(0)
await checkAndBuyDT(ocean, dataTokenAddress, account, config)
rawAlgorithmMeta.container = computeContainer
rawAlgorithmMeta.rawcode = algorithmRawCode
const output = {}
Logger.log(
'compute order',
accountId,
did,
computeService,
rawAlgorithmMeta,
marketFeeAddress
)
const tokenTransfer = await ocean.compute.order(
accountId,
did,
computeService.index,
undefined,
rawAlgorithmMeta,
marketFeeAddress
)
setStep(1)
// const computeOrder = JSON.parse(order)
// Logger.log('compute order', computeOrder)
// const tokenTransfer = await ocean.datatokens.transferWei(
// computeOrder.dataToken,
// computeOrder.to,
// String(computeOrder.numTokens),
// computeOrder.from
// )
setStep(2)
const response = await ocean.compute.start(
did,
tokenTransfer,
const userOwnedTokens = await ocean.accounts.getTokenBalance(
dataTokenAddress,
account,
undefined,
rawAlgorithmMeta,
output,
`${computeService.index}`,
computeService.type
account
)
return response
if (parseFloat(userOwnedTokens) < 1) {
setComputeError('Not enough datatokens')
} else {
rawAlgorithmMeta.container = computeContainer
rawAlgorithmMeta.rawcode = algorithmRawCode
const output = {}
Logger.log(
'compute order',
accountId,
did,
computeService,
rawAlgorithmMeta,
marketFeeAddress
)
const tokenTransfer = await ocean.compute.order(
accountId,
did,
computeService.index,
undefined,
rawAlgorithmMeta,
marketFeeAddress
)
setStep(1)
setStep(2)
const response = await ocean.compute.start(
did,
tokenTransfer,
dataTokenAddress,
account,
undefined,
rawAlgorithmMeta,
output,
`${computeService.index}`,
computeService.type
)
return response
}
} catch (error) {
Logger.error(error)
setComputeError(error.message)

View File

@ -2,7 +2,6 @@ import { useState } from 'react'
import { useOcean } from 'providers'
import { feedback } from 'utils'
import { DID, Logger, ServiceType } from '@oceanprotocol/lib'
import { checkAndBuyDT } from 'utils/dtUtils'
interface UseConsume {
consume: (
@ -49,38 +48,33 @@ function useConsume(): UseConsume {
try {
setStep(0)
await checkAndBuyDT(ocean, dataTokenAddress, account, config)
setStep(1)
const tokenTransfer = await ocean.assets.order(
did as string,
serviceType,
accountId,
undefined,
marketFeeAddress
)
Logger.log('order created', tokenTransfer)
setStep(2)
// const res = JSON.parse(order)
// Logger.log('order parsed', res)
// Logger.log('ocean.datatokens before transfer', ocean.datatokens)
// const tokenTransfer = await ocean.datatokens.transferWei(
// res.dataToken,
// res.to,
// String(res.numTokens),
// res.from
// )
// Logger.log('token transfered', tokenTransfer)
setStep(3)
await ocean.assets.download(
did as string,
tokenTransfer,
const userOwnedTokens = await ocean.accounts.getTokenBalance(
dataTokenAddress,
account,
''
account
)
setStep(4)
if (parseFloat(userOwnedTokens) < 1) {
setConsumeError('Not enough datatokens')
} else {
setStep(1)
const tokenTransfer = await ocean.assets.order(
did as string,
serviceType,
accountId,
undefined,
marketFeeAddress
)
Logger.log('order created', tokenTransfer)
setStep(2)
setStep(3)
await ocean.assets.download(
did as string,
tokenTransfer,
dataTokenAddress,
account,
''
)
setStep(4)
}
} catch (error) {
setConsumeError(error.message)
Logger.error(error)

View File

@ -1,6 +1,6 @@
export interface PriceOptions {
price: number
tokensToMint: number
dtAmount: number
type: 'fixed' | 'dynamic' | string
weightOnDataToken: string
swapFee: string

View File

@ -0,0 +1,39 @@
# `usePublish`
Post asset for sale by creating liquidity pools or fixed rate exchange
## Usage
```tsx
import React from 'react'
import { useOcean, usePostforSale } from '@oceanprotocol/react'
import { Metadata } from '@oceanprotocol/lib'
export default function MyComponent() {
const { accountId } = useOcean()
// Publish helpers
const { publish, publishStep } = usePostforSale()
const priceOptions = {
price: 10,
dtAmount: 10,
type: 'fixed',
weightOnDataToken: '',
swapFee: ''
}
async function handlePostforSale() {
const ddo = await createPricing(dataTokenAddress, priceOptions)
}
return (
<div>
<h1>Post for sale</h1>
<p>Your account: {accountId}</p>
<button onClick={handlePostforSale}>Post for sale</button>
</div>
)
}
```

View File

@ -0,0 +1,2 @@
export * from './usePostforSale'
export * from './PriceOptions'

View File

@ -0,0 +1,84 @@
import { DID, DDO, Logger, Metadata } from '@oceanprotocol/lib'
import {
Service,
ServiceComputePrivacy,
ServiceType
} from '@oceanprotocol/lib/dist/node/ddo/interfaces/Service'
import { useState } from 'react'
import { useOcean } from 'providers'
import ProviderStatus from 'providers/OceanProvider/ProviderStatus'
import { publishFeedback } from 'utils'
import { PriceOptions } from './PriceOptions'
interface UsePostforSale {
createPricing: (
dataTokenAddress: string,
priceOptions: PriceOptions,
) => Promise<void | null>
publishStep?: number
publishStepText?: string
publishError?: string
isLoading: boolean
}
function usePostforSale(): UsePostforSale {
const { ocean, status, account, accountId, config } = useOcean()
const [isLoading, setIsLoading] = useState(false)
const [publishStep, setPublishStep] = useState<number | undefined>()
const [publishStepText, setPublishStepText] = useState<string | undefined>()
const [publishError, setPublishError] = useState<string | undefined>()
function setStep(index?: number) {
setPublishStep(index)
index && setPublishStepText(publishFeedback[index])
}
async function createPricing(
dataTokenAddress: string,
priceOptions: PriceOptions
): Promise<void | null> {
switch (priceOptions.type) {
case 'dynamic': {
await ocean.pool.createDTPool(
accountId,
dataTokenAddress,
priceOptions.dtAmount.toString(),
priceOptions.weightOnDataToken,
priceOptions.swapFee
)
break
}
case 'fixed': {
if (!config.fixedRateExchangeAddress) {
Logger.error(`'fixedRateExchangeAddress' not set in ccnfig.`)
return null
}
await ocean.fixedRateExchange.create(
dataTokenAddress,
priceOptions.price.toString(),
accountId
)
await ocean.datatokens.approve(
dataTokenAddress,
config.fixedRateExchangeAddress,
priceOptions.dtAmount,
accountId
)
break
}
}
}
return {
createPricing,
publishStep,
publishStepText,
isLoading,
publishError
}
}
export { usePostforSale, UsePostforSale }
export default usePostforSale

View File

@ -1,4 +1,5 @@
export interface DataTokenOptions {
tokensToMint: number
cap?: string
name?: string
symbol?: string

View File

@ -1,6 +1,6 @@
# `usePublish`
Publish data sets, and create data tokens and liquidity pools for them.
Create data tokens, Mint and Publish data sets
## Usage
@ -24,16 +24,12 @@ export default function MyComponent() {
}
}
const priceOptions = {
price: 10,
tokensToMint: 10,
type: 'fixed',
weightOnDataToken: '',
swapFee: ''
const dataTokenOptions = {
tokensToMint: 10
}
async function handlePublish() {
const ddo = await publish(metadata, priceOptions, 'access')
const ddo = await publish(metadata, 'access', dataTokenOptions)
}
return (

View File

@ -1,3 +1,2 @@
export * from './usePublish'
export * from './PriceOptions'
export * from './DataTokenOptions'

View File

@ -5,18 +5,16 @@ import {
ServiceType
} from '@oceanprotocol/lib/dist/node/ddo/interfaces/Service'
import { useState } from 'react'
import { DataTokenOptions } from '.'
import { DataTokenOptions } from './DataTokenOptions'
import { useOcean } from 'providers'
import ProviderStatus from 'providers/OceanProvider/ProviderStatus'
import { publishFeedback } from 'utils'
import { PriceOptions } from './PriceOptions'
interface UsePublish {
publish: (
asset: Metadata,
priceOptions: PriceOptions,
serviceConfigs: ServiceType,
dataTokenOptions?: DataTokenOptions,
dataTokenOptions: DataTokenOptions,
providerUri?: string
) => Promise<DDO | undefined | null>
mint: (tokenAddress: string, tokensToMint: string) => void
@ -43,44 +41,6 @@ function usePublish(): UsePublish {
await ocean.datatokens.mint(tokenAddress, accountId, tokensToMint)
}
async function createPricing(
priceOptions: PriceOptions,
dataTokenAddress: string,
mintedTokens: string
): Promise<void | null> {
switch (priceOptions.type) {
case 'dynamic': {
await ocean.pool.createDTPool(
accountId,
dataTokenAddress,
priceOptions.tokensToMint.toString(),
priceOptions.weightOnDataToken,
priceOptions.swapFee
)
break
}
case 'fixed': {
if (!config.fixedRateExchangeAddress) {
Logger.error(`'fixedRateExchangeAddress' not set in ccnfig.`)
return null
}
await ocean.fixedRateExchange.create(
dataTokenAddress,
priceOptions.price.toString(),
accountId
)
await ocean.datatokens.approve(
dataTokenAddress,
config.fixedRateExchangeAddress,
mintedTokens,
accountId
)
break
}
}
}
/**
* Publish an asset.It also creates the datatoken, mints tokens and gives the market allowance
* @param {Metadata} asset The metadata of the asset.
@ -91,9 +51,8 @@ function usePublish(): UsePublish {
*/
async function publish(
asset: Metadata,
priceOptions: PriceOptions,
serviceType: ServiceType,
dataTokenOptions?: DataTokenOptions,
dataTokenOptions: DataTokenOptions,
providerUri?: string
): Promise<DDO | undefined | null> {
if (status !== ProviderStatus.CONNECTED || !ocean || !account) return null
@ -102,7 +61,7 @@ function usePublish(): UsePublish {
setPublishError(undefined)
try {
const tokensToMint = priceOptions.tokensToMint.toString()
const tokensToMint = dataTokenOptions.tokensToMint.toString()
const publishedDate =
new Date(Date.now()).toISOString().split('.')[0] + 'Z'
@ -189,8 +148,8 @@ function usePublish(): UsePublish {
await mint(ddo.dataToken, tokensToMint)
Logger.log(`minted ${tokensToMint} tokens`)
await createPricing(priceOptions, ddo.dataToken, tokensToMint)
setStep(8)
// await createPricing(priceOptions, ddo.dataToken, tokensToMint)
// setStep(8)
return ddo
} catch (error) {
setPublishError(error.message)

View File

@ -44,6 +44,33 @@ export async function getCheapestPool(
}
}
export async function getFirstPool(
ocean: Ocean,
dataTokenAddress: string
): Promise<Pool | null> {
if (!ocean || !dataTokenAddress) return null
const tokenPools = await ocean.pool.searchPoolforDT(dataTokenAddress)
if (tokenPools === undefined || tokenPools.length === 0) {
return {
address: '',
price: 0
}
}
const firstPoolAddress = tokenPools[0]
const firstPoolPrice = await ocean.pool.getOceanNeeded(firstPoolAddress, '1')
const oceanReserve = await ocean.pool.getOceanReserve(firstPoolAddress)
const dtReserve = await ocean.pool.getDTReserve(firstPoolAddress)
return {
address: firstPoolAddress,
price: Number(firstPoolPrice),
ocean: Number(oceanReserve),
datatoken: Number(dtReserve)
}
}
export async function getCheapestExchange(
ocean: Ocean,
dataTokenAddress: string
@ -90,7 +117,7 @@ export async function getBestDataTokenPrice(
ocean: Ocean,
dataTokenAddress: string
): Promise<BestPrice> {
const cheapestPool = await getCheapestPool(ocean, dataTokenAddress)
const cheapestPool = await getFirstPool(ocean, dataTokenAddress)
const cheapestExchange = await getCheapestExchange(ocean, dataTokenAddress)
Decimal.set({ precision: 5 })
@ -119,62 +146,3 @@ export async function getBestDataTokenPrice(
} as BestPrice
}
}
export async function checkAndBuyDT(
ocean: Ocean,
dataTokenAddress: string,
account: Account,
config: Config
): Promise<TransactionReceipt | undefined> {
const userOwnedTokens = await ocean.accounts.getTokenBalance(
dataTokenAddress,
account
)
Logger.log(`User has ${userOwnedTokens} tokens`)
if (userOwnedTokens === '0') {
const bestPrice = await getBestDataTokenPrice(ocean, dataTokenAddress)
switch (bestPrice?.type) {
case 'pool': {
const price = new Decimal(bestPrice.value).times(1.05).toString()
const maxPrice = new Decimal(bestPrice.value).times(2).toString()
Logger.log('Buying token from pool', bestPrice, account.getId(), price)
const buyResponse = await ocean.pool.buyDT(
account.getId(),
bestPrice.address,
'1',
price,
maxPrice
)
Logger.log('DT buy response', buyResponse)
return buyResponse
}
case 'exchange': {
if (!config.oceanTokenAddress) {
Logger.error(`'oceanTokenAddress' not set in config`)
return
}
if (!config.fixedRateExchangeAddress) {
Logger.error(`'fixedRateExchangeAddress' not set in config`)
return
}
Logger.log('Buying token from exchange', bestPrice, account.getId())
await ocean.datatokens.approve(
config.oceanTokenAddress,
config.fixedRateExchangeAddress,
bestPrice.value.toString(),
account.getId()
)
const exchange = await ocean.fixedRateExchange.buyDT(
bestPrice.address,
'1',
account.getId()
)
Logger.log('DT exchange buy response', exchange)
return exchange
}
}
}
}

View File

@ -31,12 +31,11 @@ export const feedback: { [key in number]: string } = {
}
export const publishFeedback: { [key in number]: string } = {
0: '1/6 Creating datatoken ...',
2: '2/6 Encrypting files ...',
4: '3/6 Generating proof ...',
6: '4/6 Storing ddo ...',
7: '5/6 Minting tokens ...',
8: '6/6 Asset published succesfully'
0: '1/5 Creating datatoken ...',
2: '2/5 Encrypting files ...',
4: '3/5 Storing ddo ...',
6: '4/5 Minting tokens ...',
8: '5/5 Asset published succesfully'
}
export * from './web3'