1
0
mirror of https://github.com/oceanprotocol-archive/squid-js.git synced 2024-02-02 15:31:51 +01:00

Merge branch 'master' into feature/compute

# Conflicts:
#	src/ocean/OceanAssets.ts
This commit is contained in:
ssallam 2020-01-23 09:34:40 +01:00
commit e31aa81dcc
41 changed files with 1192 additions and 1721 deletions

2
.gitignore vendored
View File

@ -7,3 +7,5 @@ test/**/*.js
src/**/*.js
src/metadata\.json
.idea
.vscode

View File

@ -15,6 +15,8 @@ matrix:
before_install:
- npm install -g npm
- npm install -g codacy-coverage release-it greenkeeper-lockfile ganache-cli@~6.5.1
- curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter
- chmod +x ./cc-test-reporter
before_script:
- greenkeeper-lockfile-update
@ -22,9 +24,9 @@ before_script:
- git clone https://github.com/oceanprotocol/barge
- cd barge
- export AQUARIUS_VERSION=v1.0.5
- export BRIZO_VERSION=v0.7.2
- export KEEPER_VERSION=v0.12.7
- export EVENTS_HANDLER_VERSION=v0.3.4
- export BRIZO_VERSION=v0.8.1
- export KEEPER_VERSION=v0.13.2
- export EVENTS_HANDLER_VERSION=v0.4.4
- export KEEPER_OWNER_ROLE_ADDRESS="0xe2DD09d719Da89e5a3D0F2549c7E24566e947260"
- rm -rf "${HOME}/.ocean/keeper-contracts/artifacts"
- bash -x start_ocean.sh --no-commons --no-dashboard 2>&1 > start_ocean.log &
@ -37,9 +39,13 @@ script:
- npm run build
- npm run doc
- npm run integration:cover
- npm run report-coverage
after_script:
- npm run report-codacy
- ./cc-test-reporter format-coverage -t lcov -o coverage/codeclimate.unit.json coverage/unit/lcov.info # Format unit test coverage
- ./cc-test-reporter format-coverage -t lcov -o coverage/codeclimate.integration.json coverage/integration/lcov.info # Format integration test coverage
- ./cc-test-reporter sum-coverage coverage/codeclimate.*.json -p 2 # Sum both coverage parts into coverage/codeclimate.json
- if [[ "$TRAVIS_TEST_RESULT" == 0 ]]; then ./cc-test-reporter upload-coverage; fi # Upload coverage/codeclimate.json
- greenkeeper-lockfile-upload
notifications:

View File

