diff --git a/CodeExamples.md b/CodeExamples.md index b9e85205..4cab818b 100644 --- a/CodeExamples.md +++ b/CodeExamples.md @@ -84,9 +84,11 @@ Now open the `marketplace.js` file in your text editor. Start by importing all of the necessary dependencies ```Typescript +import fs from 'fs' -import { AbiItem } from 'web3-utils' +import { ethers, providers, Signer } from 'ethers' import { SHA256 } from 'crypto-js' +import { homedir } from 'os' import { approve, Aquarius, @@ -108,9 +110,14 @@ import { ProviderInstance, transfer, ZERO_ADDRESS, - sendTx + sendTx, + ConfigHelper, + configHelperNetworks, + amountToUnits, + ValidateMetadata, + getEventFromTx, + DDO } from '@oceanprotocol/lib' -import { getAddresses, getTestConfig, web3 } from '../config' ``` - -``` - - ### 5.2 Next, lets get the address of the deployed contracts -```Typescript - addresses = getAddresses() ``` ### 5.3 We send some OCEAN to consumer and staker accounts ```Typescript - transfer(web3, config, publisherAccount, addresses.Ocean, consumerAccount, '100') - transfer(web3, config, publisherAccount, addresses.Ocean, stakerAccount, '100') + transfer( + publisherAccount, + config, + addresses.Ocean, + await consumerAccount.getAddress(), + '100' + ) + transfer( + publisherAccount, + config, + addresses.Ocean, + await stakerAccount.getAddress(), + '100' + ) ``` @@ -275,7 +296,7 @@ Again, lets console log the values so that we can check that they have been save ### 6.1 Publish a dataset (create NFT + Datatoken) with a fixed rate exchange ```Typescript - const factory = new NftFactory(addresses.ERC721Factory, web3) + const factory = new NftFactory(addresses.ERC721Factory, publisherAccount) const nftParams: NftCreateData = { name: FRE_NFT_NAME, @@ -283,7 +304,7 @@ Again, lets console log the values so that we can check that they have been save templateIndex: 1, tokenURI: '', transferable: true, - owner: publisherAccount + owner: await publisherAccount.getAddress() } const datatokenParams: DatatokenCreateParams = { @@ -292,15 +313,15 @@ Again, lets console log the values so that we can check that they have been save feeAmount: '0', paymentCollector: ZERO_ADDRESS, feeToken: ZERO_ADDRESS, - minter: publisherAccount, + minter: await publisherAccount.getAddress(), mpFeeAddress: ZERO_ADDRESS } const freParams: FreCreationParams = { fixedRateAddress: addresses.FixedPrice, baseTokenAddress: addresses.Ocean, - owner: publisherAccount, - marketFeeCollector: publisherAccount, + owner: await publisherAccount.getAddress(), + marketFeeCollector: await publisherAccount.getAddress(), baseTokenDecimals: 18, datatokenDecimals: 18, fixedRate: '1', @@ -309,17 +330,22 @@ Again, lets console log the values so that we can check that they have been save withMint: false } - const tx = await factory.createNftWithDatatokenWithFixedRate( - publisherAccount, + const bundleNFT = await factory.createNftWithDatatokenWithFixedRate( nftParams, datatokenParams, freParams ) - freNftAddress = tx.events.NFTCreated.returnValues[0] - freDatatokenAddress = tx.events.TokenCreated.returnValues[0] - freAddress = tx.events.NewFixedRate.returnValues.exchangeContract - freId = tx.events.NewFixedRate.returnValues.exchangeId + const trxReceipt = await bundleNFT.wait() + // events have been emitted + const nftCreatedEvent = getEventFromTx(trxReceipt, 'NFTCreated') + const tokenCreatedEvent = getEventFromTx(trxReceipt, 'TokenCreated') + const newFreEvent = getEventFromTx(trxReceipt, 'NewFixedRate') + + freNftAddress = nftCreatedEvent.args.newTokenAddress + freDatatokenAddress = tokenCreatedEvent.args.newTokenAddress + freAddress = newFreEvent.args.exchangeContract + freId = newFreEvent.args.exchangeId ``` Now let's console log each of those values to check everything is working @@ -333,54 +359,64 @@ Now let's console log each of those values to check everything is working ### 6.2 Set metadata in the fixed rate exchange NFT ```Typescript - const nft = new Nft(web3) + const nft = new Nft( + publisherAccount, + (await publisherAccount.provider.getNetwork()).chainId + ) + + fixedDDO = { ...genericAsset } ``` Now we are going to update the ddo and set the did ```Typescript - DDO.chainId = await web3.eth.getChainId() - DDO.id = + + fixedDDO.chainId = (await publisherAccount.provider.getNetwork()).chainId + fixedDDO.id = 'did:op:' + - SHA256(web3.utils.toChecksumAddress(freNftAddress) + DDO.chainId.toString(10)) - DDO.nftAddress = freNftAddress + SHA256(ethers.utils.getAddress(freNftAddress) + fixedDDO.chainId.toString(10)) + fixedDDO.nftAddress = freNftAddress ``` Next, let's encrypt the file(s) using provider ```Typescript ASSET_URL.datatokenAddress = freDatatokenAddress ASSET_URL.nftAddress = freNftAddress - const encryptedFiles = await ProviderInstance.encrypt( + fixedDDO.services[0].files = await ProviderInstance.encrypt( ASSET_URL, - DDO.chainId, + fixedDDO.chainId, providerUrl ) - DDO.services[0].files = await encryptedFiles - DDO.services[0].datatokenAddress = freDatatokenAddress + fixedDDO.services[0].datatokenAddress = freDatatokenAddress ``` Now let's console log the DID to check everything is working ```Typescript - console.log(`DID: ${DDO.id}`) + console.log(`DID: ${fixedDDO.id}`) - const providerResponse = await ProviderInstance.encrypt(DDO, DDO.chainId, providerUrl) + const providerResponse = await ProviderInstance.encrypt( + fixedDDO, + fixedDDO.chainId, + providerUrl + ) const encryptedDDO = await providerResponse - const metadataHash = getHash(JSON.stringify(DDO)) + const isAssetValid: ValidateMetadata = await aquarius.validate(fixedDDO) + assert(isAssetValid.valid === true, 'Published asset is not valid') await nft.setMetadata( freNftAddress, - publisherAccount, + await publisherAccount.getAddress(), 0, providerUrl, '', '0x2', encryptedDDO, - '0x' + metadataHash + isAssetValid.hash ) }) ``` ### 6.3 Marketplace displays fixed rate asset for sale ```Typescript - const fixedRate = new FixedRateExchange(freAddress, web3) + const fixedRate = new FixedRateExchange(freAddress, publisherAccount) const oceanAmount = await ( await fixedRate.calcBaseInGivenDatatokensOut(freId, '1') ).baseTokenAmount @@ -393,47 +429,75 @@ Now that the market has fetched those values it can display the asset on the fro ### 6.4 Consumer buys a fixed rate asset data asset, and downloads it ```Typescript - const datatoken = new Datatoken(web3) + datatoken = new Datatoken(publisherAccount) const DATATOKEN_AMOUNT = '10000' - await datatoken.mint(freDatatokenAddress, publisherAccount, DATATOKEN_AMOUNT) + await datatoken.mint( + freDatatokenAddress, + await publisherAccount.getAddress(), + DATATOKEN_AMOUNT + ) - const consumerETHBalance = await web3.eth.getBalance(consumerAccount) + const consumerBalance = await provider.getBalance(await consumerAccount.getAddress()) + const consumerETHBalance = ethers.utils.formatEther(consumerBalance) ``` Let's do a quick check of the consumer ETH balance before the swap ```Typescript console.log(`Consumer ETH balance: ${consumerETHBalance}`) - let consumerOCEANBalance = await balance(web3, addresses.Ocean, consumerAccount) + let consumerOCEANBalance = await balance( + consumerAccount, + addresses.Ocean, + await consumerAccount.getAddress() + ) console.log(`Consumer OCEAN balance before swap: ${consumerOCEANBalance}`) - let consumerDTBalance = await balance(web3, freDatatokenAddress, consumerAccount) + let consumerDTBalance = await balance( + consumerAccount, + freDatatokenAddress, + await consumerAccount.getAddress() + ) console.log(`Consumer ${FRE_NFT_SYMBOL} balance before swap: ${consumerDTBalance}`) ``` Before we call the contract we have to call `approve` so that the contract can move our tokens. This is standard when using any ERC20 Datatokens ```Typescript - await approve(web3, config, consumerAccount, addresses.Ocean, freAddress, '100') await approve( - web3, + consumerAccount, config, + await consumerAccount.getAddress(), + addresses.Ocean, + freAddress, + '100' + ) + await approve( publisherAccount, + config, + await publisherAccount.getAddress(), freDatatokenAddress, freAddress, DATATOKEN_AMOUNT ) - const fixedRate = new FixedRateExchange(freAddress, web3) + const fixedRate = new FixedRateExchange(freAddress, consumerAccount) ``` Now we can make the contract call ```Typescript - await fixedRate.buyDatatokens(consumerAccount, freId, '1', '2') + await fixedRate.buyDatatokens(freId, '1', '2') - consumerOCEANBalance = await balance(web3, addresses.Ocean, consumerAccount) + consumerOCEANBalance = await balance( + consumerAccount, + addresses.Ocean, + await consumerAccount.getAddress() + ) console.log(`Consumer OCEAN balance after swap: ${consumerOCEANBalance}`) - consumerDTBalance = await balance(web3, freDatatokenAddress, consumerAccount) + consumerDTBalance = await balance( + consumerAccount, + freDatatokenAddress, + await consumerAccount.getAddress() + ) console.log(`Consumer ${FRE_NFT_SYMBOL} balance after swap: ${consumerDTBalance}`) - const resolvedDDO = await aquarius.waitForAqua(DDO.id) + const resolvedDDO = await aquarius.waitForAqua(fixedDDO.id) assert(resolvedDDO, 'Cannot fetch DDO from Aquarius') ``` @@ -443,7 +507,7 @@ Next, we need to initialize the provider resolvedDDO.id, resolvedDDO.services[0].id, 0, - consumerAccount, + await consumerAccount.getAddress(), providerUrl ) @@ -458,27 +522,29 @@ Next, we need to initialize the provider validUntil: initializeData.providerFee.validUntil } + datatoken = new Datatoken(consumerAccount) + ``` Lets now make the payment ```Typescript const tx = await datatoken.startOrder( freDatatokenAddress, - consumerAccount, - consumerAccount, + await consumerAccount.getAddress(), 0, providerFees ) + const orderTx = await tx.wait() + const orderStartedTx = getEventFromTx(orderTx, 'OrderStarted') ``` Now we can get the url ```Typescript const downloadURL = await ProviderInstance.getDownloadUrl( - DDO.id, - consumerAccount, - DDO.services[0].id, + fixedDDO.id, + fixedDDO.services[0].id, 0, - tx.transactionHash, + orderStartedTx.transactionHash, providerUrl, - web3 + consumerAccount ) ``` @@ -486,9 +552,17 @@ Lets check that the download URL was successfully received ```Typescript console.log(`Download URL: ${downloadURL}`) - consumerOCEANBalance = await balance(web3, addresses.Ocean, consumerAccount) + consumerOCEANBalance = await balance( + consumerAccount, + addresses.Ocean, + await consumerAccount.getAddress() + ) console.log(`Consumer OCEAN balance after order: ${consumerOCEANBalance}`) - consumerDTBalance = await balance(web3, freDatatokenAddress, consumerAccount) + consumerDTBalance = await balance( + consumerAccount, + freDatatokenAddress, + await consumerAccount.getAddress() + ) console.log(`Consumer ${FRE_NFT_SYMBOL} balance after order: ${consumerDTBalance}`) try { @@ -504,7 +578,7 @@ Lets check that the download URL was successfully received ### 7.1 Publish a dataset (create NFT + Datatoken) with a dispenser ```Typescript - const factory = new NftFactory(addresses.ERC721Factory, web3) + const factory = new NftFactory(addresses.ERC721Factory, publisherAccount) const nftParams: NftCreateData = { name: DISP_NFT_NAME, @@ -512,7 +586,7 @@ Lets check that the download URL was successfully received templateIndex: 1, tokenURI: '', transferable: true, - owner: publisherAccount + owner: await publisherAccount.getAddress() } const datatokenParams: DatatokenCreateParams = { @@ -521,7 +595,7 @@ Lets check that the download URL was successfully received feeAmount: '0', paymentCollector: ZERO_ADDRESS, feeToken: ZERO_ADDRESS, - minter: publisherAccount, + minter: await publisherAccount.getAddress(), mpFeeAddress: ZERO_ADDRESS } @@ -533,16 +607,19 @@ Lets check that the download URL was successfully received allowedSwapper: ZERO_ADDRESS } - const tx = await factory.createNftWithDatatokenWithDispenser( - publisherAccount, + const bundleNFT = await factory.createNftWithDatatokenWithDispenser( nftParams, datatokenParams, dispenserParams ) + const trxReceipt = await bundleNFT.wait() + const nftCreatedEvent = getEventFromTx(trxReceipt, 'NFTCreated') + const tokenCreatedEvent = getEventFromTx(trxReceipt, 'TokenCreated') + const dispenserCreatedEvent = getEventFromTx(trxReceipt, 'DispenserCreated') - dispenserNftAddress = tx.events.NFTCreated.returnValues[0] - dispenserDatatokenAddress = tx.events.TokenCreated.returnValues[0] - dispenserAddress = tx.events.DispenserCreated.returnValues[0] + dispenserNftAddress = nftCreatedEvent.args.newTokenAddress + dispenserDatatokenAddress = tokenCreatedEvent.args.newTokenAddress + dispenserAddress = dispenserCreatedEvent.args.newTokenAddress // double check this ``` Lets check that we managed to received all of those values without any problems ```Typescript @@ -554,57 +631,63 @@ Lets check that we managed to received all of those values without any problems ### 7.2 Set metadata in the dispenser NFT ```Typescript - const nft = new Nft(web3) + const nft = new Nft( + publisherAccount, + (await publisherAccount.provider.getNetwork()).chainId + ) ``` Lets start by updating the ddo and setting the did ```Typescript - DDO.chainId = await web3.eth.getChainId() - DDO.id = - 'did:op:' + - SHA256(web3.utils.toChecksumAddress(dispenserNftAddress) + DDO.chainId.toString(10)) - DDO.nftAddress = dispenserNftAddress + fixedDDO.chainId = (await publisherAccount.provider.getNetwork()).chainId + fixedDDO.id = + 'did:op:' + + SHA256(ethers.utils.getAddress(dispenserNftAddress) + fixedDDO.chainId.toString(10)) + fixedDDO.nftAddress = dispenserNftAddress ``` Now we need to encrypt file(s) using provider ```Typescript ASSET_URL.datatokenAddress = dispenserDatatokenAddress ASSET_URL.nftAddress = dispenserNftAddress - const encryptedFiles = await ProviderInstance.encrypt( + fixedDDO.services[0].files = await ProviderInstance.encrypt( ASSET_URL, - DDO.chainId, + fixedDDO.chainId, providerUrl ) - DDO.services[0].files = await encryptedFiles - DDO.services[0].datatokenAddress = dispenserDatatokenAddress + fixedDDO.services[0].datatokenAddress = dispenserDatatokenAddress - console.log(`DID: ${DDO.id}`) + console.log(`DID: ${fixedDDO.id}`) - const providerResponse = await ProviderInstance.encrypt(DDO, DDO.chainId, providerUrl) - const encryptedDDO = await providerResponse - const metadataHash = getHash(JSON.stringify(DDO)) + const encryptedDDO = await ProviderInstance.encrypt( + fixedDDO, + fixedDDO.chainId, + providerUrl + ) + const isAssetValid: ValidateMetadata = await aquarius.validate(fixedDDO) + assert(isAssetValid.valid === true, 'Published asset is not valid') await nft.setMetadata( dispenserNftAddress, - publisherAccount, + await publisherAccount.getAddress(), 0, providerUrl, '', '0x2', encryptedDDO, - '0x' + metadataHash + isAssetValid.hash ) ``` ### 7.3 Consumer gets a dispenser data asset, and downloads it ```Typescript - const datatoken = new Datatoken(web3) - const dispenser = new Dispenser(addresses.Dispenser, web3) + datatoken = new Datatoken(publisherAccount) + const dispenser = new Dispenser(addresses.Dispenser, consumerAccount) let consumerDTBalance = await balance( - web3, + consumerAccount, dispenserDatatokenAddress, - consumerAccount + await consumerAccount.getAddress() ) console.log( `Consumer ${DISP_NFT_SYMBOL} balance before dispense: ${consumerDTBalance}` @@ -612,18 +695,24 @@ Now we need to encrypt file(s) using provider await dispenser.dispense( dispenserDatatokenAddress, - consumerAccount, '1', - consumerAccount + await consumerAccount.getAddress() ) - consumerDTBalance = await balance(web3, dispenserDatatokenAddress, consumerAccount) + consumerDTBalance = await balance( + consumerAccount, + dispenserDatatokenAddress, + await consumerAccount.getAddress() + ) console.log( `Consumer ${DISP_NFT_SYMBOL} balance after dispense: ${consumerDTBalance}` ) - const resolvedDDO = await aquarius.waitForAqua(DDO.id) + const resolvedDDO = await aquarius.waitForAqua(fixedDDO.id) assert(resolvedDDO, 'Cannot fetch DDO from Aquarius') + + datatoken = new Datatoken(publisherAccount) + ``` At this point we need to encrypt file(s) using provider ```Typescript @@ -631,7 +720,7 @@ At this point we need to encrypt file(s) using provider resolvedDDO.id, resolvedDDO.services[0].id, 0, - consumerAccount, + await consumerAccount.getAddress(), providerUrl ) @@ -650,29 +739,33 @@ Now we need to make the payment ```Typescript const tx = await datatoken.startOrder( dispenserDatatokenAddress, - consumerAccount, - consumerAccount, + await consumerAccount.getAddress(), 0, providerFees ) + const orderTx = await tx.wait() + const orderStartedTx = getEventFromTx(orderTx, 'OrderStarted') ``` Now we can get the download URL ```Typescript const downloadURL = await ProviderInstance.getDownloadUrl( - DDO.id, - consumerAccount, - DDO.services[0].id, + fixedDDO.id, + fixedDDO.services[0].id, 0, - tx.transactionHash, + orderStartedTx.transactionHash, providerUrl, - web3 + consumerAccount ) ``` Let's check we received the download URL ok ```Typescript console.log(`Download URL: ${downloadURL}`) - consumerDTBalance = await balance(web3, dispenserDatatokenAddress, consumerAccount) + consumerDTBalance = await balance( + consumerAccount, + dispenserDatatokenAddress, + await consumerAccount.getAddress() + ) console.log(`Consumer ${DISP_NFT_SYMBOL} balance after order: ${consumerDTBalance}`) try { @@ -700,10 +793,10 @@ Here are the steps: ### 8.1 Add key-value pair to data NFT Let's start by using the `setData` method to update the nft key value store with some data ```Typescript - const nft = new Nft(web3) + const nft = new Nft(publisherAccount) const data = 'SomeData' try { - await nft.setData(freNftAddress, publisherAccount, '1', data) + await nft.setData(freNftAddress, await publisherAccount.getAddress(), '1', data) } catch (e) { assert.fail('Failed to set data in NFT ERC725 key value store', e) }