mirror of
https://github.com/oceanprotocol/market.git
synced 2024-12-02 05:57:29 +01:00
Merge branch 'main' into orbis
This commit is contained in:
commit
728f79cf69
@ -3,6 +3,7 @@ import { assetAquarius } from './assetAquarius'
|
||||
export const asset: AssetExtended = {
|
||||
...assetAquarius,
|
||||
accessDetails: {
|
||||
templateId: 1,
|
||||
publisherMarketOrderFee: '0',
|
||||
type: 'fixed',
|
||||
addressOrId:
|
||||
|
@ -73,6 +73,7 @@ export const assets: AssetExtended[] = [
|
||||
},
|
||||
version: '4.1.0',
|
||||
accessDetails: {
|
||||
templateId: 1,
|
||||
type: 'NOT_SUPPORTED'
|
||||
} as any
|
||||
},
|
||||
@ -159,6 +160,7 @@ export const assets: AssetExtended[] = [
|
||||
},
|
||||
version: '4.1.0',
|
||||
accessDetails: {
|
||||
templateId: 1,
|
||||
publisherMarketOrderFee: '0',
|
||||
type: 'fixed',
|
||||
addressOrId:
|
||||
@ -252,6 +254,7 @@ export const assets: AssetExtended[] = [
|
||||
},
|
||||
version: '4.1.0',
|
||||
accessDetails: {
|
||||
templateId: 2,
|
||||
publisherMarketOrderFee: '0',
|
||||
type: 'fixed',
|
||||
addressOrId:
|
||||
@ -345,6 +348,7 @@ export const assets: AssetExtended[] = [
|
||||
},
|
||||
version: '4.1.0',
|
||||
accessDetails: {
|
||||
templateId: 1,
|
||||
publisherMarketOrderFee: '0',
|
||||
type: 'fixed',
|
||||
addressOrId:
|
||||
@ -444,6 +448,7 @@ export const assets: AssetExtended[] = [
|
||||
},
|
||||
version: '4.1.0',
|
||||
accessDetails: {
|
||||
templateId: 1,
|
||||
publisherMarketOrderFee: '0',
|
||||
type: 'fixed',
|
||||
addressOrId:
|
||||
@ -468,6 +473,7 @@ export const assets: AssetExtended[] = [
|
||||
{
|
||||
'@context': ['https://w3id.org/did/v1'],
|
||||
accessDetails: {
|
||||
templateId: 1,
|
||||
publisherMarketOrderFee: '0',
|
||||
type: 'fixed',
|
||||
addressOrId:
|
||||
@ -660,6 +666,7 @@ export const assets: AssetExtended[] = [
|
||||
},
|
||||
version: '4.1.0',
|
||||
accessDetails: {
|
||||
templateId: 1,
|
||||
publisherMarketOrderFee: '0',
|
||||
type: 'fixed',
|
||||
addressOrId:
|
||||
@ -753,6 +760,7 @@ export const assets: AssetExtended[] = [
|
||||
},
|
||||
version: '4.1.0',
|
||||
accessDetails: {
|
||||
templateId: 1,
|
||||
publisherMarketOrderFee: '0',
|
||||
type: 'fixed',
|
||||
addressOrId:
|
||||
@ -843,6 +851,7 @@ export const assets: AssetExtended[] = [
|
||||
},
|
||||
version: '4.1.0',
|
||||
accessDetails: {
|
||||
templateId: 1,
|
||||
publisherMarketOrderFee: '0',
|
||||
type: 'free',
|
||||
addressOrId: '0x0a81f1c69e5428067e6124817c7affe8bc0adf9f',
|
||||
@ -927,6 +936,7 @@ export const assets: AssetExtended[] = [
|
||||
},
|
||||
version: '4.1.0',
|
||||
accessDetails: {
|
||||
templateId: 1,
|
||||
publisherMarketOrderFee: '0',
|
||||
type: 'fixed',
|
||||
addressOrId:
|
||||
@ -1015,6 +1025,7 @@ export const assets: AssetExtended[] = [
|
||||
},
|
||||
version: '4.1.0',
|
||||
accessDetails: {
|
||||
templateId: 2,
|
||||
publisherMarketOrderFee: '0',
|
||||
type: 'free',
|
||||
addressOrId: '0x772224c2c2bddb88a55b3905aaaf8c7188b02ce3',
|
||||
@ -1099,6 +1110,7 @@ export const assets: AssetExtended[] = [
|
||||
},
|
||||
version: '4.1.0',
|
||||
accessDetails: {
|
||||
templateId: 2,
|
||||
publisherMarketOrderFee: '0',
|
||||
type: 'free',
|
||||
addressOrId: '0x89a0170556bb80438081d69f43d8c07a90e9aa24',
|
||||
@ -1181,6 +1193,7 @@ export const assets: AssetExtended[] = [
|
||||
},
|
||||
version: '4.1.0',
|
||||
accessDetails: {
|
||||
templateId: 2,
|
||||
publisherMarketOrderFee: '0',
|
||||
type: 'free',
|
||||
addressOrId: '0xad42c7afee47140b5cd87f05d5846c418145f43a',
|
||||
@ -1335,6 +1348,7 @@ export const assets: AssetExtended[] = [
|
||||
},
|
||||
version: '4.1.0',
|
||||
accessDetails: {
|
||||
templateId: 2,
|
||||
publisherMarketOrderFee: '0',
|
||||
type: 'fixed',
|
||||
addressOrId:
|
||||
@ -1423,6 +1437,7 @@ export const assets: AssetExtended[] = [
|
||||
},
|
||||
version: '4.1.0',
|
||||
accessDetails: {
|
||||
templateId: 2,
|
||||
publisherMarketOrderFee: '0',
|
||||
type: 'free',
|
||||
addressOrId: '0x23c1fd10dadcaf558fb7173b79cfd0d867568a3d',
|
||||
@ -1514,6 +1529,7 @@ export const assets: AssetExtended[] = [
|
||||
},
|
||||
version: '4.1.0',
|
||||
accessDetails: {
|
||||
templateId: 2,
|
||||
publisherMarketOrderFee: '0',
|
||||
type: 'fixed',
|
||||
addressOrId:
|
||||
|
@ -18,6 +18,7 @@ module.exports = {
|
||||
|
||||
infuraProjectId: process.env.NEXT_PUBLIC_INFURA_PROJECT_ID || 'xxx',
|
||||
|
||||
defaultDatatokenTemplateIndex: 2,
|
||||
// The ETH address the marketplace fee will be sent to.
|
||||
marketFeeAddress:
|
||||
process.env.NEXT_PUBLIC_MARKET_FEE_ADDRESS ||
|
||||
|
@ -66,6 +66,13 @@
|
||||
"type": "tags",
|
||||
"placeholder": "e.g. logistics",
|
||||
"required": false
|
||||
},
|
||||
{
|
||||
"name": "paymentCollector",
|
||||
"label": "Payment Collector Address",
|
||||
"placeholder": "e.g. 0X123ABC...",
|
||||
"help": "This address will receive the revenue from all sales. More info available in our [docs](https://docs.oceanprotocol.com/core-concepts/datanft-and-datatoken#revenue).",
|
||||
"required": false
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ export interface AppConfig {
|
||||
infuraProjectId: string
|
||||
chainIds: number[]
|
||||
chainIdsSupported: number[]
|
||||
defaultDatatokenTemplateIndex: number
|
||||
marketFeeAddress: string
|
||||
publisherMarketOrderFee: string
|
||||
publisherMarketFixedSwapFee: string
|
||||
|
1
src/@types/Price.d.ts
vendored
1
src/@types/Price.d.ts
vendored
@ -39,6 +39,7 @@ declare global {
|
||||
interface AccessDetails {
|
||||
type: 'fixed' | 'free' | 'NOT_SUPPORTED'
|
||||
price: string
|
||||
templateId: number
|
||||
addressOrId: string
|
||||
baseToken: TokenInfo
|
||||
datatoken: TokenInfo
|
||||
|
@ -30,6 +30,7 @@ const tokensPriceQuery = gql`
|
||||
publishMarketFeeAddress
|
||||
publishMarketFeeToken
|
||||
publishMarketFeeAmount
|
||||
templateId
|
||||
orders(
|
||||
where: { payer: $account }
|
||||
orderBy: createdTimestamp
|
||||
@ -84,6 +85,7 @@ const tokenPriceQuery = gql`
|
||||
id
|
||||
symbol
|
||||
name
|
||||
templateId
|
||||
publishMarketFeeAddress
|
||||
publishMarketFeeToken
|
||||
publishMarketFeeAmount
|
||||
@ -160,7 +162,7 @@ function getAccessDetailsFromTokenPrice(
|
||||
// the last valid order should be the last reuse order tx id if there is one
|
||||
accessDetails.validOrderTx = reusedOrder?.tx || order?.tx
|
||||
}
|
||||
|
||||
accessDetails.templateId = tokenPrice.templateId
|
||||
// TODO: fetch order fee from sub query
|
||||
accessDetails.publisherMarketOrderFee = tokenPrice?.publishMarketFeeAmount
|
||||
|
||||
@ -169,6 +171,7 @@ function getAccessDetailsFromTokenPrice(
|
||||
const dispenser = tokenPrice.dispensers[0]
|
||||
accessDetails.type = 'free'
|
||||
accessDetails.addressOrId = dispenser.token.id
|
||||
|
||||
accessDetails.price = '0'
|
||||
accessDetails.isPurchasable = dispenser.active
|
||||
accessDetails.datatoken = {
|
||||
|
@ -3,6 +3,8 @@ import {
|
||||
approve,
|
||||
approveWei,
|
||||
Datatoken,
|
||||
Dispenser,
|
||||
FixedRateExchange,
|
||||
FreOrderParams,
|
||||
LoggerInstance,
|
||||
OrderParams,
|
||||
@ -83,22 +85,6 @@ export async function order(
|
||||
switch (asset.accessDetails?.type) {
|
||||
case 'fixed': {
|
||||
// this assumes all fees are in ocean
|
||||
const txApprove = await approve(
|
||||
web3,
|
||||
config,
|
||||
accountId,
|
||||
asset.accessDetails.baseToken.address,
|
||||
asset.accessDetails.datatoken.address,
|
||||
await amountToUnits(
|
||||
web3,
|
||||
asset?.accessDetails?.baseToken?.address,
|
||||
orderPriceAndFees.price
|
||||
),
|
||||
false
|
||||
)
|
||||
if (!txApprove) {
|
||||
return
|
||||
}
|
||||
|
||||
const freParams = {
|
||||
exchangeContract: config.fixedRateExchangeAddress,
|
||||
@ -109,23 +95,96 @@ export async function order(
|
||||
swapMarketFee: consumeMarketFixedSwapFee,
|
||||
marketFeeAddress
|
||||
} as FreOrderParams
|
||||
const tx = await datatoken.buyFromFreAndOrder(
|
||||
asset.accessDetails.datatoken.address,
|
||||
accountId,
|
||||
orderParams,
|
||||
freParams
|
||||
)
|
||||
|
||||
return tx
|
||||
if (asset.accessDetails.templateId === 1) {
|
||||
// buy datatoken
|
||||
const txApprove = await approve(
|
||||
web3,
|
||||
config,
|
||||
accountId,
|
||||
asset.accessDetails.baseToken.address,
|
||||
config.fixedRateExchangeAddress,
|
||||
await amountToUnits(
|
||||
web3,
|
||||
asset?.accessDetails?.baseToken?.address,
|
||||
orderPriceAndFees.price
|
||||
),
|
||||
false
|
||||
)
|
||||
if (!txApprove) {
|
||||
return
|
||||
}
|
||||
const fre = new FixedRateExchange(config.fixedRateExchangeAddress, web3)
|
||||
const freTx = await fre.buyDatatokens(
|
||||
accountId,
|
||||
asset.accessDetails?.addressOrId,
|
||||
'1',
|
||||
orderPriceAndFees.price,
|
||||
marketFeeAddress,
|
||||
consumeMarketFixedSwapFee
|
||||
)
|
||||
|
||||
return await datatoken.startOrder(
|
||||
asset.accessDetails.datatoken.address,
|
||||
accountId,
|
||||
orderParams.consumer,
|
||||
orderParams.serviceIndex,
|
||||
orderParams._providerFee,
|
||||
orderParams._consumeMarketFee
|
||||
)
|
||||
}
|
||||
if (asset.accessDetails.templateId === 2) {
|
||||
const txApprove = await approve(
|
||||
web3,
|
||||
config,
|
||||
accountId,
|
||||
asset.accessDetails.baseToken.address,
|
||||
asset.accessDetails.datatoken.address,
|
||||
await amountToUnits(
|
||||
web3,
|
||||
asset?.accessDetails?.baseToken?.address,
|
||||
orderPriceAndFees.price
|
||||
),
|
||||
false
|
||||
)
|
||||
if (!txApprove) {
|
||||
return
|
||||
}
|
||||
return await datatoken.buyFromFreAndOrder(
|
||||
asset.accessDetails.datatoken.address,
|
||||
accountId,
|
||||
orderParams,
|
||||
freParams
|
||||
)
|
||||
}
|
||||
break
|
||||
}
|
||||
case 'free': {
|
||||
const tx = await datatoken.buyFromDispenserAndOrder(
|
||||
asset.services[0].datatokenAddress,
|
||||
accountId,
|
||||
orderParams,
|
||||
config.dispenserAddress
|
||||
)
|
||||
return tx
|
||||
if (asset.accessDetails.templateId === 1) {
|
||||
const dispenser = new Dispenser(config.dispenserAddress, web3)
|
||||
const dispenserTx = await dispenser.dispense(
|
||||
asset.accessDetails?.datatoken.address,
|
||||
accountId,
|
||||
'1',
|
||||
accountId
|
||||
)
|
||||
return await datatoken.startOrder(
|
||||
asset.accessDetails.datatoken.address,
|
||||
accountId,
|
||||
orderParams.consumer,
|
||||
orderParams.serviceIndex,
|
||||
orderParams._providerFee,
|
||||
orderParams._consumeMarketFee
|
||||
)
|
||||
}
|
||||
if (asset.accessDetails.templateId === 2) {
|
||||
return await datatoken.buyFromDispenserAndOrder(
|
||||
asset.services[0].datatokenAddress,
|
||||
accountId,
|
||||
orderParams,
|
||||
config.dispenserAddress
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,23 +2,9 @@ import { gql, OperationResult, TypedDocumentNode, OperationContext } from 'urql'
|
||||
import { LoggerInstance } from '@oceanprotocol/lib'
|
||||
import { getUrqlClientInstance } from '@context/UrqlProvider'
|
||||
import { getOceanConfig } from './ocean'
|
||||
import { AssetPreviousOrder } from '../@types/subgraph/AssetPreviousOrder'
|
||||
import { OrdersData_orders as OrdersData } from '../@types/subgraph/OrdersData'
|
||||
import { OpcFeesQuery as OpcFeesData } from '../@types/subgraph/OpcFeesQuery'
|
||||
|
||||
const PreviousOrderQuery = gql`
|
||||
query AssetPreviousOrder($id: String!, $account: String!) {
|
||||
orders(
|
||||
first: 1
|
||||
where: { datatoken: $id, payer: $account }
|
||||
orderBy: createdTimestamp
|
||||
orderDirection: desc
|
||||
) {
|
||||
createdTimestamp
|
||||
tx
|
||||
}
|
||||
}
|
||||
`
|
||||
import appConfig from '../../app.config'
|
||||
|
||||
const UserTokenOrders = gql`
|
||||
query OrdersData($user: String!) {
|
||||
@ -76,6 +62,11 @@ export function getSubgraphUri(chainId: number): string {
|
||||
|
||||
export function getQueryContext(chainId: number): OperationContext {
|
||||
try {
|
||||
if (!appConfig.chainIdsSupported.includes(chainId))
|
||||
throw Object.assign(
|
||||
new Error('network not supported, query context cancelled')
|
||||
)
|
||||
|
||||
const queryContext: OperationContext = {
|
||||
url: `${getSubgraphUri(
|
||||
Number(chainId)
|
||||
|
@ -21,6 +21,14 @@ export default function FilesInput(props: InputProps): ReactElement {
|
||||
? props.form?.values?.services[0].providerUrl.url
|
||||
: asset.services[0].serviceEndpoint
|
||||
setIsLoading(true)
|
||||
|
||||
// TODO: handled on provider
|
||||
if (url.includes('drive.google')) {
|
||||
throw Error(
|
||||
'Google Drive is not a supported hosting service. Please use an alternative.'
|
||||
)
|
||||
}
|
||||
|
||||
const checkedFile = await getFileUrlInfo(url, providerUrl)
|
||||
|
||||
// error if something's not right from response
|
||||
|
@ -2,6 +2,8 @@ import React, { FormEvent, ReactElement } from 'react'
|
||||
import Button from '../../../@shared/atoms/Button'
|
||||
import styles from './index.module.css'
|
||||
import Loader from '../../../@shared/atoms/Loader'
|
||||
import { useWeb3 } from '@context/Web3'
|
||||
import Web3 from 'web3'
|
||||
|
||||
export interface ButtonBuyProps {
|
||||
action: 'download' | 'compute'
|
||||
@ -28,12 +30,11 @@ export interface ButtonBuyProps {
|
||||
priceType?: string
|
||||
algorithmPriceType?: string
|
||||
isAlgorithmConsumable?: boolean
|
||||
isSupportedOceanNetwork?: boolean
|
||||
hasProviderFee?: boolean
|
||||
retry?: boolean
|
||||
}
|
||||
|
||||
// TODO: we need to take a look at these messages
|
||||
|
||||
function getConsumeHelpText(
|
||||
btSymbol: string,
|
||||
dtBalance: string,
|
||||
@ -43,12 +44,14 @@ function getConsumeHelpText(
|
||||
assetType: string,
|
||||
isConsumable: boolean,
|
||||
isBalanceSufficient: boolean,
|
||||
consumableFeedback: string
|
||||
consumableFeedback: string,
|
||||
isSupportedOceanNetwork: boolean,
|
||||
web3: Web3
|
||||
) {
|
||||
const text =
|
||||
isConsumable === false
|
||||
? consumableFeedback
|
||||
: hasPreviousOrder
|
||||
: hasPreviousOrder && web3 && isSupportedOceanNetwork
|
||||
? `You bought this ${assetType} already allowing you to use it without paying again.`
|
||||
: hasDatatoken
|
||||
? `You own ${dtBalance} ${dtSymbol} allowing you to use this dataset by spending 1 ${dtSymbol}, but without paying ${btSymbol} again.`
|
||||
@ -58,6 +61,35 @@ function getConsumeHelpText(
|
||||
return text
|
||||
}
|
||||
|
||||
function getAlgoHelpText(
|
||||
dtSymbolSelectedComputeAsset: string,
|
||||
dtBalanceSelectedComputeAsset: string,
|
||||
isConsumable: boolean,
|
||||
isAlgorithmConsumable: boolean,
|
||||
hasPreviousOrderSelectedComputeAsset: boolean,
|
||||
selectedComputeAssetType: string,
|
||||
hasDatatokenSelectedComputeAsset: boolean,
|
||||
isBalanceSufficient: boolean,
|
||||
isSupportedOceanNetwork: boolean,
|
||||
web3: Web3
|
||||
) {
|
||||
const text =
|
||||
(!dtSymbolSelectedComputeAsset && !dtBalanceSelectedComputeAsset) ||
|
||||
isConsumable === false ||
|
||||
isAlgorithmConsumable === false
|
||||
? ''
|
||||
: hasPreviousOrderSelectedComputeAsset && web3 && isSupportedOceanNetwork
|
||||
? `You already bought the selected ${selectedComputeAssetType}, allowing you to use it without paying again.`
|
||||
: hasDatatokenSelectedComputeAsset
|
||||
? `You own ${dtBalanceSelectedComputeAsset} ${dtSymbolSelectedComputeAsset} allowing you to use the selected ${selectedComputeAssetType} by spending 1 ${dtSymbolSelectedComputeAsset}, but without paying OCEAN again.`
|
||||
: web3 && !isSupportedOceanNetwork
|
||||
? `Connect to the correct network to interact with this asset.`
|
||||
: isBalanceSufficient === false
|
||||
? ''
|
||||
: `Additionally, you will buy 1 ${dtSymbolSelectedComputeAsset} for the ${selectedComputeAssetType} and spend it back to its publisher and pool.`
|
||||
return text
|
||||
}
|
||||
|
||||
function getComputeAssetHelpText(
|
||||
hasPreviousOrder: boolean,
|
||||
hasDatatoken: boolean,
|
||||
@ -74,6 +106,8 @@ function getComputeAssetHelpText(
|
||||
dtBalanceSelectedComputeAsset?: string,
|
||||
selectedComputeAssetType?: string,
|
||||
isAlgorithmConsumable?: boolean,
|
||||
isSupportedOceanNetwork?: boolean,
|
||||
web3?: Web3,
|
||||
hasProviderFee?: boolean
|
||||
) {
|
||||
const computeAssetHelpText = getConsumeHelpText(
|
||||
@ -85,21 +119,24 @@ function getComputeAssetHelpText(
|
||||
assetType,
|
||||
isConsumable,
|
||||
isBalanceSufficient,
|
||||
consumableFeedback
|
||||
consumableFeedback,
|
||||
isSupportedOceanNetwork,
|
||||
web3
|
||||
)
|
||||
|
||||
const computeAlgoHelpText = getAlgoHelpText(
|
||||
dtSymbolSelectedComputeAsset,
|
||||
dtBalanceSelectedComputeAsset,
|
||||
isConsumable,
|
||||
isAlgorithmConsumable,
|
||||
hasPreviousOrderSelectedComputeAsset,
|
||||
selectedComputeAssetType,
|
||||
hasDatatokenSelectedComputeAsset,
|
||||
isBalanceSufficient,
|
||||
isSupportedOceanNetwork,
|
||||
web3
|
||||
)
|
||||
|
||||
const computeAlgoHelpText =
|
||||
(!dtSymbolSelectedComputeAsset && !dtBalanceSelectedComputeAsset) ||
|
||||
isConsumable === false ||
|
||||
isAlgorithmConsumable === false
|
||||
? ''
|
||||
: hasPreviousOrderSelectedComputeAsset
|
||||
? `You already bought the selected ${selectedComputeAssetType}, allowing you to use it without paying again.`
|
||||
: hasDatatokenSelectedComputeAsset
|
||||
? `You own ${dtBalanceSelectedComputeAsset} ${dtSymbolSelectedComputeAsset} allowing you to use the selected ${selectedComputeAssetType} by spending 1 ${dtSymbolSelectedComputeAsset}, but without paying ${btSymbol} again.`
|
||||
: isBalanceSufficient === false
|
||||
? ''
|
||||
: `Additionally, you will buy 1 ${dtSymbolSelectedComputeAsset} for the ${selectedComputeAssetType} and spend it back to its publisher.`
|
||||
const providerFeeHelpText = hasProviderFee
|
||||
? 'In order to start the job you also need to pay the fees for renting the c2d resources.'
|
||||
: 'C2D resources required to start the job are available, no payment required for those fees.'
|
||||
@ -133,8 +170,10 @@ export default function ButtonBuy({
|
||||
algorithmPriceType,
|
||||
isAlgorithmConsumable,
|
||||
hasProviderFee,
|
||||
retry
|
||||
retry,
|
||||
isSupportedOceanNetwork
|
||||
}: ButtonBuyProps): ReactElement {
|
||||
const { web3 } = useWeb3()
|
||||
const buttonText = retry
|
||||
? 'Retry'
|
||||
: action === 'download'
|
||||
@ -177,7 +216,9 @@ export default function ButtonBuy({
|
||||
assetType,
|
||||
isConsumable,
|
||||
isBalanceSufficient,
|
||||
consumableFeedback
|
||||
consumableFeedback,
|
||||
isSupportedOceanNetwork,
|
||||
web3
|
||||
)
|
||||
: getComputeAssetHelpText(
|
||||
hasPreviousOrder,
|
||||
@ -195,6 +236,8 @@ export default function ButtonBuy({
|
||||
dtBalanceSelectedComputeAsset,
|
||||
selectedComputeAssetType,
|
||||
isAlgorithmConsumable,
|
||||
isSupportedOceanNetwork,
|
||||
web3,
|
||||
hasProviderFee
|
||||
)}
|
||||
</div>
|
||||
|
@ -9,7 +9,7 @@ import PriceOutput from './PriceOutput'
|
||||
import { useAsset } from '@context/Asset'
|
||||
import { useWeb3 } from '@context/Web3'
|
||||
import content from '../../../../../content/pages/startComputeDataset.json'
|
||||
import { Asset } from '@oceanprotocol/lib'
|
||||
import { Asset, ZERO_ADDRESS } from '@oceanprotocol/lib'
|
||||
import { getAccessDetails } from '@utils/accessDetailsAndPricing'
|
||||
import { useMarketMetadata } from '@context/MarketMetadata'
|
||||
import Alert from '@shared/atoms/Alert'
|
||||
@ -75,7 +75,7 @@ export default function FormStartCompute({
|
||||
retry: boolean
|
||||
}): ReactElement {
|
||||
const { siteContent } = useMarketMetadata()
|
||||
const { accountId, balance } = useWeb3()
|
||||
const { accountId, balance, isSupportedOceanNetwork } = useWeb3()
|
||||
const { isValid, values }: FormikContextType<{ algorithm: string }> =
|
||||
useFormikContext()
|
||||
const { asset, isAssetNetwork } = useAsset()
|
||||
@ -98,7 +98,7 @@ export default function FormStartCompute({
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (!values.algorithm || !accountId || !isConsumable) return
|
||||
if (!values.algorithm || !isConsumable) return
|
||||
|
||||
async function fetchAlgorithmAssetExtended() {
|
||||
const algorithmAsset = getAlgorithmAsset(values.algorithm)
|
||||
@ -106,7 +106,7 @@ export default function FormStartCompute({
|
||||
algorithmAsset.chainId,
|
||||
algorithmAsset.services[0].datatokenAddress,
|
||||
algorithmAsset.services[0].timeout,
|
||||
accountId
|
||||
accountId || ZERO_ADDRESS // if user is not connected, use ZERO_ADDRESS as accountId
|
||||
)
|
||||
const extendedAlgoAsset: AssetExtended = {
|
||||
...algorithmAsset,
|
||||
@ -198,15 +198,20 @@ export default function FormStartCompute({
|
||||
}
|
||||
setTotalPrices(totalPrices)
|
||||
}, [
|
||||
asset?.accessDetails,
|
||||
selectedAlgorithmAsset?.accessDetails,
|
||||
asset,
|
||||
hasPreviousOrder,
|
||||
hasDatatoken,
|
||||
hasPreviousOrderSelectedComputeAsset,
|
||||
hasDatatokenSelectedComputeAsset,
|
||||
datasetOrderPriceAndFees,
|
||||
algoOrderPriceAndFees,
|
||||
providerFeeAmount
|
||||
providerFeeAmount,
|
||||
isAssetNetwork,
|
||||
selectedAlgorithmAsset?.accessDetails,
|
||||
datasetOrderPrice,
|
||||
algoOrderPrice,
|
||||
algorithmSymbol,
|
||||
datasetSymbol
|
||||
])
|
||||
|
||||
useEffect(() => {
|
||||
@ -216,12 +221,13 @@ export default function FormStartCompute({
|
||||
setIsBalanceSufficient(false)
|
||||
return
|
||||
}
|
||||
|
||||
// if one comparison of baseTokenBalance and token price comparison is false then the state will be false
|
||||
setIsBalanceSufficient(
|
||||
isBalanceSufficient && compareAsBN(baseTokenBalance, `${price.value}`)
|
||||
baseTokenBalance && compareAsBN(baseTokenBalance, `${price.value}`)
|
||||
)
|
||||
})
|
||||
}, [balance, dtBalance, datasetSymbol, algorithmSymbol])
|
||||
}, [balance, dtBalance, datasetSymbol, algorithmSymbol, totalPrices])
|
||||
|
||||
return (
|
||||
<Form className={styles.form}>
|
||||
@ -295,6 +301,7 @@ export default function FormStartCompute({
|
||||
isAlgorithmConsumable={
|
||||
selectedAlgorithmAsset?.accessDetails?.isPurchasable
|
||||
}
|
||||
isSupportedOceanNetwork={isSupportedOceanNetwork}
|
||||
hasProviderFee={providerFeeAmount && providerFeeAmount !== '0'}
|
||||
retry={retry}
|
||||
/>
|
||||
|
@ -5,6 +5,7 @@ import Tooltip from '@shared/atoms/Tooltip'
|
||||
import styles from './PriceOutput.module.css'
|
||||
import { MAX_DECIMALS } from '@utils/constants'
|
||||
import Decimal from 'decimal.js'
|
||||
import { useWeb3 } from '@context/Web3'
|
||||
|
||||
interface PriceOutputProps {
|
||||
hasPreviousOrder: boolean
|
||||
@ -40,13 +41,21 @@ function Row({
|
||||
sign?: string
|
||||
type?: string
|
||||
}) {
|
||||
const { isSupportedOceanNetwork } = useWeb3()
|
||||
|
||||
return (
|
||||
<div className={styles.priceRow}>
|
||||
<div className={styles.sign}>{sign}</div>
|
||||
<div className={styles.type}>{type}</div>
|
||||
<div>
|
||||
<PriceUnit
|
||||
price={hasPreviousOrder || hasDatatoken ? 0 : Number(price)}
|
||||
price={
|
||||
!isSupportedOceanNetwork
|
||||
? hasPreviousOrder || hasDatatoken
|
||||
? 0
|
||||
: Number(price)
|
||||
: Number(price)
|
||||
}
|
||||
symbol={symbol}
|
||||
size="small"
|
||||
className={styles.price}
|
||||
|
@ -45,6 +45,7 @@ import { getComputeFeedback } from '@utils/feedback'
|
||||
import { getDummyWeb3 } from '@utils/web3'
|
||||
import { initializeProviderForCompute } from '@utils/provider'
|
||||
import { useUserPreferences } from '@context/UserPreferences'
|
||||
import { useAsset } from '@context/Asset'
|
||||
|
||||
const refreshInterval = 10000 // 10 sec.
|
||||
export default function Compute({
|
||||
@ -60,8 +61,10 @@ export default function Compute({
|
||||
fileIsLoading?: boolean
|
||||
consumableFeedback?: string
|
||||
}): ReactElement {
|
||||
const { accountId, web3 } = useWeb3()
|
||||
const { accountId, web3, isSupportedOceanNetwork } = useWeb3()
|
||||
const { chainIds } = useUserPreferences()
|
||||
const { isAssetNetwork } = useAsset()
|
||||
|
||||
const newAbortController = useAbortController()
|
||||
const newCancelToken = useCancelToken()
|
||||
|
||||
@ -116,7 +119,7 @@ export default function Compute({
|
||||
const datatokenInstance = new Datatoken(web3)
|
||||
const dtBalance = await datatokenInstance.balance(
|
||||
asset?.services[0].datatokenAddress,
|
||||
accountId
|
||||
accountId || ZERO_ADDRESS // if the user is not connected, we use ZERO_ADDRESS as accountId
|
||||
)
|
||||
setAlgorithmDTBalance(new Decimal(dtBalance).toString())
|
||||
const hasAlgoDt = Number(dtBalance) >= 1
|
||||
@ -134,9 +137,10 @@ export default function Compute({
|
||||
const initializedProvider = await initializeProviderForCompute(
|
||||
asset,
|
||||
selectedAlgorithmAsset,
|
||||
accountId,
|
||||
accountId || ZERO_ADDRESS, // if the user is not connected, we use ZERO_ADDRESS as accountId
|
||||
computeEnv
|
||||
)
|
||||
|
||||
if (
|
||||
!initializedProvider ||
|
||||
!initializedProvider?.datasets ||
|
||||
@ -145,13 +149,17 @@ export default function Compute({
|
||||
throw new Error(`Error initializing provider for the compute job!`)
|
||||
|
||||
setInitializedProviderResponse(initializedProvider)
|
||||
setProviderFeeAmount(
|
||||
await unitsToAmount(
|
||||
web3,
|
||||
initializedProvider?.datasets?.[0]?.providerFee?.providerFeeToken,
|
||||
initializedProvider?.datasets?.[0]?.providerFee?.providerFeeAmount
|
||||
)
|
||||
|
||||
const feeAmount = await unitsToAmount(
|
||||
!isSupportedOceanNetwork || !isAssetNetwork
|
||||
? await getDummyWeb3(asset?.chainId)
|
||||
: web3,
|
||||
initializedProvider?.datasets?.[0]?.providerFee?.providerFeeToken,
|
||||
initializedProvider?.datasets?.[0]?.providerFee?.providerFeeAmount
|
||||
)
|
||||
|
||||
setProviderFeeAmount(feeAmount)
|
||||
|
||||
const computeDuration = (
|
||||
parseInt(initializedProvider?.datasets?.[0]?.providerFee?.validUntil) -
|
||||
Math.floor(Date.now() / 1000)
|
||||
@ -217,7 +225,7 @@ export default function Compute({
|
||||
}, [asset?.accessDetails, accountId, isUnsupportedPricing])
|
||||
|
||||
useEffect(() => {
|
||||
if (!selectedAlgorithmAsset?.accessDetails || !accountId) return
|
||||
if (!selectedAlgorithmAsset?.accessDetails) return
|
||||
|
||||
setIsRequestingAlgoOrderPrice(true)
|
||||
setIsConsumableAlgorithmPrice(
|
||||
@ -306,6 +314,7 @@ export default function Compute({
|
||||
documentId: selectedAlgorithmAsset.id,
|
||||
serviceId: selectedAlgorithmAsset.services[0].id
|
||||
}
|
||||
|
||||
const allowed = await isOrderable(
|
||||
asset,
|
||||
computeService.id,
|
||||
@ -450,14 +459,12 @@ export default function Compute({
|
||||
setSelectedAlgorithm={setSelectedAlgorithmAsset}
|
||||
isLoading={isOrdering || isRequestingAlgoOrderPrice}
|
||||
isComputeButtonDisabled={isComputeButtonDisabled}
|
||||
hasPreviousOrder={validOrderTx !== undefined}
|
||||
hasPreviousOrder={!!validOrderTx}
|
||||
hasDatatoken={hasDatatoken}
|
||||
dtBalance={dtBalance}
|
||||
assetType={asset?.metadata.type}
|
||||
assetTimeout={secondsToString(asset?.services[0].timeout)}
|
||||
hasPreviousOrderSelectedComputeAsset={
|
||||
validAlgorithmOrderTx !== undefined
|
||||
}
|
||||
hasPreviousOrderSelectedComputeAsset={!!validAlgorithmOrderTx}
|
||||
hasDatatokenSelectedComputeAsset={hasAlgoAssetDatatoken}
|
||||
datasetSymbol={asset?.accessDetails?.baseToken?.symbol || 'OCEAN'}
|
||||
algorithmSymbol={
|
||||
|
@ -33,7 +33,7 @@ export default function Download({
|
||||
fileIsLoading?: boolean
|
||||
consumableFeedback?: string
|
||||
}): ReactElement {
|
||||
const { accountId, web3 } = useWeb3()
|
||||
const { accountId, web3, isSupportedOceanNetwork } = useWeb3()
|
||||
const { getOpcFeeForToken } = useMarketMetadata()
|
||||
const { isInPurgatory, isAssetNetwork } = useAsset()
|
||||
const isMounted = useIsMounted()
|
||||
@ -184,6 +184,7 @@ export default function Download({
|
||||
isBalanceSufficient={isBalanceSufficient}
|
||||
consumableFeedback={consumableFeedback}
|
||||
retry={retry}
|
||||
isSupportedOceanNetwork={isSupportedOceanNetwork}
|
||||
/>
|
||||
)
|
||||
|
||||
|
@ -1,12 +1,29 @@
|
||||
import React, { ReactElement } from 'react'
|
||||
import React, { ReactElement, useState, useEffect } from 'react'
|
||||
import MetaItem from './MetaItem'
|
||||
import styles from './MetaFull.module.css'
|
||||
import Publisher from '@shared/Publisher'
|
||||
import { useAsset } from '@context/Asset'
|
||||
import { Asset } from '@oceanprotocol/lib'
|
||||
import { useWeb3 } from '@context/Web3'
|
||||
import { Asset, Datatoken, LoggerInstance } from '@oceanprotocol/lib'
|
||||
|
||||
export default function MetaFull({ ddo }: { ddo: Asset }): ReactElement {
|
||||
const [paymentCollector, setPaymentCollector] = useState<string>()
|
||||
const { isInPurgatory } = useAsset()
|
||||
const { web3 } = useWeb3()
|
||||
|
||||
useEffect(() => {
|
||||
async function getInitialPaymentCollector() {
|
||||
try {
|
||||
const datatoken = new Datatoken(web3)
|
||||
setPaymentCollector(
|
||||
await datatoken.getPaymentCollector(ddo.datatokens[0].address)
|
||||
)
|
||||
} catch (error) {
|
||||
LoggerInstance.error('[MetaFull: getInitialPaymentCollector]', error)
|
||||
}
|
||||
}
|
||||
getInitialPaymentCollector()
|
||||
}, [ddo, web3])
|
||||
|
||||
function DockerImage() {
|
||||
const containerInfo = ddo?.metadata?.algorithm?.container
|
||||
@ -23,6 +40,12 @@ export default function MetaFull({ ddo }: { ddo: Asset }): ReactElement {
|
||||
title="Owner"
|
||||
content={<Publisher account={ddo?.nft?.owner} />}
|
||||
/>
|
||||
{paymentCollector && paymentCollector !== ddo?.nft?.owner && (
|
||||
<MetaItem
|
||||
title="Revenue Sent To"
|
||||
content={<Publisher account={paymentCollector} />}
|
||||
/>
|
||||
)}
|
||||
|
||||
{ddo?.metadata?.type === 'algorithm' && ddo?.metadata?.algorithm && (
|
||||
<MetaItem title="Docker Image" content={<DockerImage />} />
|
||||
|
@ -1,11 +1,12 @@
|
||||
import React, { ReactElement, useState } from 'react'
|
||||
import React, { ReactElement, useState, useEffect } from 'react'
|
||||
import { Formik } from 'formik'
|
||||
import {
|
||||
LoggerInstance,
|
||||
Metadata,
|
||||
FixedRateExchange,
|
||||
Asset,
|
||||
Service
|
||||
Service,
|
||||
Datatoken
|
||||
} from '@oceanprotocol/lib'
|
||||
import { validationSchema } from './_validation'
|
||||
import { getInitialValues } from './_constants'
|
||||
@ -36,10 +37,28 @@ export default function Edit({
|
||||
const { accountId, web3 } = useWeb3()
|
||||
const newAbortController = useAbortController()
|
||||
const [success, setSuccess] = useState<string>()
|
||||
const [paymentCollector, setPaymentCollector] = useState<string>()
|
||||
const [error, setError] = useState<string>()
|
||||
const isComputeType = asset?.services[0]?.type === 'compute'
|
||||
const hasFeedback = error || success
|
||||
|
||||
useEffect(() => {
|
||||
async function getInitialPaymentCollector() {
|
||||
try {
|
||||
const datatoken = new Datatoken(web3)
|
||||
setPaymentCollector(
|
||||
await datatoken.getPaymentCollector(asset?.datatokens[0].address)
|
||||
)
|
||||
} catch (error) {
|
||||
LoggerInstance.error(
|
||||
'[EditMetadata: getInitialPaymentCollector]',
|
||||
error
|
||||
)
|
||||
}
|
||||
}
|
||||
getInitialPaymentCollector()
|
||||
}, [asset, web3])
|
||||
|
||||
async function updateFixedPrice(newPrice: string) {
|
||||
const config = getOceanConfig(asset.chainId)
|
||||
|
||||
@ -81,6 +100,15 @@ export default function Edit({
|
||||
values.price !== asset.accessDetails.price &&
|
||||
(await updateFixedPrice(values.price))
|
||||
|
||||
if (values.paymentCollector !== paymentCollector) {
|
||||
const datatoken = new Datatoken(web3)
|
||||
await datatoken.setPaymentCollector(
|
||||
asset?.datatokens[0].address,
|
||||
accountId,
|
||||
values.paymentCollector
|
||||
)
|
||||
}
|
||||
|
||||
if (values.files[0]?.url) {
|
||||
const file = {
|
||||
nftAddress: asset.nftAddress,
|
||||
@ -147,7 +175,8 @@ export default function Edit({
|
||||
initialValues={getInitialValues(
|
||||
asset?.metadata,
|
||||
asset?.services[0]?.timeout,
|
||||
asset?.accessDetails?.price
|
||||
asset?.accessDetails?.price,
|
||||
paymentCollector
|
||||
)}
|
||||
validationSchema={validationSchema}
|
||||
onSubmit={async (values, { resetForm }) => {
|
||||
|
15
src/components/Asset/Edit/FormActions.test.tsx
Normal file
15
src/components/Asset/Edit/FormActions.test.tsx
Normal file
@ -0,0 +1,15 @@
|
||||
import { render, screen } from '@testing-library/react'
|
||||
import React from 'react'
|
||||
import { useFormikContext } from 'formik'
|
||||
import FormActions from './FormActions'
|
||||
|
||||
jest.mock('formik')
|
||||
|
||||
describe('src/components/Asset/Edit/FormActions.tsx', () => {
|
||||
it('renders fixed price', () => {
|
||||
const isValid = true
|
||||
;(useFormikContext as jest.Mock).mockReturnValue([isValid])
|
||||
render(<FormActions />)
|
||||
expect(screen.getByText('Submit')).toBeInTheDocument()
|
||||
})
|
||||
})
|
@ -1,5 +1,5 @@
|
||||
import React, { ReactElement, useEffect } from 'react'
|
||||
import { Field, Form, useField, useFormikContext } from 'formik'
|
||||
import { Field, Form, useFormikContext } from 'formik'
|
||||
import Input, { InputProps } from '@shared/FormInput'
|
||||
import FormActions from './FormActions'
|
||||
import { useAsset } from '@context/Asset'
|
||||
@ -60,7 +60,16 @@ export default function FormEditMetadata({
|
||||
asset?.metadata?.links?.[0] &&
|
||||
getFileUrlInfo(asset.metadata.links[0], providerUrl).then(
|
||||
(checkedFile) => {
|
||||
console.log(checkedFile)
|
||||
// set valid false if url is using google drive
|
||||
if (asset.metadata.links[0].includes('drive.google')) {
|
||||
setFieldValue('links', [
|
||||
{
|
||||
url: asset.metadata.links[0],
|
||||
valid: false
|
||||
}
|
||||
])
|
||||
return
|
||||
}
|
||||
// initiate link with values from asset metadata
|
||||
setFieldValue('links', [
|
||||
{
|
||||
|
@ -5,7 +5,8 @@ import { ComputeEditForm, MetadataEditForm } from './_types'
|
||||
export function getInitialValues(
|
||||
metadata: Metadata,
|
||||
timeout: number,
|
||||
price: string
|
||||
price: string,
|
||||
paymentCollector: string
|
||||
): Partial<MetadataEditForm> {
|
||||
return {
|
||||
name: metadata?.name,
|
||||
@ -15,7 +16,8 @@ export function getInitialValues(
|
||||
files: [{ url: '', type: '' }],
|
||||
timeout: secondsToString(timeout),
|
||||
author: metadata?.author,
|
||||
tags: metadata?.tags
|
||||
tags: metadata?.tags,
|
||||
paymentCollector
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3,6 +3,7 @@ export interface MetadataEditForm {
|
||||
name: string
|
||||
description: string
|
||||
timeout: string
|
||||
paymentCollector: string
|
||||
price?: string
|
||||
files: FileInfo[]
|
||||
links?: FileInfo[]
|
||||
|
@ -1,5 +1,6 @@
|
||||
import { FileInfo } from '@oceanprotocol/lib'
|
||||
import * as Yup from 'yup'
|
||||
import web3 from 'web3'
|
||||
|
||||
export const validationSchema = Yup.object().shape({
|
||||
name: Yup.string()
|
||||
@ -41,7 +42,14 @@ export const validationSchema = Yup.object().shape({
|
||||
.nullable(),
|
||||
timeout: Yup.string().required('Required'),
|
||||
author: Yup.string().nullable(),
|
||||
tags: Yup.array<string[]>().nullable()
|
||||
tags: Yup.array<string[]>().nullable(),
|
||||
paymentCollector: Yup.string().test(
|
||||
'ValidAddress',
|
||||
'Must be a valid Ethereum Address.',
|
||||
(value) => {
|
||||
return web3.utils.isAddress(value)
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
export const computeSettingsValidationSchema = Yup.object().shape({
|
||||
|
@ -17,6 +17,7 @@ export default function Preview(): ReactElement {
|
||||
asset.accessDetails = {
|
||||
type: values.pricing.type,
|
||||
addressOrId: ZERO_ADDRESS,
|
||||
templateId: 1,
|
||||
price: `${values.pricing.price}`,
|
||||
baseToken: {
|
||||
address: ZERO_ADDRESS,
|
||||
|
@ -23,7 +23,8 @@ import { FormPublishData, MetadataAlgorithmContainer } from './_types'
|
||||
import {
|
||||
marketFeeAddress,
|
||||
publisherMarketOrderFee,
|
||||
publisherMarketFixedSwapFee
|
||||
publisherMarketFixedSwapFee,
|
||||
defaultDatatokenTemplateIndex
|
||||
} from '../../../app.config'
|
||||
import { sanitizeUrl } from '@utils/url'
|
||||
import { getContainerChecksum } from '@utils/docker'
|
||||
@ -211,7 +212,7 @@ export async function createTokensAndPricing(
|
||||
|
||||
// TODO: cap is hardcoded for now to 1000, this needs to be discussed at some point
|
||||
const ercParams: DatatokenCreateParams = {
|
||||
templateIndex: 2,
|
||||
templateIndex: defaultDatatokenTemplateIndex,
|
||||
minter: accountId,
|
||||
paymentCollector: accountId,
|
||||
mpFeeAddress: marketFeeAddress,
|
||||
|
Loading…
Reference in New Issue
Block a user