@ -4,6 +4,29 @@ All notable changes to this project will be documented in this file. Dates are d
Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
#### [v1.1.0](https://github.com/oceanprotocol/squid-js/compare/v1.1.0-beta.0...v1.1.0)
> 22 January 2020
- add codeclimate coverage reporting [`#359`](https://github.com/oceanprotocol/squid-js/pull/359)
- Update to keeper-contracts v0.13 [`#344`](https://github.com/oceanprotocol/squid-js/pull/344)
- Greenkeeper/typedoc 0.16.5 [`#356`](https://github.com/oceanprotocol/squid-js/pull/356)
- Update whatwg-url to the latest version 🚀 [`#349`](https://github.com/oceanprotocol/squid-js/pull/349)
- Update @types/node to the latest version 🚀 [`#348`](https://github.com/oceanprotocol/squid-js/pull/348)
- Update nyc to the latest version 🚀 [`#347`](https://github.com/oceanprotocol/squid-js/pull/347)
- chore(package): update typedoc to version 0.16.5 [`#352`](https://github.com/oceanprotocol/squid-js/issues/352)
- Fix tests. [`48c4f64`](https://github.com/oceanprotocol/squid-js/commit/48c4f6459910069c79424ac67fc6a0d28a9d1839)
- Remove all .js files that were unintentionally committed. [`7ccac88`](https://github.com/oceanprotocol/squid-js/commit/7ccac889ed20b9dabe9358e4e4989eed55245d52)
- package updates [`216ae33`](https://github.com/oceanprotocol/squid-js/commit/216ae3330e3ffa147ca0d8417a901fa9f5a0d4cf)
#### [v1.1.0-beta.0](https://github.com/oceanprotocol/squid-js/compare/v1.0.0...v1.1.0-beta.0)
> 17 December 2019
- package updates [`eb23b04`](https://github.com/oceanprotocol/squid-js/commit/eb23b04ffec69a0f9f31f09985bc1012f3a386d2)
- Release 1.1.0-beta.0 [`86c6a5a`](https://github.com/oceanprotocol/squid-js/commit/86c6a5a176203b222f2dc1f215c0c5fa6a418728)
- bump to keeper-contracts v0.13.0 [`21a0815`](https://github.com/oceanprotocol/squid-js/commit/21a08152d2a33f73b9bfc6509ef19731904bbd9b)
#### [v1.0.0](https://github.com/oceanprotocol/squid-js/compare/v1.0.0-beta.7...v1.0.0)
> 9 December 2019
@ -11,7 +34,7 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
- v2 release: new DDO [`#328`](https://github.com/oceanprotocol/squid-js/pull/328)
- package updates [`ccf7250`](https://github.com/oceanprotocol/squid-js/commit/ccf7250af87abf986d94c5023ac960fd155d0789)
- lint fixes, bump Ocean components [`414c885`](https://github.com/oceanprotocol/squid-js/commit/414c885163325a69eb315b20f8fe3837bc557656)
- typos [`d6a233e`](https://github.com/oceanprotocol/squid-js/commit/d6a233e590631087ba1302ac44f1e597b512c34e)
- Release 1.0.0 [`df53099`](https://github.com/oceanprotocol/squid-js/commit/df530992a1e578ecb4459d54d2669972479ccb5b)
#### [v1.0.0-beta.7](https://github.com/oceanprotocol/squid-js/compare/v0.8.3...v1.0.0-beta.7)

View File

@ -8,7 +8,8 @@
[![npm](https://img.shields.io/npm/v/@oceanprotocol/squid.svg)](https://www.npmjs.com/package/@oceanprotocol/squid)
[![Travis (.com)](https://img.shields.io/travis/com/oceanprotocol/squid-js.svg)](https://travis-ci.com/oceanprotocol/squid-js)
[![GitHub contributors](https://img.shields.io/github/contributors/oceanprotocol/squid-js.svg)](https://github.com/oceanprotocol/squid-js/graphs/contributors)
[![Codacy Badge](https://api.codacy.com/project/badge/Grade/8508313231b44b0997ec84898cd6f9db)](https://app.codacy.com/app/ocean-protocol/squid-js?utm_source=github.com&utm_medium=referral&utm_content=oceanprotocol/squid-js&utm_campaign=Badge_Grade_Settings)
[![Maintainability](https://api.codeclimate.com/v1/badges/ff173cf1c7adc6b21ae5/maintainability)](https://codeclimate.com/github/oceanprotocol/squid-js/maintainability)
[![Test Coverage](https://api.codeclimate.com/v1/badges/ff173cf1c7adc6b21ae5/test_coverage)](https://codeclimate.com/github/oceanprotocol/squid-js/test_coverage)
[![js oceanprotocol](https://img.shields.io/badge/js-oceanprotocol-7b1173.svg)](https://github.com/oceanprotocol/eslint-config-oceanprotocol)
[![Greenkeeper badge](https://badges.greenkeeper.io/oceanprotocol/squid-js.svg)](https://greenkeeper.io/)
@ -72,6 +73,19 @@ const ocean: Ocean = await Ocean.getInstance({
For an overview of endpoint configurations making up various Ocean networks, please refer to [`.env.local.example`](https://github.com/oceanprotocol/commons/blob/master/client/.env.local.example) from commons.
Optionally, you can initialize an Aquarius connection without relying on the rest of Ocean to be loaded. This is useful for outputting asset metadata stored in Aquarius without the need to configure Web3 and all other Ocean Protocol network connections.
```js
import { Ocean, Aquarius, Logger } from 'squid'
const aquarius = new Aquarius('http://localhost:5000', Logger)
const asset = aquarius.retrieveDDO('did:op:e6fda48e8d814d5d9655645aac3c046cc87528dbc1a9449799e579d7b83d1360')
const ocean = await Ocean.getInstance({ ... })
// Aquarius will still be available under ocean.aquarius, just later
const asset = ocean.aquarius.retrieveDDO('did:op:e6fda48e8d814d5d9655645aac3c046cc87528dbc1a9449799e579d7b83d1360')
```
### Examples
You can see how `squid-js` is used on:
@ -160,6 +174,8 @@ export SEED_WORDS="taxi music thumb unique chat sand crew more leg another off l
Once everything is up, run the integration tests:
```bash
# integration tests work with the spree network and the SEED_WORDS in previous step are required.
# Make sure to reset `ETH_PORT` to 8545 (or whatever port is used in `spree1)
npm run integration
```

View File

@ -6,7 +6,7 @@ const configJson: Config = {
aquariusUri: 'http://aquarius:5000',
brizoUri: 'http://localhost:8030',
secretStoreUri: 'http://localhost:12001',
brizoAddress: '0x068ed00cf0441e4829d9784fcbe7b9e26d4bd8d0',
brizoAddress: '0x068Ed00cF0441e4829D9784fCBe7b9e26D4BD8d0',
verbose: false
}

View File

@ -90,13 +90,17 @@ describe('Consume Asset', () => {
accessService.index,
serviceAgreementSignatureResult.signature,
consumer,
publisher
config.brizoAddress,
consumer
)
assert.isTrue(success)
})
it('should get the agreement conditions status not fulfilled', async () => {
// Wait for the agreement event
// await ocean.keeper.agreementStoreManager
// .getAgreementCreatedEvent(serviceAgreementSignatureResult.agreementId).once()
const status = await ocean.agreements.status(
serviceAgreementSignatureResult.agreementId
)

View File

@ -39,7 +39,7 @@ describe('Consume Asset (Brizo)', () => {
await consumer.authenticate()
})
it('should regiester an asset', async () => {
it('should register an asset', async () => {
const steps = []
ddo = await ocean.assets
.create(metadata as any, publisher)

View File

@ -43,7 +43,7 @@ xdescribe('Consume Asset (Large size)', () => {
}
})
it('should regiester an asset', async () => {
it('should register an asset', async () => {
ddo = await ocean.assets.create(metadata as any, publisher)
assert.instanceOf(ddo, DDO)

View File

@ -48,7 +48,7 @@ describe('Register Escrow Access Secret Store Template', () => {
describe('Propose and approve template', () => {
it('should propose the template', async () => {
await keeper.templateStoreManager.proposeTemplate(
template.getAddress(),
template.getId(),
consumer.getId(),
true
)
@ -58,7 +58,7 @@ describe('Register Escrow Access Secret Store Template', () => {
it('should approve the template', async () => {
await keeper.templateStoreManager.approveTemplate(
template.getAddress(),
template.getId(),
templateManagerOwner.getId(),
true
)
@ -122,7 +122,9 @@ describe('Register Escrow Access Secret Store Template', () => {
})
it('should have condition instances asociated', async () => {
const conditionInstances = await template.getConditions()
const conditionInstances = (await template.getConditionTypes()).map(address =>
keeper.getConditionByAddress(address)
)
assert.equal(conditionInstances.length, 3, 'Expected 3 conditions.')
@ -145,14 +147,15 @@ describe('Register Escrow Access Secret Store Template', () => {
})
it('should create a new agreement', async () => {
const agreement = await template.createAgreement(
const agreement = await keeper.agreementStoreManager.createAgreement(
agreementId,
did,
[conditionIdAccess, conditionIdLock, conditionIdEscrow],
template.getId(),
[conditionIdLock, conditionIdAccess, conditionIdEscrow],
[0, 0, 0],
[0, 0, 0],
consumer.getId(),
publisher.getId()
[consumer.getId(), config.brizoAddress],
consumer.getId()
)
assert.isTrue(agreement.status)
@ -244,7 +247,8 @@ describe('Register Escrow Access Secret Store Template', () => {
did,
escrowAmount,
consumer.getId(),
publisher.getId()
config.brizoAddress,
consumer.getId()
)
assert.match(agreementId, /^0x[a-f0-9]{64}$/i)

View File

@ -48,7 +48,7 @@ describe('Register Escrow Compute Execution Template', () => {
describe('Propose and approve template', () => {
it('should propose the template', async () => {
await keeper.templateStoreManager.proposeTemplate(
template.getAddress(),
template.getId(),
consumer.getId(),
true
)
@ -58,7 +58,7 @@ describe('Register Escrow Compute Execution Template', () => {
it('should approve the template', async () => {
await keeper.templateStoreManager.approveTemplate(
template.getAddress(),
template.getId(),
templateManagerOwner.getId(),
true
)
@ -145,14 +145,15 @@ describe('Register Escrow Compute Execution Template', () => {
})
it('should create a new agreement', async () => {
const agreement = await template.createAgreement(
const agreement = await keeper.agreementStoreManager.createAgreement(
agreementId,
did,
[conditionIdCompute, conditionIdLock, conditionIdEscrow],
template.getId(),
[conditionIdLock, conditionIdCompute, conditionIdEscrow],
[0, 0, 0],
[0, 0, 0],
consumer.getId(),
publisher.getId()
[consumer.getId(), config.brizoAddress],
consumer.getId()
)
assert.isTrue(agreement.status)
@ -244,7 +245,8 @@ describe('Register Escrow Compute Execution Template', () => {
did,
escrowAmount,
consumer.getId(),
publisher.getId()
config.brizoAddress,
consumer.getId()
)
assert.match(agreementId, /^0x[a-f0-9]{64}$/i)

View File

@ -18,7 +18,7 @@ describe('Signature', () => {
})
it('hashServiceAgreement should generate the correct signature', () => {
const templateId = `0x${'f'.repeat(40)}`
const templateId = `0x${'f'.repeat(64)}`
const agreementId = `0x${'e'.repeat(64)}`
const accessId = `0x${'a'.repeat(64)}`
@ -28,14 +28,14 @@ describe('Signature', () => {
const hash = ocean.utils.agreements.hashServiceAgreement(
templateId,
agreementId,
[accessId, lockId, escrowId],
[lockId, accessId, escrowId],
[0, 0, 0],
[0, 0, 0]
)
assert.equal(
hash,
'0x67901517c18a3d23e05806fff7f04235cc8ae3b1f82345b8bfb3e4b02b5800c7',
'0x464dac3b79a47f8acad54f67a0f4473249330f025c69687531e58c2e43b36437',
'The signature is not correct.'
)
})
@ -44,7 +44,7 @@ describe('Signature', () => {
const { templates } = ocean.keeper
const did = `did:op:${'c'.repeat(64)}`
const templateId = `0x${'f'.repeat(40)}`
const templateId = `0x${'f'.repeat(64)}`
const agreementId = `0x${'e'.repeat(64)}`
const serviceAgreementTemplate = await templates.escrowAccessSecretStoreTemplate.getServiceAgreementTemplate()
@ -84,7 +84,7 @@ describe('Signature', () => {
assert.equal(
signature,
'0x3aa8a1c48b8e582d694bbd4ba3a29fde573b78da9720dc48baeb831b2163e1fa6e10e983882ebf8a00f4124de2505136354fd146934053f0d58bba4eced5f8d01b',
'0xa04568fccdda7e1594e3e615f8d71b14733705aabe5294af0b7f46f0aedb9d5906a2caa6142ee4de10534a47c5a7083b21b2d3e9a96ac462bc0b9d25070e981e1c',
'The signature is not correct.'
)
})

View File

@ -7,11 +7,11 @@
"dependencies": [
{
"name": "keeper-contracts",
"version": "~0.12.7"
"version": "~0.13.2"
},
{
"name": "brizo",
"version": "~0.7.2"
"version": "~0.8.1"
},
{
"name": "aquarius",
@ -19,7 +19,7 @@
},
{
"name": "events-handler",
"version": "~0.3.4"
"version": "~0.4.1"
}
]
}

1508
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
{
"name": "@oceanprotocol/squid",
"version": "1.0.0",
"version": "1.1.0",
"description": "JavaScript client library for Ocean Protocol",
"main": "./dist/node/squid.js",
"typings": "./dist/node/squid.d.ts",
@ -26,10 +26,9 @@
"format": "prettier --parser typescript --ignore-path .gitignore --write '**/*.{js,jsx,ts,tsx}'",
"doc": "typedoc --mode modules --out ./doc/ ./src/",
"doc:json": "./scripts/typedoc.js",
"merge-coverages": "npx lcov-result-merger \"coverage/*/lcov.info\" coverage/lcov.info",
"report-coverage": "npm run report-coverage:unit && npm run report-coverage:integration",
"report-coverage:unit": "cat coverage/unit/lcov.info | codacy-coverage --token 71ef0d15f6f04ac29b31d704b28f866a",
"report-coverage:integration": "cat coverage/integration/lcov.info | codacy-coverage --token 71ef0d15f6f04ac29b31d704b28f866a",
"report-codacy": "npm run report-coverage:unit && npm run report-coverage:integration",
"report-codacy:unit": "cat coverage/unit/lcov.info | codacy-coverage --token 71ef0d15f6f04ac29b31d704b28f866a",
"report-codacy:integration": "cat coverage/integration/lcov.info | codacy-coverage --token 71ef0d15f6f04ac29b31d704b28f866a",
"run": "ts-node",
"release": "release-it --non-interactive",
"changelog": "auto-changelog -p",
@ -52,7 +51,7 @@
"web3": "^1.2.3"
},
"dependencies": {
"@oceanprotocol/keeper-contracts": "^0.12.7",
"@oceanprotocol/keeper-contracts": "^0.13.2",
"@oceanprotocol/secret-store-client": "^0.0.15",
"bignumber.js": "^9.0.0",
"deprecated-decorator": "^0.1.6",
@ -64,14 +63,14 @@
},
"devDependencies": {
"@release-it/bumper": "^1.0.5",
"@truffle/hdwallet-provider": "^1.0.26",
"@types/chai": "^4.2.6",
"@truffle/hdwallet-provider": "^1.0.27",
"@types/chai": "^4.2.7",
"@types/chai-spies": "^1.0.1",
"@types/mocha": "^5.2.7",
"@types/node": "^13.1.0",
"@types/node-fetch": "^2.5.4",
"@typescript-eslint/eslint-plugin": "^2.10.0",
"@typescript-eslint/parser": "^2.10.0",
"@typescript-eslint/eslint-plugin": "^2.12.0",
"@typescript-eslint/parser": "^2.12.0",
"auto-changelog": "^1.16.2",
"chai": "^4.2.0",
"chai-spies": "^1.0.0",
@ -79,7 +78,7 @@
"eslint": "^6.7.2",
"eslint-config-oceanprotocol": "^1.5.0",
"eslint-config-prettier": "^6.7.0",
"eslint-plugin-prettier": "^3.1.1",
"eslint-plugin-prettier": "^3.1.2",
"lcov-result-merger": "^3.1.0",
"mocha": "^6.2.2",
"mock-local-storage": "^1.1.11",
@ -88,10 +87,10 @@
"prettier": "^1.19.1",
"source-map-support": "^0.5.16",
"ts-node": "^8.5.4",
"typedoc": "^0.15.3",
"typescript": "^3.7.3",
"typedoc": "^0.16.8",
"typescript": "^3.7.5",
"uglifyjs-webpack-plugin": "^2.2.0",
"webpack": "^4.41.2",
"webpack": "^4.41.3",
"webpack-cli": "^3.3.10",
"webpack-merge": "^4.2.2"
},

View File

@ -3,7 +3,7 @@
/* eslint-disable security/detect-non-literal-fs-filename */
const fs = require('fs')
const typedoc = require('typedoc')
const TypeDoc = require('typedoc')
const typescript = require('typescript')
const ora = require('ora')
const squidJsPackage = require('../package.json')
@ -21,7 +21,11 @@ const generateJson = () => {
const spinnerTypedoc = ora('Generating TypeDoc json...').start()
// Setup our TypeDoc app
const app = new typedoc.Application({
const app = new TypeDoc.Application()
app.options.addReader(new TypeDoc.TSConfigReader())
app.options.addReader(new TypeDoc.TypeDocReader())
app.bootstrap({
tsconfig: config
})

View File

@ -1,7 +1,8 @@
import { URL } from 'whatwg-url'
import { DDO } from '../ddo/DDO'
import DID from '../ocean/DID'
import { Instantiable, InstantiableConfig } from '../Instantiable.abstract'
import { Logger } from '../utils'
import { WebServiceConnector } from '../ocean/utils/WebServiceConnector'
const apiPath = '/api/v1/aquarius/assets/ddo'
@ -21,25 +22,35 @@ export interface SearchQuery {
}
/**
* Provides a interface with Aquarius.
* Provides an interface with Aquarius.
* Aquarius provides an off-chain database store for metadata about data assets.
*/
export class Aquarius extends Instantiable {
export class Aquarius {
public fetch: WebServiceConnector
private logger: Logger
private aquariusUri: string
private get url() {
return this.config.aquariusUri
return this.aquariusUri
}
constructor(config: InstantiableConfig) {
super()
this.setInstanceConfig(config)
/**
* Instantiate Aquarius (independently of Ocean) for off-chain interaction.
* @param {String} aquariusUri
* @param {Logger} logger
*/
constructor(aquariusUri: string, logger: Logger) {
this.fetch = new WebServiceConnector(logger)
this.logger = logger
this.aquariusUri = aquariusUri
}
public async getVersionInfo() {
return (await this.ocean.utils.fetch.get(this.url)).json()
return (await this.fetch.get(this.url)).json()
}
public async getAccessUrl(accessToken: any, payload: any): Promise<string> {
const accessUrl: string = await this.ocean.utils.fetch
const accessUrl: string = await this.fetch
.post(`${accessToken.service_endpoint}/${accessToken.resource_id}`, payload)
.then((response: any): string => {
if (response.ok) {
@ -69,7 +80,7 @@ export class Aquarius extends Instantiable {
* @return {Promise<QueryResult>}
*/
public async queryMetadata(query: SearchQuery): Promise<QueryResult> {
const result: QueryResult = await this.ocean.utils.fetch
const result: QueryResult = await this.fetch
.post(`${this.url}${apiPath}/query`, JSON.stringify(query))
.then((response: any) => {
if (response.ok) {
@ -107,7 +118,8 @@ export class Aquarius extends Instantiable {
)
fullUrl.searchParams.append('offset', query.offset.toString())
fullUrl.searchParams.append('page', query.page.toString())
const result: QueryResult = await this.ocean.utils.fetch
const result: QueryResult = await this.fetch
.get(fullUrl)
.then((response: any) => {
if (response.ok) {
@ -138,7 +150,7 @@ export class Aquarius extends Instantiable {
*/
public async storeDDO(ddo: DDO): Promise<DDO> {
const fullUrl = `${this.url}${apiPath}`
const result: DDO = await this.ocean.utils.fetch
const result: DDO = await this.fetch
.post(fullUrl, DDO.serialize(ddo))
.then((response: any) => {
if (response.ok) {
@ -174,7 +186,7 @@ export class Aquarius extends Instantiable {
): Promise<DDO> {
did = did && DID.parse(did)
const fullUrl = metadataServiceEndpoint || `${this.url}${apiPath}/${did.getDid()}`
const result = await this.ocean.utils.fetch
const result = await this.fetch
.get(fullUrl)
.then((response: any) => {
if (response.ok) {

View File

@ -11,7 +11,6 @@ import {
ComputeExecutionCondition
} from './contracts/conditions'
import {
AgreementTemplate,
EscrowAccessSecretStoreTemplate,
EscrowComputeExecutionTemplate
} from './contracts/templates'
@ -25,6 +24,7 @@ import { objectPromiseAll } from '../utils'
import { EventHandler } from './EventHandler'
import { Instantiable, InstantiableConfig } from '../Instantiable.abstract'
import { AgreementTemplateBase } from './contracts/templates/AgreementTemplateBase'
/**
* Interface with Ocean Keeper contracts.
@ -62,14 +62,7 @@ export class Keeper extends Instantiable {
accessSecretStoreCondition: AccessSecretStoreCondition.getInstance(
config
),
computeExecutionCondition: ComputeExecutionCondition.getInstance(config),
// Templates
escrowAccessSecretStoreTemplate: EscrowAccessSecretStoreTemplate.getInstance(
config
),
escrowComputeExecutionTemplate: EscrowComputeExecutionTemplate.getInstance(
config
)
computeExecutionCondition: ComputeExecutionCondition.getInstance(config)
})
keeper.connected = true
@ -100,7 +93,19 @@ export class Keeper extends Instantiable {
accessSecretStoreCondition: keeper.instances.accessSecretStoreCondition,
computeExecutionCondition: keeper.instances.computeExecutionCondition
}
// Conditions
// Templates
keeper.instances.escrowAccessSecretStoreTemplate = new EscrowAccessSecretStoreTemplate(
keeper.templateStoreManager,
keeper.agreementStoreManager,
keeper.didRegistry,
keeper.conditions
)
keeper.instances.escrowComputeExecutionTemplate = new EscrowComputeExecutionTemplate(
keeper.templateStoreManager,
keeper.agreementStoreManager,
keeper.didRegistry,
keeper.conditions
)
keeper.templates = {
escrowAccessSecretStoreTemplate:
keeper.instances.escrowAccessSecretStoreTemplate,
@ -198,22 +203,22 @@ export class Keeper extends Instantiable {
/**
* Returns a template by name.
* @param {string} name Template name.
* @return {AgreementTemplate} Agreement template instance.
* @return {AgreementTemplateBase} AgreementTemplateBase instance.
*/
public getTemplateByName(name: string): AgreementTemplate {
public getTemplateByName(name: string): AgreementTemplateBase {
return Object.values(this.templates).find(
template => template.contractName === name
template => template.templateName === name
)
}
/**
* Returns a template by address.
* @param {string} address Template address.
* @return {AgreementTemplate} Agreement template instance.
* @param {string} templateId Template id (hex representation of bytes32).
* @return {AgreementTemplateBase} AgreementTemplateBase instance.
*/
public getTemplateByAddress(address: string): AgreementTemplate {
public getTemplateById(templateId: string): AgreementTemplateBase {
return Object.values(this.templates).find(
template => template.getAddress() === address
template => template.getId() === templateId
)
}

View File

@ -37,6 +37,11 @@ export default class DIDRegistry extends ContractBase {
return this.call('isDIDProvider', [didZeroX(did), zeroX(provider)])
}
public async getDIDProviders(did: string): Promise<string[]> {
const { providers } = await this.call('getDIDRegister', [didZeroX(did)])
return providers
}
public async getAttributesByOwner(owner: string): Promise<string[]> {
return (
await this.getPastEvents('DIDAttributeRegistered', {

View File

@ -1,5 +1,5 @@
import { Condition } from './Condition.abstract'
import { zeroX, didZeroX, didPrefixed } from '../../../utils'
import { zeroX, didZeroX } from '../../../utils'
import { InstantiableConfig } from '../../../Instantiable.abstract'
export class ComputeExecutionCondition extends Condition {

View File

@ -15,11 +15,11 @@ export class AgreementStoreManager extends ContractBase {
public static async getInstance(
config: InstantiableConfig
): Promise<AgreementStoreManager> {
const templateStoreManeger: AgreementStoreManager = new AgreementStoreManager(
const templateStoreManager: AgreementStoreManager = new AgreementStoreManager(
'AgreementStoreManager'
)
await templateStoreManeger.init(config)
return templateStoreManeger
await templateStoreManager.init(config)
return templateStoreManager
}
public getOwner(): Promise<string> {
@ -44,4 +44,59 @@ export class AgreementStoreManager extends ContractBase {
blockNumberUpdated: +blockNumberUpdated
} as AgreementData
}
/**
* Create a agreement using EscrowComputeExecutionTemplate.
* @param {string} agreementId Generated agreement ID.
* @param {string} did Asset DID.
* @param {string} templateId Template ID.
* @param {string[]} conditionIds List of conditions IDs.
* @param {number[]} timeLocks Timelocks.
* @param {number[]} timeOuts Timeouts.
* @param {string[]} actors ETH account addresses of provider, consumer, etc.
* @param {string} from Action sender.
*
* @return {any} Transaction receipt.
*/
public async createAgreement(
agreementId: string,
did: string,
templateId: string,
conditionIds: string[],
timeLocks: number[],
timeOuts: number[],
actors: string[],
from?: string
): Promise<any> {
return this.sendFrom(
'createAgreement',
[
zeroX(agreementId),
zeroX(did),
zeroX(templateId),
conditionIds.map(zeroX),
timeLocks,
timeOuts,
actors
],
from
)
}
/**
* Generates and returns the agreement creation event.
* @param {string} agreementId Agreement ID.
* @return {Event} Agreement created event.
*/
public getAgreementCreatedEvent(agreementId: string) {
return this.getEvent('AgreementCreated', {
agreementId: zeroX(agreementId)
})
}
public getAgreementActorAddedEvent(agreementId: string) {
return this.getEvent('AgreementActorAdded', {
agreementId: zeroX(agreementId)
})
}
}

View File

@ -14,6 +14,8 @@ export interface TemplateMetadata {
owner: string
lastUpdatedBy: string
blockNumberUpdated: number
conditionTypes: string[]
actorTypeIds: string[]
}
export class TemplateStoreManager extends ContractBase {
@ -27,54 +29,83 @@ export class TemplateStoreManager extends ContractBase {
return templateStoreManeger
}
public generateId(templateName: string) {
const args: any = [{ type: 'string', value: templateName }]
return this.web3.utils.soliditySha3(...args)
}
public getOwner(): Promise<string> {
return this.call('owner', [])
}
public async proposeTemplate(address: string, from?: string, ignoreExists?: boolean) {
const template = await this.getTemplate(address)
public async proposeTemplate(
templateId: string,
from?: string,
ignoreExists?: boolean
) {
const template = await this.getTemplate(templateId)
if (template.blockNumberUpdated !== 0) {
this.logger.warn(`Template "${address}" already exist.`)
this.logger.warn(`Template "${templateId}" already exist.`)
if (!ignoreExists) {
throw new Error('Template already exist.')
}
} else {
return this.sendFrom('proposeTemplate', [zeroX(address)], from)
return this.sendFrom('proposeTemplate', [zeroX(templateId)], from)
}
}
public async approveTemplate(
address: string,
templateId: string,
from?: string,
ignoreApproved?: boolean
) {
const template = await this.getTemplate(address)
const template = await this.getTemplate(templateId)
if (template.state !== TemplateState.Proposed) {
this.logger.warn(`Template "${address}" is not in "proposed" state.`)
this.logger.warn(`Template "${templateId}" is not in "proposed" state.`)
if (!ignoreApproved) {
throw new Error(`Template not in "proposed" state.`)
}
} else {
return this.sendFrom('approveTemplate', [zeroX(address)], from)
return this.sendFrom('approveTemplate', [zeroX(templateId)], from)
}
}
public revokeTemplate(address: string, from?: string) {
return this.sendFrom('revokeTemplate', [zeroX(address)], from)
public revokeTemplate(templateId: string, from?: string) {
return this.sendFrom('revokeTemplate', [zeroX(templateId)], from)
}
public async getTemplate(address: string) {
public async getConditionTypes(templateId: string): Promise<string[]> {
const { conditionTypes } = await this.getTemplate(templateId)
return conditionTypes
}
public getConditions(conditionTypes: string[]) {
return conditionTypes.map(address =>
this.ocean.keeper.getConditionByAddress(address)
)
}
public async getActorTypeValue(actorTypeId: string) {
const typeValue = await this.call('getTemplateActorTypeValue', [actorTypeId])
return typeValue
}
public async getTemplate(templateId: string) {
const {
state,
owner,
lastUpdatedBy,
blockNumberUpdated
} = await this.call('getTemplate', [zeroX(address)])
blockNumberUpdated,
conditionTypes,
actorTypeIds
} = await this.call('getTemplate', [zeroX(templateId)])
return {
state: +state,
owner,
lastUpdatedBy,
blockNumberUpdated: +blockNumberUpdated
blockNumberUpdated: +blockNumberUpdated,
conditionTypes,
actorTypeIds
} as TemplateMetadata
}
}

View File

@ -1,235 +0,0 @@
import ContractBase from '../ContractBase'
import {
Condition,
ConditionState,
conditionStateNames
} from '../conditions/Condition.abstract'
import { DDO } from '../../../ddo/DDO'
import { ServiceAgreementTemplate } from '../../../ddo/ServiceAgreementTemplate'
import { zeroX } from '../../../utils'
import { InstantiableConfig } from '../../../Instantiable.abstract'
export interface AgreementConditionsStatus {
[condition: string]: {
condition: string
contractName: string
state: ConditionState
blocked: boolean
blockedBy: string[]
}
}
export abstract class AgreementTemplate extends ContractBase {
public static async getInstance(
config: InstantiableConfig,
conditionName: string,
templateClass: any
): Promise<AgreementTemplate & any> {
const condition: AgreementTemplate = new (templateClass as any)(conditionName)
await condition.init(config)
return condition
}
protected constructor(contractName: string) {
super(contractName)
}
public createAgreement(
agreementId: string,
did: string,
conditionIds: string[],
timeLocks: number[],
timeOuts: number[],
...args: any[]
)
public createAgreement(
agreementId: string,
did: string,
conditionIds: string[],
timeLocks: number[],
timeOuts: number[],
extraArgs: any[],
from?: string
) {
return this.sendFrom(
'createAgreement',
[
zeroX(agreementId),
zeroX(did),
conditionIds.map(zeroX),
timeLocks,
timeOuts,
...extraArgs
],
from
)
}
/**
* Conditions address list.
* @return {Promise<string[]>} Conditions address.
*/
public getConditionTypes(): Promise<string[]> {
return this.call('getConditionTypes', [])
}
/**
* List of condition contracts.
* @return {Promise<Condition[]>} Conditions contracts.
*/
public async getConditions(): Promise<Condition[]> {
return (await this.getConditionTypes()).map(address =>
this.ocean.keeper.getConditionByAddress(address)
)
}
/**
* Get agreement conditions IDs.
* @param {string} agreementId Agreement ID.
* @param {DDO} ddo DDO.
* @param {string} from Consumer address.
* @return {Promise<string[]>} Condition IDs.
*/
public abstract getAgreementIdsFromDDO(
agreementId: string,
ddo: DDO,
consumer: string,
from?: string
): Promise<string[]>
/**
* 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<boolean>} Success.
*/
public abstract createAgreementFromDDO(
agreementId: string,
ddo: DDO,
consumer: string,
from?: string
): Promise<boolean>
public abstract async getServiceAgreementTemplate(): Promise<ServiceAgreementTemplate>
public async getServiceAgreementTemplateConditions() {
const serviceAgreementTemplate = await this.getServiceAgreementTemplate()
return serviceAgreementTemplate.conditions
}
public async getServiceAgreementTemplateConditionByRef(ref: string) {
const name = (await this.getServiceAgreementTemplateConditions()).find(
({ name: conditionRef }) => conditionRef === ref
).contractName
return (await this.getConditions()).find(
condition => condition.contractName === name
)
}
public async getServiceAgreementTemplateDependencies() {
const serviceAgreementTemplate = await this.getServiceAgreementTemplate()
return serviceAgreementTemplate.conditionDependency
}
/**
* Returns the status of the conditions.
* @param {string} agreementId Agreement ID.
* @return {Promise} Conditions status.
*/
public async getAgreementStatus(
agreementId: string
): Promise<AgreementConditionsStatus | false> {
const agreementStore = this.ocean.keeper.agreementStoreManager
const conditionStore = this.ocean.keeper.conditionStoreManager
const dependencies = await this.getServiceAgreementTemplateDependencies()
const { conditionIds } = await agreementStore.getAgreement(agreementId)
if (!conditionIds.length) {
this.logger.error(`Agreement not creeated yet: "${agreementId}"`)
return false
}
const conditionIdByConddition = (await this.getConditions()).reduce(
(acc, { contractName }, i) => ({
...acc,
[contractName]: conditionIds[i]
}),
{}
)
const statesPromises = Object.keys(dependencies).map(async (ref, i) => {
const { contractName } = await this.getServiceAgreementTemplateConditionByRef(
ref
)
return {
ref,
contractName,
state: (
await conditionStore.getCondition(
conditionIdByConddition[contractName]
)
).state
}
})
const states = await Promise.all(statesPromises)
return states.reduce((acc, { contractName, ref, state }) => {
const blockers = dependencies[ref]
.map(dependency => states.find(_ => _.ref === dependency))
.filter(condition => condition.state !== ConditionState.Fulfilled)
return {
...acc,
[ref]: {
condition: ref,
contractName,
state,
blocked: !!blockers.length,
blockedBy: blockers.map(_ => _.ref)
}
}
}, {})
}
/**
* Prints the agreement status.
* @param {string} agreementId Agreement ID.
*/
public async printAgreementStatus(agreementId: string) {
const status = await this.getAgreementStatus(agreementId)
this.logger.bypass('-'.repeat(80))
this.logger.bypass('Template:', this.contractName)
this.logger.bypass('Agreement ID:', agreementId)
this.logger.bypass('-'.repeat(40))
if (!status) {
this.logger.bypass('Agreement not created yet!')
}
Object.values(status || []).forEach(
({ condition, contractName, state, blocked, blockedBy }, i) => {
if (i) {
this.logger.bypass('-'.repeat(20))
}
this.logger.bypass(`${condition} (${contractName})`)
this.logger.bypass(' Status:', state, `(${conditionStateNames[state]})`)
if (blocked) {
this.logger.bypass(' Blocked by:', blockedBy)
}
}
)
this.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) {
return this.getEvent('AgreementCreated', {
agreementId: zeroX(agreementId)
})
}
}

View File

@ -0,0 +1,314 @@
import {
TemplateStoreManager,
AgreementStoreManager,
ConditionStoreManager
} from '../managers'
import DIDRegistry from '../DIDRegistry'
import { LockRewardCondition } from '../conditions/LockRewardCondition'
import { AccessSecretStoreCondition } from '../conditions/AccessSecretStoreCondition'
import { EscrowReward } from '../conditions/EscrowReward'
import { DDO } from '../../../ddo/DDO'
import { generateId, LoggerInstance, Logger, zeroX } from '../../../utils'
import {
ComputeExecutionCondition,
Condition,
ConditionState,
conditionStateNames
} from '../conditions'
import { ServiceType } from '../../../ddo/Service'
export interface Conditions {
lockRewardCondition: LockRewardCondition
accessSecretStoreCondition?: AccessSecretStoreCondition
computeExecutionCondition?: ComputeExecutionCondition
escrowReward: EscrowReward
}
export interface AgreementConditionsStatus {
[condition: string]: {
condition: string
contractName: string
state: ConditionState
blocked: boolean
blockedBy: string[]
}
}
export class AgreementTemplateBase {
public templateName: string
public templateManager: TemplateStoreManager
public agreementStoreManager: AgreementStoreManager
public didRegistry: DIDRegistry
public conditions: Conditions
private logger: Logger
public constructor(
templateManager: TemplateStoreManager,
agreementStoreManager: AgreementStoreManager,
didRegistry: DIDRegistry,
conditions: Conditions
) {
this.templateManager = templateManager
this.agreementStoreManager = agreementStoreManager
this.didRegistry = didRegistry
this.conditions = conditions
this.logger = LoggerInstance
this.templateName = 'invalid'
}
public async createAgreementFromDDO(
agreementId: string,
ddo: DDO,
serviceType: ServiceType,
consumer: string,
provider: string,
from?: string
) {
return !!(await this.createFullAgreement(
ddo.shortId(),
ddo.findServiceByType(serviceType).attributes.main.price,
consumer,
provider,
from,
agreementId
))
}
public async getConditionIdsFromDDO(
agreementId: string,
ddo: DDO,
consumer: string,
from?: string
) {
return this.createFullAgreementData(
agreementId,
ddo.shortId(),
ddo.findServiceByType('metadata').attributes.main.price,
consumer
)
}
public getName() {
return this.templateName
}
public getId() {
return this.templateManager.generateId(this.getName())
}
/**
* Create a agreement using EscrowAccessSecretStoreTemplate using only the most important information.
* @param {string} did Asset DID.
* @param {number} amount Asset price.
* @param {string} consumer ethereum address of consumer.
* @param {string} provider ethereum address of service provider (brizo address)
* @param {string} from Consumer address.
* @param {string} agreementId bytes32 agreement id.
*
* @return {Promise<string>} Agreement ID.
*/
public async createFullAgreement(
did: string,
amount: number | string,
consumer: string,
provider: string,
from?: string,
agreementId: string = generateId()
): Promise<string> {
const conditionIds = await this.createFullAgreementData(
agreementId,
did,
amount,
consumer
)
const timeouts = [0, 0, 0]
const timelocks = [0, 0, 0]
await this.agreementStoreManager.createAgreement(
agreementId,
did,
this.getId(),
conditionIds,
timelocks,
timeouts,
[consumer, provider],
from
)
return zeroX(agreementId)
}
protected async createFullAgreementData(
agreementId: string,
did: string,
amount: number | string,
consumer: string
): Promise<string[]> {
return null
}
/**
* Conditions address list.
* @return {Promise<string[]>} Conditions address.
*/
public async getConditionTypes(): Promise<string[]> {
return this.templateManager.getConditionTypes(this.getId())
}
/**
* List of condition contracts.
* @return {Promise<Condition[]>} Conditions contracts.
*/
public async getConditions(): Promise<Condition[]> {
return this.templateManager.getConditions(await this.getConditionTypes())
}
public async getServiceAgreementTemplate() {
return null
}
public async getServiceAgreementTemplateConditions() {
const serviceAgreementTemplate = await this.getServiceAgreementTemplate()
return serviceAgreementTemplate.conditions
}
public async getServiceAgreementTemplateConditionByRef(ref: string) {
const name = (await this.getServiceAgreementTemplateConditions()).find(
({ name: conditionRef }) => conditionRef === ref
).contractName
return (await this.getConditions()).find(
condition => condition.contractName === name
)
}
public async getServiceAgreementTemplateDependencies() {
const serviceAgreementTemplate = await this.getServiceAgreementTemplate()
return serviceAgreementTemplate.conditionDependency
}
/**
* Returns the status of the conditions.
* @param {string} agreementId Agreement ID.
* @param {ConditionStoreManager} conditionStoreManager
* @return {Promise} Conditions status.
*/
public async getAgreementStatus(
agreementId: string,
conditionStoreManager: ConditionStoreManager
): Promise<AgreementConditionsStatus | false> {
const dependencies = await this.getServiceAgreementTemplateDependencies()
const { conditionIds } = await this.agreementStoreManager.getAgreement(
agreementId
)
if (!conditionIds.length) {
// this.logger.error(`Agreement not creeated yet: "${agreementId}"`)
return false
}
const conditionIdByCondition = (await this.getConditions()).reduce(
(acc, { contractName }, i) => ({
...acc,
[contractName]: conditionIds[i]
}),
{}
)
const statesPromises = Object.keys(dependencies).map(async (ref, i) => {
const { contractName } = await this.getServiceAgreementTemplateConditionByRef(
ref
)
return {
ref,
contractName,
state: (
await conditionStoreManager.getCondition(
conditionIdByCondition[contractName]
)
).state
}
})
const states = await Promise.all(statesPromises)
return states.reduce((acc, { contractName, ref, state }) => {
const blockers = dependencies[ref]
.map(dependency => states.find(_ => _.ref === dependency))
.filter(condition => condition.state !== ConditionState.Fulfilled)
return {
...acc,
[ref]: {
condition: ref,
contractName,
state,
blocked: !!blockers.length,
blockedBy: blockers.map(_ => _.ref)
}
}
}, {})
}
/**
* Prints the agreement status.
* @param {string} agreementId Agreement ID.
* @param {ConditionStoreManager} conditionStoreManager
*/
public async printAgreementStatus(
agreementId: string,
conditionStoreManager: ConditionStoreManager
) {
const status = await this.getAgreementStatus(agreementId, conditionStoreManager)
this.logger.bypass('-'.repeat(80))
this.logger.bypass('Template:', this.templateName)
this.logger.bypass('Agreement ID:', agreementId)
this.logger.bypass('-'.repeat(40))
if (!status) {
this.logger.bypass('Agreement not created yet!')
}
Object.values(status || []).forEach(
({ condition, contractName, state, blocked, blockedBy }, i) => {
if (i) {
this.logger.bypass('-'.repeat(20))
}
this.logger.bypass(`${condition} (${contractName})`)
this.logger.bypass(' Status:', state, `(${conditionStateNames[state]})`)
if (blocked) {
this.logger.bypass(' Blocked by:', blockedBy)
}
}
)
this.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) {
return this.agreementStoreManager.getAgreementCreatedEvent(agreementId)
}
/**
* Return actor type ids for this template (specified by subclass)
*
*/
public async getActorTypeIds() {
const { actorTypeIds } = await this.templateManager.getTemplate(this.getId())
return actorTypeIds
}
/**
* Return actor types (strings) for this template (specified by subclass)
*
*/
public async getActorTypes() {
const actorTypeIds = await this.getActorTypeIds()
return actorTypeIds.map(typeId => this.templateManager.getActorTypeValue(typeId))
}
}

View File

@ -1,43 +0,0 @@
import { AgreementTemplate } from './AgreementTemplate.abstract'
import { DDO } from '../../../ddo/DDO'
import { generateId, zeroX } from '../../../utils'
import { InstantiableConfig } from '../../../Instantiable.abstract'
// import { EscrowComputeExecutionTemplateServiceAgreementTemplate } from './EscrowComputeExecutionTemplate.serviceAgreementTemplate'
export abstract class BaseEscrowTemplate extends AgreementTemplate {
/**
* Create a agreement using EscrowComputeExecutionTemplate.
* @param {string} agreementId Generated agreement ID.
* @param {string} did Asset DID.
* @param {string[]} conditionIds List of conditions IDs.
* @param {number[]} timeLocks Timelocks.
* @param {number[]} timeOuts Timeouts.
* @param {string} accessConsumer Consumer address.
* @param {string} from Action sender.
* @param {any} Transaction receipt.
*/
public createAgreement(
agreementId: string,
did: string,
conditionIds: string[],
timeLocks: number[],
timeOuts: number[],
accessConsumer: string,
from?: string
) {
return super.createAgreement(
agreementId,
did,
conditionIds,
timeLocks,
timeOuts,
[accessConsumer],
from
)
}
public async getAgreementData(agreementId: string) {
return this.call<any>('getAgreementData', [zeroX(agreementId)])
}
}

View File

@ -1,6 +1,6 @@
import { ServiceAgreementTemplate } from '../../../ddo/ServiceAgreementTemplate'
export const escrowAccessSecretStoreTemplateServiceAgreementTemplate: ServiceAgreementTemplate = {
export const escrowAccessServiceAgreementTemplate: ServiceAgreementTemplate = {
contractName: 'EscrowAccessSecretStoreTemplate',
events: [
{

View File

@ -1,113 +1,40 @@
import { AgreementTemplate } from './AgreementTemplate.abstract'
import { BaseEscrowTemplate } from './BaseEscrowTemplate.abstract'
import { DDO } from '../../../ddo/DDO'
import { generateId, zeroX } from '../../../utils'
import { InstantiableConfig } from '../../../Instantiable.abstract'
import { AgreementTemplateBase, Conditions } from './AgreementTemplateBase'
import { escrowAccessServiceAgreementTemplate } from './EscrowAccess.serviceAgreementTemplate'
import { AgreementStoreManager, TemplateStoreManager } from '../managers'
import DIDRegistry from '../DIDRegistry'
import { escrowAccessSecretStoreTemplateServiceAgreementTemplate } from './EscrowAccessSecretStoreTemplate.serviceAgreementTemplate'
export class EscrowAccessSecretStoreTemplate extends BaseEscrowTemplate {
public static async getInstance(
config: InstantiableConfig
): Promise<EscrowAccessSecretStoreTemplate> {
return AgreementTemplate.getInstance(
config,
'EscrowAccessSecretStoreTemplate',
EscrowAccessSecretStoreTemplate
)
export class EscrowAccessSecretStoreTemplate extends AgreementTemplateBase {
public constructor(
templateManager: TemplateStoreManager,
agreementStoreManager: AgreementStoreManager,
didRegistry: DIDRegistry,
conditions: Conditions
) {
super(templateManager, agreementStoreManager, didRegistry, conditions)
this.templateName = 'EscrowAccessSecretStoreTemplate'
}
public async getServiceAgreementTemplate() {
return escrowAccessSecretStoreTemplateServiceAgreementTemplate
return escrowAccessServiceAgreementTemplate
}
public async createAgreementFromDDO(
agreementId: string,
ddo: DDO,
consumer: string,
from?: string
) {
return !!(await this.createFullAgreement(
ddo.shortId(),
ddo.findServiceByType('metadata').attributes.main.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').attributes.main.price,
consumer
)
return [accessSecretStoreConditionId, lockRewardConditionId, escrowRewardId]
}
/**
* Create a agreement using EscrowAccessSecretStoreTemplate using only the most important information.
* @param {string} did Asset DID.
* @param {number} amount Asset price.
* @param {string} from Consumer address.
* @return {Promise<string>} Agreement ID.
*/
public async createFullAgreement(
did: string,
amount: number | string,
consumer: string,
from?: string,
agreementId: string = generateId()
): Promise<string> {
const {
accessSecretStoreConditionId,
lockRewardConditionId,
escrowRewardId
} = await this.createFullAgreementData(agreementId, did, amount, consumer)
await this.createAgreement(
agreementId,
did,
[accessSecretStoreConditionId, lockRewardConditionId, escrowRewardId],
[0, 0, 0],
[0, 0, 0],
consumer,
from
)
return zeroX(agreementId)
}
private async createFullAgreementData(
protected async createFullAgreementData(
agreementId: string,
did: string,
amount: number | string,
consumer: string
) {
const { didRegistry, conditions } = this.ocean.keeper
const {
accessSecretStoreCondition,
lockRewardCondition,
accessSecretStoreCondition,
escrowReward
} = conditions
const publisher = await didRegistry.getDIDOwner(did)
} = this.conditions
const publisher = await this.didRegistry.getDIDOwner(did)
const lockRewardConditionId = await lockRewardCondition.generateIdHash(
agreementId,
await escrowReward.getAddress(),
amount
String(amount)
)
const accessSecretStoreConditionId = await accessSecretStoreCondition.generateIdHash(
agreementId,
@ -122,11 +49,6 @@ export class EscrowAccessSecretStoreTemplate extends BaseEscrowTemplate {
lockRewardConditionId,
accessSecretStoreConditionId
)
return {
lockRewardConditionId,
accessSecretStoreConditionId,
escrowRewardId
}
return [lockRewardConditionId, accessSecretStoreConditionId, escrowRewardId]
}
}

View File

@ -1,6 +1,6 @@
import { ServiceAgreementTemplate } from '../../../ddo/ServiceAgreementTemplate'
export const escrowComputeExecutionTemplateServiceAgreementTemplate: ServiceAgreementTemplate = {
export const escrowComputeServiceAgreementTemplate: ServiceAgreementTemplate = {
contractName: 'EscrowComputeExecutionTemplate',
events: [
{

View File

@ -1,108 +1,36 @@
import { AgreementTemplate } from './AgreementTemplate.abstract'
import { BaseEscrowTemplate } from './BaseEscrowTemplate.abstract'
import { DDO } from '../../../ddo/DDO'
import { generateId, zeroX } from '../../../utils'
import { InstantiableConfig } from '../../../Instantiable.abstract'
import { AgreementTemplateBase, Conditions } from './AgreementTemplateBase'
import { escrowComputeServiceAgreementTemplate } from './EscrowCompute.serviceAgreementTemplate'
import { AgreementStoreManager, TemplateStoreManager } from '../managers'
import DIDRegistry from '../DIDRegistry'
import { escrowComputeExecutionTemplateServiceAgreementTemplate } from './EscrowComputeExecutionTemplate.serviceAgreementTemplate'
export class EscrowComputeExecutionTemplate extends BaseEscrowTemplate {
public static async getInstance(
config: InstantiableConfig
): Promise<EscrowComputeExecutionTemplate> {
return AgreementTemplate.getInstance(
config,
'EscrowComputeExecutionTemplate',
EscrowComputeExecutionTemplate
)
export class EscrowComputeExecutionTemplate extends AgreementTemplateBase {
public constructor(
templateManager: TemplateStoreManager,
agreementStoreManager: AgreementStoreManager,
didRegistry: DIDRegistry,
conditions: Conditions
) {
super(templateManager, agreementStoreManager, didRegistry, conditions)
this.templateName = 'EscrowComputeExecutionTemplate'
}
public async getServiceAgreementTemplate() {
return escrowComputeExecutionTemplateServiceAgreementTemplate
return escrowComputeServiceAgreementTemplate
}
public async createAgreementFromDDO(
agreementId: string,
ddo: DDO,
consumer: string,
from?: string
) {
return !!(await this.createFullAgreement(
ddo.shortId(),
ddo.findServiceByType('metadata').attributes.main.price,
consumer,
from,
agreementId
))
}
public async getAgreementIdsFromDDO(
agreementId: string,
ddo: DDO,
consumer: string,
from?: string
) {
const {
computeExecutionConditionId,
lockRewardConditionId,
escrowRewardId
} = await this.createFullAgreementData(
agreementId,
ddo.shortId(),
ddo.findServiceByType('metadata').attributes.main.price,
consumer
)
return [computeExecutionConditionId, lockRewardConditionId, escrowRewardId]
}
/**
* Create a agreement using EscrowAccess____SecretStoreTemplate using only the most important information.
* @param {string} did Asset DID.
* @param {number} amount Asset price.
* @param {string} from Consumer address.
* @return {Promise<string>} Agreement ID.
*/
public async createFullAgreement(
did: string,
amount: number | string,
consumer: string,
from?: string,
agreementId: string = generateId()
): Promise<string> {
const {
computeExecutionConditionId,
lockRewardConditionId,
escrowRewardId
} = await this.createFullAgreementData(agreementId, did, amount, consumer)
await this.createAgreement(
agreementId,
did,
[computeExecutionConditionId, lockRewardConditionId, escrowRewardId],
[0, 0, 0],
[0, 0, 0],
consumer,
from
)
return zeroX(agreementId)
}
private async createFullAgreementData(
protected async createFullAgreementData(
agreementId: string,
did: string,
amount: number | string,
consumer: string
) {
const { didRegistry, conditions } = this.ocean.keeper
const {
computeExecutionCondition,
lockRewardCondition,
computeExecutionCondition,
escrowReward
} = conditions
} = this.conditions
const publisher = await didRegistry.getDIDOwner(did)
const publisher = await this.didRegistry.getDIDOwner(did)
const lockRewardConditionId = await lockRewardCondition.generateIdHash(
agreementId,
@ -122,11 +50,6 @@ export class EscrowComputeExecutionTemplate extends BaseEscrowTemplate {
lockRewardConditionId,
computeExecutionConditionId
)
return {
lockRewardConditionId,
computeExecutionConditionId,
escrowRewardId
}
return [lockRewardConditionId, computeExecutionConditionId, escrowRewardId]
}
}

View File

@ -1,4 +1,3 @@
export * from './AgreementTemplate.abstract'
export { BaseEscrowTemplate } from './BaseEscrowTemplate.abstract'
export * from './AgreementTemplateBase'
export { EscrowAccessSecretStoreTemplate } from './EscrowAccessSecretStoreTemplate'
export { EscrowComputeExecutionTemplate } from './EscrowComputeExecutionTemplate'

View File

@ -38,10 +38,14 @@ export class Ocean extends Instantiable {
}
instance.setInstanceConfig(instanceConfig)
instance.utils = await OceanUtils.getInstance(instanceConfig)
instance.keeper = await Keeper.getInstance(instanceConfig)
instance.brizo = new Brizo(instanceConfig)
instance.aquarius = new Aquarius(instanceConfig)
instance.aquarius = new Aquarius(
instanceConfig.config.aquariusUri,
instanceConfig.logger
)
instance.accounts = await OceanAccounts.getInstance(instanceConfig)
instance.auth = await OceanAuth.getInstance(instanceConfig)
@ -52,8 +56,6 @@ export class Ocean extends Instantiable {
instance.tokens = await OceanTokens.getInstance(instanceConfig)
instance.versions = await OceanVersions.getInstance(instanceConfig)
instance.utils = await OceanUtils.getInstance(instanceConfig)
return instance
}

View File

@ -3,7 +3,7 @@ import Account from './Account'
import DID from './DID'
import { zeroX, didPrefixed } from '../utils'
import { Instantiable, InstantiableConfig } from '../Instantiable.abstract'
import { AgreementConditionsStatus } from '../keeper/contracts/templates/AgreementTemplate.abstract'
import { AgreementConditionsStatus } from '../keeper/contracts/templates/AgreementTemplateBase'
import { ConditionState } from '../keeper/contracts/conditions/Condition.abstract'
import { OceanAgreementsConditions } from './OceanAgreementsConditions'
@ -57,7 +57,7 @@ export class OceanAgreements extends Instantiable {
.serviceAgreementTemplate.contractName
const agreementConditionsIds = await this.ocean.keeper
.getTemplateByName(templateName)
.getAgreementIdsFromDDO(agreementId, ddo, consumer.getId(), consumer.getId())
.getConditionIdsFromDDO(agreementId, ddo, consumer.getId(), consumer.getId())
const signature = await this.ocean.utils.agreements.signServiceAgreement(
ddo,
@ -106,7 +106,8 @@ export class OceanAgreements extends Instantiable {
* @param {number} index Service index.
* @param {string} signature Service agreement signature.
* @param {Account} consumer Consumer account.
* @param {Account} publisher Publisher account.
* @param {string} provider ethereum address of service provider
* @param {Account} from account of party creating the agreement (usually the consumer).
* @return {Promise<boolean>}
*/
public async create(
@ -115,18 +116,23 @@ export class OceanAgreements extends Instantiable {
index: number,
signature: string,
consumer: Account,
publisher: Account
provider: string,
from: Account
) {
const d: DID = DID.parse(did)
const ddo = await this.ocean.aquarius.retrieveDDO(d)
const templateName = ddo.findServiceById<'access'>(index).attributes
.serviceAgreementTemplate.contractName
await this.ocean.keeper
const service = ddo.findServiceById(index)
const templateName = service.attributes.serviceAgreementTemplate.contractName
return this.ocean.keeper
.getTemplateByName(templateName)
.createAgreementFromDDO(agreementId, ddo, consumer.getId(), publisher.getId())
return true
.createAgreementFromDDO(
agreementId,
ddo,
service.type,
consumer.getId(),
provider,
from.getId()
)
}
/**
@ -149,9 +155,17 @@ export class OceanAgreements extends Instantiable {
const { templateId } = await this.ocean.keeper.agreementStoreManager.getAgreement(
agreementId
)
if (templateId === `0x${'0'.repeat(64)}`) {
this.logger.error(
`agreement ${agreementId} is not found, templateId is ${templateId}`
)
return
}
const fullStatus = await this.ocean.keeper
.getTemplateByAddress(templateId)
.getAgreementStatus(agreementId)
.getTemplateById(templateId)
.getAgreementStatus(agreementId, this.ocean.keeper.conditionStoreManager)
if (!fullStatus) {
return

View File

@ -56,7 +56,8 @@ export class OceanAssets extends Instantiable {
/**
* Creates a new DDO.
* @param {MetaData} metadata DDO metadata.
* @param {Account} publisher Publisher account.
* @param {Account} publisher Publisher account.
* @param {list} services list of Service description documents
* @return {Promise<DDO>}
*/
public create(
@ -106,7 +107,7 @@ export class OceanAssets extends Instantiable {
{
type: 'access',
serviceEndpoint: this.ocean.brizo.getConsumeEndpoint(),
templateId: templates.escrowAccessSecretStoreTemplate.getAddress(),
templateId: templates.escrowAccessSecretStoreTemplate.getId(),
attributes: {
main: {
creator: publisher.getId(),
@ -285,12 +286,14 @@ export class OceanAssets extends Instantiable {
* @param {string} did Decentralized ID.
* @param {number} index Service index.
* @param {Account} consumerAccount Consumer account.
* @param {string} provider ethereum address of service provider (optional)
* @return {Promise<string>} Returns Agreement ID
*/
public order(
did: string,
index: number,
consumerAccount: Account
provider?: string
): SubscribablePromise<OrderProgressStep, string> {
return new SubscribablePromise(async observer => {
const oceanAgreements = this.ocean.agreements
@ -344,12 +347,23 @@ export class OceanAssets extends Instantiable {
observer.next(OrderProgressStep.CreatingAgreement)
this.logger.log('Creating agreement')
// Get provider from didRegistry if not given in arguments
let _provider = provider
if (!provider) {
const providers = await keeper.didRegistry.getDIDProviders(ddo.shortId())
if (providers) {
_provider = providers[0]
}
}
await oceanAgreements.create(
did,
agreementId,
index,
undefined,
consumerAccount,
_provider,
consumerAccount
)
this.logger.log('Agreement created')

View File

@ -16,9 +16,13 @@ export class OceanUtils extends Instantiable {
const instance = new OceanUtils()
instance.setInstanceConfig(config)
instance.agreements = new ServiceAgreement(config)
instance.signature = new SignatureUtils(config)
instance.fetch = new WebServiceConnector(config)
instance.agreements = new ServiceAgreement(
config.ocean,
config.logger,
config.web3
)
instance.signature = new SignatureUtils(config.web3, config.logger)
instance.fetch = new WebServiceConnector(config.logger)
return instance
}

View File

@ -2,13 +2,18 @@ import { ServiceAgreementTemplateCondition } from '../../ddo/ServiceAgreementTem
import { DDO } from '../../ddo/DDO'
import { ServiceAccess } from '../../ddo/Service'
import Account from '../Account'
import { zeroX } from '../../utils'
import { Instantiable, InstantiableConfig } from '../../Instantiable.abstract'
import { zeroX, Logger } from '../../utils'
import { Ocean } from '../../squid'
import Web3 from 'web3'
export class ServiceAgreement extends Instantiable {
constructor(config: InstantiableConfig) {
super()
this.setInstanceConfig(config)
export class ServiceAgreement {
private ocean: Ocean
private logger: Logger
private web3: Web3
constructor(ocean: Ocean, logger: Logger, web3: Web3) {
this.ocean = ocean
this.logger = logger
this.web3 = web3
}
public async signServiceAgreement(
@ -76,7 +81,7 @@ export class ServiceAgreement extends Instantiable {
timeouts: number[]
): string {
const args: any = [
{ type: 'address', value: zeroX(serviceAgreementTemplateId) },
{ type: 'bytes32', value: zeroX(serviceAgreementTemplateId) },
{ type: 'bytes32[]', value: valueHashes.map(zeroX) },
{ type: 'uint256[]', value: timelocks },
{ type: 'uint256[]', value: timeouts },

View File

@ -1,9 +1,13 @@
import { Instantiable, InstantiableConfig } from '../../Instantiable.abstract'
import Web3 from 'web3'
import { Logger } from '../../utils'
export class SignatureUtils extends Instantiable {
constructor(config: InstantiableConfig) {
super()
this.setInstanceConfig(config)
export class SignatureUtils {
private web3: Web3
private logger: Logger
constructor(web3: Web3, logger: Logger) {
this.web3 = web3
this.logger = logger
}
public async signText(

View File

@ -1,6 +1,6 @@
import { BodyInit, RequestInit, Response } from 'node-fetch'
import fs from 'fs'
import { Instantiable, InstantiableConfig } from '../../Instantiable.abstract'
import { Logger } from '../../utils'
const fetch = require('node-fetch')
import save = require('save-file')
@ -8,10 +8,10 @@ import save = require('save-file')
/**
* Provides a common interface to web services.
*/
export class WebServiceConnector extends Instantiable {
constructor(config: InstantiableConfig) {
super()
this.setInstanceConfig(config)
export class WebServiceConnector {
public logger: Logger
constructor(logger: Logger) {
this.logger = logger
}
public post(url: string, payload: BodyInit): Promise<Response> {

View File

@ -4,6 +4,7 @@ import DID from './ocean/DID'
import { Ocean } from './ocean/Ocean'
import { LoggerInstance as Logger } from './utils/Logger'
import Keeper from './keeper/Keeper'
import { Aquarius } from './aquarius/Aquarius'
import * as templates from './keeper/contracts/templates'
import * as conditions from './keeper/contracts/conditions'
@ -21,7 +22,17 @@ export {
OceanPlatformVersions
} from './ocean/OceanVersions'
export { AgreementTemplate } from './keeper/contracts/templates'
export { Condition, ConditionState } from './keeper/contracts/conditions'
export { Ocean, Account, Config, DID, Logger, Keeper, conditions, templates, utils }
export {
Ocean,
Account,
Config,
DID,
Logger,
Keeper,
Aquarius,
conditions,
templates,
utils
}

View File

@ -5,6 +5,7 @@ import { Aquarius, SearchQuery } from '../../src/aquarius/Aquarius'
import { DDO } from '../../src/ddo/DDO'
import DID from '../../src/ocean/DID'
import config from '../config'
import { LoggerInstance } from '../../src/utils'
use(spies)
@ -53,7 +54,7 @@ describe('Aquarius', () => {
} as SearchQuery
it('should query metadata', async () => {
spy.on(ocean.utils.fetch, 'post', () => reponsify(getResults([new DDO()])))
spy.on(aquarius.fetch, 'post', () => reponsify(getResults([new DDO()])))
const result = await aquarius.queryMetadata(query)
assert.typeOf(result.results, 'array')
@ -64,7 +65,7 @@ describe('Aquarius', () => {
})
it('should query metadata and return real ddo', async () => {
spy.on(ocean.utils.fetch, 'post', () => reponsify(getResults([new DDO()])))
spy.on(aquarius.fetch, 'post', () => reponsify(getResults([new DDO()])))
const result = await aquarius.queryMetadata(query)
assert.typeOf(result.results, 'array')
@ -87,7 +88,7 @@ describe('Aquarius', () => {
} as SearchQuery
it('should query metadata by text', async () => {
spy.on(ocean.utils.fetch, 'get', () => reponsify(getResults([new DDO()])))
spy.on(aquarius.fetch, 'get', () => reponsify(getResults([new DDO()])))
const result = await aquarius.queryMetadataByText(query)
assert.typeOf(result.results, 'array')
@ -97,8 +98,20 @@ describe('Aquarius', () => {
assert.equal(result.totalResults, 1)
})
it('should query metadata by text with a new instance', async () => {
const aquariusNew = new Aquarius(config.aquariusUri, LoggerInstance)
spy.on(aquariusNew.fetch, 'get', () => reponsify(getResults([new DDO()])))
const result = await aquariusNew.queryMetadataByText(query)
assert.typeOf(result.results, 'array')
assert.lengthOf(result.results, 1)
assert.equal(result.page, 0)
assert.equal(result.totalPages, 1)
assert.equal(result.totalResults, 1)
})
it('should query metadata and return real ddo', async () => {
spy.on(ocean.utils.fetch, 'get', () => reponsify(getResults([new DDO()])))
spy.on(aquarius.fetch, 'get', () => reponsify(getResults([new DDO()])))
const result = await aquarius.queryMetadataByText(query)
assert.typeOf(result.results, 'array')
@ -114,7 +127,7 @@ describe('Aquarius', () => {
id: did.getId()
})
spy.on(ocean.utils.fetch, 'post', () => reponsify(ddo))
spy.on(aquarius.fetch, 'post', () => reponsify(ddo))
const result: DDO = await aquarius.storeDDO(ddo)
assert(result)
@ -129,8 +142,8 @@ describe('Aquarius', () => {
id: did.getId()
})
spy.on(ocean.utils.fetch, 'post', () => reponsify(ddo))
spy.on(ocean.utils.fetch, 'get', () => reponsify(ddo))
spy.on(aquarius.fetch, 'post', () => reponsify(ddo))
spy.on(aquarius.fetch, 'get', () => reponsify(ddo))
const storageResult: DDO = await aquarius.storeDDO(ddo)
assert(storageResult)

View File

@ -1,6 +1,5 @@
import { assert, expect, spy, use } from 'chai'
import spies from 'chai-spies'
import Web3 from 'web3'
import { DDO } from '../../src/ddo/DDO'
import { Service } from '../../src/ddo/Service'
@ -164,13 +163,11 @@ describe('DDO', () => {
]
})
let web3: Web3
let ocean: Ocean
beforeEach(async () => {
await TestContractHandler.prepareContracts()
ocean = await Ocean.getInstance(config)
;({ web3 } = ocean as any)
})
afterEach(() => {

View File

@ -87,9 +87,8 @@ export default class TestContractHandler extends ContractHandler {
didRegistry.options.address
]
)
// Conditions
const lockRewardCondition = await TestContractHandler.deployContract(
const lockCondition = await TestContractHandler.deployContract(
'LockRewardCondition',
deployerAddress,
[
@ -98,7 +97,7 @@ export default class TestContractHandler extends ContractHandler {
token.options.address
]
)
const accessSecretStoreCondition = await TestContractHandler.deployContract(
const accessCondition = await TestContractHandler.deployContract(
'AccessSecretStoreCondition',
deployerAddress,
[
@ -107,9 +106,8 @@ export default class TestContractHandler extends ContractHandler {
agreementStoreManager.options.address
]
)
// Conditions rewards
const escrowReward = await TestContractHandler.deployContract(
const escrowCondition = await TestContractHandler.deployContract(
'EscrowReward',
deployerAddress,
[
@ -118,20 +116,7 @@ export default class TestContractHandler extends ContractHandler {
token.options.address
]
)
// Templates
await TestContractHandler.deployContract(
'EscrowAccessSecretStoreTemplate',
deployerAddress,
[
deployerAddress,
agreementStoreManager.options.address,
didRegistry.options.address,
accessSecretStoreCondition.options.address,
lockRewardCondition.options.address,
escrowReward.options.address
]
)
Logger.log(lockCondition, accessCondition, escrowCondition)
}
private static async deployContract(

View File

@ -1,24 +0,0 @@
import { assert } from 'chai'
import { EscrowAccessSecretStoreTemplate } from '../../../src/keeper/contracts/templates'
import config from '../../config'
import TestContractHandler from '../TestContractHandler'
import { Ocean } from '../../../src/ocean/Ocean'
let condition: EscrowAccessSecretStoreTemplate
describe('EscrowAccessSecretStoreTemplate', () => {
before(async () => {
const ocean: Ocean = await Ocean.getInstance(config)
await TestContractHandler.prepareContracts()
condition = ocean.keeper.templates.escrowAccessSecretStoreTemplate
})
// describe("#hashValues()", () => {
// it("should hash the values", async () => {
// const address = `0x${"a".repeat(40)}`
// const hash = await condition.hashValues(address, 15)
// assert.match(hash, /^0x[a-f0-9]{64}$/i)
// })
// })
})