diff --git a/CodeExamples.md b/CodeExamples.md index 9085df90..a385b17e 100644 --- a/CodeExamples.md +++ b/CodeExamples.md @@ -1,22 +1,12 @@ # Ocean.js Code Examples -The following guide runs you through the process of using ocean.js in a publish flow. The code examples below are all working and you can learn how to publish by following along. +The following guide runs you through the process of using ocean.js to publish and then consume a dataset. The code examples below are all working and you can learn how to publish by following along. Start by importing all of the necessary dependencies ```Typescript -import MockERC20 from '@oceanprotocol/contracts/artifacts/contracts/utils/mock/MockERC20Decimals.sol/MockERC20Decimals.json' -import { assert } from 'chai' + import { SHA256 } from 'crypto-js' -import { AbiItem } from 'web3-utils' -import { - ValidateMetadata, - DDO, - Erc20CreateParams, - PoolCreationParams, - FreCreationParams, - DispenserCreationParams -} from '../../src/@types' import { web3, getTestConfig, getAddresses } from '../config' import { Config, @@ -24,56 +14,43 @@ import { Aquarius, NftFactory, NftCreateData, + Datatoken, getHash, - ZERO_ADDRESS, - Nft + Nft, + downloadFile } from '../../src' -``` +import { ProviderFees, Erc20CreateParams } from '../../src/@types' -Here we define some variables that we will use later -```Typescript -let nft: Nft -let factory: NftFactory -let accounts: string[] -``` - -We will need a file to publish, so here we define the file that we intend to publish. - -```Typescript -const files = [ +const assetUrl = [ { type: 'url', url: 'https://raw.githubusercontent.com/oceanprotocol/testdatasets/main/shs_dataset_test.txt', method: 'GET' } ] -``` - -Next, we define the metadata that will describe our data asset. This is what we call the DDO -```Typescript -const genericAsset: DDO = { +const ddo = { '@context': ['https://w3id.org/did/v1'], - id: 'testFakeDid', + id: 'did:op:efba17455c127a885ec7830d687a8f6e64f5ba559f8506f8723c1f10f05c049c', version: '4.0.0', chainId: 4, nftAddress: '0x0', metadata: { created: '2021-12-20T14:35:20Z', updated: '2021-12-20T14:35:20Z', - name: 'dataset-name', type: 'dataset', - description: 'Ocean protocol test dataset description', - author: 'oceanprotocol-team', - license: 'MIT', - tags: ['white-papers'], - additionalInformation: { 'test-key': 'test-value' }, - links: ['http://data.ceda.ac.uk/badc/ukcp09/'] + name: 'dfgdfgdg', + description: 'd dfgd fgd dfg dfgdfgd dfgdf', + tags: [''], + author: 'dd', + license: 'https://market.oceanprotocol.com/terms', + additionalInformation: { + termsAndConditions: true + } }, services: [ { - id: 'testFakeId', + id: 'notAnId', type: 'access', - description: 'Download service', files: '', datatokenAddress: '0xa15024b732A8f2146423D14209eFd074e61964F3', serviceEndpoint: 'https://providerv4.rinkeby.oceanprotocol.com', @@ -81,10 +58,8 @@ const genericAsset: DDO = { } ] } -``` -## Publishing a dataset -```Typescript +## Simple Publish & consume test let config: Config let addresses: any let aquarius: Aquarius @@ -95,247 +70,56 @@ const genericAsset: DDO = { addresses = getAddresses() aquarius = new Aquarius(config.metadataCacheUri) providerUrl = config.providerUri - ``` - - ### initialise testes classes -```Typescript - nft = new Nft(web3) - factory = new NftFactory(addresses.ERC721Factory, web3) - accounts = await web3.eth.getAccounts() - const daiContract = new web3.eth.Contract( - MockERC20.abi as AbiItem[], - addresses.MockDAI - ) - await daiContract.methods - .approve(addresses.ERC721Factory, web3.utils.toWei('100000')) - .send({ from: accounts[0] }) }) -``` - ### should publish a dataset with pool (create NFT + ERC20 + pool) and with Metdata proof -```Typescript - const poolDdo: DDO = { ...genericAsset } + ### should publish a dataset (create NFT + ERC20) + const nft = new Nft(web3) + const datatoken = new Datatoken(web3) + const Factory = new NftFactory(addresses.ERC721Factory, web3) + const accounts = await web3.eth.getAccounts() + const publisherAccount = accounts[0] + const consumerAccount = accounts[1] const nftParams: NftCreateData = { - name: 'testNftPool', - symbol: 'TSTP', + name: 'testNFT', + symbol: 'TST', templateIndex: 1, tokenURI: '', transferable: true, - owner: accounts[0] + owner: publisherAccount } const erc20Params: Erc20CreateParams = { templateIndex: 1, cap: '100000', feeAmount: '0', - paymentCollector: ZERO_ADDRESS, - feeToken: ZERO_ADDRESS, - minter: accounts[0], - mpFeeAddress: ZERO_ADDRESS + paymentCollector: '0x0000000000000000000000000000000000000000', + feeToken: '0x0000000000000000000000000000000000000000', + minter: publisherAccount, + mpFeeAddress: '0x0000000000000000000000000000000000000000' } - const poolParams: PoolCreationParams = { - ssContract: addresses.Staking, - baseTokenAddress: addresses.MockDAI, - baseTokenSender: addresses.ERC721Factory, - publisherAddress: accounts[0], - marketFeeCollector: accounts[0], - poolTemplateAddress: addresses.poolTemplate, - rate: '1', - baseTokenDecimals: 18, - vestingAmount: '10000', - vestedBlocks: 2500000, - initialBaseTokenLiquidity: '2000', - swapFeeLiquidityProvider: '0.001', - swapFeeMarketRunner: '0.001' - } - const bundleNFT = await factory.createNftErc20WithPool( - accounts[0], + const result = await Factory.createNftWithErc20( + publisherAccount, nftParams, - erc20Params, - poolParams + erc20Params ) + const erc721Address = result.events.NFTCreated.returnValues[0] + const datatokenAddress = result.events.TokenCreated.returnValues[0] - const nftAddress = bundleNFT.events.NFTCreated.returnValues[0] - const datatokenAddress = bundleNFT.events.TokenCreated.returnValues[0] - const poolAdress = bundleNFT.events.NewPool.returnValues[0] - - const encryptedFiles = await ProviderInstance.encrypt(files, providerUrl) - - poolDdo.metadata.name = 'test-dataset-pool' - poolDdo.services[0].files = await encryptedFiles - poolDdo.services[0].datatokenAddress = datatokenAddress - - poolDdo.nftAddress = nftAddress + // create the files encrypted string + let providerResponse = await ProviderInstance.encrypt(assetUrl, providerUrl) + ddo.services[0].files = await providerResponse + ddo.services[0].datatokenAddress = datatokenAddress + // update ddo and set the right did + ddo.nftAddress = erc721Address const chain = await web3.eth.getChainId() - poolDdo.chainId = chain - poolDdo.id = - 'did:op:' + SHA256(web3.utils.toChecksumAddress(nftAddress) + chain.toString(10)) + ddo.id = + 'did:op:' + SHA256(web3.utils.toChecksumAddress(erc721Address) + chain.toString(10)) - const AssetValidation: ValidateMetadata = await aquarius.validate(poolDdo) - assert(AssetValidation.valid === true, 'Published asset is not valid') - - const encryptedDdo = await ProviderInstance.encrypt(poolDdo, providerUrl) - const encryptedResponse = await encryptedDdo - const metadataHash = getHash(JSON.stringify(poolDdo)) - // just to make sure that our hash matches one computed by aquarius - assert(AssetValidation.hash === '0x' + metadataHash, 'Metadata hash is a missmatch') - const tx = await nft.setMetadata( - nftAddress, - accounts[0], - 0, - providerUrl, - '', - '0x2', - encryptedResponse, - '0x' + metadataHash, - [AssetValidation.proof] - ) - - const resolvedDDO = await aquarius.waitForAqua(poolDdo.id) - assert(resolvedDDO, 'Cannot fetch DDO from Aquarius') - }) -``` - - ### should publish a dataset with fixed price (create NFT + ERC20 + fixed price) with an explicit empty Metadata Proof -```Typescript - const fixedPriceDdo: DDO = { ...genericAsset } - const nftParams: NftCreateData = { - name: 'testNftFre', - symbol: 'TSTF', - templateIndex: 1, - tokenURI: '', - transferable: true, - owner: accounts[0] - } - const erc20Params: Erc20CreateParams = { - templateIndex: 1, - cap: '100000', - feeAmount: '0', - paymentCollector: ZERO_ADDRESS, - feeToken: ZERO_ADDRESS, - minter: accounts[0], - mpFeeAddress: ZERO_ADDRESS - } - - const fixedPriceParams: FreCreationParams = { - fixedRateAddress: addresses.FixedPrice, - baseTokenAddress: addresses.MockDAI, - owner: accounts[0], - marketFeeCollector: accounts[0], - baseTokenDecimals: 18, - datatokenDecimals: 18, - fixedRate: '1', - marketFee: '0', - allowedConsumer: accounts[0], - withMint: false - } - - const bundleNFT = await factory.createNftErc20WithFixedRate( - accounts[0], - nftParams, - erc20Params, - fixedPriceParams - ) - - const nftAddress = bundleNFT.events.NFTCreated.returnValues[0] - const datatokenAddress = bundleNFT.events.TokenCreated.returnValues[0] - const fixedPrice = bundleNFT.events.NewFixedRate.returnValues[0] - - const encryptedFiles = await ProviderInstance.encrypt(files, providerUrl) - - fixedPriceDdo.metadata.name = 'test-dataset-fixedPrice' - fixedPriceDdo.services[0].files = await encryptedFiles - fixedPriceDdo.services[0].datatokenAddress = datatokenAddress - - fixedPriceDdo.nftAddress = nftAddress - const chain = await web3.eth.getChainId() - fixedPriceDdo.chainId = chain - fixedPriceDdo.id = - 'did:op:' + SHA256(web3.utils.toChecksumAddress(nftAddress) + chain.toString(10)) - - const isAssetValid: ValidateMetadata = await aquarius.validate(fixedPriceDdo) - assert(isAssetValid.valid === true, 'Published asset is not valid') - - const encryptedDdo = await ProviderInstance.encrypt(fixedPriceDdo, providerUrl) - const encryptedResponse = await encryptedDdo - const metadataHash = getHash(JSON.stringify(fixedPriceDdo)) - // this is publishing with an explicit empty metadataProofs + providerResponse = await ProviderInstance.encrypt(ddo, providerUrl) + const encryptedResponse = await providerResponse + const metadataHash = getHash(JSON.stringify(ddo)) const res = await nft.setMetadata( - nftAddress, - accounts[0], - 0, - providerUrl, - '', - '0x2', - encryptedResponse, - '0x' + metadataHash, - [] - ) - const resolvedDDO = await aquarius.waitForAqua(fixedPriceDdo.id) - assert(resolvedDDO, 'Cannot fetch DDO from Aquarius') - ``` - - - ### should publish a dataset with dispenser (create NFT + ERC20 + dispenser) with no defined MetadataProof -```Typescript - const dispenserDdo: DDO = { ...genericAsset } - const nftParams: NftCreateData = { - name: 'testNftDispenser', - symbol: 'TSTD', - templateIndex: 1, - tokenURI: '', - transferable: true, - owner: accounts[0] - } - const erc20Params: Erc20CreateParams = { - templateIndex: 1, - cap: '100000', - feeAmount: '0', - paymentCollector: ZERO_ADDRESS, - feeToken: ZERO_ADDRESS, - minter: accounts[0], - mpFeeAddress: ZERO_ADDRESS - } - - const dispenserParams: DispenserCreationParams = { - dispenserAddress: addresses.Dispenser, - maxTokens: '1', - maxBalance: '1', - withMint: true, - allowedSwapper: ZERO_ADDRESS - } - - const bundleNFT = await factory.createNftErc20WithDispenser( - accounts[0], - nftParams, - erc20Params, - dispenserParams - ) - - const nftAddress = bundleNFT.events.NFTCreated.returnValues[0] - const datatokenAddress = bundleNFT.events.TokenCreated.returnValues[0] - const dispenserAddress = bundleNFT.events.DispenserCreated.returnValues[0] - - const encryptedFiles = await ProviderInstance.encrypt(files, providerUrl) - dispenserDdo.metadata.name = 'test-dataset-dispenser' - dispenserDdo.services[0].files = await encryptedFiles - dispenserDdo.services[0].datatokenAddress = datatokenAddress - - dispenserDdo.nftAddress = nftAddress - const chain = await web3.eth.getChainId() - dispenserDdo.chainId = chain - dispenserDdo.id = - 'did:op:' + SHA256(web3.utils.toChecksumAddress(nftAddress) + chain.toString(10)) - - const isAssetValid: ValidateMetadata = await aquarius.validate(dispenserDdo) - assert(isAssetValid.valid === true, 'Published asset is not valid') - - const encryptedDdo = await ProviderInstance.encrypt(dispenserDdo, providerUrl) - const encryptedResponse = await encryptedDdo - const metadataHash = getHash(JSON.stringify(dispenserDdo)) - // this is publishing with any explicit metadataProofs - const res = await nft.setMetadata( - nftAddress, - accounts[0], + erc721Address, + publisherAccount, 0, providerUrl, '', @@ -343,7 +127,51 @@ const genericAsset: DDO = { encryptedResponse, '0x' + metadataHash ) - const resolvedDDO = await aquarius.waitForAqua(dispenserDdo.id) + const resolvedDDO = await aquarius.waitForAqua(ddo.id) assert(resolvedDDO, 'Cannot fetch DDO from Aquarius') - ``` - + // mint 1 ERC20 and send it to the consumer + await datatoken.mint(datatokenAddress, publisherAccount, '1', consumerAccount) + // initialize provider + const initializeData = await ProviderInstance.initialize( + resolvedDDO.id, + resolvedDDO.services[0].id, + 0, + consumerAccount, + providerUrl + ) + const providerFees: ProviderFees = { + providerFeeAddress: initializeData.providerFee.providerFeeAddress, + providerFeeToken: initializeData.providerFee.providerFeeToken, + providerFeeAmount: initializeData.providerFee.providerFeeAmount, + v: initializeData.providerFee.v, + r: initializeData.providerFee.r, + s: initializeData.providerFee.s, + providerData: initializeData.providerFee.providerData, + validUntil: initializeData.providerFee.validUntil + } + // make the payment + const txid = await datatoken.startOrder( + datatokenAddress, + consumerAccount, + consumerAccount, + 0, + providerFees + ) + // get the url + const downloadURL = await ProviderInstance.getDownloadUrl( + ddo.id, + consumerAccount, + ddo.services[0].id, + 0, + txid.transactionHash, + providerUrl, + web3 + ) + assert(downloadURL, 'Provider getDownloadUrl failed') + try { + const fileData = await downloadFile(downloadURL) + } catch (e) { + assert.fail('Download failed') + } + }) +}) diff --git a/scripts/createGuide.sh b/scripts/createGuide.sh index 348f9526..89381b2e 100755 --- a/scripts/createGuide.sh +++ b/scripts/createGuide.sh @@ -1,6 +1,10 @@ #!/bin/bash # Create markdown file -cp test/integration/ReameFlow.test.ts CodeExamples.md +cp test/integration/ReadmeFlow.test.ts CodeExamples.md + +# Remove unneccessay imports +sed -i "s/import { assert } from 'chai'//" CodeExamples.md + # Replace comments sed -i 's/}) \/\/\/ //' CodeExamples.md diff --git a/test/integration/ReadmeFlow.test.ts b/test/integration/ReadmeFlow.test.ts new file mode 100644 index 00000000..5b6da188 --- /dev/null +++ b/test/integration/ReadmeFlow.test.ts @@ -0,0 +1,177 @@ +/// # Ocean.js Code Examples + +/// The following guide runs you through the process of using ocean.js to publish and then consume a dataset. The code examples below are all working and you can learn how to publish by following along. + +/// Start by importing all of the necessary dependencies + +/// ```Typescript +import { assert } from 'chai' +import { SHA256 } from 'crypto-js' +import { web3, getTestConfig, getAddresses } from '../config' +import { + Config, + ProviderInstance, + Aquarius, + NftFactory, + NftCreateData, + Datatoken, + getHash, + Nft, + downloadFile +} from '../../src' +import { ProviderFees, Erc20CreateParams } from '../../src/@types' + +const assetUrl = [ + { + type: 'url', + url: 'https://raw.githubusercontent.com/oceanprotocol/testdatasets/main/shs_dataset_test.txt', + method: 'GET' + } +] +const ddo = { + '@context': ['https://w3id.org/did/v1'], + id: 'did:op:efba17455c127a885ec7830d687a8f6e64f5ba559f8506f8723c1f10f05c049c', + version: '4.0.0', + chainId: 4, + nftAddress: '0x0', + metadata: { + created: '2021-12-20T14:35:20Z', + updated: '2021-12-20T14:35:20Z', + type: 'dataset', + name: 'dfgdfgdg', + description: 'd dfgd fgd dfg dfgdfgd dfgdf', + tags: [''], + author: 'dd', + license: 'https://market.oceanprotocol.com/terms', + additionalInformation: { + termsAndConditions: true + } + }, + services: [ + { + id: 'notAnId', + type: 'access', + files: '', + datatokenAddress: '0xa15024b732A8f2146423D14209eFd074e61964F3', + serviceEndpoint: 'https://providerv4.rinkeby.oceanprotocol.com', + timeout: 0 + } + ] +} + +describe('Simple Publish & consume test', async () => { + let config: Config + let addresses: any + let aquarius: Aquarius + let providerUrl: any + + before(async () => { + config = await getTestConfig(web3) + addresses = getAddresses() + aquarius = new Aquarius(config.metadataCacheUri) + providerUrl = config.providerUri + }) + + it('should publish a dataset (create NFT + ERC20)', async () => { + const nft = new Nft(web3) + const datatoken = new Datatoken(web3) + const Factory = new NftFactory(addresses.ERC721Factory, web3) + const accounts = await web3.eth.getAccounts() + const publisherAccount = accounts[0] + const consumerAccount = accounts[1] + const nftParams: NftCreateData = { + name: 'testNFT', + symbol: 'TST', + templateIndex: 1, + tokenURI: '', + transferable: true, + owner: publisherAccount + } + const erc20Params: Erc20CreateParams = { + templateIndex: 1, + cap: '100000', + feeAmount: '0', + paymentCollector: '0x0000000000000000000000000000000000000000', + feeToken: '0x0000000000000000000000000000000000000000', + minter: publisherAccount, + mpFeeAddress: '0x0000000000000000000000000000000000000000' + } + const result = await Factory.createNftWithErc20( + publisherAccount, + nftParams, + erc20Params + ) + const erc721Address = result.events.NFTCreated.returnValues[0] + const datatokenAddress = result.events.TokenCreated.returnValues[0] + + // create the files encrypted string + let providerResponse = await ProviderInstance.encrypt(assetUrl, providerUrl) + ddo.services[0].files = await providerResponse + ddo.services[0].datatokenAddress = datatokenAddress + // update ddo and set the right did + ddo.nftAddress = erc721Address + const chain = await web3.eth.getChainId() + ddo.id = + 'did:op:' + SHA256(web3.utils.toChecksumAddress(erc721Address) + chain.toString(10)) + + providerResponse = await ProviderInstance.encrypt(ddo, providerUrl) + const encryptedResponse = await providerResponse + const metadataHash = getHash(JSON.stringify(ddo)) + const res = await nft.setMetadata( + erc721Address, + publisherAccount, + 0, + providerUrl, + '', + '0x2', + encryptedResponse, + '0x' + metadataHash + ) + const resolvedDDO = await aquarius.waitForAqua(ddo.id) + assert(resolvedDDO, 'Cannot fetch DDO from Aquarius') + // mint 1 ERC20 and send it to the consumer + await datatoken.mint(datatokenAddress, publisherAccount, '1', consumerAccount) + // initialize provider + const initializeData = await ProviderInstance.initialize( + resolvedDDO.id, + resolvedDDO.services[0].id, + 0, + consumerAccount, + providerUrl + ) + const providerFees: ProviderFees = { + providerFeeAddress: initializeData.providerFee.providerFeeAddress, + providerFeeToken: initializeData.providerFee.providerFeeToken, + providerFeeAmount: initializeData.providerFee.providerFeeAmount, + v: initializeData.providerFee.v, + r: initializeData.providerFee.r, + s: initializeData.providerFee.s, + providerData: initializeData.providerFee.providerData, + validUntil: initializeData.providerFee.validUntil + } + // make the payment + const txid = await datatoken.startOrder( + datatokenAddress, + consumerAccount, + consumerAccount, + 0, + providerFees + ) + // get the url + const downloadURL = await ProviderInstance.getDownloadUrl( + ddo.id, + consumerAccount, + ddo.services[0].id, + 0, + txid.transactionHash, + providerUrl, + web3 + ) + assert(downloadURL, 'Provider getDownloadUrl failed') + try { + const fileData = await downloadFile(downloadURL) + } catch (e) { + assert.fail('Download failed') + } + }) +}) diff --git a/test/integration/ReameFlow.test.ts b/test/integration/ReamePublishFlow.test.ts similarity index 98% rename from test/integration/ReameFlow.test.ts rename to test/integration/ReamePublishFlow.test.ts index 538b1b65..c047cf5c 100644 --- a/test/integration/ReameFlow.test.ts +++ b/test/integration/ReamePublishFlow.test.ts @@ -84,7 +84,7 @@ const genericAsset: DDO = { /// ``` describe('Publishing a dataset', async () => { -/// ```Typescript + /// ```Typescript let config: Config let addresses: any let aquarius: Aquarius @@ -98,7 +98,7 @@ describe('Publishing a dataset', async () => { }) /// ``` it('initialise testes classes', async () => { -/// ```Typescript + /// ```Typescript nft = new Nft(web3) factory = new NftFactory(addresses.ERC721Factory, web3) accounts = await web3.eth.getAccounts() @@ -112,7 +112,7 @@ describe('Publishing a dataset', async () => { }) /// ``` it('should publish a dataset with pool (create NFT + ERC20 + pool) and with Metdata proof', async () => { -/// ```Typescript + /// ```Typescript const poolDdo: DDO = { ...genericAsset } const nftParams: NftCreateData = { name: 'testNftPool', @@ -194,7 +194,7 @@ describe('Publishing a dataset', async () => { }) /// ``` it('should publish a dataset with fixed price (create NFT + ERC20 + fixed price) with an explicit empty Metadata Proof', async () => { -/// ```Typescript + /// ```Typescript const fixedPriceDdo: DDO = { ...genericAsset } const nftParams: NftCreateData = { name: 'testNftFre', @@ -272,9 +272,8 @@ describe('Publishing a dataset', async () => { assert(resolvedDDO, 'Cannot fetch DDO from Aquarius') }) /// ``` - it('should publish a dataset with dispenser (create NFT + ERC20 + dispenser) with no defined MetadataProof', async () => { -/// ```Typescript + /// ```Typescript const dispenserDdo: DDO = { ...genericAsset } const nftParams: NftCreateData = { name: 'testNftDispenser', @@ -344,4 +343,4 @@ describe('Publishing a dataset', async () => { const resolvedDDO = await aquarius.waitForAqua(dispenserDdo.id) assert(resolvedDDO, 'Cannot fetch DDO from Aquarius') }) /// ``` -}) /// +}) ///