diff --git a/package-lock.json b/package-lock.json index 19190eb35..54e00bb5e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,7 +14,7 @@ "@coingecko/cryptoformat": "^0.4.2", "@loadable/component": "^5.15.0", "@oceanprotocol/art": "^3.0.0", - "@oceanprotocol/lib": "^0.16.1", + "@oceanprotocol/lib": "^0.16.2", "@oceanprotocol/typographies": "^0.1.0", "@portis/web3": "^4.0.4", "@sindresorhus/slugify": "^2.1.0", @@ -4871,9 +4871,9 @@ } }, "node_modules/@oceanprotocol/lib": { - "version": "0.16.1", - "resolved": "https://registry.npmjs.org/@oceanprotocol/lib/-/lib-0.16.1.tgz", - "integrity": "sha512-zSVs1VaC8T+BBo9MeL88odU6wFNRHAptaLPHT6qGf2Nvc8MyhHdP15TdnHpeLJF4Ez0k6WKemnOQ1DNuaW8FlA==", + "version": "0.16.2", + "resolved": "https://registry.npmjs.org/@oceanprotocol/lib/-/lib-0.16.2.tgz", + "integrity": "sha512-hESsrSjTf/6O4oLrJgBzzTn7EkANtpa+Sl+fp/VXBZ3YvJRbp4instlKJMCqWHi+CA4dYr/uLRmaXeY/PGyx5w==", "dependencies": { "@ethereum-navigator/navigator": "^0.5.3", "@oceanprotocol/contracts": "^0.6.4", @@ -58189,9 +58189,9 @@ } }, "@oceanprotocol/lib": { - "version": "0.16.1", - "resolved": "https://registry.npmjs.org/@oceanprotocol/lib/-/lib-0.16.1.tgz", - "integrity": "sha512-zSVs1VaC8T+BBo9MeL88odU6wFNRHAptaLPHT6qGf2Nvc8MyhHdP15TdnHpeLJF4Ez0k6WKemnOQ1DNuaW8FlA==", + "version": "0.16.2", + "resolved": "https://registry.npmjs.org/@oceanprotocol/lib/-/lib-0.16.2.tgz", + "integrity": "sha512-hESsrSjTf/6O4oLrJgBzzTn7EkANtpa+Sl+fp/VXBZ3YvJRbp4instlKJMCqWHi+CA4dYr/uLRmaXeY/PGyx5w==", "requires": { "@ethereum-navigator/navigator": "^0.5.3", "@oceanprotocol/contracts": "^0.6.4", diff --git a/package.json b/package.json index c9e69c4e6..6a9e9fa62 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,7 @@ "@coingecko/cryptoformat": "^0.4.2", "@loadable/component": "^5.15.0", "@oceanprotocol/art": "^3.0.0", - "@oceanprotocol/lib": "^0.16.1", + "@oceanprotocol/lib": "^0.16.2", "@oceanprotocol/typographies": "^0.1.0", "@portis/web3": "^4.0.4", "@sindresorhus/slugify": "^2.1.0", diff --git a/src/components/atoms/ButtonBuy.tsx b/src/components/atoms/ButtonBuy.tsx index 50acd944d..2846589f6 100644 --- a/src/components/atoms/ButtonBuy.tsx +++ b/src/components/atoms/ButtonBuy.tsx @@ -12,6 +12,8 @@ interface ButtonBuyProps { dtBalance: string assetType: string assetTimeout: string + isConsumable: boolean + consumableFeedback: string hasPreviousOrderSelectedComputeAsset?: boolean hasDatatokenSelectedComputeAsset?: boolean dtSymbolSelectedComputeAsset?: string @@ -23,6 +25,7 @@ interface ButtonBuyProps { type?: 'submit' priceType?: string algorithmPriceType?: string + algorithmConsumableStatus?: number } function getConsumeHelpText( @@ -30,13 +33,18 @@ function getConsumeHelpText( dtSymbol: string, hasDatatoken: boolean, hasPreviousOrder: boolean, - assetType: string + assetType: string, + isConsumable: boolean, + consumableFeedback: string ) { - const text = hasPreviousOrder - ? `You bought this ${assetType} already allowing you to use it without paying again.` - : hasDatatoken - ? `You own ${dtBalance} ${dtSymbol} allowing you to use this data set by spending 1 ${dtSymbol}, but without paying OCEAN again.` - : `For using this ${assetType}, you will buy 1 ${dtSymbol} and immediately spend it back to the publisher and pool.` + const text = + isConsumable === false + ? consumableFeedback + : hasPreviousOrder + ? `You bought this ${assetType} already allowing you to use it without paying again.` + : hasDatatoken + ? `You own ${dtBalance} ${dtSymbol} allowing you to use this data set by spending 1 ${dtSymbol}, but without paying OCEAN again.` + : `For using this ${assetType}, you will buy 1 ${dtSymbol} and immediately spend it back to the publisher and pool.` return text } @@ -47,22 +55,34 @@ function getComputeAssetHelpText( dtSymbol: string, dtBalance: string, assetType: string, + isConsumable: boolean, + consumableFeedback: string, hasPreviousOrderSelectedComputeAsset?: boolean, hasDatatokenSelectedComputeAsset?: boolean, dtSymbolSelectedComputeAsset?: string, dtBalanceSelectedComputeAsset?: string, - selectedComputeAssetType?: string + selectedComputeAssetType?: string, + algorithmConsumableStatus?: number ) { const computeAssetHelpText = getConsumeHelpText( dtBalance, dtSymbol, hasDatatoken, hasPreviousOrder, - assetType + assetType, + isConsumable, + consumableFeedback ) const text = - !dtSymbolSelectedComputeAsset && !dtBalanceSelectedComputeAsset + (!dtSymbolSelectedComputeAsset && !dtBalanceSelectedComputeAsset) || + isConsumable === false ? '' + : algorithmConsumableStatus === 1 + ? 'The selected algorithm has been temporarily disabled by the publisher, please try again later.' + : algorithmConsumableStatus === 2 + ? 'Access denied, your wallet address is not found on the selected algorithm allow list.' + : algorithmConsumableStatus === 3 + ? 'Access denied, your wallet address is found on the selected algorithm deny list.' : hasPreviousOrderSelectedComputeAsset ? `You already bought the selected ${selectedComputeAssetType}, allowing you to use it without paying again.` : hasDatatokenSelectedComputeAsset @@ -81,6 +101,8 @@ export default function ButtonBuy({ dtBalance, assetType, assetTimeout, + isConsumable, + consumableFeedback, hasPreviousOrderSelectedComputeAsset, hasDatatokenSelectedComputeAsset, dtSymbolSelectedComputeAsset, @@ -91,7 +113,8 @@ export default function ButtonBuy({ isLoading, type, priceType, - algorithmPriceType + algorithmPriceType, + algorithmConsumableStatus }: ButtonBuyProps): ReactElement { const buttonText = action === 'download' @@ -127,7 +150,9 @@ export default function ButtonBuy({ dtSymbol, hasDatatoken, hasPreviousOrder, - assetType + assetType, + isConsumable, + consumableFeedback ) : getComputeAssetHelpText( hasPreviousOrder, @@ -135,11 +160,14 @@ export default function ButtonBuy({ dtSymbol, dtBalance, assetType, + isConsumable, + consumableFeedback, hasPreviousOrderSelectedComputeAsset, hasDatatokenSelectedComputeAsset, dtSymbolSelectedComputeAsset, dtBalanceSelectedComputeAsset, - selectedComputeAssetType + selectedComputeAssetType, + algorithmConsumableStatus )} diff --git a/src/components/molecules/FormFields/Credential/index.tsx b/src/components/molecules/FormFields/Credential/index.tsx index 3aa21085d..f9977d21e 100644 --- a/src/components/molecules/FormFields/Credential/index.tsx +++ b/src/components/molecules/FormFields/Credential/index.tsx @@ -30,11 +30,11 @@ export default function Credentials(props: InputProps) { toast.error('Wallet address is invalid') return } - if (arrayInput.includes(value)) { + if (arrayInput.includes(value.toLowerCase())) { toast.error('Wallet address already added into list') return } - setArrayInput((arrayInput) => [...arrayInput, value]) + setArrayInput((arrayInput) => [...arrayInput, value.toLowerCase()]) setValue('') } diff --git a/src/components/organisms/AssetActions/Compute/FormComputeDataset.tsx b/src/components/organisms/AssetActions/Compute/FormComputeDataset.tsx index 3ce3c24ea..a8faa5334 100644 --- a/src/components/organisms/AssetActions/Compute/FormComputeDataset.tsx +++ b/src/components/organisms/AssetActions/Compute/FormComputeDataset.tsx @@ -9,6 +9,8 @@ import { AssetSelectionAsset } from '../../../molecules/FormFields/AssetSelectio import ButtonBuy from '../../../atoms/ButtonBuy' import PriceOutput from './PriceOutput' import { useAsset } from '../../../../providers/Asset' +import { useOcean } from '../../../../providers/Ocean' +import { useWeb3 } from '../../../../providers/Web3' const contentQuery = graphql` query StartComputeDatasetQuery { @@ -58,7 +60,9 @@ export default function FormStartCompute({ selectedComputeAssetType, selectedComputeAssetTimeout, stepText, - algorithmPrice + algorithmPrice, + isConsumable, + consumableFeedback }: { algorithms: AssetSelectionAsset[] ddoListAlgorithms: DDO[] @@ -78,6 +82,8 @@ export default function FormStartCompute({ selectedComputeAssetTimeout?: string stepText: string algorithmPrice: BestPrice + isConsumable: boolean + consumableFeedback: string }): ReactElement { const data = useStaticQuery(contentQuery) const content = data.content.edges[0].node.childPagesJson @@ -86,6 +92,10 @@ export default function FormStartCompute({ useFormikContext() const { price, ddo, isAssetNetwork } = useAsset() const [totalPrice, setTotalPrice] = useState(price?.value) + const { accountId } = useWeb3() + const { ocean } = useOcean() + const [algorithmConsumableStatus, setAlgorithmConsumableStatus] = + useState() function getAlgorithmAsset(algorithmId: string): DDO { let assetDdo = null @@ -97,8 +107,19 @@ export default function FormStartCompute({ useEffect(() => { if (!values.algorithm) return - setSelectedAlgorithm(getAlgorithmAsset(values.algorithm)) - }, [values.algorithm]) + const algorithmDDO = getAlgorithmAsset(values.algorithm) + setSelectedAlgorithm(algorithmDDO) + + if (!accountId || !isConsumable) return + async function checkIsConsumable() { + const consumable = await ocean.assets.isConsumable( + algorithmDDO, + accountId.toLowerCase() + ) + if (consumable) setAlgorithmConsumableStatus(consumable.status) + } + checkIsConsumable() + }, [values.algorithm, accountId, isConsumable]) // // Set price for calculation output @@ -149,7 +170,12 @@ export default function FormStartCompute({ 0 + } hasPreviousOrder={hasPreviousOrder} hasDatatoken={hasDatatoken} dtSymbol={ddo.dataTokenInfo.symbol} @@ -168,6 +194,9 @@ export default function FormStartCompute({ type="submit" priceType={price?.type} algorithmPriceType={algorithmPrice?.type} + isConsumable={isConsumable} + consumableFeedback={consumableFeedback} + algorithmConsumableStatus={algorithmConsumableStatus} /> ) diff --git a/src/components/organisms/AssetActions/Compute/index.tsx b/src/components/organisms/AssetActions/Compute/index.tsx index e4f7239a2..1bedd93da 100644 --- a/src/components/organisms/AssetActions/Compute/index.tsx +++ b/src/components/organisms/AssetActions/Compute/index.tsx @@ -50,12 +50,16 @@ export default function Compute({ isBalanceSufficient, dtBalance, file, - fileIsLoading + fileIsLoading, + isConsumable, + consumableFeedback }: { isBalanceSufficient: boolean dtBalance: string file: FileMetadata fileIsLoading?: boolean + isConsumable?: boolean + consumableFeedback?: string }): ReactElement { const { appConfig } = useSiteMetadata() const { accountId } = useWeb3() @@ -82,7 +86,11 @@ export default function Compute({ const [algorithmTimeout, setAlgorithmTimeout] = useState() const isComputeButtonDisabled = - isJobStarting === true || file === null || !ocean || !isBalanceSufficient + isJobStarting === true || + file === null || + !ocean || + !isBalanceSufficient || + !isConsumable const hasDatatoken = Number(dtBalance) >= 1 async function checkPreviousOrders(ddo: DDO) { @@ -418,6 +426,8 @@ export default function Compute({ selectedComputeAssetTimeout={algorithmTimeout} stepText={pricingStepText || 'Starting Compute Job...'} algorithmPrice={algorithmPrice} + isConsumable={isConsumable} + consumableFeedback={consumableFeedback} /> )} diff --git a/src/components/organisms/AssetActions/Consume.tsx b/src/components/organisms/AssetActions/Consume.tsx index 2c94c6154..70c6b5799 100644 --- a/src/components/organisms/AssetActions/Consume.tsx +++ b/src/components/organisms/AssetActions/Consume.tsx @@ -36,13 +36,17 @@ export default function Consume({ file, isBalanceSufficient, dtBalance, - fileIsLoading + fileIsLoading, + isConsumable, + consumableFeedback }: { ddo: DDO file: FileMetadata isBalanceSufficient: boolean dtBalance: string fileIsLoading?: boolean + isConsumable?: boolean + consumableFeedback?: string }): ReactElement { const { accountId } = useWeb3() const { ocean } = useOcean() @@ -55,7 +59,7 @@ export default function Consume({ const { consumeStepText, consume, consumeError, isLoading } = useConsume() const [isDisabled, setIsDisabled] = useState(true) const [hasDatatoken, setHasDatatoken] = useState(false) - const [isConsumable, setIsConsumable] = useState(true) + const [isConsumablePrice, setIsConsumablePrice] = useState(true) const [assetTimeout, setAssetTimeout] = useState('') const { data } = useQuery(previousOrderQuery, { variables: { @@ -93,7 +97,7 @@ export default function Consume({ useEffect(() => { if (!price) return - setIsConsumable( + setIsConsumablePrice( price.isConsumable !== undefined ? price.isConsumable === 'true' : true ) }, [price]) @@ -104,14 +108,15 @@ export default function Consume({ useEffect(() => { setIsDisabled( - (!ocean || - !isBalanceSufficient || - !isAssetNetwork || - typeof consumeStepText !== 'undefined' || - pricingIsLoading || - !isConsumable) && - !hasPreviousOrder && - !hasDatatoken + !isConsumable || + ((!ocean || + !isBalanceSufficient || + !isAssetNetwork || + typeof consumeStepText !== 'undefined' || + pricingIsLoading || + !isConsumablePrice) && + !hasPreviousOrder && + !hasDatatoken) ) }, [ ocean, @@ -120,8 +125,9 @@ export default function Consume({ isAssetNetwork, consumeStepText, pricingIsLoading, - isConsumable, - hasDatatoken + isConsumablePrice, + hasDatatoken, + isConsumable ]) async function handleConsume() { @@ -162,6 +168,8 @@ export default function Consume({ stepText={consumeStepText || pricingStepText} isLoading={pricingIsLoading || isLoading} priceType={price?.type} + isConsumable={isConsumable} + consumableFeedback={consumableFeedback} /> ) diff --git a/src/components/organisms/AssetActions/index.tsx b/src/components/organisms/AssetActions/index.tsx index 0974f9b7b..b41a0773e 100644 --- a/src/components/organisms/AssetActions/index.tsx +++ b/src/components/organisms/AssetActions/index.tsx @@ -26,6 +26,24 @@ export default function AssetActions(): ReactElement { const [fileIsLoading, setFileIsLoading] = useState(false) const isCompute = Boolean(ddo?.findServiceByType('compute')) + const [isConsumable, setIsConsumable] = useState(true) + const [consumableFeedback, setConsumableFeedback] = useState('') + + useEffect(() => { + if (!ddo || !accountId) return + async function checkIsConsumable() { + const consumable: any = await ocean.assets.isConsumable( + ddo, + accountId.toLowerCase() + ) + if (consumable) { + setIsConsumable(consumable.result) + setConsumableFeedback(consumable.message) + } + } + checkIsConsumable() + }, [accountId, ddo]) + useEffect(() => { const { attributes } = ddo.findServiceByType('metadata') setFileMetadata(attributes.main.files[0]) @@ -88,6 +106,8 @@ export default function AssetActions(): ReactElement { isBalanceSufficient={isBalanceSufficient} file={fileMetadata} fileIsLoading={fileIsLoading} + isConsumable={isConsumable} + consumableFeedback={consumableFeedback} /> ) : ( ) diff --git a/src/utils/metadata.ts b/src/utils/metadata.ts index d29e3d6e2..691576286 100644 --- a/src/utils/metadata.ts +++ b/src/utils/metadata.ts @@ -116,6 +116,7 @@ export function transformPublishFormToMetadata( name, author, dateCreated: ddo ? ddo.created : currentTime, + datePublished: '', files: typeof files !== 'string' && files, license: 'https://market.oceanprotocol.com/terms' },