react/src/hooks/usePricing/usePricing.ts

289 lines
8.2 KiB
TypeScript
Raw Normal View History

import { DDO, Logger } from '@oceanprotocol/lib'
import { useEffect, useState } from 'react'
2020-10-14 13:55:18 +02:00
import { useOcean } from 'providers'
2020-10-19 11:47:12 +02:00
import { PriceOptions } from './PriceOptions'
2020-10-14 13:55:18 +02:00
import { TransactionReceipt } from 'web3-core'
import { getBestDataTokenPrice, getFirstPool } from 'utils/dtUtils'
import { Decimal } from 'decimal.js'
2020-10-19 11:47:12 +02:00
interface UsePricing {
2020-10-19 13:11:53 +02:00
dtSymbol?: string
dtName?: string
2020-10-19 11:47:12 +02:00
createPricing: (
priceOptions: PriceOptions
2020-10-21 00:31:32 +02:00
) => Promise<TransactionReceipt | string | void>
buyDT: (dtAmount: number | string) => Promise<TransactionReceipt | void>
sellDT: (dtAmount: number | string) => Promise<TransactionReceipt | void>
mint: (tokensToMint: string) => Promise<TransactionReceipt>
2020-10-19 11:47:12 +02:00
pricingStep?: number
pricingStepText?: string
pricingError?: string
pricingIsLoading: boolean
2020-10-14 13:55:18 +02:00
}
2020-10-19 11:47:12 +02:00
export const createPricingFeedback: { [key in number]: string } = {
2020-10-21 00:31:32 +02:00
0: 'Minting DT ...',
1: 'Approving DT ...',
2: 'Approving Ocean ...',
3: 'Creating ...',
4: 'Pricing created.'
2020-10-19 11:47:12 +02:00
}
2020-10-14 13:55:18 +02:00
export const buyDTFeedback: { [key in number]: string } = {
0: '1/3 Approving OCEAN ...',
1: '2/3 Buying DT ...',
2020-10-14 14:05:45 +02:00
2: '3/3 DT Bought'
2020-10-14 13:55:18 +02:00
}
2020-10-14 13:55:18 +02:00
export const sellDTFeedback: { [key in number]: string } = {
0: '1/3 Approving DT ...',
1: '2/3 Selling DT ...',
2020-10-14 14:05:45 +02:00
2: '3/3 DT sold'
2020-10-14 13:55:18 +02:00
}
function usePricing(ddo: DDO): UsePricing {
const { ocean, account, accountId, config } = useOcean()
2020-10-19 11:47:12 +02:00
const [pricingIsLoading, setPricingIsLoading] = useState(false)
const [pricingStep, setPricingStep] = useState<number>()
const [pricingStepText, setPricingStepText] = useState<string>()
const [pricingError, setPricingError] = useState<string>()
2020-10-16 13:08:06 +02:00
const [dtSymbol, setDtSymbol] = useState<string>()
2020-10-19 12:44:31 +02:00
const [dtName, setDtName] = useState<string>()
2020-10-14 13:55:18 +02:00
const { dataToken, dataTokenInfo } = ddo
2020-10-19 12:44:31 +02:00
// Get Datatoken info, from DDO first, then from chain
useEffect(() => {
if (!dataToken) return
async function init() {
2020-10-19 12:44:31 +02:00
const dtSymbol = dataTokenInfo
? dataTokenInfo.symbol
: await ocean?.datatokens.getSymbol(dataToken)
setDtSymbol(dtSymbol)
2020-10-19 12:44:31 +02:00
const dtName = dataTokenInfo
? dataTokenInfo.name
: await ocean?.datatokens.getName(dataToken)
setDtName(dtName)
}
init()
2020-10-19 12:44:31 +02:00
}, [ocean, dataToken, dataTokenInfo])
2020-10-19 11:47:12 +02:00
function setStepCreatePricing(index?: number) {
setPricingStep(index)
if (!index) return
const message = dtSymbol
? createPricingFeedback[index].replace(/DT/g, dtSymbol)
: createPricingFeedback[index]
setPricingStepText(message)
2020-10-19 11:47:12 +02:00
}
2020-10-16 13:08:06 +02:00
function setStepBuyDT(index?: number) {
2020-10-19 11:47:12 +02:00
setPricingStep(index)
if (!index) return
const message = dtSymbol
? buyDTFeedback[index].replace(/DT/g, dtSymbol)
: buyDTFeedback[index]
setPricingStepText(message)
2020-10-14 13:55:18 +02:00
}
2020-10-16 13:08:06 +02:00
function setStepSellDT(index?: number) {
2020-10-19 11:47:12 +02:00
setPricingStep(index)
if (!index) return
const message = dtSymbol
? sellDTFeedback[index].replace(/DT/g, dtSymbol)
: sellDTFeedback[index]
setPricingStepText(message)
2020-10-14 13:55:18 +02:00
}
2020-10-21 00:31:32 +02:00
async function mint(tokensToMint: string): Promise<TransactionReceipt> {
Logger.log('mint function', dataToken, accountId)
2020-10-21 00:31:32 +02:00
const tx = await ocean.datatokens.mint(dataToken, accountId, tokensToMint)
return tx
2020-10-19 11:47:12 +02:00
}
2020-10-14 13:55:18 +02:00
async function buyDT(
2020-10-14 14:05:45 +02:00
dtAmount: number | string
2020-10-21 00:31:32 +02:00
): Promise<TransactionReceipt | void> {
if (!ocean || !account || !accountId) return
2020-10-14 13:55:18 +02:00
try {
2020-10-19 11:47:12 +02:00
setPricingIsLoading(true)
setPricingError(undefined)
2020-10-16 12:59:10 +02:00
setStepBuyDT(0)
const bestPrice = await getBestDataTokenPrice(ocean, dataToken)
2020-10-14 13:55:18 +02:00
switch (bestPrice?.type) {
case 'pool': {
const price = new Decimal(bestPrice.value).times(1.05).toString()
const maxPrice = new Decimal(bestPrice.value).times(2).toString()
2020-10-16 13:08:06 +02:00
setStepBuyDT(1)
2020-10-14 14:05:45 +02:00
Logger.log(
'Buying token from pool',
bestPrice,
account.getId(),
price
)
2020-10-14 13:55:18 +02:00
const buyResponse = await ocean.pool.buyDT(
account.getId(),
bestPrice.address,
String(dtAmount),
price,
maxPrice
)
setStepBuyDT(2)
Logger.log('DT buy response', buyResponse)
return buyResponse
}
case 'exchange': {
if (!config.oceanTokenAddress) {
Logger.error(`'oceanTokenAddress' not set in config`)
2020-10-21 00:31:32 +02:00
return
2020-10-14 13:55:18 +02:00
}
if (!config.fixedRateExchangeAddress) {
Logger.error(`'fixedRateExchangeAddress' not set in config`)
2020-10-21 00:31:32 +02:00
return
2020-10-14 13:55:18 +02:00
}
Logger.log('Buying token from exchange', bestPrice, account.getId())
await ocean.datatokens.approve(
config.oceanTokenAddress,
config.fixedRateExchangeAddress,
bestPrice.value.toString(),
account.getId()
)
2020-10-16 13:08:06 +02:00
setStepBuyDT(1)
2020-10-14 13:55:18 +02:00
const exchange = await ocean.fixedRateExchange.buyDT(
bestPrice.address,
String(dtAmount),
account.getId()
)
setStepBuyDT(2)
Logger.log('DT exchange buy response', exchange)
return exchange
}
}
} catch (error) {
2020-10-19 11:47:12 +02:00
setPricingError(error.message)
2020-10-14 13:55:18 +02:00
Logger.error(error)
} finally {
2020-10-19 11:47:12 +02:00
setStepBuyDT(undefined)
setPricingStepText(undefined)
setPricingIsLoading(false)
2020-10-14 13:55:18 +02:00
}
}
async function sellDT(
2020-10-14 14:05:45 +02:00
dtAmount: number | string
2020-10-21 00:31:32 +02:00
): Promise<TransactionReceipt | void> {
if (!ocean || !account || !accountId) return
2020-10-14 18:19:22 +02:00
if (!config.oceanTokenAddress) {
Logger.error(`'oceanTokenAddress' not set in config`)
2020-10-21 00:31:32 +02:00
return
2020-10-14 18:19:22 +02:00
}
2020-10-14 13:55:18 +02:00
try {
2020-10-19 11:47:12 +02:00
setPricingIsLoading(true)
setPricingError(undefined)
2020-10-16 13:08:06 +02:00
setStepSellDT(0)
const pool = await getFirstPool(ocean, dataToken)
2020-10-21 00:31:32 +02:00
if (!pool || pool.price === 0) return
2020-10-14 18:19:22 +02:00
const price = new Decimal(pool.price).times(0.95).toString()
2020-10-16 13:08:06 +02:00
setStepSellDT(1)
2020-10-14 13:55:18 +02:00
Logger.log('Selling token to pool', pool, account.getId(), price)
const sellResponse = await ocean.pool.sellDT(
2020-10-14 14:05:45 +02:00
account.getId(),
pool.address,
String(dtAmount),
price
)
2020-10-14 13:55:18 +02:00
setStepSellDT(2)
Logger.log('DT sell response', sellResponse)
return sellResponse
} catch (error) {
2020-10-19 11:47:12 +02:00
setPricingError(error.message)
2020-10-14 13:55:18 +02:00
Logger.error(error)
} finally {
setStepSellDT(undefined)
2020-10-19 11:47:12 +02:00
setPricingStepText(undefined)
setPricingIsLoading(false)
}
}
async function createPricing(
priceOptions: PriceOptions
2020-10-21 00:31:32 +02:00
): Promise<TransactionReceipt | string | void> {
if (!ocean || !account || !accountId) return
const { type, dtAmount, price, weightOnDataToken, swapFee } = priceOptions
const isPool = type === 'dynamic'
if (!isPool && !config.fixedRateExchangeAddress) {
Logger.error(`'fixedRateExchangeAddress' not set in ccnfig.`)
return
}
2020-10-19 11:47:12 +02:00
try {
setPricingIsLoading(true)
setPricingError(undefined)
2020-10-21 00:31:32 +02:00
2020-10-19 11:47:12 +02:00
setStepCreatePricing(0)
2020-10-21 00:31:32 +02:00
await mint(`${dtAmount}`)
2020-10-21 00:31:32 +02:00
setStepCreatePricing(3)
const response = isPool
? // TODO: in ocean.js: ocean.pool.createDTPool should be ocean.pool.create
// And if it involves mutliple wallet interacts the method itself should emit step events.
await ocean.pool.createDTPool(
2020-10-19 11:47:12 +02:00
accountId,
dataToken,
2020-10-21 00:31:32 +02:00
`${dtAmount}`,
weightOnDataToken,
swapFee
2020-10-19 11:47:12 +02:00
)
2020-10-21 00:31:32 +02:00
: // TODO: in ocean.js: ocean.fixedRateExchange.create should return tx receipt
await ocean.fixedRateExchange.create(dataToken, `${price}`, accountId)
// TODO: why is approve after the creation?
if (!isPool && config.fixedRateExchangeAddress) {
setStepCreatePricing(1)
await ocean.datatokens.approve(
dataToken,
config.fixedRateExchangeAddress,
`${dtAmount}`,
accountId
)
2020-10-19 11:47:12 +02:00
}
2020-10-21 00:31:32 +02:00
setStepCreatePricing(4)
return response
2020-10-19 11:47:12 +02:00
} catch (error) {
setPricingError(error.message)
Logger.error(error)
} finally {
setPricingStep(undefined)
setPricingStepText(undefined)
setPricingIsLoading(false)
2020-10-14 13:55:18 +02:00
}
}
2020-10-14 14:05:45 +02:00
2020-10-14 13:55:18 +02:00
return {
2020-10-19 12:44:31 +02:00
dtSymbol,
dtName,
2020-10-19 11:47:12 +02:00
createPricing,
2020-10-14 13:55:18 +02:00
buyDT,
sellDT,
2020-10-19 11:47:12 +02:00
mint,
pricingStep,
pricingStepText,
pricingIsLoading,
pricingError
2020-10-14 13:55:18 +02:00
}
}
2020-10-19 11:47:12 +02:00
export { usePricing, UsePricing }
export default usePricing