1
0
mirror of https://github.com/oceanprotocol/market.git synced 2024-06-28 00:27:49 +02:00
market/src/@utils/accessDetailsAndPricing.ts
Bogdan Fazakas 5387b9a3dd
Restore compute functionality (#1069)
* add balance check and check is consumable

* add isOrderable and other helpers

* finish start compute job

* removed unused methods

* add more comments

* add pool logic for order

* move asset selection to compute helper

* small fix

* fixed get algo list

* refactor start compute job and more fixes

* update order params

* use compute env and compute consumer address

* fix prices

* fix algorithms selection list on allowAllPublisher case

* fix edit compute settings

* update compute resources valid until logic

* fixes and cleanups

* wip compute jobs

* fix compute timeout value

* fixed compute jobs logic

* fix algo selection list name

* fixed compute jobs from profile loading

* update start compute flow messages

* update set algo access details

* update compute message logic

* added logs

* update package lock

* remove logs

* fix edit compute checksums for files and container

* Fix compute dataset algorithm list (#1194)

* fix query

Signed-off-by: mihaisc <mihai.scarlat@smartcontrol.ro>

* remove comment

Signed-off-by: mihaisc <mihai.scarlat@smartcontrol.ro>

* Fix previous order tx (#1197)

* rename nft update query

Signed-off-by: mihaisc <mihai.scarlat@smartcontrol.ro>

* fix previous order

Signed-off-by: mihaisc <mihai.scarlat@smartcontrol.ro>

* fix build

* handle order price, NaN and default 0

* optional value for all fee, prevent breaking when no value

* fix aquarius call and added logs

* update provider compute status call

* remove percentage fee from price sum, depends smart contract calculation (#1249)

Co-authored-by: Soon Huat <soon_huat.phan@daimler.com>

* fix display of compute datasets with free price

* removed to lowerCase on eth address

* fix compute jobs section and your jobs

* bumo ocean lib to 1.0.0-next.32

* c2d show price with fee, exclude provider fee

* wip get results

* include loading when calculating data + algo price, tooltip show order price

* update get compute url and use oceanjs helper for download

* update computeStatus signature to fix build and CI

* added logs

* refactor setting price and fees for assets

* update compute details and compute results UI and style

* update flex value

* update download buttons style

* update download buttons text

* bump ocean lib version and lint fixes

* get provier uri for compute results based on job input did

* use zero adress for price and fees order

* some fixes

* Add reuse order in start compute flow  (#1352)

* wip add reuse order logic

* add reuse order in start job

* added missing check if no jobs found

* update lib

Signed-off-by: mihaisc <mihai.scarlat@smartcontrol.ro>

* fix lint

Signed-off-by: mihaisc <mihai.scarlat@smartcontrol.ro>

Co-authored-by: mihaisc <mihai.scarlat@smartcontrol.ro>

* fix fixed rate

* fix build

* fix your compute jobs section when asset network not selected

* disable edit compute settings for algorithms

* fix compute jobs infinite loading when no jobs found

* fix compute form

* show token symbol for free assets also on compute price output

* removed swp file

* some decimal fixes

* partial fix for asset with pool fees, algo not working yet

* more decimal fixes

* fix algo with pool price and fees fetching

* fix selecting algorithms when on different network

* fix compute jobs table auto refresh and details  modal closing

* wip compute initialize

* order fixes

* fix lint

* fix conditions and cleanups

* fix compute status text display

* init prices and fees after starting a compute job

* start/order button tweaks

* kick in loader earlier

* update compute status feedback messages

* fixed initial price

* compute jobs refetch and reuse order

* remove logs

* removed logs and added some explanations

* use compute env max duration value in seconds

* error handling on intializeCompute and order

* removed console logs and added one new check

* use optional on initialized provider check

* remove toast from provider helper

* fix compute env issue on start order

* disable job selection during actions execution

* temporary fix publish algo with custom docker image

* fix provider fee display

* remove unnecessary condition

* fix alignment based button on action type (#1491)

* fix alignment based on action type

* moving to CSS modules

* send providerFeeAmount as string

* remove cast on providerFeeAmount

* removed some logs and added few comments

* update price output tooltip and total price logic

* set providerFee amount only when avaialable

* bump oceanlib to 1.1.2

* replace FIleMetadata to fix build

* used approveWei for approving provider fees

* fix free algo price selection and display

* fix provider fee load at first algo selection

* update compute help text

* fix provider fee approve for free assets

* cleanup

* remove commented out code
* remove unused state
* removed unused imports
* typos in comments, variables, props

* more typos

* shorten getAccessDetailsFromTokenPrice() a bit

* state & hooks access reordering

* Update src/@utils/ddo.ts

remove metadata from service type

Co-authored-by: Matthias Kretschmann <m@kretschmann.io>

* effect dependency fixes

* state renaming

* effect dependency fixes

* compute jobs profile visual fixes

* effect dependency fixes

* more comments removal

* add accountId as a dependency in effect

* move isOwner to asset provider

* refactor handleComputeOrder for less complexity and more useful error reporting

* more proper error throwing

* provider fee statement tweak

* more obvious edit action

* empty array for `publisherTrustedAlgorithms` & `publisherTrustedAlgorithmPublishers` by default

* ref #1538
* ref #1539

* don t use initial tx values as valid order use subgraph value

* fix algo list fetching

* closes #1537
* addresses #1538

* fix disable compute button if algo is consumable

* move isOwner check to single effect

* Correctly display trusted algorithms in compute asset (#1541)

* fix allowed algo

* fix trusted algo filter

Co-authored-by: mihaisc <mihai.scarlat@smartcontrol.ro>
Co-authored-by: Soon Huat <soon_huat.phan@daimler.com>
Co-authored-by: Soon Huat <soonhuat.phan@hotmail.com>
Co-authored-by: Enzo Vezzaro <enzo-vezzaro@live.it>
Co-authored-by: Matthias Kretschmann <m@kretschmann.io>
Co-authored-by: mihaisc <mihai@oceanprotocol.com>
2022-06-23 16:53:05 +01:00

407 lines
11 KiB
TypeScript

import { gql, OperationResult } from 'urql'
import { fetchData, getQueryContext } from './subgraph'
import {
TokenPriceQuery,
TokenPriceQuery_token as TokenPrice
} from '../@types/subgraph/TokenPriceQuery'
import {
TokensPriceQuery,
TokensPriceQuery_tokens as TokensPrice
} from '../@types/subgraph/TokensPriceQuery'
import {
Asset,
LoggerInstance,
ProviderFees,
ProviderInstance
} from '@oceanprotocol/lib'
import { AssetExtended } from 'src/@types/AssetExtended'
import { calcInGivenOut } from './pool'
import { getFixedBuyPrice } from './fixedRateExchange'
import { AccessDetails, OrderPriceAndFees } from 'src/@types/Price'
import Decimal from 'decimal.js'
import { consumeMarketOrderFee } from '../../app.config'
import Web3 from 'web3'
const tokensPriceQuery = gql`
query TokensPriceQuery($datatokenIds: [ID!], $account: String) {
tokens(where: { id_in: $datatokenIds }) {
id
symbol
name
publishMarketFeeAddress
publishMarketFeeToken
publishMarketFeeAmount
orders(
where: { payer: $account }
orderBy: createdTimestamp
orderDirection: desc
) {
tx
serviceIndex
createdTimestamp
reuses(orderBy: createdTimestamp, orderDirection: desc) {
id
caller
createdTimestamp
tx
block
}
}
dispensers {
id
active
isMinter
maxBalance
token {
id
name
symbol
}
}
fixedRateExchanges {
id
exchangeId
price
publishMarketSwapFee
baseToken {
symbol
name
address
}
datatoken {
symbol
name
address
}
active
}
pools {
id
spotPrice
isFinalized
datatokenLiquidity
baseToken {
symbol
name
address
}
datatoken {
symbol
name
address
}
}
}
}
`
const tokenPriceQuery = gql`
query TokenPriceQuery($datatokenId: ID!, $account: String) {
token(id: $datatokenId) {
id
symbol
name
publishMarketFeeAddress
publishMarketFeeToken
publishMarketFeeAmount
orders(
where: { payer: $account }
orderBy: createdTimestamp
orderDirection: desc
) {
tx
serviceIndex
createdTimestamp
reuses(orderBy: createdTimestamp, orderDirection: desc) {
id
caller
createdTimestamp
tx
block
}
}
dispensers {
id
active
isMinter
maxBalance
token {
id
name
symbol
}
}
fixedRateExchanges {
id
exchangeId
price
publishMarketSwapFee
baseToken {
symbol
name
address
}
datatoken {
symbol
name
address
}
active
}
pools {
id
spotPrice
isFinalized
datatokenLiquidity
baseToken {
symbol
name
address
}
datatoken {
symbol
name
address
}
}
}
}
`
function getAccessDetailsFromTokenPrice(
tokenPrice: TokenPrice | TokensPrice,
timeout?: number
): AccessDetails {
const accessDetails = {} as AccessDetails
if (tokenPrice?.orders?.length > 0) {
const order = tokenPrice.orders[0]
const reusedOrder = order?.reuses?.length > 0 ? order.reuses[0] : null
// asset is owned if there is an order and asset has timeout 0 (forever) or if the condition is valid
accessDetails.isOwned =
timeout === 0 || Date.now() / 1000 - order?.createdTimestamp < timeout
// the last valid order should be the last reuse order tx id if there is one
accessDetails.validOrderTx = reusedOrder?.tx || order?.tx
}
// TODO: fetch order fee from sub query
accessDetails.publisherMarketOrderFee = tokenPrice?.publishMarketFeeAmount
// free is always the best price
if (tokenPrice?.dispensers?.length > 0) {
const dispenser = tokenPrice.dispensers[0]
accessDetails.type = 'free'
accessDetails.addressOrId = dispenser.token.id
accessDetails.price = '0'
accessDetails.isPurchasable = dispenser.active
accessDetails.datatoken = {
address: dispenser.token.id,
name: dispenser.token.name,
symbol: dispenser.token.symbol
}
return accessDetails
}
// checking for fixed price
if (tokenPrice?.fixedRateExchanges?.length > 0) {
const fixed = tokenPrice.fixedRateExchanges[0]
accessDetails.type = 'fixed'
accessDetails.addressOrId = fixed.exchangeId
accessDetails.price = fixed.price
// in theory we should check dt balance here, we can skip this because in the market we always create fre with minting capabilities.
accessDetails.isPurchasable = fixed.active
accessDetails.baseToken = {
address: fixed.baseToken.address,
name: fixed.baseToken.name,
symbol: fixed.baseToken.symbol
}
accessDetails.datatoken = {
address: fixed.datatoken.address,
name: fixed.datatoken.name,
symbol: fixed.datatoken.symbol
}
return accessDetails
}
// checking for pools
if (tokenPrice?.pools?.length > 0) {
const pool = tokenPrice.pools[0]
accessDetails.type = 'dynamic'
accessDetails.addressOrId = pool.id
accessDetails.price = pool.spotPrice
// TODO: pool.datatokenLiquidity > 3 is kinda random here, we shouldn't run into this anymore now , needs more thinking/testing
accessDetails.isPurchasable =
pool.isFinalized && pool.datatokenLiquidity > 3
accessDetails.baseToken = {
address: pool.baseToken.address,
name: pool.baseToken.name,
symbol: pool.baseToken.symbol
}
accessDetails.datatoken = {
address: pool.datatoken.address,
name: pool.datatoken.name,
symbol: pool.datatoken.symbol
}
return accessDetails
}
return accessDetails
}
/**
* This will be used to get price including fees before ordering
* @param {AssetExtended} asset
* @return {Promise<OrdePriceAndFee>}
*/
export async function getOrderPriceAndFees(
asset: AssetExtended,
accountId?: string,
paramsForPool?: CalcInGivenOutParams,
providerFees?: ProviderFees
): Promise<OrderPriceAndFees> {
const orderPriceAndFee = {
price: '0',
publisherMarketOrderFee:
asset?.accessDetails?.publisherMarketOrderFee || '0',
publisherMarketPoolSwapFee: '0',
publisherMarketFixedSwapFee: '0',
consumeMarketOrderFee: consumeMarketOrderFee || '0',
consumeMarketPoolSwapFee: '0',
consumeMarketFixedSwapFee: '0',
providerFee: {
providerFeeAmount: '0'
},
opcFee: '0'
} as OrderPriceAndFees
// fetch provider fee
const initializeData =
!providerFees &&
(await ProviderInstance.initialize(
asset?.id,
asset?.services[0].id,
0,
accountId,
asset?.services[0].serviceEndpoint
))
orderPriceAndFee.providerFee = providerFees || initializeData.providerFee
// fetch price and swap fees
switch (asset?.accessDetails?.type) {
case 'dynamic': {
const poolPrice = calcInGivenOut(paramsForPool)
orderPriceAndFee.price = poolPrice.tokenAmount
orderPriceAndFee.liquidityProviderSwapFee =
poolPrice.liquidityProviderSwapFeeAmount
orderPriceAndFee.publisherMarketPoolSwapFee =
poolPrice.publishMarketSwapFeeAmount
orderPriceAndFee.consumeMarketPoolSwapFee =
poolPrice.consumeMarketSwapFeeAmount
break
}
case 'fixed': {
const fixed = await getFixedBuyPrice(asset?.accessDetails, asset?.chainId)
orderPriceAndFee.price = fixed.baseTokenAmount
orderPriceAndFee.opcFee = fixed.oceanFeeAmount
orderPriceAndFee.publisherMarketFixedSwapFee = fixed.marketFeeAmount
orderPriceAndFee.consumeMarketFixedSwapFee = fixed.consumeMarketFeeAmount
break
}
}
// calculate full price, we assume that all the values are in ocean, otherwise this will be incorrect
orderPriceAndFee.price = new Decimal(+orderPriceAndFee.price || 0)
.add(new Decimal(+orderPriceAndFee?.consumeMarketOrderFee || 0))
.add(new Decimal(+orderPriceAndFee?.publisherMarketOrderFee || 0))
.toString()
return orderPriceAndFee
}
/**
* @param {number} chainId
* @param {string} datatokenAddress
* @param {number} timeout timout of the service, this is needed to return order details
* @param {string} account account that wants to buy, is needed to return order details
* @returns {Promise<AccessDetails>}
*/
export async function getAccessDetails(
chainId: number,
datatokenAddress: string,
timeout?: number,
account = ''
): Promise<AccessDetails> {
try {
const queryContext = getQueryContext(Number(chainId))
const tokenQueryResult: OperationResult<
TokenPriceQuery,
{ datatokenId: string; account: string }
> = await fetchData(
tokenPriceQuery,
{
datatokenId: datatokenAddress.toLowerCase(),
account: account?.toLowerCase()
},
queryContext
)
const tokenPrice: TokenPrice = tokenQueryResult.data.token
const accessDetails = getAccessDetailsFromTokenPrice(tokenPrice, timeout)
return accessDetails
} catch (error) {
LoggerInstance.error('Error getting access details: ', error.message)
}
}
export async function getAccessDetailsForAssets(
assets: Asset[],
account = ''
): Promise<AssetExtended[]> {
const assetsExtended: AssetExtended[] = assets
const chainAssetLists: { [key: number]: string[] } = {}
try {
for (const asset of assets) {
if (chainAssetLists[asset.chainId]) {
chainAssetLists[asset.chainId].push(
asset.services[0].datatokenAddress.toLowerCase()
)
} else {
chainAssetLists[asset.chainId] = []
chainAssetLists[asset.chainId].push(
asset.services[0].datatokenAddress.toLowerCase()
)
}
}
for (const chainKey in chainAssetLists) {
const queryContext = getQueryContext(Number(chainKey))
const tokenQueryResult: OperationResult<
TokensPriceQuery,
{ datatokenIds: [string]; account: string }
> = await fetchData(
tokensPriceQuery,
{
datatokenIds: chainAssetLists[chainKey],
account: account?.toLowerCase()
},
queryContext
)
tokenQueryResult.data?.tokens.forEach((token) => {
const currentAsset = assetsExtended.find(
(asset) =>
asset.services[0].datatokenAddress.toLowerCase() === token.id
)
const accessDetails = getAccessDetailsFromTokenPrice(
token,
currentAsset?.services[0]?.timeout
)
currentAsset.accessDetails = accessDetails
})
}
return assetsExtended
} catch (error) {
LoggerInstance.error('Error getting access details: ', error.message)
}
}