diff --git a/src/datatokens/Datatokens.ts b/src/datatokens/Datatokens.ts index d8d1201d..b8f90f99 100644 --- a/src/datatokens/Datatokens.ts +++ b/src/datatokens/Datatokens.ts @@ -40,9 +40,9 @@ export class DataTokens { */ public async create(metaDataStoreURI: string, account: Account): Promise { // Create factory contract object - const factory = new this.web3.eth.Contract(this.factoryABI, this.factoryAddress, { - from: account - }) + const factory = new this.web3.eth.Contract( + this.factoryABI, this.factoryAddress, {from: account} + ) const estGas = await factory.methods .createToken(metaDataStoreURI) .estimateGas(function (err, estGas) { diff --git a/src/ddo/interfaces/Service.ts b/src/ddo/interfaces/Service.ts index c60d7c05..6e69c86b 100644 --- a/src/ddo/interfaces/Service.ts +++ b/src/ddo/interfaces/Service.ts @@ -33,7 +33,7 @@ export interface ServiceComputeAttributes extends ServiceCommonAttributes { main: { creator: string datePublished: string - price: string + cost: string timeout: number provider?: ServiceComputeProvider name: string @@ -57,7 +57,7 @@ export interface ServiceComputeProvider { supportedServers: { serverId: string serverType: string - price: string + cost: string cpu: string gpu: string memory: string @@ -74,13 +74,11 @@ export interface ServiceMetadata extends ServiceCommon { export interface ServiceAccess extends ServiceCommon { type: 'access' - templateId?: string attributes: ServiceAccessAttributes } export interface ServiceCompute extends ServiceCommon { type: 'compute' - templateId?: string attributes: ServiceComputeAttributes } diff --git a/src/ocean/Assets.ts b/src/ocean/Assets.ts index 1a8bf501..1143d54c 100644 --- a/src/ocean/Assets.ts +++ b/src/ocean/Assets.ts @@ -33,20 +33,6 @@ export enum OrderProgressStep { TransferDataToken } -export const ComputeJobStatus = Object.freeze({ - Started: 10, - ConfiguringVolumes: 20, - ProvisioningSuccess: 30, - DataProvisioningFailed: 31, - AlgorithmProvisioningFailed: 32, - RunningAlgorithm: 40, - FilteringResults: 50, - PublishingResult: 60, - Completed: 70, - Stopped: 80, - Deleted: 90 -}) - /** * Assets submodule of Ocean Protocol. */ @@ -458,205 +444,4 @@ export class Assets extends Instantiable { return serviceEndpoint } - - /** - * Start the execution of a compute job. - * @param {Account} consumerAccount The account of the consumer ordering the service. - * @param {string} did Decentralized identifer for the asset - * @param {string} algorithmDid The DID of the algorithm asset (of type `algorithm`) to run on the asset. - * @param {MetaData} algorithmMeta Metadata about the algorithm being run if `algorithm` is being used. This is ignored when `algorithmDid` is specified. - * @param {Output} output Define algorithm output publishing. Publishing the result of a compute job is turned off by default. - * @return {Promise} Returns compute job ID under status.jobId - */ - public async start( - consumerAccount: Account, - did: string, - algorithmDid?: string, - algorithmMeta?: MetadataAlgorithm, - output?: Output - ): Promise { - output = this.checkOutput(consumerAccount, output) - if (did) { - const computeJobsList = await this.ocean.provider.compute( - 'post', - did, - consumerAccount, - algorithmDid, - algorithmMeta, - undefined, - output - ) - return computeJobsList[0] as ComputeJob - } else return null - } - - /** - * Ends a running compute job. - * @param {Account} consumerAccount The account of the consumer ordering the service. - * @param {string} did Decentralized identifier. - * @param {string} jobId The ID of the compute job to be stopped - * @return {Promise} Returns the new status of a job - */ - public async stop( - consumerAccount: Account, - did: string, - jobId: string - ): Promise { - const computeJobsList = await this.ocean.provider.compute( - 'put', - did, - consumerAccount, - undefined, - undefined, - jobId - ) - - return computeJobsList[0] as ComputeJob - } - - /** - * Deletes a compute job and all resources associated with the job. If job is running it will be stopped first. - * @param {Account} consumerAccount The account of the consumer ordering the service. - * @param {string} did Decentralized identifier. - * @param {string} jobId The ID of the compute job to be stopped - * @return {Promise} Returns the new status of a job - */ - public async delete( - consumerAccount: Account, - did: string, - jobId: string - ): Promise { - const computeJobsList = await this.ocean.provider.compute( - 'delete', - did, - consumerAccount, - undefined, - undefined, - jobId - ) - - return computeJobsList[0] as ComputeJob - } - - /** - * Ends a running compute job and starts it again. - * @param {Account} consumerAccount The account of the consumer ordering the service. - * @param {string} did Decentralized identifier. - * @param {string} jobId The ID of the compute job to be stopped - * @return {Promise} Returns the new status of a job - */ - public async restart( - consumerAccount: Account, - did: string, - jobId: string - ): Promise { - await this.stop(consumerAccount, did, jobId) - const result = await this.start(consumerAccount, did, jobId) - return result - } - - /** - * Returns information about the status of all compute jobs, or a single compute job. - * @param {Account} consumerAccount The account of the consumer ordering the service. - * @param {string} did Decentralized identifier. - * @param {string} jobId The ID of the compute job to be stopped - * @return {Promise} Returns the status - */ - public async status( - consumerAccount: Account, - did?: string, - jobId?: string - ): Promise { - const computeJobsList = await this.ocean.provider.compute( - 'get', - did, - consumerAccount, - undefined, - undefined, - jobId - ) - - return computeJobsList as ComputeJob[] - } - - /** - * Returns the final result of a specific compute job published as an asset. - * @param {Account} consumerAccount The account of the consumer ordering the service. - * @param {string} did Decentralized identifier. - * @param {string} jobId The ID of the compute job to be stopped. - * @return {Promise} Returns the DDO of the result asset. - */ - public async result( - consumerAccount: Account, - did: string, - jobId: string - ): Promise { - const computeJobsList = await this.ocean.provider.compute( - 'get', - did, - consumerAccount, - undefined, - undefined, - jobId - ) - - return computeJobsList[0] as ComputeJob - } - - public async createComputeServiceAttributes( - consumerAccount: Account, - price: string, - datePublished: string, - computePrivacy?: ServiceComputePrivacy, - timeout?: number - ): Promise { - const name = 'dataAssetComputingService' - if (!timeout) timeout = 3600 - // TODO - const service = { - type: 'compute', - index: 3, - serviceEndpoint: this.ocean.provider.getComputeEndpoint(), - attributes: { - main: { - creator: consumerAccount.getId(), - datePublished, - price, - privacy: {}, - timeout: timeout, - name - } - } - } - if (computePrivacy) service.attributes.main.privacy = computePrivacy - return service as ServiceCompute - } - - /** - * Check the output object and add default properties if needed - * @param {Account} consumerAccount The account of the consumer ordering the service. - * @param {Output} output Output section used for publishing the result. - * @return {Promise} Returns output object - */ - private checkOutput(consumerAccount: Account, output?: Output): Output { - const isDefault = - !output || (!output.publishAlgorithmLog && !output.publishOutput) - - if (isDefault) { - return { - publishAlgorithmLog: false, - publishOutput: false - } - } - - return { - publishAlgorithmLog: output.publishAlgorithmLog, - publishOutput: output.publishOutput, - providerAddress: output.providerAddress || this.config.providerAddress, - providerUri: output.providerUri || this.config.providerUri, - metadataUri: output.metadataUri || this.config.metadataStoreUri, - nodeUri: output.nodeUri || this.config.nodeUri, - owner: output.owner || consumerAccount.getId() - } - } } diff --git a/src/ocean/Compute.ts b/src/ocean/Compute.ts new file mode 100644 index 00000000..2b62c5e4 --- /dev/null +++ b/src/ocean/Compute.ts @@ -0,0 +1,309 @@ +import { SearchQuery } from '../metadatastore/MetadataStore' +import { DDO } from '../ddo/DDO' +import { Metadata } from '../ddo/interfaces/Metadata' +import { MetadataAlgorithm } from '../ddo/interfaces/MetadataAlgorithm' +import { + Service, + ServiceComputePrivacy, + ServiceCompute +} from '../ddo/interfaces/Service' +import { EditableMetadata } from '../ddo/interfaces/EditableMetadata' +import Account from './Account' +import DID from './DID' +import { SubscribablePromise } from '../utils' +import { Instantiable, InstantiableConfig } from '../Instantiable.abstract' +import {Output} from "./interfaces/ComputeOutput"; +import {ComputeJob} from "./interfaces/ComputeJob"; +// import { WebServiceConnector } from './utils/WebServiceConnector' +// import { Output } from './interfaces/ComputeOutput' +// import { ComputeJob } from './interfaces/ComputeJob' + +export enum OrderProgressStep { + TransferDataToken +} + +export const ComputeJobStatus = Object.freeze({ + Started: 10, + ConfiguringVolumes: 20, + ProvisioningSuccess: 30, + DataProvisioningFailed: 31, + AlgorithmProvisioningFailed: 32, + RunningAlgorithm: 40, + FilteringResults: 50, + PublishingResult: 60, + Completed: 70, + Stopped: 80, + Deleted: 90 +}) + +/** + * Compute submodule of Ocean Protocol. + */ +export class Compute extends Instantiable { + /** + * Returns the instance of Compute. + * @return {Promise} + */ + public static async getInstance(config: InstantiableConfig): Promise { + const instance = new Compute() + instance.setInstanceConfig(config) + + return instance + } + + /** + * Start the execution of a compute job. + * @param {Account} consumerAccount The account of the consumer ordering the service. + * @param {string} did Decentralized identifer for the asset + * @param {string} algorithmDid The DID of the algorithm asset (of type `algorithm`) to run on the asset. + * @param {MetaData} algorithmMeta Metadata about the algorithm being run if `algorithm` is being used. This is ignored when `algorithmDid` is specified. + * @param {Output} output Define algorithm output publishing. Publishing the result of a compute job is turned off by default. + * @return {Promise} Returns compute job ID under status.jobId + */ + public async start( + consumerAccount: Account, + did: string, + algorithmDid?: string, + algorithmMeta?: MetadataAlgorithm, + output?: Output + ): Promise { + output = this.checkOutput(consumerAccount, output) + if (did) { + const computeJobsList = await this.ocean.provider.compute( + 'post', + did, + consumerAccount, + algorithmDid, + algorithmMeta, + undefined, + output + ) + return computeJobsList[0] as ComputeJob + } else return null + } + + /** + * Ends a running compute job. + * @param {Account} consumerAccount The account of the consumer ordering the service. + * @param {string} did Decentralized identifier. + * @param {string} jobId The ID of the compute job to be stopped + * @return {Promise} Returns the new status of a job + */ + public async stop( + consumerAccount: Account, + did: string, + jobId: string + ): Promise { + const computeJobsList = await this.ocean.provider.compute( + 'put', + did, + consumerAccount, + undefined, + undefined, + jobId + ) + + return computeJobsList[0] as ComputeJob + } + + /** + * Returns information about the status of all compute jobs, or a single compute job. + * @param {Account} consumerAccount The account of the consumer ordering the service. + * @param {string} did Decentralized identifier. + * @param {string} jobId The ID of the compute job to be stopped + * @return {Promise} Returns the status + */ + public async status( + consumerAccount: Account, + did?: string, + jobId?: string + ): Promise { + const computeJobsList = await this.ocean.provider.compute( + 'get', + did, + consumerAccount, + undefined, + undefined, + jobId + ) + + return computeJobsList as ComputeJob[] + } + + /** + * Returns the final result of a specific compute job published as an asset. + * @param {Account} consumerAccount The account of the consumer ordering the service. + * @param {string} did Decentralized identifier. + * @param {string} jobId The ID of the compute job to be stopped. + * @return {Promise} Returns the DDO of the result asset. + */ + public async result( + consumerAccount: Account, + did: string, + jobId: string + ): Promise { + const computeJobsList = await this.ocean.provider.compute( + 'get', + did, + consumerAccount, + undefined, + undefined, + jobId + ) + + return computeJobsList[0] as ComputeJob + } + + public createServerAttributes( + serverId: string, serverType: string, cost: string, + cpu: string, gpu: string, memory: string, + disk: string, maxExecutionTime: number + ): object { + return { + serverId, serverType, cost, cpu, gpu, memory, disk, maxExecutionTime + } + } + + public createContainerAttributes(image: string, tag: string, checksum: string): object { + return {image, tag, checksum} + } + + public createClusterAttributes(type: string, url: string): object { + return {type, url} + } + + public createProviderAttributes( + type: string, description: string, cluster: object, containers: object[], servers: object[] + ): object { + return { + type, + description, + environment: { + cluster: cluster, + supportedServers: containers, + supportedContainers: servers + } + } + } + + public createComputeService( + consumerAccount: Account, + cost: string, + datePublished: string, + providerAttributes: object, + computePrivacy?: ServiceComputePrivacy, + timeout?: number, + ): ServiceCompute { + const name = 'dataAssetComputingService' + if (!timeout) timeout = 3600 + + const service = { + type: 'compute', + index: 3, + serviceEndpoint: this.ocean.provider.getComputeEndpoint(), + attributes: { + main: { + name, + creator: consumerAccount.getId(), + datePublished, + cost, + timeout: timeout, + provider: providerAttributes, + privacy: {} + } + } + } + + if (computePrivacy) + service.attributes.main.privacy = computePrivacy + + return service as ServiceCompute + } + + /** + * Check the output object and add default properties if needed + * @param {Account} consumerAccount The account of the consumer ordering the service. + * @param {Output} output Output section used for publishing the result. + * @return {Promise} Returns output object + */ + private checkOutput(consumerAccount: Account, output?: Output): Output { + const isDefault = + !output || (!output.publishAlgorithmLog && !output.publishOutput) + + if (isDefault) { + return { + publishAlgorithmLog: false, + publishOutput: false + } + } + // 'signature': signature, + // 'documentId': did, + // 'serviceId': sa.index, + // 'serviceType': sa.type, + // 'consumerAddress': cons_acc.address, + // 'transferTxId': Web3.toHex(tx_id), + // 'dataToken': data_token, + // 'output': build_stage_output_dict(dict(), dataset_ddo_w_compute_service, cons_acc.address, pub_acc), + // 'algorithmDid': alg_ddo.did, + // 'algorithmMeta': {}, + // 'algorithmDataToken': alg_data_token + + return { + publishAlgorithmLog: output.publishAlgorithmLog, + publishOutput: output.publishOutput, + providerAddress: output.providerAddress || this.config.providerAddress, + providerUri: output.providerUri || this.config.providerUri, + metadataUri: output.metadataUri || this.config.metadataStoreUri, + nodeUri: output.nodeUri || this.config.nodeUri, + owner: output.owner || consumerAccount.getId() + } + } + +} +// "creator": "0x00Bd138aBD70e2F00903268F3Db08f2D25677C9e", + // "datePublished": "2019-04-09T19:02:11Z", + // "cost": "10", + // "timeout": 86400, + // "provider": { + // "type": "Azure", + // "description": "", + // "environment": { + // "cluster": { + // "type": "Kubernetes", + // "url": "http://10.0.0.17/xxx" + // }, + // "supportedContainers": [ + // { + // "image": "tensorflow/tensorflow", + // "tag": "latest", + // "checksum": "sha256:cb57ecfa6ebbefd8ffc7f75c0f00e57a7fa739578a429b6f72a0df19315deadc" + // }, + // { + // "image": "tensorflow/tensorflow", + // "tag": "latest", + // "checksum": "sha256:cb57ecfa6ebbefd8ffc7f75c0f00e57a7fa739578a429b6f72a0df19315deadc" + // } + // ], + // "supportedServers": [ + // { + // "serverId": "1", + // "serverType": "xlsize", + // "cost": "50", + // "cpu": "16", + // "gpu": "0", + // "memory": "128gb", + // "disk": "160gb", + // "maxExecutionTime": 86400 + // }, + // { + // "serverId": "2", + // "serverType": "medium", + // "cost": "10", + // "cpu": "2", + // "gpu": "0", + // "memory": "8gb", + // "disk": "80gb", + // "maxExecutionTime": 86400 + // } + // ] + // } diff --git a/src/ocean/Ocean.ts b/src/ocean/Ocean.ts index e52f95a8..ac18104b 100644 --- a/src/ocean/Ocean.ts +++ b/src/ocean/Ocean.ts @@ -17,6 +17,7 @@ import { Instantiable, generateIntantiableConfigFromConfig } from '../Instantiable.abstract' +import {Compute} from "./Compute"; /** * Main interface for Ocean Protocol. @@ -47,7 +48,7 @@ export class Ocean extends Instantiable { instance.accounts = await Accounts.getInstance(instanceConfig) // instance.auth = await Auth.getInstance(instanceConfig) instance.assets = await Assets.getInstance(instanceConfig) - // instance.compute = await Compute.getInstance(instanceConfig) + instance.compute = await Compute.getInstance(instanceConfig) instance.datatokens = new DataTokens( instanceConfig.config.factoryAddress, instanceConfig.config.factoryABI, @@ -105,9 +106,8 @@ export class Ocean extends Instantiable { /** * Ocean compute submodule * @type {Compute} - + */ public compute: Compute - */ /** * Ocean secretStore submodule diff --git a/src/provider/Provider.ts b/src/provider/Provider.ts index 9c14a763..263f06ad 100644 --- a/src/provider/Provider.ts +++ b/src/provider/Provider.ts @@ -174,6 +174,17 @@ export class Provider extends Instantiable { url += `&serviceType=${serviceType}` || '' url += `&dataToken=${tokenAddress}` || '' url += `&consumerAddress=${consumerAccount.getId()}` || '' + // 'signature': signature, + // 'documentId': did, + // 'serviceId': sa.index, + // 'serviceType': sa.type, + // 'consumerAddress': cons_acc.address, + // 'transferTxId': Web3.toHex(tx_id), + // 'dataToken': data_token, + // 'output': build_stage_output_dict(dict(), dataset_ddo_w_compute_service, cons_acc.address, pub_acc), + // 'algorithmDid': alg_ddo.did, + // 'algorithmMeta': {}, + // 'algorithmDataToken': alg_data_token // switch fetch method let fetch diff --git a/test/integration/ComputeFlow.test.ts b/test/integration/ComputeFlow.test.ts index 33bd3ed8..c13ddbca 100644 --- a/test/integration/ComputeFlow.test.ts +++ b/test/integration/ComputeFlow.test.ts @@ -22,9 +22,10 @@ describe('Marketplace flow', () => { let service1 let price let ocean - let accessService + let computeService let data let blob + const dateCreated = new Date(Date.now()).toISOString().split('.')[0] + 'Z' // remove milliseconds const marketplaceAllowance = 20 const tokenAmount = 100 @@ -60,13 +61,75 @@ describe('Marketplace flow', () => { assert(tokenAddress != null) }) - // it('Alice publishes dataset with a compute service', async () => {}) + it('Generates metadata', async () => { + asset = { + main: { + type: 'dataset', + name: 'UK Weather information 2011', + dateCreated: dateCreated, + author: 'Met Office', + license: 'CC-BY', + files: [ + { + url:'https://raw.githubusercontent.com/tbertinmahieux/MSongsDB/master/Tasks_Demos/CoverSongs/shs_dataset_test.txt', + checksum: 'efb2c764274b745f5fc37f97c6b0e764', + contentLength: '4535431', + contentType: 'text/csv', + encoding: 'UTF-8', + compression: 'zip' + } + ] + } + } + }) - // it('Alice mints 100 DTs and tranfers them to the compute marketplace', async () => {}) + it('Alice publishes dataset with a compute service', async () => { + price = 10 // in datatoken + const timeout = 86400 + 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) + ] + 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 computeService = ocean.compute.createComputeService( + alice, price, dateCreated, provider + ) + ddo = await ocean.assets.create(asset, alice, [computeService], tokenAddress) + assert(ddo.dataToken === tokenAddress) - // it('Markeplace post compute service for sale', async () => {}) + }) - // it('Bob buys datatokens from open market and order a compute service', async () => {}) + it('Alice mints 100 DTs and tranfers them to the compute marketplace', async () => { + await datatoken.mint(tokenAddress, alice.getId(), tokenAmount) + }) + + it('Marketplace posts compute service for sale', async () => { + computeService = await ocean.assets.getServiceByType(ddo.id, 'compute') + assert(computeService.attributes.main.cost === price) + }) + + it('Bob buys datatokens from open market and order a compute service', async () => { + const dTamount = 20 + await datatoken + .transfer(tokenAddress, bob.getId(), dTamount, alice.getId()) + .then(async () => { + const balance = await datatoken.balance(tokenAddress, bob.getId()) + assert(balance.toString() === dTamount.toString()) + }) + }) // it('Bob starts compute job', async () => {}) diff --git a/test/integration/Computeflow.test.ts b/test/integration/Computeflow.test.ts new file mode 100644 index 00000000..00ddf9bf --- /dev/null +++ b/test/integration/Computeflow.test.ts @@ -0,0 +1,188 @@ +import { TestContractHandler } from '../TestContractHandler' +import { DataTokens } from '../../src/datatokens/Datatokens' +import { Ocean } from '../../src/ocean/Ocean' +import config from './config' +import { assert } from 'console' + +const Web3 = require('web3') +const web3 = new Web3('http://127.0.0.1:8545') +const factory = require('@oceanprotocol/contracts/artifacts/development/Factory.json') +const datatokensTemplate = require('@oceanprotocol/contracts/artifacts/development/DataTokenTemplate.json') + +describe('Compute-2-Data flow', () => { + let owner + let bob + let ddo + let alice + let asset + let marketplace + let contracts + let datatoken + let tokenAddress + let service1 + let price + let ocean + let accessService + let data + let blob + + const marketplaceAllowance = 20 + const tokenAmount = 100 + + describe('#test', () => { + it('Initialize Ocean contracts v3', async () => { + contracts = new TestContractHandler( + factory.abi, + datatokensTemplate.abi, + datatokensTemplate.bytecode, + factory.bytecode, + web3 + ) + + ocean = await Ocean.getInstance(config) + owner = (await ocean.accounts.list())[0] + alice = (await ocean.accounts.list())[1] + bob = (await ocean.accounts.list())[2] + marketplace = (await ocean.accounts.list())[3] + data = { t: 1, url: ocean.config.metadataStoreUri } + blob = JSON.stringify(data) + await contracts.deployContracts(owner.getId()) + }) + + it('Alice publishes a datatoken contract', async () => { + datatoken = new DataTokens( + contracts.factoryAddress, + factory.abi, + datatokensTemplate.abi, + web3 + ) + tokenAddress = await datatoken.create(blob, alice.getId()) + assert(tokenAddress != null) + }) + + it('Generates metadata', async () => { + asset = { + main: { + type: 'dataset', + name: 'UK Weather information 2011', + dateCreated: new Date(Date.now()).toISOString().split('.')[0] + 'Z', // remove milliseconds + author: 'Met Office', + license: 'CC-BY', + files: [ + { + url:'https://raw.githubusercontent.com/tbertinmahieux/MSongsDB/master/Tasks_Demos/CoverSongs/shs_dataset_test.txt', + checksum: 'efb2c764274b745f5fc37f97c6b0e764', + contentLength: '4535431', + contentType: 'text/csv', + encoding: 'UTF-8', + compression: 'zip' + } + ] + } + } + }) + + it('Alice publishes a dataset', async () => { + price = 10 // in datatoken + const publishedDate = new Date(Date.now()).toISOString().split('.')[0] + 'Z' + const timeout = 0 + service1 = await ocean.assets.createAccessServiceAttributes( + alice, + price, + publishedDate, + timeout + ) + ddo = await ocean.assets.create(asset, alice, [service1], tokenAddress) + assert(ddo.dataToken === tokenAddress) + }) + + it('Alice mints 100 tokens', async () => { + await datatoken.mint(tokenAddress, alice.getId(), tokenAmount) + }) + + it('Alice allows marketplace to sell her datatokens', async () => { + await datatoken + .approve( + tokenAddress, + marketplace.getId(), + marketplaceAllowance, + alice.getId() + ) + .then(async () => { + const allowance = await datatoken.allowance( + tokenAddress, + alice.getId(), + marketplace.getId() + ) + assert(allowance.toString() === marketplaceAllowance.toString()) + }) + }) + + it('Marketplace withdraw Alice tokens from allowance', async () => { + const allowance = await datatoken.allowance( + tokenAddress, + alice.getId(), + marketplace.getId() + ) + await datatoken + .transferFrom(tokenAddress, alice.getId(), allowance, marketplace.getId()) + .then(async () => { + const marketplaceBalance = await datatoken.balance( + tokenAddress, + marketplace.getId() + ) + assert( + marketplaceBalance.toString() === marketplaceAllowance.toString() + ) + }) + }) + it('Marketplace should resolve asset using DID', async () => { + await ocean.assets.resolve(ddo.id).then((newDDO) => { + assert(newDDO.id === ddo.id) + }) + }) + + it('Marketplace posts asset for sale', async () => { + accessService = await ocean.assets.getServiceByType(ddo.id, 'access') + price = 20 + assert(accessService.attributes.main.cost * price === 200) + }) + + it('Bob gets datatokens', async () => { + const dTamount = 20 + await datatoken + .transfer(tokenAddress, bob.getId(), dTamount, alice.getId()) + .then(async () => { + const balance = await datatoken.balance(tokenAddress, bob.getId()) + assert(balance.toString() === dTamount.toString()) + }) + }) + + it('Bob consumes asset 1', async () => { + await ocean.assets + .order(ddo.id, accessService.type, bob.getId()) + .then(async (res: string) => { + res = JSON.parse(res) + return await datatoken.transfer( + res['dataToken'], + res['to'], + res['numTokens'], + res['from'] + ) + }) + .then(async (tx) => { + await ocean.assets.download( + ddo.id, + tx.transactionHash, + tokenAddress, + bob, + './node_modules/my-datasets' + ) + }) + }) + it('owner can list there assets', async () => { + const assets = await ocean.assets.ownerAssets(alice.getId()) + assert(assets.length > 0) + }) + }) +})