From f93664d07747e6e714f43d51ccf4d5184e3201fe Mon Sep 17 00:00:00 2001 From: Aitor <1726644+aaitor@users.noreply.github.com> Date: Tue, 3 Oct 2023 09:57:11 +0200 Subject: [PATCH 1/3] test: fix services e2e services flow --- integration/external/Services.e2e.test.ts | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/integration/external/Services.e2e.test.ts b/integration/external/Services.e2e.test.ts index dfdd99c99..6b79ad7e5 100644 --- a/integration/external/Services.e2e.test.ts +++ b/integration/external/Services.e2e.test.ts @@ -9,7 +9,12 @@ import { NFTAttributes, ResourceAuthentication, } from '../../src' -import { EscrowPaymentCondition, TransferNFT721Condition, Token } from '../../src/keeper' +import { + EscrowPaymentCondition, + TransferNFT721Condition, + Token, + ContractHandler, +} from '../../src/keeper' import { config } from '../config' import { generateWebServiceMetadata, getMetadata } from '../utils' import TestContractHandler from '../../test/keeper/TestContractHandler' @@ -209,10 +214,12 @@ describe('Gate-keeping of Web Services using NFT ERC-721 End-to-End', () => { // Deploy NFT TestContractHandler.setConfig(config) - const contractABI = await TestContractHandler.getABI( + const contractABI = await ContractHandler.getABI( 'NFT721SubscriptionUpgradeable', - './test/resources/artifacts/', + config.artifactsFolder, + await nevermined.keeper.getNetworkName(), ) + subscriptionNFT = await SubscriptionNFTApi.deployInstance(config, contractABI, publisher, [ publisher.getId(), nevermined.keeper.didRegistry.address, @@ -346,13 +353,17 @@ describe('Gate-keeping of Web Services using NFT ERC-721 End-to-End', () => { const subscriberBalanceBefore = await token.balanceOf(subscriber.getId()) assert.equal(subscriberBalanceBefore, initialBalances.subscriber + subscriptionPrice) + console.log(`Subscriber balance before: ${subscriberBalanceBefore}`) + agreementId = await nevermined.nfts721.order(subscriptionDDO.id, subscriber) assert.isDefined(agreementId) const subscriberBalanceAfter = await token.balanceOf(subscriber.getId()) - assert.equal(subscriberBalanceAfter, subscriberBalanceAfter - initialBalances.subscriber) + console.log(`Subscriber balance after: ${subscriberBalanceAfter}`) + + assert.isTrue(subscriberBalanceAfter < subscriberBalanceBefore) }) it('The Publisher can check the payment and transfer the NFT to the Subscriber', async () => { @@ -491,11 +502,13 @@ describe('Gate-keeping of Web Services using NFT ERC-721 End-to-End', () => { ) assert.equal(result.totalResults.value, 1) + // console.log(`QUERY RESULTS = ${JSON.stringify(result.results)}`) + assert.isTrue( result.results.every((r) => r .findServiceByType('metadata') - .attributes.main.webService.openEndpoints.some((e) => e === '/openapi.json'), + .attributes.main.webService.openEndpoints.some((e) => e.includes('.json')), ), ) }) From e97c3acfb5b80d22aca29328e92f2c9f66a153bd Mon Sep 17 00:00:00 2001 From: Aitor <1726644+aaitor@users.noreply.github.com> Date: Tue, 3 Oct 2023 15:34:43 +0200 Subject: [PATCH 2/3] fix: adaptations and tests for NVM App 1155 flows --- integration/external/Datasets.e2e.test.ts | 6 +- .../external/Services_NFT1155.e2e.test.ts | 553 ++++++++++++++++++ ...2e.test.ts => Services_NFT721.e2e.test.ts} | 4 +- integration/nevermined/NVMAppFlows.ts | 1 - package.json | 2 +- src/nevermined/api/SearchApi.ts | 87 ++- src/nevermined/api/nfts/NFT721Api.ts | 21 - src/nevermined/api/nfts/NFTsBaseApi.ts | 21 + 8 files changed, 651 insertions(+), 44 deletions(-) create mode 100644 integration/external/Services_NFT1155.e2e.test.ts rename integration/external/{Services.e2e.test.ts => Services_NFT721.e2e.test.ts} (99%) diff --git a/integration/external/Datasets.e2e.test.ts b/integration/external/Datasets.e2e.test.ts index 91c6b70d3..b533384f2 100644 --- a/integration/external/Datasets.e2e.test.ts +++ b/integration/external/Datasets.e2e.test.ts @@ -335,7 +335,7 @@ describe('Gate-keeping of Dataset using NFT ERC-721 End-to-End', () => { }) it('should be able to retrieve subscriptions purchased', async () => { - const result = await nevermined.search.subscriptionsPurchased(subscriber) + const result = await nevermined.search.subscriptionsPurchased(subscriber, 721) assert.isAbove(result.totalResults.value, 1) const dids = result.results.map((ddo) => ddo.id) @@ -363,7 +363,7 @@ describe('Gate-keeping of Dataset using NFT ERC-721 End-to-End', () => { }) it('should be able to retrieve subscriptions purchased filtering by tags', async () => { - const result = await nevermined.search.subscriptionsPurchased(subscriber, tagsFilter) + const result = await nevermined.search.subscriptionsPurchased(subscriber, 721, tagsFilter) assert.isAbove(result.totalResults.value, 1) assert.isTrue( @@ -376,7 +376,7 @@ describe('Gate-keeping of Dataset using NFT ERC-721 End-to-End', () => { }) it('should not be able to retrieve not subscriptions purchased filtering by tags which do not exist', async () => { - const result = await nevermined.search.subscriptionsPurchased(subscriber, tagsFilter2) + const result = await nevermined.search.subscriptionsPurchased(subscriber, 721, tagsFilter2) assert.equal(result.totalResults.value, 0) }) diff --git a/integration/external/Services_NFT1155.e2e.test.ts b/integration/external/Services_NFT1155.e2e.test.ts new file mode 100644 index 000000000..0a162110b --- /dev/null +++ b/integration/external/Services_NFT1155.e2e.test.ts @@ -0,0 +1,553 @@ +import { assert } from 'chai' +import { decodeJwt, JWTPayload } from 'jose' +import { + Account, + DDO, + MetaData, + Nevermined, + AssetPrice, + NFTAttributes, + ResourceAuthentication, +} from '../../src' +import { + EscrowPaymentCondition, + TransferNFTCondition, + Token, + ContractHandler, +} from '../../src/keeper' +import { config } from '../config' +import { generateWebServiceMetadata, getMetadata } from '../utils' +import TestContractHandler from '../../test/keeper/TestContractHandler' +import { ethers } from 'ethers' +import { didZeroX } from '../../src/utils' +import { EventOptions } from '../../src/events' +import { + getRoyaltyAttributes, + RoyaltyAttributes, + RoyaltyKind, + DID, + NFT1155Api, + SubscriptionCreditsNFTApi, + PublishMetadataOptions, + PublishOnChainOptions, +} from '../../src/nevermined' +import { RequestInit } from 'node-fetch' +import fetch from 'node-fetch' + +describe('Gate-keeping of Web Services using NFT ERC-1155 End-to-End', () => { + let publisher: Account + let subscriber: Account + let reseller: Account + + let nevermined: Nevermined + let token: Token + let escrowPaymentCondition: EscrowPaymentCondition + let transferNftCondition: TransferNFTCondition + let subscriptionDDO: DDO + let serviceDDO: DDO + + let agreementId: string + + // Configuration of First Sale: + // Editor -> Subscriber, the Reseller get a cut (25%) + let subscriptionPrice = 20n + let amounts = [15n, 5n] + let receivers: string[] + let assetPrice: AssetPrice + let royaltyAttributes: RoyaltyAttributes + + let subscriptionMetadata: MetaData + let serviceMetadata: MetaData + + const preMint = false + const royalties = 0 + const nftTransfer = false + const subscriptionDuration = 1000 // in blocks + const subscriptionCredits = 10n // How much credits are giving purchasing the subscription + const costServiceInCredits = 1n // How many credits cost every access to the service + + // The service to register into Nevermined and attach to a subscription + const SERVICE_ENDPOINT = process.env.SERVICE_ENDPOINT || 'http://127.0.0.1:3000' + + // The path of the SERVICE_ENDPOINT open that can be accessed via Proxy without authentication + const OPEN_PATH = process.env.OPEN_PATH || '/openapi.json' + + const SKIP_OPEN_ENDPOINT = process.env.SKIP_OPEN_ENDPOINT === 'true' + + // The URL of the OPEN API endpoint that can be accessed via Proxy without authentication + const OPEN_ENDPOINT = process.env.OPEN_ENDPOINT || `${SERVICE_ENDPOINT}${OPEN_PATH}` + + // We separate how the authorization of the service is done. + // If oauth we will use the AUTHORIZATION_TOKEN env + // If basic we will use the AUTHORIZATION_USER and AUTHORIZATION_PASSWORD envs + const AUTHORIZATION_TYPE = (process.env.AUTHORIZATION_TYPE || + 'oauth') as ResourceAuthentication['type'] + + // The http authorization bearer token required by the service + const AUTHORIZATION_TOKEN = process.env.AUTHORIZATION_TOKEN || 'new_authorization_token' + + // If the Authe + const AUTHORIZATION_USER = process.env.AUTHORIZATION_USER || 'user' + + const AUTHORIZATION_PASSWORD = process.env.AUTHORIZATION_PASSWORD || 'password' + + // The NVM proxy that will be used to authorize the service requests + const PROXY_URL = process.env.PROXY_URL || 'http://127.0.0.1:3128' + + // Required because we are dealing with self signed certificates locally + process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0' + + // let proxyAgent + const opts: RequestInit = {} + + let initialBalances: any + let scale: bigint + + // let nft: ethers.Contract + let subscriptionNFT: NFT1155Api + let neverminedNodeAddress + + let payload: JWTPayload + + let accessToken: string + + before(async () => { + TestContractHandler.setConfig(config) + + nevermined = await Nevermined.getInstance(config) + ;[, publisher, subscriber, , reseller] = await nevermined.accounts.list() + + const clientAssertion = await nevermined.utils.jwt.generateClientAssertion(publisher) + + await nevermined.services.marketplace.login(clientAssertion) + payload = decodeJwt(config.marketplaceAuthToken) + + neverminedNodeAddress = await nevermined.services.node.getProviderAddress() + + // conditions + ;({ escrowPaymentCondition, transferNftCondition } = nevermined.keeper.conditions) + + // components + ;({ token } = nevermined.keeper) + + scale = 10n ** BigInt(await token.decimals()) + + subscriptionPrice = subscriptionPrice * scale + amounts = amounts.map((v) => v * scale) + receivers = [publisher.getId(), reseller.getId()] + assetPrice = new AssetPrice( + new Map([ + [receivers[0], amounts[0]], + [receivers[1], amounts[1]], + ]), + ).setTokenAddress(token.address) + + royaltyAttributes = getRoyaltyAttributes(nevermined, RoyaltyKind.Standard, royalties) + + initialBalances = { + editor: await token.balanceOf(publisher.getId()), + subscriber: await token.balanceOf(subscriber.getId()), + reseller: await token.balanceOf(reseller.getId()), + escrowPaymentCondition: Number(await token.balanceOf(escrowPaymentCondition.address)), + } + + console.log(`USING CONFIG:`) + console.log(` PROXY_URL=${PROXY_URL}`) + console.log(` SERVICE_ENDPOINT=${SERVICE_ENDPOINT}`) + console.log(` OPEN_ENDPOINT=${OPEN_ENDPOINT}`) + console.log(` AUTHORIZATION_TYPE=${AUTHORIZATION_TYPE}`) + if (AUTHORIZATION_TYPE === 'oauth') console.log(` AUTHORIZATION_TOKEN=${AUTHORIZATION_TOKEN}`) + else { + console.log(` AUTHORIZATION_USER=${AUTHORIZATION_USER}`) + console.log(` AUTHORIZATION_PASSWORD=${AUTHORIZATION_PASSWORD}`) + } + console.log(` REQUEST_DATA=${process.env.REQUEST_DATA}`) + }) + + describe('As Subscriber I want to get access to a web service I am not subscribed', () => { + it('The subscriber can not access the service endpoints because does not have a subscription yet', async () => { + const result = await fetch(SERVICE_ENDPOINT, opts) + + assert.isFalse(result.ok) + assert.isTrue(result.status >= 400) + }) + }) + + describe('As Publisher I want to register new web service and provide access via subscriptions to it', () => { + it('I want to register a subscription NFT that gives access to a web service to the holders', async () => { + // Deploy NFT + TestContractHandler.setConfig(config) + + const contractABI = await ContractHandler.getABI( + 'NFT1155SubscriptionUpgradeable', + config.artifactsFolder, + await nevermined.keeper.getNetworkName(), + ) + + subscriptionNFT = await SubscriptionCreditsNFTApi.deployInstance( + config, + contractABI, + publisher, + [ + publisher.getId(), + nevermined.keeper.didRegistry.address, + 'Subscription Service NFT1155', + 'NVM', + '', + nevermined.keeper.nvmConfig.address, + ], + ) + + await nevermined.contracts.loadNft1155(subscriptionNFT.address) + + await subscriptionNFT.grantOperatorRole(transferNftCondition.address, publisher) + + const isOperator = await subscriptionNFT.getContract.isOperator(transferNftCondition.address) + assert.isTrue(isOperator) + + subscriptionMetadata = getMetadata(undefined, 'Service Subscription NFT1155') + subscriptionMetadata.main.type = 'subscription' + const nftAttributes = NFTAttributes.getCreditsSubscriptionInstance({ + metadata: subscriptionMetadata, + services: [ + { + serviceType: 'nft-sales', + price: assetPrice, + nft: { + duration: subscriptionDuration, + amount: subscriptionCredits, + nftTransfer, + }, + }, + ], + providers: [neverminedNodeAddress], + nftContractAddress: subscriptionNFT.address, + preMint, + royaltyAttributes: royaltyAttributes, + }) + subscriptionDDO = await nevermined.nfts1155.create(nftAttributes, publisher) + console.log(`Subscription registered with DID: ${subscriptionDDO.id}`) + assert.isDefined(subscriptionDDO) + }) + + it('I want to register a new web service and tokenize (via NFT)', async () => { + serviceMetadata = generateWebServiceMetadata( + 'Nevermined Web Service Metadata', + // regex to match the service endpoints + // works with: https://www.npmjs.com/package/path-to-regexp + // Example of regex: `https://api.openai.com/v1/(.*)`, + `${SERVICE_ENDPOINT}(.*)`, + [OPEN_ENDPOINT], + AUTHORIZATION_TYPE, + AUTHORIZATION_TOKEN, + AUTHORIZATION_USER, + AUTHORIZATION_PASSWORD, + ) as MetaData + serviceMetadata.userId = payload.sub + + console.log(`Registering service with metadata: ${JSON.stringify(serviceMetadata)}`) + + const nftAttributes = NFTAttributes.getCreditsSubscriptionInstance({ + metadata: serviceMetadata, + services: [ + { + serviceType: 'nft-access', + nft: { + tokenId: subscriptionDDO.shortId(), + duration: 0, // Doesnt expire + amount: costServiceInCredits, // The cost of accessing the service + nftTransfer, + }, + }, + ], + providers: [neverminedNodeAddress], + nftContractAddress: subscriptionNFT.address, + preMint, + royaltyAttributes: royaltyAttributes, + }) + serviceDDO = await nevermined.nfts1155.create(nftAttributes, publisher, { + metadata: PublishMetadataOptions.OnlyMetadataAPI, + did: PublishOnChainOptions.OnlyOffchain, + }) + console.log(`Using NFT contract address: ${subscriptionNFT.address}`) + console.log(`Service registered with DID: ${serviceDDO.id}`) + assert.isDefined(serviceDDO) + }) + }) + + describe('As random user I want to get access to the OPEN endpoints WITHOUT a subscription', () => { + it('The user can access the open service endpoints directly', async function () { + if (SKIP_OPEN_ENDPOINT) { + console.log(`Skipping Open Endpoints test because SKIP_OPEN_ENDPOINT is set to true`) + this.skip() + } + console.log(`Using Open Endpoint: ${OPEN_ENDPOINT}`) + + const result = await fetch(OPEN_ENDPOINT, opts) + + assert.isTrue(result.ok) + assert.isTrue(result.status === 200) + }) + + it('The subscriber can access the open service endpoints through the proxy', async function () { + if (SKIP_OPEN_ENDPOINT) { + console.log(`Skipping Open Endpoints test because SKIP_OPEN_ENDPOINT is set to true`) + this.skip() + } + + const proxyUrl = new URL(PROXY_URL) + const serviceDID = DID.parse(serviceDDO.id) + const subdomain = serviceDID.getEncoded() + + const OPEN_PROXY_URL = `${proxyUrl.protocol}//${subdomain}.${proxyUrl.host}${OPEN_PATH}` + + console.log(`Using Proxied Open Endpoint: ${OPEN_PROXY_URL} for DID: ${serviceDDO.id}`) + + const didFromEncoded = DID.fromEncoded(subdomain) + + console.log(`DID from encoded: ${didFromEncoded.getDid()}`) + + const result = await fetch(OPEN_PROXY_URL, opts) + + assert.isTrue(result.ok) + assert.isTrue(result.status === 200) + }) + }) + + describe('As a Subscriber I want to get access to a web service', () => { + it('I check the details of the subscription NFT', async () => { + const details = await nevermined.nfts1155.details(subscriptionDDO.id) + assert.equal(details.owner, publisher.getId()) + }) + + it('I am ordering the subscription NFT', async () => { + await subscriber.requestTokens(subscriptionPrice / scale) + + const subscriberBalanceBefore = await token.balanceOf(subscriber.getId()) + assert.equal(subscriberBalanceBefore, initialBalances.subscriber + subscriptionPrice) + + console.log(`Subscriber balance before: ${subscriberBalanceBefore}`) + + agreementId = await nevermined.nfts1155.order( + subscriptionDDO.id, + subscriptionCredits, + subscriber, + ) + + assert.isDefined(agreementId) + + const subscriberBalanceAfter = await token.balanceOf(subscriber.getId()) + + console.log(`Subscriber balance after: ${subscriberBalanceAfter}`) + + assert.isTrue(subscriberBalanceAfter < subscriberBalanceBefore) + }) + + it('The Publisher can check the payment and transfer the NFT to the Subscriber', async () => { + // Let's use the Node to mint the subscription and release the payments + + const receipt = await nevermined.nfts1155.claim( + agreementId, + publisher.getId(), + subscriber.getId(), + subscriptionCredits, + ) + assert.isTrue(receipt) + }) + + it('the Publisher and reseller can receive their payment', async () => { + const receiver0Balance = await token.balanceOf(assetPrice.getReceivers()[0]) + const receiver1Balance = await token.balanceOf(assetPrice.getReceivers()[1]) + + assert.equal(receiver0Balance, initialBalances.editor + assetPrice.getAmounts()[0]) + assert.equal(receiver1Balance, initialBalances.reseller + assetPrice.getAmounts()[1]) + }) + + it('the subscription can be checked on chain', async () => { + const eventOptions: EventOptions = { + eventName: 'Fulfilled', + filterSubgraph: { + where: { + _did: didZeroX(subscriptionDDO.id), + _receiver: subscriber.getId(), + }, + }, + filterJsonRpc: { + _did: didZeroX(subscriptionDDO.id), + _receiver: subscriber.getId(), + }, + result: { + _agreementId: true, + _did: true, + _receiver: true, + }, + } + // wait for the event to be picked by the subgraph + await nevermined.keeper.conditions.transferNftCondition.events.once((e) => e, eventOptions) + const [event] = await nevermined.keeper.conditions.transferNftCondition.events.getPastEvents( + eventOptions, + ) + + // subgraph event or json-rpc event? + const eventValues = event.args || event + + assert.equal(eventValues._agreementId, agreementId) + assert.equal(eventValues._did, didZeroX(subscriptionDDO.id)) + + // thegraph stores the addresses in lower case + assert.equal(ethers.getAddress(eventValues._receiver), subscriber.getId()) + }) + }) + + describe('As a subscriber I want to get an access token for the web service', () => { + it('Nevermined One issues an access token', async () => { + const response = await nevermined.nfts1155.getSubscriptionToken(serviceDDO.id, subscriber) + accessToken = response.accessToken + + assert.isDefined(accessToken) + }) + }) + + describe('As Subscriber I want to get access to the web service as part of my subscription', () => { + let creditsBalanceBefore: bigint + + it('As subscriber I can see my credits balance', async () => { + creditsBalanceBefore = await subscriptionNFT.balance(subscriptionDDO.id, subscriber.getId()) + + console.log(`Credits balance before: ${creditsBalanceBefore}`) + assert.equal(creditsBalanceBefore, subscriptionCredits) + }) + + it('The subscriber access the service endpoints available', async () => { + const url = new URL(SERVICE_ENDPOINT) + const proxyEndpoint = `${PROXY_URL}${url.pathname}` + + console.log(accessToken) + opts.headers = { + // The proxy expects the `HTTP Authorization` header with the JWT + authorization: `Bearer ${accessToken}`, + 'content-type': 'application/json', + // Host header is not required anymore from the proxy, it picks this up from the JWT + // host: url.port ? url.hostname.concat(`:${url.port}`) : url.hostname, + } + + if (process.env.REQUEST_DATA) { + opts.method = 'POST' + opts.body = JSON.stringify(JSON.parse(process.env.REQUEST_DATA)) + } + + // console.debug(JSON.stringify(opts)) + const result = await fetch(proxyEndpoint, opts) + + console.debug(` ${result.status} - ${await result.text()}`) + + assert.isTrue(result.ok) + assert.equal(result.status, 200) + }) + + it.skip('As subscriber I can see my credits are burned after accessing the service', async () => { + const creditsBalanceAfter = await subscriptionNFT.balance( + subscriptionDDO.id, + subscriber.getId(), + ) + + console.log(`Credits balance after: ${creditsBalanceAfter}`) + assert.equal(creditsBalanceBefore - 1n, creditsBalanceAfter) + }) + }) + + describe('As a user I want to be able to search DDOs by subscriptions', () => { + const endpointsFilter = [ + { + nested: { + path: ['service'], + query: { + bool: { + filter: [ + { match: { 'service.type': 'metadata' } }, + { + match: { + 'service.attributes.main.webService.openEndpoints': '/openapi.json', + }, + }, + ], + }, + }, + }, + }, + ] + + const endpointsFilter2 = [ + { + nested: { + path: ['service'], + query: { + bool: { + filter: [ + { match: { 'service.type': 'metadata' } }, + { + match: { + 'service.attributes.main.webService.openEndpoints': '/nvm.json', + }, + }, + ], + }, + }, + }, + }, + ] + + it('should be able to retrieve the subscriptionDDO by contractAddress', async () => { + const result = await nevermined.search.bySubscriptionContractAddress(subscriptionNFT.address) + assert.equal(result.totalResults.value, 1) + }) + + it('should be able to retrieve subscriptions created', async () => { + const result = await nevermined.search.subscriptionsCreated(publisher) + assert.isAbove(result.totalResults.value, 1) + + const dids = result.results.map((ddo) => ddo.id) + assert.include(dids, subscriptionDDO.id) + }) + + it('should be able to retrieve subscriptions purchased', async () => { + const result = await nevermined.search.subscriptionsPurchased(subscriber, 1155) + assert.isAbove(result.totalResults.value, 1) + + const dids = result.results.map((ddo) => ddo.id) + assert.include(dids, subscriptionDDO.id) + }) + + it('should be able to retrieve all services associated with a subscription', async () => { + const result = await nevermined.search.servicesBySubscription(subscriptionDDO.id) + assert.equal(result.totalResults.value, 1) + + const ddo = result.results.pop() + assert.equal(ddo.id, serviceDDO.id) + }) + + it('should be able to retrieve services associated with a subscription filtering by endpoints', async () => { + const result = await nevermined.search.servicesBySubscription( + subscriptionDDO.id, + endpointsFilter, + ) + assert.equal(result.totalResults.value, 1) + + assert.isTrue( + result.results.every((r) => + r + .findServiceByType('metadata') + .attributes.main.webService.openEndpoints.some((e) => e.includes('.json')), + ), + ) + }) + + it('should not be able to retrieve any services associated with a subscription filtering by endpoints which do not exist', async () => { + const result = await nevermined.search.servicesBySubscription( + subscriptionDDO.id, + endpointsFilter2, + ) + assert.equal(result.totalResults.value, 0) + }) + }) +}) diff --git a/integration/external/Services.e2e.test.ts b/integration/external/Services_NFT721.e2e.test.ts similarity index 99% rename from integration/external/Services.e2e.test.ts rename to integration/external/Services_NFT721.e2e.test.ts index 6b79ad7e5..ccb184bbc 100644 --- a/integration/external/Services.e2e.test.ts +++ b/integration/external/Services_NFT721.e2e.test.ts @@ -480,7 +480,7 @@ describe('Gate-keeping of Web Services using NFT ERC-721 End-to-End', () => { }) it('should be able to retrieve subscriptions purchased', async () => { - const result = await nevermined.search.subscriptionsPurchased(subscriber) + const result = await nevermined.search.subscriptionsPurchased(subscriber, 721) assert.isAbove(result.totalResults.value, 1) const dids = result.results.map((ddo) => ddo.id) @@ -502,8 +502,6 @@ describe('Gate-keeping of Web Services using NFT ERC-721 End-to-End', () => { ) assert.equal(result.totalResults.value, 1) - // console.log(`QUERY RESULTS = ${JSON.stringify(result.results)}`) - assert.isTrue( result.results.every((r) => r diff --git a/integration/nevermined/NVMAppFlows.ts b/integration/nevermined/NVMAppFlows.ts index a1a3784f1..8f73acaef 100644 --- a/integration/nevermined/NVMAppFlows.ts +++ b/integration/nevermined/NVMAppFlows.ts @@ -212,7 +212,6 @@ describe('NVM App main flows using Credit NFTs (ERC-1155)', () => { serviceType: 'nft-access', nft: { tokenId: timeSubscriptionDDO.shortId(), - // TODO: Review duration: subscriptionBronzeDuration, amount: 0n, nftTransfer, diff --git a/package.json b/package.json index 352cb1622..07500453e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@nevermined-io/sdk", - "version": "2.0.0-rc11", + "version": "2.0.0-rc12", "description": "Javascript SDK for connecting with Nevermined Data Platform ", "main": "./dist/node/sdk.js", "typings": "./dist/node/sdk.d.ts", diff --git a/src/nevermined/api/SearchApi.ts b/src/nevermined/api/SearchApi.ts index 216b70eeb..3e7e9bb1f 100644 --- a/src/nevermined/api/SearchApi.ts +++ b/src/nevermined/api/SearchApi.ts @@ -6,6 +6,7 @@ import { DID, didPrefixed, EventOptions, + NeverminedNFT1155Type, NeverminedNFT721Type, SearchQuery, } from '../../sdk' @@ -151,7 +152,7 @@ export class SearchApi extends Instantiable { /** * Search for all subscription DDOs with `contractAddress` * - * @param contractAddress - The address of the NFT-721 subscription contract + * @param contractAddress - The address of the subscription contract * @param offset - The number of results to return * @param customNestedQueries - Custom nested queries to add to the search * @param page @@ -177,8 +178,20 @@ export class SearchApi extends Instantiable { filter: [ { match: { 'service.type': 'metadata' } }, { - match: { - 'service.attributes.main.nftType': NeverminedNFT721Type.nft721Subscription, + bool: { + should: [ + { + match: { + 'service.attributes.main.nftType': + NeverminedNFT721Type.nft721Subscription, + }, + }, + { + match: { + 'service.attributes.main.nftType': NeverminedNFT1155Type.nft1155Credit, + }, + }, + ], }, }, ], @@ -255,8 +268,20 @@ export class SearchApi extends Instantiable { filter: [ { match: { 'service.type': 'metadata' } }, { - match: { - 'service.attributes.main.nftType': NeverminedNFT721Type.nft721Subscription, + bool: { + should: [ + { + match: { + 'service.attributes.main.nftType': + NeverminedNFT721Type.nft721Subscription, + }, + }, + { + match: { + 'service.attributes.main.nftType': NeverminedNFT1155Type.nft1155Credit, + }, + }, + ], }, }, ], @@ -305,13 +330,14 @@ export class SearchApi extends Instantiable { */ public async subscriptionsPurchased( account: Account, + ercType: 721 | 1155, customNestedQueries?: SearchQuery['query'][], offset = 100, page = 1, sort = 'desc', appId?: string, ): Promise { - // get on chain dids for nft-721 bought + // get on chain dids for nft bought const eventOptions: EventOptions = { eventName: 'Fulfilled', filterSubgraph: { @@ -328,9 +354,14 @@ export class SearchApi extends Instantiable { } const events = - await this.nevermined.keeper.conditions.transferNft721Condition.events.getPastEvents( - eventOptions, - ) + ercType === 721 + ? await this.nevermined.keeper.conditions.transferNft721Condition.events.getPastEvents( + eventOptions, + ) + : await this.nevermined.keeper.conditions.transferNftCondition.events.getPastEvents( + eventOptions, + ) + const dids = events.map((e) => e._did || e.args._did).map((did) => didPrefixed(did)) let search: SearchQuery['query'][] = [ @@ -342,8 +373,20 @@ export class SearchApi extends Instantiable { filter: [ { match: { 'service.type': 'metadata' } }, { - match: { - 'service.attributes.main.nftType': NeverminedNFT721Type.nft721Subscription, + bool: { + should: [ + { + match: { + 'service.attributes.main.nftType': + NeverminedNFT721Type.nft721Subscription, + }, + }, + { + match: { + 'service.attributes.main.nftType': NeverminedNFT1155Type.nft1155Credit, + }, + }, + ], }, }, ], @@ -407,8 +450,15 @@ export class SearchApi extends Instantiable { filter: [ { match: { 'service.type': 'metadata' } }, { - match: { - 'service.attributes.main.nftType': NeverminedNFT721Type.nft721, + bool: { + should: [ + { match: { 'service.attributes.main.nftType': NeverminedNFT721Type.nft721 } }, + { + match: { + 'service.attributes.main.nftType': NeverminedNFT1155Type.nft1155Credit, + }, + }, + ], }, }, { @@ -537,8 +587,15 @@ export class SearchApi extends Instantiable { filter: [ { match: { 'service.type': 'metadata' } }, { - match: { - 'service.attributes.main.nftType': NeverminedNFT721Type.nft721, + bool: { + should: [ + { match: { 'service.attributes.main.nftType': NeverminedNFT721Type.nft721 } }, + { + match: { + 'service.attributes.main.nftType': NeverminedNFT1155Type.nft1155Credit, + }, + }, + ], }, }, { diff --git a/src/nevermined/api/nfts/NFT721Api.ts b/src/nevermined/api/nfts/NFT721Api.ts index b06bd3b4d..efcd82979 100644 --- a/src/nevermined/api/nfts/NFT721Api.ts +++ b/src/nevermined/api/nfts/NFT721Api.ts @@ -13,7 +13,6 @@ import { NFTError } from '../../../errors/NFTError' import { ContractTransactionReceipt, ethers } from 'ethers' import { NFTsBaseApi } from './NFTsBaseApi' import { CreateProgressStep, OrderProgressStep } from '../../ProgressSteps' -import { SubscriptionToken } from '../../../services' /** * Allows the interaction with external ERC-721 NFT contracts built on top of the Nevermined NFT extra features. @@ -641,26 +640,6 @@ export class NFT721Api extends NFTsBaseApi { return this._details(did, 721) } - /** - * Get a JWT token for an asset associated with a webService - * - * @example - * ```ts - * const response = await nevermined.nfts721.getSubscriptionToken(serviceDDO.id, subscriber) - * - * assert.isDefined(response.accessToken) - * assert.isDefined(response.neverminedProxyUri) - * ``` - * - * @param did - The did of the asset with a webService resource and an associated subscription - * @param account - Account of the user requesting the token - * - * @returns {@link SubscriptionToken} - */ - public async getSubscriptionToken(did: string, account: Account): Promise { - return this.nevermined.services.node.getSubscriptionToken(did, account) - } - public async isOperatorOfDID(did: string, address: string): Promise { return super.isOperatorOfDID(did, address, 721) } diff --git a/src/nevermined/api/nfts/NFTsBaseApi.ts b/src/nevermined/api/nfts/NFTsBaseApi.ts index af96e6cb7..b93e1a648 100644 --- a/src/nevermined/api/nfts/NFTsBaseApi.ts +++ b/src/nevermined/api/nfts/NFTsBaseApi.ts @@ -8,6 +8,7 @@ import { ServiceSecondary } from '../../../ddo' import { NFTError } from '../../../errors' import { generateId } from '../../../utils' import { RegistryBaseApi } from '../RegistryBaseApi' +import { SubscriptionToken } from '../../../services' /** * Abstract class providing common NFT methods for different ERC implementations. @@ -457,4 +458,24 @@ export abstract class NFTsBaseApi extends RegistryBaseApi { } return result } + + /** + * Get a JWT token for an asset associated with a webService + * + * @example + * ```ts + * const response = await nevermined.nfts721.getSubscriptionToken(serviceDDO.id, subscriber) + * + * assert.isDefined(response.accessToken) + * assert.isDefined(response.neverminedProxyUri) + * ``` + * + * @param did - The did of the asset with a webService resource and an associated subscription + * @param account - Account of the user requesting the token + * + * @returns {@link SubscriptionToken} + */ + public async getSubscriptionToken(did: string, account: Account): Promise { + return this.nevermined.services.node.getSubscriptionToken(did, account) + } } From 1108abab1cf0bb137ee6d88f0393e7d10453db30 Mon Sep 17 00:00:00 2001 From: Aitor <1726644+aaitor@users.noreply.github.com> Date: Tue, 3 Oct 2023 17:09:49 +0200 Subject: [PATCH 3/3] chore: adding v2.0.0-rc12 Changelog updates --- CHANGELOG.md | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 475aa06d0..d03fbe65f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -66,10 +66,18 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog). - feat: subscription by credits api [`f97aa61`](https://github.com/nevermined-io/sdk-js/commit/f97aa61c4328a7bc8ea1f14f584b3664876970db) - chore: adapting nft 1155 to duration and transfer params [`a133315`](https://github.com/nevermined-io/sdk-js/commit/a133315c8b217cec7d41e6f863277dfe94fce98a) -#### [v2.0.0-rc2](https://github.com/nevermined-io/sdk-js/compare/v2.0.0-rc11...v2.0.0-rc2) +#### [v2.0.0-rc2](https://github.com/nevermined-io/sdk-js/compare/v2.0.0-rc12...v2.0.0-rc2) > 26 July 2023 +#### [v2.0.0-rc12](https://github.com/nevermined-io/sdk-js/compare/v2.0.0-rc11...v2.0.0-rc12) + +> 3 October 2023 + +- fix: adaptations and tests for NVM App 1155 flows [`e97c3ac`](https://github.com/nevermined-io/sdk-js/commit/e97c3acfb5b80d22aca29328e92f2c9f66a153bd) +- test: fix services e2e services flow [`f93664d`](https://github.com/nevermined-io/sdk-js/commit/f93664d07747e6e714f43d51ccf4d5184e3201fe) +- chore: adding v2.0.0-rc11 Changelog updates [`222bec9`](https://github.com/nevermined-io/sdk-js/commit/222bec960167fa95caabcff30d29fef68623332a) + #### [v2.0.0-rc11](https://github.com/nevermined-io/sdk-js/compare/v2.0.0-rc10...v2.0.0-rc11) > 3 October 2023