1
0
mirror of https://github.com/oceanprotocol/react.git synced 2024-12-24 10:06:20 +01:00

Merge pull request #71 from oceanprotocol/feature/consume

Feature/consume
This commit is contained in:
Matthias Kretschmann 2020-08-05 10:08:41 +02:00 committed by GitHub
commit 2403c67a80
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 3120 additions and 1573 deletions

4337
example/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -3,7 +3,6 @@
"version": "0.1.0", "version": "0.1.0",
"private": true, "private": true,
"dependencies": { "dependencies": {
"-": "0.0.1",
"@oceanprotocol/react": "file:../", "@oceanprotocol/react": "file:../",
"@toruslabs/torus-embed": "^1.8.2", "@toruslabs/torus-embed": "^1.8.2",
"@types/jest": "^24.9.1", "@types/jest": "^24.9.1",

View File

@ -1,17 +1,18 @@
import React from 'react' import React from 'react'
import { useOcean, usePublish } from '@oceanprotocol/react' import { useOcean, usePublish } from '@oceanprotocol/react'
import { Metadata, DDO } from '@oceanprotocol/lib' import { DDO } from '@oceanprotocol/lib'
import { useState } from 'react' import { useState } from 'react'
import { useEffect } from 'react' import { useEffect } from 'react'
import shortid from 'shortid' import shortid from 'shortid'
export function AllDdos() { export function AllDdos() {
const { accountId, ocean } = useOcean() const { accountId, account, ocean } = useOcean()
const [ddos, setDdos] = useState<DDO[] | undefined>() const [ddos, setDdos] = useState<DDO[] | undefined>()
useEffect(() => { useEffect(() => {
async function init() { async function init() {
if (ocean === undefined) return if (ocean === undefined || account === undefined) return
const assets = await ocean.assets.query({ const assets = await ocean.assets.query({
page: 1, page: 1,
offset: 10, offset: 10,
@ -22,7 +23,7 @@ export function AllDdos() {
setDdos(assets.results) setDdos(assets.results)
} }
init() init()
}, [ocean]) }, [ocean, account])
return ( return (
<> <>

View File

@ -3,7 +3,7 @@ import './App.css'
import { OceanProvider } from '@oceanprotocol/react' import { OceanProvider } from '@oceanprotocol/react'
import { Wallet } from './Wallet' import { Wallet } from './Wallet'
import { Publish } from './Publish' import { Publish } from './Publish'
import { Config } from '@oceanprotocol/lib' import { Config, ConfigHelper } from '@oceanprotocol/lib'
import { AllDdos } from './AllDdos' import { AllDdos } from './AllDdos'
import { ConsumeDdo } from './ConsumeDdo' import { ConsumeDdo } from './ConsumeDdo'
@ -18,12 +18,7 @@ const config = {
factoryAddress: '0x2fC1fd21cb222Dc180Ef817dE4c426fd9230b5A5' factoryAddress: '0x2fC1fd21cb222Dc180Ef817dE4c426fd9230b5A5'
} as Config } as Config
const configRinkeby = { const configRinkeby = new ConfigHelper().getConfig('rinkeby')
metadataStoreUri: 'https://aquarius.rinkeby.v3.dev-ocean.com',
providerUri: 'https://provider.rinkeby.v3.dev-ocean.com',
nodeUri: `https://rinkeby.infura.io/a983b53583044593956054de049922fd`,
factoryAddress: '0xB9d406D24B310A7D821D0b782a36909e8c925471'
} as Config
const providerOptions = { const providerOptions = {
walletconnect: { walletconnect: {
@ -57,26 +52,24 @@ function App() {
}, []) }, [])
return ( return (
<div className="app"> <OceanProvider config={configRinkeby} web3ModalOpts={web3ModalOpts}>
<OceanProvider config={config} web3ModalOpts={web3ModalOpts}> <div className="container">
<div className="container"> <div>
<div> <Wallet />
<Wallet />
</div>
<div>
<AllDdos />
</div>
<div>
<Publish />
</div>
<div>
<ConsumeDdo />
</div>
</div> </div>
</OceanProvider> <div>
</div> <AllDdos />
</div>
<div>
<Publish />
</div>
<div>
<ConsumeDdo />
</div>
</div>
</OceanProvider>
) )
} }

View File

@ -1,10 +1,11 @@
import React from 'react' import React from 'react'
import { useOcean, usePublish } from '@oceanprotocol/react' import { useOcean, usePublish } from '@oceanprotocol/react'
import { Metadata, DDO } from '@oceanprotocol/lib' import { DDO } from '@oceanprotocol/lib'
import { useState } from 'react' import { useState } from 'react'
import { Metadata } from '@oceanprotocol/lib/dist/node/ddo/interfaces/Metadata'
export function Publish() { export function Publish() {
const { accountId } = useOcean() const { accountId, ocean } = useOcean()
const { publish, publishStepText } = usePublish() const { publish, publishStepText } = usePublish()
const [ddo, setDdo] = useState<DDO | undefined>() const [ddo, setDdo] = useState<DDO | undefined>()
@ -30,11 +31,15 @@ export function Publish() {
} }
const publishAsset = async () => { const publishAsset = async () => {
const ddo = await publish(asset as Metadata, '4', [ const ddo = await publish(asset as Metadata, '90', 'access', '', '')
{ serviceType: 'access', cost: '1' },
{ serviceType: 'compute', cost: '1' }
])
console.log(ddo) console.log(ddo)
const pool = ocean.pool.createDTPool(
accountId,
ddo.dataToken,
'90',
'9',
'0.03'
)
setDdo(ddo) setDdo(ddo)
} }
return ( return (

12
package-lock.json generated
View File

@ -1298,13 +1298,14 @@
"integrity": "sha512-ZQ5RHQWp6xkmATt7Sl12LhnH4dovewgKPX1gGeZoDSyFcmpjMDngtJpDns8jMsaclU61tPScw7K/EmxS1ydiCg==" "integrity": "sha512-ZQ5RHQWp6xkmATt7Sl12LhnH4dovewgKPX1gGeZoDSyFcmpjMDngtJpDns8jMsaclU61tPScw7K/EmxS1ydiCg=="
}, },
"@oceanprotocol/lib": { "@oceanprotocol/lib": {
"version": "0.1.10", "version": "0.1.11",
"resolved": "https://registry.npmjs.org/@oceanprotocol/lib/-/lib-0.1.10.tgz", "resolved": "https://registry.npmjs.org/@oceanprotocol/lib/-/lib-0.1.11.tgz",
"integrity": "sha512-wb0SOX0/ulLMho2Ftm1dFFLCz1+vM8mJQYNS5Ay62AUEny6fymsAMpcTLBsDU5CseqU87fHU6A5g5Rvlu7RRwQ==", "integrity": "sha512-DvsCWOACxNlsNpGWdbHhKsN2Lj+/B0UAp6l2/29fywFZnFp0mjywKFbhVEY25PGaHZIUG+7YZ0Eot615tKpNjw==",
"requires": { "requires": {
"@ethereum-navigator/navigator": "^0.5.0", "@ethereum-navigator/navigator": "^0.5.0",
"@oceanprotocol/contracts": "^0.3.1", "@oceanprotocol/contracts": "^0.3.1",
"bignumber.js": "^9.0.0", "bignumber.js": "^9.0.0",
"decimal.js": "^10.2.0",
"fs": "0.0.1-security", "fs": "0.0.1-security",
"node-fetch": "^2.6.0", "node-fetch": "^2.6.0",
"save-file": "^2.3.1", "save-file": "^2.3.1",
@ -3285,6 +3286,11 @@
"integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=",
"dev": true "dev": true
}, },
"decimal.js": {
"version": "10.2.0",
"resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.2.0.tgz",
"integrity": "sha512-vDPw+rDgn3bZe1+F/pyEwb1oMG2XTlRVgAa6B4KccTEpYgF8w6eQllVbQcfIJnZyvzFtFpxnpGtx8dd7DJp/Rw=="
},
"decode-uri-component": { "decode-uri-component": {
"version": "0.2.0", "version": "0.2.0",
"resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz",

View File

@ -25,8 +25,9 @@
"dist/" "dist/"
], ],
"dependencies": { "dependencies": {
"@oceanprotocol/lib": "^0.1.10", "@oceanprotocol/lib": "^0.1.11",
"axios": "^0.19.2", "axios": "^0.19.2",
"decimal.js": "^10.2.0",
"web3": "^1.2.11", "web3": "^1.2.11",
"web3modal": "^1.9.0" "web3modal": "^1.9.0"
}, },

View File

@ -5,6 +5,7 @@ import { feedback } from './../../utils'
import { DID, Logger } from '@oceanprotocol/lib' import { DID, Logger } from '@oceanprotocol/lib'
import { MetadataAlgorithm } from '@oceanprotocol/lib/dist/node/ddo/interfaces/MetadataAlgorithm' import { MetadataAlgorithm } from '@oceanprotocol/lib/dist/node/ddo/interfaces/MetadataAlgorithm'
import { ComputeJob } from '@oceanprotocol/lib/dist/node/ocean/interfaces/ComputeJob' import { ComputeJob } from '@oceanprotocol/lib/dist/node/ocean/interfaces/ComputeJob'
import { checkAndBuyDT } from '../../utils/dtUtils'
interface UseCompute { interface UseCompute {
compute: ( compute: (
@ -63,6 +64,8 @@ function useCompute(): UseCompute {
try { try {
setIsLoading(true) setIsLoading(true)
setStep(0) setStep(0)
await checkAndBuyDT(ocean, dataTokenAddress, account)
rawAlgorithmMeta.container = computeContainer rawAlgorithmMeta.container = computeContainer
rawAlgorithmMeta.rawcode = algorithmRawCode rawAlgorithmMeta.rawcode = algorithmRawCode

View File

@ -2,7 +2,7 @@ import { useState } from 'react'
import { useOcean } from '../../providers' import { useOcean } from '../../providers'
import { feedback } from '../../utils' import { feedback } from '../../utils'
import { DID, Logger, ServiceType } from '@oceanprotocol/lib' import { DID, Logger, ServiceType } from '@oceanprotocol/lib'
import { checkAndBuyDT } from '../../utils/dtUtils'
interface UseConsume { interface UseConsume {
consume: ( consume: (
did: DID | string, did: DID | string,
@ -34,17 +34,20 @@ function useConsume(): UseConsume {
setConsumeStep(index) setConsumeStep(index)
setConsumeStepText(consumeFeedback[index]) setConsumeStepText(consumeFeedback[index])
} }
async function consume( async function consume(
did: string, did: string,
dataTokenAddress: string, dataTokenAddress: string,
serviceType: ServiceType = 'access' serviceType: ServiceType = 'access'
): Promise<void> { ): Promise<void> {
if (!ocean || !account) return if (!ocean || !account || !accountId) return
setIsLoading(true) setIsLoading(true)
setConsumeError(undefined) setConsumeError(undefined)
try { try {
setStep(0) setStep(0)
await checkAndBuyDT(ocean, dataTokenAddress, account)
setStep(1) setStep(1)
const order = await ocean.assets.order(did, serviceType, accountId) const order = await ocean.assets.order(did, serviceType, accountId)
Logger.log('order created', order) Logger.log('order created', order)

View File

@ -1,14 +1,8 @@
import { useState, useEffect } from 'react' import { useState, useEffect } from 'react'
import { import { DID, DDO, Metadata, MetadataStore, Logger } from '@oceanprotocol/lib'
DID,
DDO,
Metadata,
MetadataStore,
Logger,
ConfigHelper
} from '@oceanprotocol/lib'
import { useOcean } from '../../providers' import { useOcean } from '../../providers'
import ProviderStatus from '../../providers/OceanProvider/ProviderStatus' import ProviderStatus from '../../providers/OceanProvider/ProviderStatus'
import { getBestDataTokenPrice } from '../../utils/dtUtils'
interface UseMetadata { interface UseMetadata {
ddo: DDO ddo: DDO
@ -17,10 +11,11 @@ interface UseMetadata {
getDDO: (did: DID | string) => Promise<DDO> getDDO: (did: DID | string) => Promise<DDO>
getMetadata: (did: DID | string) => Promise<Metadata> getMetadata: (did: DID | string) => Promise<Metadata>
getTitle: (did: DID | string) => Promise<string> getTitle: (did: DID | string) => Promise<string>
getBestPrice: (dataTokenAddress: string) => Promise<string>
} }
function useMetadata(did?: DID | string): UseMetadata { function useMetadata(did?: DID | string): UseMetadata {
const { ocean, status, config } = useOcean() const { ocean, status, config, accountId } = useOcean()
const [ddo, setDDO] = useState<DDO | undefined>() const [ddo, setDDO] = useState<DDO | undefined>()
const [metadata, setMetadata] = useState<Metadata | undefined>() const [metadata, setMetadata] = useState<Metadata | undefined>()
const [title, setTitle] = useState<string | undefined>() const [title, setTitle] = useState<string | undefined>()
@ -37,6 +32,10 @@ function useMetadata(did?: DID | string): UseMetadata {
return ddo return ddo
} }
async function getBestPrice(dataTokenAddress: string): Promise<string> {
return await getBestDataTokenPrice(ocean, accountId, dataTokenAddress)
}
async function getMetadata(did: DID | string): Promise<Metadata> { async function getMetadata(did: DID | string): Promise<Metadata> {
const ddo = await getDDO(did) const ddo = await getDDO(did)
if (!ddo) return if (!ddo) return
@ -68,7 +67,8 @@ function useMetadata(did?: DID | string): UseMetadata {
title, title,
getDDO, getDDO,
getMetadata, getMetadata,
getTitle getTitle,
getBestPrice
} }
} }

View File

@ -4,7 +4,8 @@ import { useOcean } from '../../providers'
import ProviderStatus from '../../providers/OceanProvider/ProviderStatus' import ProviderStatus from '../../providers/OceanProvider/ProviderStatus'
import { import {
Service, Service,
ServiceComputePrivacy ServiceComputePrivacy,
ServiceType
} from '@oceanprotocol/lib/dist/node/ddo/interfaces/Service' } from '@oceanprotocol/lib/dist/node/ddo/interfaces/Service'
import { ServiceConfig } from './ServiceConfig' import { ServiceConfig } from './ServiceConfig'
import { publishFeedback } from '../../utils' import { publishFeedback } from '../../utils'
@ -13,8 +14,9 @@ interface UsePublish {
publish: ( publish: (
asset: Metadata, asset: Metadata,
tokensToMint: string, tokensToMint: string,
serviceConfigs: ServiceConfig[], serviceConfigs: ServiceType,
dtAddress?: string mpAddress: string,
mpFee: string
) => Promise<DDO> ) => Promise<DDO>
mint: (tokenAddress: string, tokensToMint: string) => void mint: (tokenAddress: string, tokensToMint: string) => void
publishStep?: number publishStep?: number
@ -24,7 +26,7 @@ interface UsePublish {
} }
function usePublish(): UsePublish { function usePublish(): UsePublish {
const { web3, ocean, status, account, accountId, config } = useOcean() const { ocean, status, account, accountId, config } = useOcean()
const [isLoading, setIsLoading] = useState(false) const [isLoading, setIsLoading] = useState(false)
const [publishStep, setPublishStep] = useState<number | undefined>() const [publishStep, setPublishStep] = useState<number | undefined>()
const [publishStepText, setPublishStepText] = useState<string | undefined>() const [publishStepText, setPublishStepText] = useState<string | undefined>()
@ -40,26 +42,26 @@ function usePublish(): UsePublish {
* @param {Metadata} asset The metadata of the asset. * @param {Metadata} asset The metadata of the asset.
* @param {string} tokensToMint Numer of tokens to mint and give allowance to market * @param {string} tokensToMint Numer of tokens to mint and give allowance to market
* @param {ServiceConfig[]} serviceConfigs Desired services of the asset, ex: [{serviceType: 'access', cost:'1'}] * @param {ServiceConfig[]} serviceConfigs Desired services of the asset, ex: [{serviceType: 'access', cost:'1'}]
* @param {string} dtAddress The address of the market * @param {string} mpAddress The address of the market
* @param {string} mpFee The fee of the market
* @return {Promise<DDO>} Returns the newly published ddo * @return {Promise<DDO>} Returns the newly published ddo
*/ */
async function publish( async function publish(
asset: Metadata, asset: Metadata,
tokensToMint: string, tokensToMint: string,
serviceConfigs: ServiceConfig[], serviceType: ServiceType,
dtAddress?: string mpAddress: string,
mpFee: string
): Promise<DDO> { ): Promise<DDO> {
if (status !== ProviderStatus.CONNECTED || !ocean || !account) return if (status !== ProviderStatus.CONNECTED || !ocean || !account) return
setIsLoading(true) setIsLoading(true)
setPublishError(undefined) setPublishError(undefined)
try { try {
if (dtAddress) { setStep(0)
setStep(0) const data = { t: 1, url: config.metadataStoreUri }
const data = { t: 1, url: config.metadataStoreUri } const blob = JSON.stringify(data)
const blob = JSON.stringify(data) const dtAddress = await ocean.datatokens.create(blob, accountId)
dtAddress = await ocean.datatokens.create(blob, accountId) Logger.log('datatoken created', dtAddress)
Logger.log('datatoken created', dtAddress)
}
setStep(1) setStep(1)
await mint(dtAddress, tokensToMint) await mint(dtAddress, tokensToMint)
@ -71,68 +73,67 @@ function usePublish(): UsePublish {
const timeout = 0 const timeout = 0
const services: Service[] = [] const services: Service[] = []
serviceConfigs.forEach(async (serviceConfig) => { const price = ocean.datatokens.toWei('1')
const price = ocean.datatokens.toWei(serviceConfig.cost) switch (serviceType) {
switch (serviceConfig.serviceType) { case 'access': {
case 'access': { const accessService = await ocean.assets.createAccessServiceAttributes(
const accessService = await ocean.assets.createAccessServiceAttributes( account,
account, price,
price, publishedDate,
publishedDate, timeout
)
Logger.log('access service created', accessService)
services.push(accessService)
break
}
case 'compute': {
const cluster = ocean.compute.createClusterAttributes(
'Kubernetes',
'http://10.0.0.17/xxx'
)
const servers = [
ocean.compute.createServerAttributes(
'1',
'xlsize',
'50',
'16',
'0',
'128gb',
'160gb',
timeout timeout
) )
Logger.log('access service created', accessService) ]
services.push(accessService) const containers = [
break ocean.compute.createContainerAttributes(
} 'tensorflow/tensorflow',
case 'compute': { 'latest',
const cluster = ocean.compute.createClusterAttributes( 'sha256:cb57ecfa6ebbefd8ffc7f75c0f00e57a7fa739578a429b6f72a0df19315deadc'
'Kubernetes', )
'http://10.0.0.17/xxx' ]
) const provider = ocean.compute.createProviderAttributes(
const servers = [ 'Azure',
ocean.compute.createServerAttributes( 'Compute service with 16gb ram for each node.',
'1', cluster,
'xlsize', containers,
'50', servers
'16', )
'0', const origComputePrivacy = {
'128gb', allowRawAlgorithm: true,
'160gb', allowNetworkAccess: false,
timeout trustedAlgorithms: []
)
]
const containers = [
ocean.compute.createContainerAttributes(
'tensorflow/tensorflow',
'latest',
'sha256:cb57ecfa6ebbefd8ffc7f75c0f00e57a7fa739578a429b6f72a0df19315deadc'
)
]
const provider = ocean.compute.createProviderAttributes(
'Azure',
'Compute service with 16gb ram for each node.',
cluster,
containers,
servers
)
const origComputePrivacy = {
allowRawAlgorithm: true,
allowNetworkAccess: false,
trustedAlgorithms: []
}
const computeService = ocean.compute.createComputeService(
account,
price,
publishedDate,
provider,
origComputePrivacy as ServiceComputePrivacy
)
services.push(computeService)
break
} }
const computeService = ocean.compute.createComputeService(
account,
price,
publishedDate,
provider,
origComputePrivacy as ServiceComputePrivacy
)
services.push(computeService)
break
} }
}) }
Logger.log('services created', services) Logger.log('services created', services)
setStep(3) setStep(3)
const ddo = await ocean.assets.create(asset, account, services, dtAddress) const ddo = await ocean.assets.create(asset, account, services, dtAddress)

View File

@ -30,6 +30,7 @@ interface OceanProviderValue {
status: ProviderStatus status: ProviderStatus
connect: (opts?: Partial<ICoreOptions>) => Promise<void> connect: (opts?: Partial<ICoreOptions>) => Promise<void>
logout: () => Promise<void> logout: () => Promise<void>
refreshBalance: () => Promise<void>
} }
const OceanContext = createContext(null) const OceanContext = createContext(null)
@ -121,7 +122,10 @@ function OceanProvider({
Logger.error(error) Logger.error(error)
} }
} }
async function refreshBalance() {
const balance = await getBalance(account)
setBalance(balance)
}
async function logout() { async function logout() {
// TODO: #67 check how is the proper way to logout // TODO: #67 check how is the proper way to logout
web3Modal.clearCachedProvider() web3Modal.clearCachedProvider()
@ -181,7 +185,8 @@ function OceanProvider({
status, status,
config, config,
connect, connect,
logout logout,
refreshBalance
} as OceanProviderValue } as OceanProviderValue
} }
> >

79
src/utils/dtUtils.ts Normal file
View File

@ -0,0 +1,79 @@
import { Logger, Ocean, Account } from '@oceanprotocol/lib'
import { Decimal } from 'decimal.js'
export async function getCheapestPool(
ocean: Ocean,
accountId: string,
dataTokenAddress: string
): Promise<{ poolAddress: string; poolPrice: string }> {
const tokenPools = await ocean.pool.searchPoolforDT(
accountId,
dataTokenAddress
)
Logger.log('DT Pool found', tokenPools)
let cheapestPoolAddress
let cheapestPoolPrice = new Decimal(999999999999)
if (tokenPools) {
for (let i = 0; i < tokenPools.length; i++) {
const poolPrice = await ocean.pool.getOceanNeeded(
accountId,
tokenPools[i],
'1'
)
const decimalPoolPrice = new Decimal(poolPrice)
Logger.log('Pool price ', tokenPools[i], poolPrice)
if (decimalPoolPrice < cheapestPoolPrice) {
cheapestPoolPrice = decimalPoolPrice
cheapestPoolAddress = tokenPools[i]
}
}
}
return {
poolAddress: cheapestPoolAddress,
poolPrice: cheapestPoolPrice.toString()
}
}
export async function getBestDataTokenPrice(
ocean: Ocean,
accountId: string,
dataTokenAddress: string
): Promise<string> {
const bestPool = await getCheapestPool(ocean, accountId, dataTokenAddress)
return bestPool.poolPrice
}
export async function checkAndBuyDT(
ocean: Ocean,
dataTokenAddress: string,
account: Account
) {
const userOwnedTokens = await ocean.accounts.getTokenBalance(
dataTokenAddress,
account
)
Logger.log(`User has ${userOwnedTokens} tokens`)
let cheapestPool
if (userOwnedTokens === '0') {
cheapestPool = await getCheapestPool(
ocean,
account.getId(),
dataTokenAddress
)
Decimal.set({ precision: 5 })
const price = new Decimal(cheapestPool.poolPrice).times(1.05).toString()
const maxPrice = new Decimal(cheapestPool.poolPrice).times(2).toString()
Logger.log('Buying token', cheapestPool, account.getId(), price)
const buyResponse = await ocean.pool.buyDT(
account.getId(),
cheapestPool.poolAddress,
'1',
price,
maxPrice
)
Logger.log('DT buy response', buyResponse)
return buyResponse
}
}

View File

@ -14,9 +14,9 @@ export function readFileContent(file: File): Promise<string> {
export const feedback: { [key in number]: string } = { export const feedback: { [key in number]: string } = {
99: 'Decrypting file URL...', 99: 'Decrypting file URL...',
0: '1/3 Ordering asset...', 0: '1/3 Looking for data token. Buying if none found...',
1: '1/3 Transfering data token.', 1: '2/3 Transfering data token.',
2: '2/3 Payment confirmed. Requesting access...' 2: '3/3 Payment confirmed. Requesting access...'
} }
export const publishFeedback: { [key in number]: string } = { export const publishFeedback: { [key in number]: string } = {