diff --git a/integration/ocean/BuyAsset.test.ts b/integration/ocean/BuyAsset.test.ts deleted file mode 100644 index 6c021a3..0000000 --- a/integration/ocean/BuyAsset.test.ts +++ /dev/null @@ -1,118 +0,0 @@ -import { assert } from 'chai' - -import { config } from "../config" - -import { Ocean, MetaData, DDO, DID, Account, ServiceAgreement } from '../../src' // @oceanprotocol/squid - -describe("Buy Asset", () => { - let ocean: Ocean - - let publisher: Account - let consumer: Account - - let metadata: Partial - - let ddo: DDO - let did: DID - let serviceAgreementSignatureResult: {agreementId: string, signature: string} - let serviceAgreement: ServiceAgreement - - before(async () => { - ocean = await Ocean.getInstance(config) - - // Accounts - publisher = (await ocean.accounts.list())[0] - publisher.setPassword(process.env.ACCOUNT_PASSWORD) - consumer = (await ocean.accounts.list())[1] - - // Data - metadata = { - base: { - name: "Office Humidity", - type: "dataset", - description: "Weather information of UK including temperature and humidity", - size: "3.1gb", - dateCreated: "2012-02-01T10:55:11+00:00", - author: "Met Office", - license: "CC-BY", - copyrightHolder: "Met Office", - encoding: "UTF-8", - compression: "zip", - contentType: "text/csv", - // tslint:disable-next-line - workExample: "stationId,latitude,longitude,datetime,temperature,humidity423432fsd,51.509865,-0.118092,2011-01-01T10:55:11+00:00,7.2,68", - files: [ - { - url: "https://testocnfiles.blob.core.windows.net/testfiles/testzkp.zip", - checksum: "085340abffh21495345af97c6b0e761", - contentLength: "12324", - }, - { - url: "https://testocnfiles.blob.core.windows.net/testfiles/testzkp2.zip", - }, - ], - links: [ - {sample1: "http://data.ceda.ac.uk/badc/ukcp09/data/gridded-land-obs/gridded-land-obs-daily/"}, - {sample2: "http://data.ceda.ac.uk/badc/ukcp09/data/gridded-land-obs/gridded-land-obs-averages-25km/"}, - {fieldsDescription: "http://data.ceda.ac.uk/badc/ukcp09/"}, - ], - inLanguage: "en", - tags: "weather, uk, 2011, temperature, humidity", - price: 10, - }, - } - }) - - it("should regiester a asset", async () => { - ddo = await ocean.assets.create(metadata as any, publisher) - did = DID.parse(ddo.id) - - assert.isDefined(ddo, "Register has not returned a DDO") - assert.match(ddo.id, /^did:op:[a-f0-9]{64}$/, "DDO id is not valid") - assert.isAtLeast(ddo.authentication.length, 1, "Default authentication not added") - assert.isDefined(ddo.findServiceByType("Access"), "DDO Access service doesn't exist") - }) - - it("should be able to request tokens for consumer", async () => { - const initialBalance = (await consumer.getBalance()).ocn; - await consumer.requestTokens(metadata.base.price) - - assert.equal((await consumer.getBalance()).ocn, initialBalance + metadata.base.price, "OCN Tokens not delivered") - }) - - it("should sign the service agreement", async () => { - const accessService = ddo.findServiceByType("Access") - - serviceAgreementSignatureResult = await ocean.agreements.prepare(ddo.id, accessService.serviceDefinitionId, consumer) - - const {agreementId, signature} = serviceAgreementSignatureResult - assert.match(agreementId, /^[a-f0-9]{64}$/, "Service agreement ID seems not valid") - assert.match(signature, /^0x[a-f0-9]{130}$/, "Service agreement signature seems not valid") - }) - - it("should execute the service agreement", async () => { - const accessService = ddo.findServiceByType("Access") - - serviceAgreement = await ocean.agreements.create( - ddo.id, - accessService.serviceDefinitionId, - serviceAgreementSignatureResult.agreementId, - serviceAgreementSignatureResult.signature, - consumer, - publisher, - ) - - assert.match(serviceAgreement.getId(), /^0x[a-f0-9]{64}$/, "Service agreement ID seems not valid") - }) - - it("should pay asset trough the service agreement", async () => { - const paid = await serviceAgreement.payAsset(did.getId(), metadata.base.price, consumer) - assert.isTrue(paid, "The asset has not been paid correctly") - }) - - xit("should consume the assets", async () => { - const accessService = ddo.findServiceByType("Access") - - await ocean.assets.consume(serviceAgreementSignatureResult.agreementId, ddo.id, accessService.serviceDefinitionId, consumer) - }) -}) diff --git a/integration/ocean/ConsumeAssetBrizo.test.ts b/integration/ocean/ConsumeAssetBrizo.test.ts new file mode 100644 index 0000000..d78f471 --- /dev/null +++ b/integration/ocean/ConsumeAssetBrizo.test.ts @@ -0,0 +1,110 @@ +import { assert } from "chai" +import * as Web3 from "web3"; +import * as fs from "fs"; + +import { config } from "../config" + +import { Ocean, MetaData, Account, DDO } from "../../src" // @oceanprotocol/squid + +describe("Consume Asset (Brizo)", () => { + let ocean: Ocean + + let publisher: Account + let consumer: Account + + let ddo: DDO + let agreementId: string + + const testHash = Math.random().toString(36).substr(2) + let metadata: Partial + let metadataGenerator = (name: string) => ({ + ...metadata, + base: { + ...metadata.base, + name: `${name}${testHash}`, + }, + }) + + before(async () => { + ocean = await Ocean.getInstance({ + ...config, + web3Provider: new Web3.providers.HttpProvider("http://localhost:8545", 0, "0x00Bd138aBD70e2F00903268F3Db08f2D25677C9e", "node0"), + }) + + // Accounts + publisher = new Account("0x00Bd138aBD70e2F00903268F3Db08f2D25677C9e") + publisher.setPassword("node0") + consumer = new Account("0x068Ed00cF0441e4829D9784fCBe7b9e26D4BD8d0") + consumer.setPassword("secret") + + // Data + metadata = { + base: { + name: undefined, + type: "dataset", + description: "Weather information of UK including temperature and humidity", + size: "3.1gb", + dateCreated: "2012-02-01T10:55:11+00:00", + author: "Met Office", + license: "CC-BY", + copyrightHolder: "Met Office", + encoding: "UTF-8", + compression: "zip", + contentType: "text/csv", + // tslint:disable-next-line + workExample: "stationId,latitude,longitude,datetime,temperature,humidity423432fsd,51.509865,-0.118092,2011-01-01T10:55:11+00:00,7.2,68", + files: [ + { + url: "https://testocnfiles.blob.core.windows.net/testfiles/testzkp.pdf", + checksum: "085340abffh21495345af97c6b0e761", + contentLength: "12324", + }, + { + url: "https://raw.githubusercontent.com/oceanprotocol/squid-js/develop/README.md", + }, + ], + links: [ + {sample1: "http://data.ceda.ac.uk/badc/ukcp09/data/gridded-land-obs/gridded-land-obs-daily/"}, + {sample2: "http://data.ceda.ac.uk/badc/ukcp09/data/gridded-land-obs/gridded-land-obs-averages-25km/"}, + {fieldsDescription: "http://data.ceda.ac.uk/badc/ukcp09/"}, + ], + inLanguage: "en", + tags: "weather, uk, 2011, temperature, humidity", + price: 10, + }, + } + }) + + it("should regiester an asset", async () => { + ddo = await ocean.assets.create(metadataGenerator("ToBeConsumed") as any, publisher); + + assert.instanceOf(ddo, DDO) + }) + + it("should order the asset", async () => { + const accessService = ddo.findServiceByType("Access") + + await consumer.requestTokens(metadata.base.price) + + agreementId = await ocean.assets.order(ddo.id, accessService.serviceDefinitionId, consumer) + + assert.isDefined(agreementId) + }) + + it("should consume and store the assets", async () => { + const accessService = ddo.findServiceByType("Access") + + const folder = "/tmp/ocean/squid-js" + const path = await ocean.assets.consume(agreementId, ddo.id, accessService.serviceDefinitionId, consumer, folder) + + assert.include(path, folder, "The storage path is not correct.") + + const files = await new Promise(resolve => { + fs.readdir(path, (err, files) => { + resolve(files) + }); + }) + + assert.deepEqual(files, ["README.md", "testzkp.pdf"], "Stored files are not correct.") + }) +}) diff --git a/package-lock.json b/package-lock.json index 4128389..1a35744 100644 --- a/package-lock.json +++ b/package-lock.json @@ -129,9 +129,9 @@ } }, "@oceanprotocol/keeper-contracts": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/@oceanprotocol/keeper-contracts/-/keeper-contracts-0.8.2.tgz", - "integrity": "sha512-NGAscVL6FScs9goCI1zD1nhbFrjbfoUvZYlW1zZMC82teVzgdxVUkefJe3kXW3ocjGUHS4eqjOwtx3y2/E2iCg==" + "version": "0.8.5", + "resolved": "https://registry.npmjs.org/@oceanprotocol/keeper-contracts/-/keeper-contracts-0.8.5.tgz", + "integrity": "sha512-GRVsKAAX60PikLyeA6SEPm1NKOPCHW5C225H4Cpe+hww+qEbGu7Y2/Y+svWSXzfxElUanRZBdZfiEx4tdudIoQ==" }, "@oceanprotocol/secret-store-client": { "version": "0.0.14", @@ -189,10 +189,13 @@ } }, "@types/handlebars": { - "version": "4.0.40", - "resolved": "https://registry.npmjs.org/@types/handlebars/-/handlebars-4.0.40.tgz", - "integrity": "sha512-sGWNtsjNrLOdKha2RV1UeF8+UbQnPSG7qbe5wwbni0mw4h2gHXyPFUMOC+xwGirIiiydM/HSqjDO4rk6NFB18w==", - "dev": true + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@types/handlebars/-/handlebars-4.1.0.tgz", + "integrity": "sha512-gq9YweFKNNB1uFK71eRqsd4niVkXrxHugqWFQkeLRJvGjnxsLr16bYtcsG4tOFwmYi0Bax+wCkbf1reUfdl4kA==", + "dev": true, + "requires": { + "handlebars": "*" + } }, "@types/highlight.js": { "version": "9.12.3", @@ -201,9 +204,9 @@ "dev": true }, "@types/lodash": { - "version": "4.14.122", - "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.122.tgz", - "integrity": "sha512-9IdED8wU93ty8gP06ninox+42SBSJHp2IAamsSYMUY76mshRTeUsid/gtbl8ovnOwy8im41ib4cxTiIYMXGKew==", + "version": "4.14.123", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.123.tgz", + "integrity": "sha512-pQvPkc4Nltyx7G1Ww45OjVqUsJP4UsZm+GWJpigXgkikZqJgRm4c48g027o6tdgubWHwFRF15iFd+Y4Pmqv6+Q==", "dev": true }, "@types/marked": { @@ -225,9 +228,9 @@ "dev": true }, "@types/node": { - "version": "10.12.29", - "resolved": "https://registry.npmjs.org/@types/node/-/node-10.12.29.tgz", - "integrity": "sha512-J/tnbnj8HcsBgCe2apZbdUpQ7hs4d7oZNTYA5bekWdP0sr2NGsOpI/HRdDroEi209tEvTcTtxhD0FfED3DhEcw==" + "version": "10.14.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-10.14.1.tgz", + "integrity": "sha512-Rymt08vh1GaW4vYB6QP61/5m/CFLGnFZP++bJpWbiNxceNa6RBipDmb413jvtSf/R1gg5a/jQVl2jY4XVRscEA==" }, "@types/node-fetch": { "version": "2.1.6", @@ -238,9 +241,9 @@ }, "dependencies": { "@types/node": { - "version": "11.10.4", - "resolved": "https://registry.npmjs.org/@types/node/-/node-11.10.4.tgz", - "integrity": "sha512-wa09itaLE8L705aXd8F80jnFpxz3Y1/KRHfKsYL2bPc0XF+wEWu8sR9n5bmeu8Ba1N9z2GRNzm/YdHcghLkLKg==" + "version": "11.11.3", + "resolved": "https://registry.npmjs.org/@types/node/-/node-11.11.3.tgz", + "integrity": "sha512-wp6IOGu1lxsfnrD+5mX6qwSwWuqsdkKKxTN4aQc4wByHAKZJf9/D4KXPQ1POUjEbnCP5LMggB0OEFNY9OTsMqg==" } } }, @@ -2366,14 +2369,32 @@ } }, "find-cache-dir": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.0.0.tgz", - "integrity": "sha512-LDUY6V1Xs5eFskUVYtIwatojt6+9xC9Chnlk/jYOOvn3FAFfSaWddxahDGyNHh0b2dMXa6YW2m0tk8TdVaXHlA==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz", + "integrity": "sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==", "dev": true, "requires": { "commondir": "^1.0.1", - "make-dir": "^1.0.0", + "make-dir": "^2.0.0", "pkg-dir": "^3.0.0" + }, + "dependencies": { + "make-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", + "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", + "dev": true, + "requires": { + "pify": "^4.0.1", + "semver": "^5.6.0" + } + }, + "pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true + } } }, "find-up": { @@ -4323,9 +4344,9 @@ } }, "nan": { - "version": "2.12.1", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.12.1.tgz", - "integrity": "sha512-JY7V6lRkStKcKTvHO5NVSQRv+RV+FIL5pvDoLiAtSL9pKlC5x9PKQcZDsq7m4FO4d57mkhC6Z+QhAh3Jdk5JFw==" + "version": "2.13.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.13.0.tgz", + "integrity": "sha512-5DDQvN0luhXdut8SCwzm/ZuAX2W+fwhqNzfq7CZ+OJzQ6NwpcqmIGyLD1R8MEt7BeErzcsI0JLr4pND2pNp2Cw==" }, "nano-json-stream-parser": { "version": "0.1.2", @@ -6175,9 +6196,9 @@ } }, "rollup": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-1.4.1.tgz", - "integrity": "sha512-YWf5zeR6SWtqZmCnuYs4a+ZJetj8NT4yfBMPXekWHW4L3144jM+J2AWagQVejB0FwCqjEUP9l8o4hg1rPDfQlg==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-1.6.0.tgz", + "integrity": "sha512-qu9iWyuiOxAuBM8cAwLuqPclYdarIpayrkfQB7aTGTiyYPbvx+qVF33sIznfq4bxZCiytQux/FvZieUBAXivCw==", "dev": true, "requires": { "@types/estree": "0.0.39", @@ -6186,9 +6207,9 @@ }, "dependencies": { "@types/node": { - "version": "11.10.4", - "resolved": "https://registry.npmjs.org/@types/node/-/node-11.10.4.tgz", - "integrity": "sha512-wa09itaLE8L705aXd8F80jnFpxz3Y1/KRHfKsYL2bPc0XF+wEWu8sR9n5bmeu8Ba1N9z2GRNzm/YdHcghLkLKg==", + "version": "11.11.3", + "resolved": "https://registry.npmjs.org/@types/node/-/node-11.11.3.tgz", + "integrity": "sha512-wp6IOGu1lxsfnrD+5mX6qwSwWuqsdkKKxTN4aQc4wByHAKZJf9/D4KXPQ1POUjEbnCP5LMggB0OEFNY9OTsMqg==", "dev": true } } @@ -6614,9 +6635,9 @@ } }, "source-map-support": { - "version": "0.5.10", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.10.tgz", - "integrity": "sha512-YfQ3tQFTK/yzlGJuX8pTwa4tifQj4QS2Mj7UegOu8jAz59MqIiMGPXxQhVQiIMNzayuUSF/jEuVnfFF5JqybmQ==", + "version": "0.5.11", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.11.tgz", + "integrity": "sha512-//sajEx/fGL3iw6fltKMdPvy8kL3kJ2O3iuYlRoT3k9Kb4BjOoZ+BZzaNHeuaruSt+Kf3Zk9tnfAQg9/AJqUVQ==", "dev": true, "requires": { "buffer-from": "^1.0.0", @@ -6894,20 +6915,20 @@ } }, "terser": { - "version": "3.16.1", - "resolved": "https://registry.npmjs.org/terser/-/terser-3.16.1.tgz", - "integrity": "sha512-JDJjgleBROeek2iBcSNzOHLKsB/MdDf+E/BOAJ0Tk9r7p9/fVobfv7LMJ/g/k3v9SXdmjZnIlFd5nfn/Rt0Xow==", + "version": "3.17.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-3.17.0.tgz", + "integrity": "sha512-/FQzzPJmCpjAH9Xvk2paiWrFq+5M6aVOf+2KRbwhByISDX/EujxsK+BAvrhb6H+2rtrLCHK9N01wO014vrIwVQ==", "dev": true, "requires": { - "commander": "~2.17.1", + "commander": "^2.19.0", "source-map": "~0.6.1", - "source-map-support": "~0.5.9" + "source-map-support": "~0.5.10" }, "dependencies": { "commander": { - "version": "2.17.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.17.1.tgz", - "integrity": "sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg==", + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.19.0.tgz", + "integrity": "sha512-6tvAOO+D6OENvRAh524Dh9jcfKTYDQAqvqezbCW82xj5X0pSrcpxtvRKHLG0yBY6SD7PSDrJaj+0AiOcKVd1Xg==", "dev": true }, "source-map": { @@ -7155,9 +7176,9 @@ "dev": true }, "tslint": { - "version": "5.13.1", - "resolved": "https://registry.npmjs.org/tslint/-/tslint-5.13.1.tgz", - "integrity": "sha512-fplQqb2miLbcPhyHoMV4FU9PtNRbgmm/zI5d3SZwwmJQM6V0eodju+hplpyfhLWpmwrDNfNYU57uYRb8s0zZoQ==", + "version": "5.14.0", + "resolved": "https://registry.npmjs.org/tslint/-/tslint-5.14.0.tgz", + "integrity": "sha512-IUla/ieHVnB8Le7LdQFRGlVJid2T/gaJe5VkjzRVSRR6pA2ODYrnfR1hmxi+5+au9l50jBwpbBL34txgv4NnTQ==", "dev": true, "requires": { "babel-code-frame": "^6.22.0", @@ -7172,7 +7193,7 @@ "resolve": "^1.3.2", "semver": "^5.3.0", "tslib": "^1.8.0", - "tsutils": "^2.27.2" + "tsutils": "^2.29.0" }, "dependencies": { "commander": { @@ -7477,9 +7498,9 @@ } }, "upath": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/upath/-/upath-1.1.0.tgz", - "integrity": "sha512-bzpH/oBhoS/QI/YtbkqCg6VEiPYjSZtrHQM6/QnJS6OL9pKUFLqb3aFh4Scvwm45+7iAgiMkLhSbaZxUqmrprw==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/upath/-/upath-1.1.2.tgz", + "integrity": "sha512-kXpym8nmDmlCBr7nKdIx8P2jNBa+pBpIUFRnKJ4dr8htyYGJFokkr2ZvERRtUN+9SY+JqXouNgUPtv6JQva/2Q==", "dev": true }, "uri-js": { @@ -7997,16 +8018,22 @@ } }, "mem": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/mem/-/mem-4.1.0.tgz", - "integrity": "sha512-I5u6Q1x7wxO0kdOpYBB28xueHADYps5uty/zg936CiG8NTe5sJL8EjrCuLneuDW3PlMdZBGDIn8BirEVdovZvg==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/mem/-/mem-4.2.0.tgz", + "integrity": "sha512-5fJxa68urlY0Ir8ijatKa3eRz5lwXnRCTvo9+TbTGAuTFJOwpGcY0X05moBd0nW45965Njt4CDI2GFQoG8DvqA==", "dev": true, "requires": { "map-age-cleaner": "^0.1.1", - "mimic-fn": "^1.0.0", + "mimic-fn": "^2.0.0", "p-is-promise": "^2.0.0" } }, + "mimic-fn": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.0.0.tgz", + "integrity": "sha512-jbex9Yd/3lmICXwYT6gA/j2mNQGU48wCh/VzRd+/Y/PjYQtlg1gLMdZqvu9s/xH7qKvngxRObl56XZR609IMbA==", + "dev": true + }, "os-locale": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-3.1.0.tgz", diff --git a/package.json b/package.json index 5d40e0b..39b753c 100644 --- a/package.json +++ b/package.json @@ -59,7 +59,7 @@ }, "homepage": "https://github.com/oceanprotocol/squid-js#readme", "dependencies": { - "@oceanprotocol/keeper-contracts": "^0.8.2", + "@oceanprotocol/keeper-contracts": "^0.8.5", "@oceanprotocol/secret-store-client": "~0.0.14", "@types/node-fetch": "^2.1.4", "bignumber.js": "^8.0.1", diff --git a/src/keeper/contracts/ContractBase.ts b/src/keeper/contracts/ContractBase.ts index 9a8aa6e..9abea11 100644 --- a/src/keeper/contracts/ContractBase.ts +++ b/src/keeper/contracts/ContractBase.ts @@ -69,7 +69,7 @@ export default abstract class ContractBase { }) return tx } catch (err) { - const mappedArgs = this.searchMethod(name).inputs.map((input, i) => { + const mappedArgs = this.searchMethod(name, args).inputs.map((input, i) => { return { name: input.name, value: args[i], @@ -99,10 +99,11 @@ export default abstract class ContractBase { } } - private searchMethod(methodName: string) { - const foundMethod = this.contract.options.jsonInterface + private searchMethod(methodName: string, args: any[] = []) { + const methods = this.contract.options.jsonInterface .map(method => ({...method, signature: (method as any).signature})) - .find((method: any) => method.name === methodName) + .filter((method: any) => method.name === methodName) + const foundMethod = methods.find(({inputs}) => inputs.length === args.length) || methods[0] if (!foundMethod) { throw new Error(`Method "${methodName}" is not part of contract "${this.contractName}"`) } diff --git a/src/keeper/contracts/conditions/AccessSecretStoreCondition.ts b/src/keeper/contracts/conditions/AccessSecretStoreCondition.ts index bd9f71c..06e7da8 100644 --- a/src/keeper/contracts/conditions/AccessSecretStoreCondition.ts +++ b/src/keeper/contracts/conditions/AccessSecretStoreCondition.ts @@ -1,5 +1,5 @@ import { Condition } from "./Condition.abstract" -import { zeroX } from "../../../utils" +import { zeroX, didZeroX } from "../../../utils" export class AccessSecretStoreCondition extends Condition { @@ -12,10 +12,10 @@ export class AccessSecretStoreCondition extends Condition { } fulfill(agreementId: string, did: string, grantee: string, from?: string) { - return super.fulfill(agreementId, [did, grantee].map(zeroX), from) + return super.fulfill(agreementId, [didZeroX(did), grantee].map(zeroX), from) } checkPermissions(grantee: string, did: string, from?: string) { - return this.call("checkPermissions", [grantee, did].map(zeroX), from) + return this.call("checkPermissions", [grantee, didZeroX(did)].map(zeroX), from) } } diff --git a/src/keeper/contracts/conditions/Condition.abstract.ts b/src/keeper/contracts/conditions/Condition.abstract.ts index 06000ea..595e909 100644 --- a/src/keeper/contracts/conditions/Condition.abstract.ts +++ b/src/keeper/contracts/conditions/Condition.abstract.ts @@ -1,5 +1,7 @@ import ContractBase from "../ContractBase" import { zeroX } from "../../../utils" +import EventListener from "../../../keeper/EventListener" +import Event from "../../../keeper/Event" export enum ConditionState { Uninitialized = 0, @@ -43,4 +45,13 @@ export abstract class Condition extends ContractBase { abortByTimeOut(agreementId: string, from?: string) { return this.sendFrom("abortByTimeOut", [zeroX(agreementId)], from) } + + public getConditionFulfilledEvent(agreementId: string): Event { + return EventListener + .subscribe( + this.contractName, + "Fulfilled", + {agreementId: zeroX(agreementId)}, + ) + } } diff --git a/src/keeper/contracts/templates/AgreementTemplate.abstract.ts b/src/keeper/contracts/templates/AgreementTemplate.abstract.ts index 9ccb962..de9e092 100644 --- a/src/keeper/contracts/templates/AgreementTemplate.abstract.ts +++ b/src/keeper/contracts/templates/AgreementTemplate.abstract.ts @@ -5,6 +5,8 @@ import Keeper from "../../Keeper" import { DDO } from '../../../ddo/DDO' import { ServiceAgreementTemplate } from '../../../ddo/ServiceAgreementTemplate' import { zeroX, Logger } from "../../../utils" +import EventListener from "../../../keeper/EventListener" +import Event from "../../../keeper/Event" export abstract class AgreementTemplate extends ContractBase { @@ -43,17 +45,41 @@ export abstract class AgreementTemplate extends ContractBase { ) } + /** + * Conditions address list. + * @return {Promise} Conditions address. + */ public getConditionTypes(): Promise { return this.call("getConditionTypes", []) } + /** + * List of condition contracts. + * @return {Promise} Conditions contracts. + */ public async getConditions(): Promise { const keeper = await Keeper.getInstance() return (await this.getConditionTypes()) .map(address => keeper.getConditionByAddress(address)) } - abstract getAgreementIdsFromDDO(agreementId: string, ddo: DDO, from: string): Promise + /** + * Get agreement conditions IDs. + * @param {string} agreementId Agreement ID. + * @param {DDO} ddo DDO. + * @param {string} from Consumer address. + * @return {Promise} Condition IDs. + */ + abstract getAgreementIdsFromDDO(agreementId: string, ddo: DDO, consumer: string, from?: string): Promise + + /** + * Create a new agreement using the data of a DDO. + * @param {string} agreementId Agreement ID. + * @param {DDO} ddo DDO. + * @param {string} from Creator address. + * @return {Promise} Success. + */ + abstract createAgreementFromDDO(agreementId: string, ddo: DDO, consumer: string, from?: string): Promise abstract async getServiceAgreementTemplate(): Promise @@ -90,12 +116,18 @@ export abstract class AgreementTemplate extends ContractBase { blocked: boolean, blockedBy: string[] } - }> { + } | false> { const agreementStore = await AgreementStoreManager.getInstance() const conditionStore = await ConditionStoreManager.getInstance() const dependencies = await this.getServiceAgreementTemplateDependencies() const {conditionIds} = await agreementStore.getAgreement(agreementId) + + if (!conditionIds.length) { + Logger.error(`Agreement not creeated yet: "${agreementId}"`) + return false + } + const conditionIdByConddition = (await this.getConditions()) .reduce((acc, {contractName}, i) => ({...acc, [contractName]: conditionIds[i]}), {}) @@ -139,7 +171,10 @@ export abstract class AgreementTemplate extends ContractBase { Logger.bypass("Template:", this.contractName) Logger.bypass("Agreement ID:", agreementId) Logger.bypass("-".repeat(40)) - Object.values(status) + if (!status) { + Logger.bypass("Agreement not created yet!") + } + Object.values(status || []) .forEach(({condition, contractName, state, blocked, blockedBy}, i) => { if (i) { Logger.bypass("-".repeat(20)) @@ -152,4 +187,18 @@ export abstract class AgreementTemplate extends ContractBase { }) Logger.bypass("-".repeat(80)) } + + /** + * Generates and returns the agreement creation event. + * @param {string} agreementId Agreement ID. + * @return {Event} Agreement created event. + */ + public getAgreementCreatedEvent(agreementId: string): Event { + return EventListener + .subscribe( + this.contractName, + "AgreementCreated", + {agreementId: zeroX(agreementId)}, + ) + } } diff --git a/src/keeper/contracts/templates/EscrowAccessSecretStoreTemplate.ts b/src/keeper/contracts/templates/EscrowAccessSecretStoreTemplate.ts index e8ae592..a9cbb91 100644 --- a/src/keeper/contracts/templates/EscrowAccessSecretStoreTemplate.ts +++ b/src/keeper/contracts/templates/EscrowAccessSecretStoreTemplate.ts @@ -47,6 +47,23 @@ export class EscrowAccessSecretStoreTemplate extends AgreementTemplate { ) } + + public async createAgreementFromDDO(agreementId: string, ddo: DDO, consumer: string, from?: string) { + return !!await this.createFullAgreement( + ddo.shortId(), + ddo.findServiceByType("Metadata").metadata.base.price, + consumer, + from, + agreementId, + ) + } + + public async getAgreementIdsFromDDO(agreementId: string, ddo: DDO, consumer: string, from?: string) { + const {accessSecretStoreConditionId, lockRewardConditionId, escrowRewardId} = + await this.createFullAgreementData(agreementId, ddo.shortId(), ddo.findServiceByType("Metadata").metadata.base.price, from) + return [accessSecretStoreConditionId, lockRewardConditionId, escrowRewardId] + } + /** * Create a agreement using EscrowAccessSecretStoreTemplate using only the most important information. * @param {string} did Asset DID. @@ -54,30 +71,24 @@ export class EscrowAccessSecretStoreTemplate extends AgreementTemplate { * @param {string} from Consumer address. * @return {Promise} Agreement ID. */ - public async createFullAgreement(did: string, amount: number, from?: string): Promise { - const agreementId = zeroX(generateId()) + public async createFullAgreement(did: string, amount: number, consumer: string, from?: string, agreementId?: string): Promise { + agreementId = agreementId || zeroX(generateId()) const {accessSecretStoreConditionId, lockRewardConditionId, escrowRewardId} = await this.createFullAgreementData(agreementId, did, amount, from) - await this.createAgreement( agreementId, did, [accessSecretStoreConditionId, lockRewardConditionId, escrowRewardId], [0, 0, 0], [0, 0, 0], + consumer, from, ) return agreementId } - public async getAgreementIdsFromDDO(agreementId: string, ddo: DDO, from: string) { - const {accessSecretStoreConditionId, lockRewardConditionId, escrowRewardId} = - await this.createFullAgreementData(agreementId, ddo.shortId(), ddo.findServiceByType("Metadata").metadata.base.price, from) - return [accessSecretStoreConditionId, lockRewardConditionId, escrowRewardId] - } - private async createFullAgreementData(agreementId: string, did: string, amount: number, from?: string) { from = await this.getFromAddress(from) diff --git a/src/ocean/OceanAgreements.ts b/src/ocean/OceanAgreements.ts index d0ba0f0..cc65c1a 100644 --- a/src/ocean/OceanAgreements.ts +++ b/src/ocean/OceanAgreements.ts @@ -3,7 +3,6 @@ import BrizoProvider from "../brizo/BrizoProvider" import { generateId } from "../utils/GeneratorHelpers" import Account from "./Account" import DID from "./DID" -import { DDO } from "../ddo/DDO" import ServiceAgreement from "./ServiceAgreements/ServiceAgreement" import { Keeper } from "../keeper/Keeper" import { zeroX, didPrefixed } from "../utils" @@ -57,6 +56,7 @@ export default class OceanAgreements { serviceDefinitionId: string, consumer: Account, ): Promise { + const d: DID = DID.parse(did as string) const ddo = await AquariusProvider.getAquarius().retrieveDDO(d) const agreementId: string = generateId() @@ -65,7 +65,7 @@ export default class OceanAgreements { const templateName = ddo.findServiceByType("Access").serviceAgreementTemplate.contractName const agreementConditionsIds = await keeper .getTemplateByName(templateName) - .getAgreementIdsFromDDO(agreementId, ddo, consumer.getId()) + .getAgreementIdsFromDDO(agreementId, ddo, consumer.getId(), consumer.getId()) const signature = await ServiceAgreement.signServiceAgreement( ddo, @@ -118,7 +118,7 @@ export default class OceanAgreements { * @param {string} signature Service agreement signature. * @param {Account} consumer Consumer account. * @param {Account} publisher Publisher account. - * @return {Promise} + * @return {Promise} */ public async create( did: string, @@ -127,23 +127,17 @@ export default class OceanAgreements { signature: string, consumer: Account, publisher: Account, - ): Promise { + ) { + const keeper = await Keeper.getInstance() + const d: DID = DID.parse(did) const ddo = await AquariusProvider.getAquarius().retrieveDDO(d) - // TODO: Use Keeper 0.7+ + const templateName = ddo.findServiceById<"Access">(serviceDefinitionId).serviceAgreementTemplate.contractName + await keeper + .getTemplateByName(templateName) + .createAgreementFromDDO(agreementId, ddo, consumer.getId(), publisher.getId()) - // const serviceAgreement: ServiceAgreement = await ServiceAgreement - // .executeServiceAgreement( - // d, - // ddo, - // agreementId, - // serviceDefinitionId, - // signature, - // consumer, - // publisher) - - // return serviceAgreement - return undefined + return true } } diff --git a/src/ocean/OceanAgreementsConditions.ts b/src/ocean/OceanAgreementsConditions.ts index 6e15113..7f9a702 100644 --- a/src/ocean/OceanAgreementsConditions.ts +++ b/src/ocean/OceanAgreementsConditions.ts @@ -39,7 +39,8 @@ export default class OceanAgreementsConditions { await this.keeper.token.approve(lockRewardCondition.getAddress(), amount, from.getId()) - return await lockRewardCondition.fulfill(agreementId, escrowReward.getAddress(), amount, from.getId()) + const receipt = await lockRewardCondition.fulfill(agreementId, escrowReward.getAddress(), amount, from.getId()) + return !!receipt.events.Fulfilled } @@ -53,7 +54,8 @@ export default class OceanAgreementsConditions { public async grantAccess(agreementId: string, did: string, grantee: string, from: Account = new Account()) { const {accessSecretStoreCondition} = this.keeper.conditions - return await accessSecretStoreCondition.fulfill(agreementId, did, grantee, from.getId()) + const receipt = await accessSecretStoreCondition.fulfill(agreementId, did, grantee, from.getId()) + return !!receipt.events.Fulfilled } /** @@ -82,7 +84,7 @@ export default class OceanAgreementsConditions { const conditionIdAccess = await accessSecretStoreCondition.generateIdHash(agreementId, did, consumer) const conditionIdLock = await lockRewardCondition.generateIdHash(agreementId, await escrowReward.getAddress(), amount) - return await escrowReward.fulfill( + const receipt = await escrowReward.fulfill( agreementId, amount, consumer, @@ -91,5 +93,6 @@ export default class OceanAgreementsConditions { conditionIdAccess, from.getId(), ) + return !!receipt.events.Fulfilled } } diff --git a/src/ocean/OceanAssets.ts b/src/ocean/OceanAssets.ts index b511350..a0108bd 100644 --- a/src/ocean/OceanAssets.ts +++ b/src/ocean/OceanAssets.ts @@ -2,20 +2,18 @@ import AquariusProvider from "../aquarius/AquariusProvider" import { SearchQuery } from "../aquarius/query/SearchQuery" import BrizoProvider from "../brizo/BrizoProvider" import ConfigProvider from "../ConfigProvider" -import { Condition } from "../ddo/Condition" import { DDO } from "../ddo/DDO" import { MetaData } from "../ddo/MetaData" +import { ServiceAgreementTemplate, ServiceAgreementTemplateCondition } from "../ddo/ServiceAgreementTemplate" import { Service, ServiceAuthorization } from "../ddo/Service" import EventListener from "../keeper/EventListener" import Keeper from "../keeper/Keeper" import SecretStoreProvider from "../secretstore/SecretStoreProvider" -import Logger from "../utils/Logger" +import { Logger, fillConditionsWithDDO } from "../utils" import Account from "./Account" import DID from "./DID" import OceanAgreements from "./OceanAgreements" import ServiceAgreement from "./ServiceAgreements/ServiceAgreement" -import ServiceAgreementTemplate from "./ServiceAgreements/ServiceAgreementTemplate" -import Access from "./ServiceAgreements/Templates/Access" /** * Assets submodule of Ocean Protocol. @@ -58,7 +56,7 @@ export default class OceanAssets { */ public async create(metadata: MetaData, publisher: Account, services: Service[] = []): Promise { const {secretStoreUri} = ConfigProvider.getConfig() - const {didRegistry} = await Keeper.getInstance() + const {didRegistry, templates} = await Keeper.getInstance() const aquarius = AquariusProvider.getAquarius() const brizo = BrizoProvider.getBrizo() @@ -72,21 +70,18 @@ export default class OceanAssets { const encryptedFiles = await SecretStoreProvider.getSecretStore(secretStoreConfig).encryptDocument(did.getId(), metadata.base.files) - const template = new Access() - const serviceAgreementTemplate = new ServiceAgreementTemplate(template) - - const conditions: Condition[] = await serviceAgreementTemplate.getConditions(metadata, did.getId()) + const serviceAgreementTemplate: ServiceAgreementTemplate = await templates.escrowAccessSecretStoreTemplate.getServiceAgreementTemplate() const serviceEndpoint = aquarius.getServiceEndpoint(did) let serviceDefinitionIdCount = 0 // create ddo itself const ddo: DDO = new DDO({ + id: did.getDid(), authentication: [{ type: "RsaSignatureAuthentication2018", publicKey: did.getDid() + "#keys-1", }], - id: did.getDid(), publicKey: [ { id: did.getDid() + "#keys-1", @@ -97,29 +92,12 @@ export default class OceanAssets { ], service: [ { - type: template.templateName, + type: "Access", purchaseEndpoint: brizo.getPurchaseEndpoint(), serviceEndpoint: brizo.getConsumeEndpoint(), - // the id of the service agreement? serviceDefinitionId: String(serviceDefinitionIdCount++), - // the id of the service agreement template - templateId: serviceAgreementTemplate.getId(), - serviceAgreementContract: { - contractName: "ServiceExecutionAgreement", - fulfillmentOperator: template.fulfillmentOperator, - events: [ - { - name: "AgreementInitialized", - actorType: "consumer", - handler: { - moduleName: "payment", - functionName: "lockPayment", - version: "0.1", - }, - }, - ], - }, - conditions, + templateId: templates.escrowAccessSecretStoreTemplate.getAddress(), + serviceAgreementTemplate, }, { type: "Compute", @@ -166,11 +144,15 @@ export default class OceanAssets { .reverse() as Service[], }) + // Overwritte initial service agreement conditions + const rawConditions: ServiceAgreementTemplateCondition[] = await templates.escrowAccessSecretStoreTemplate.getServiceAgreementTemplateConditions() + const conditions: ServiceAgreementTemplateCondition[] = fillConditionsWithDDO(rawConditions, ddo) + serviceAgreementTemplate.conditions = conditions + ddo.addChecksum() await ddo.addProof(publisher.getId(), publisher.getPassword()) const storedDdo = await aquarius.storeDDO(ddo) - await didRegistry.registerAttribute( did.getId(), ddo.getChecksum(), @@ -256,20 +238,22 @@ export default class OceanAssets { const ddo = await this.resolve(did) + const keeper = await Keeper.getInstance() + const templateName = ddo.findServiceByType("Access").serviceAgreementTemplate.contractName + const template = await keeper.getTemplateByName(templateName) + const accessCondition = await keeper.conditions.accessSecretStoreCondition + const paymentFlow = new Promise((resolve, reject) => { - EventListener - .subscribe( - "ServiceExecutionAgreement", - "AgreementInitialized", - {agreementId: "0x" + agreementId}, - ) + template + .getAgreementCreatedEvent(agreementId) .listenOnce(async (...args) => { Logger.log("Agreement initialized") - const serviceAgreement = new ServiceAgreement("0x" + agreementId) + const {metadata} = ddo.findServiceByType("Metadata") Logger.log("Locking payment") - const paid = await serviceAgreement.payAsset(ddo.shortId(), metadata.base.price, consumer) + + const paid = await oceanAgreements.conditions.lockReward(agreementId, metadata.base.price, consumer) if (paid) { Logger.log("Payment was OK") @@ -281,12 +265,8 @@ export default class OceanAssets { } }) - EventListener - .subscribe( - "AccessConditions", - "AccessGranted", - {agreementId: "0x" + agreementId}, - ) + accessCondition + .getConditionFulfilledEvent(agreementId) .listenOnce(async (...args) => { Logger.log("Access granted") resolve()