react/src/hooks/usePricing/usePricing.ts

292 lines
7.7 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 { Decimal } from 'decimal.js'
2020-10-21 13:37:01 +02:00
import {
getFirstPoolPrice,
2020-10-21 13:37:01 +02:00
getCreatePricingPoolFeedback,
getCreatePricingExchangeFeedback,
getBuyDTFeedback,
2020-10-22 10:44:36 +02:00
getSellDTFeedback,
sleep,
getDataTokenPrice
2020-10-22 10:44:36 +02:00
} from 'utils'
2020-10-14 13:55:18 +02:00
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>
2020-10-27 17:29:09 +01:00
mint: (tokensToMint: string) => Promise<TransactionReceipt | void>
2020-10-19 11:47:12 +02:00
pricingStep?: number
pricingStepText?: string
pricingError?: string
pricingIsLoading: boolean
2020-10-14 13:55:18 +02:00
}
function usePricing(ddo: DDO): UsePricing {
2020-10-21 13:48:59 +02:00
const { ocean, 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-21 13:37:01 +02:00
// Helper for setting steps & feedback for all flows
function setStep(index: number, type: 'pool' | 'exchange' | 'buy' | 'sell') {
2020-10-19 11:47:12 +02:00
setPricingStep(index)
2020-10-21 12:32:43 +02:00
if (!dtSymbol) return
2020-10-19 11:47:12 +02:00
2020-10-21 13:37:01 +02:00
let messages
switch (type) {
case 'pool':
messages = getCreatePricingPoolFeedback(dtSymbol)
break
case 'exchange':
messages = getCreatePricingExchangeFeedback(dtSymbol)
break
case 'buy':
messages = getBuyDTFeedback(dtSymbol)
break
case 'sell':
messages = getSellDTFeedback(dtSymbol)
break
}
2020-10-21 12:32:43 +02:00
setPricingStepText(messages[index])
2020-10-14 13:55:18 +02:00
}
2020-10-27 17:16:34 +01:00
async function mint(
tokensToMint: string
): Promise<TransactionReceipt | void> {
Logger.log('mint function', dataToken, accountId)
2020-10-27 17:22:22 +01:00
const balance = new Decimal(
await ocean.datatokens.balance(dataToken, accountId)
)
const tokens = new Decimal(tokensToMint)
2020-10-27 17:23:52 +01:00
if (tokens.greaterThan(balance)) {
2020-10-27 17:22:22 +01:00
const mintAmount = tokens.minus(balance)
const tx = await ocean.datatokens.mint(
dataToken,
accountId,
mintAmount.toString()
)
2020-10-27 17:16:34 +01:00
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> {
2020-10-21 13:48:59 +02:00
if (!ocean || !accountId) return
let tx
2020-10-14 13:55:18 +02:00
try {
2020-10-19 11:47:12 +02:00
setPricingIsLoading(true)
setPricingError(undefined)
2020-10-21 13:37:01 +02:00
setStep(1, 'buy')
const bestPrice = await await getDataTokenPrice(
ocean,
ddo.dataToken,
ddo?.price?.type,
ddo.price.address
)
Logger.log('Price found for buying', bestPrice)
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-21 13:37:01 +02:00
setStep(2, 'buy')
2020-10-21 13:48:59 +02:00
Logger.log('Buying token from pool', bestPrice, accountId, price)
tx = await ocean.pool.buyDT(
accountId,
2020-10-14 13:55:18 +02:00
bestPrice.address,
String(dtAmount),
price,
maxPrice
)
2020-10-21 13:37:01 +02:00
setStep(3, 'buy')
2020-10-21 13:48:59 +02:00
Logger.log('DT buy response', tx)
break
2020-10-14 13:55:18 +02:00
}
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
}
2020-10-21 13:48:59 +02:00
Logger.log('Buying token from exchange', bestPrice, accountId)
2020-10-14 13:55:18 +02:00
await ocean.datatokens.approve(
config.oceanTokenAddress,
config.fixedRateExchangeAddress,
2020-10-21 13:48:59 +02:00
`${bestPrice.value}`,
accountId
2020-10-14 13:55:18 +02:00
)
2020-10-21 13:37:01 +02:00
setStep(2, 'buy')
2020-10-21 13:48:59 +02:00
tx = await ocean.fixedRateExchange.buyDT(
2020-10-14 13:55:18 +02:00
bestPrice.address,
2020-10-21 13:48:59 +02:00
`${dtAmount}`,
accountId
2020-10-14 13:55:18 +02:00
)
2020-10-21 13:37:01 +02:00
setStep(3, 'buy')
2020-10-21 13:48:59 +02:00
Logger.log('DT exchange buy response', tx)
break
2020-10-14 13:55:18 +02:00
}
}
} 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-21 13:37:01 +02:00
setStep(0, 'buy')
2020-10-19 11:47:12 +02:00
setPricingStepText(undefined)
setPricingIsLoading(false)
2020-10-14 13:55:18 +02:00
}
2020-10-21 13:48:59 +02:00
return tx
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> {
2020-10-21 13:48:59 +02:00
if (!ocean || !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-21 13:37:01 +02:00
setStep(1, 'sell')
const pool = await getFirstPoolPrice(ocean, dataToken)
if (!pool || pool.value === 0) return
const price = new Decimal(pool.value).times(0.95).toString()
2020-10-21 13:37:01 +02:00
setStep(2, 'sell')
2020-10-21 13:48:59 +02:00
Logger.log('Selling token to pool', pool, accountId, price)
const tx = await ocean.pool.sellDT(
accountId,
2020-10-14 14:05:45 +02:00
pool.address,
2020-10-21 13:48:59 +02:00
`${dtAmount}`,
2020-10-14 14:05:45 +02:00
price
)
2020-10-21 13:37:01 +02:00
setStep(3, 'sell')
2020-10-21 13:48:59 +02:00
Logger.log('DT sell response', tx)
return tx
2020-10-14 13:55:18 +02:00
} 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-21 13:37:01 +02:00
setStep(0, 'sell')
2020-10-19 11:47:12 +02:00
setPricingStepText(undefined)
setPricingIsLoading(false)
}
}
async function createPricing(
priceOptions: PriceOptions
2020-10-21 14:24:37 +02:00
): Promise<TransactionReceipt | void> {
2020-10-21 13:48:59 +02:00
if (!ocean || !accountId || !dtSymbol) return
2020-10-21 00:31:32 +02:00
const {
type,
oceanAmount,
price,
weightOnDataToken,
swapFee
} = priceOptions
let { dtAmount } = priceOptions
2020-10-21 00:31:32 +02:00
const isPool = type === 'dynamic'
if (!isPool && !config.fixedRateExchangeAddress) {
Logger.error(`'fixedRateExchangeAddress' not set in config.`)
2020-10-21 00:31:32 +02:00
return
}
2020-10-19 11:47:12 +02:00
2020-10-21 12:32:43 +02:00
setPricingIsLoading(true)
setPricingError(undefined)
2020-10-21 13:37:01 +02:00
2020-10-21 14:24:37 +02:00
setStep(99, 'pool')
2020-10-21 00:31:32 +02:00
2020-10-21 12:32:43 +02:00
try {
// if fixedPrice set dt to max amount
if (!isPool) dtAmount = 1000
2020-10-21 00:31:32 +02:00
await mint(`${dtAmount}`)
// dtAmount for fixed price is set to max
2020-10-21 14:24:37 +02:00
const tx = isPool
? await ocean.pool
.create(
accountId,
dataToken,
`${dtAmount}`,
weightOnDataToken,
`${oceanAmount}`,
2020-10-21 14:24:37 +02:00
swapFee
)
.next((step: number) => setStep(step, 'pool'))
: await ocean.fixedRateExchange
.create(dataToken, `${price}`, accountId, `${dtAmount}`)
2020-10-21 14:24:37 +02:00
.next((step: number) => setStep(step, 'exchange'))
2020-10-21 17:21:26 +02:00
await sleep(20000)
2020-10-21 14:24:37 +02:00
return tx
2020-10-19 11:47:12 +02:00
} catch (error) {
setPricingError(error.message)
Logger.error(error)
} finally {
2020-10-21 12:32:43 +02:00
setPricingStep(0)
2020-10-19 11:47:12 +02:00
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