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

Merge pull request #31 from oceanprotocol/feature/secret_store

Squid 1.0
This commit is contained in:
Sebastian Gerske 2018-11-08 08:18:08 +01:00 committed by GitHub
commit e5a285f17a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
77 changed files with 2504 additions and 1015 deletions

5
.bumpversion.cfg Normal file
View File

@ -0,0 +1,5 @@
[bumpversion]
current_version = 0.1.7
[bumpversion:file:package.json]

View File

@ -30,4 +30,13 @@ after_script:
- greenkeeper-lockfile-upload
notifications:
email: false
email: false
deploy:
- provider: npm
email: "devops@oceanprotocol.com"
api_key: ${NPM_TOKEN}
skip_cleanup: true
on:
tags: true

View File

@ -33,7 +33,7 @@
Start by adding the package to your dependencies:
```bash
npm i @oceanprotocol/squid
npm i @oceanprotocol/squid --save
```
The package exposes `Ocean` and `Logger` which you can import in your code like this:
@ -46,10 +46,13 @@ import { Ocean, Logger } from '@oceanprotocol/squid'
const { Ocean, Logger } = require('@oceanprotocol/squid')
```
You can then connect to a running [Keeper](https://github.com/oceanprotocol/keeper-contracts) & [Provider](https://github.com/oceanprotocol/provider) instance, e.g.:
You can then connect to a running [Keeper](https://github.com/oceanprotocol/keeper-contracts) & [Aquarius](https://github.com/oceanprotocol/aquarius) instance, e.g.:
```js
const ocean = await new Ocean({nodeUri: 'http://localhost:8545', network: 'development', providerUri: 'http://localhost:5000'})
const ocean = await new Ocean({
nodeUri: 'http://localhost:8545',
aquariusUri: 'http://localhost:5000'
})
```
## Development

36
bumpversion.sh Executable file
View File

@ -0,0 +1,36 @@
#!/bin/bash
set -x
set -e
usage(){
echo "Usage: $0 {major|minor|patch} [--tag]"
exit 1
}
if ! [ -x "$(command -v bumpversion)" ]; then
echo 'Error: bumpversion is not installed.' >&2
exit 1
elif ! git diff-index --quiet HEAD -- >/dev/null 2>&1; then
echo 'There are local changes in your the git repository. Please commit or stash them before bumping version.' >&2
exit 1
fi
if [ "$#" -lt 1 ]; then
echo "Illegal number of parameters"
usage
elif [[ $1 != 'major' && $1 != 'minor' && $1 != 'patch' ]]; then
echo 'First argument must be {major|minor|patch}'
usage
fi
if [[ $2 == '--tag' ]]; then
if git branch --contains $(git rev-parse --verify HEAD) | grep -E 'master'; then
bumpversion --tag --commit $1
else
echo "Only master tags can be tagged"
exit 1
fi
else
bumpversion $1
fi

700
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,17 +1,19 @@
{
"name": "@oceanprotocol/squid",
"version": "0.1.0-beta.17",
"version": "0.1.7",
"description": "JavaScript client library for Ocean Protocol",
"main": "dist/squid.js",
"scripts": {
"test": "mocha",
"test:watch": "mocha -w --watch-extensions js,ts",
"test:watch": "mocha -w --watch-extensions js,ts,json",
"test:cover": "nyc mocha",
"lint": "tslint -c tslint.json 'src/**/*.ts'",
"start": "npm link @oceanprotocol/keeper-contracts && npm run build:watch",
"build": "npm run lint && tsc && npm run doc",
"clean": "rm -rf ./dist/ ./doc/ ./coverage ./.nyc_output",
"lint": "tslint -c tslint.json 'src/**/*.ts' 'test/**/*.ts'",
"start": "npm link @oceanprotocol/keeper-contracts @oceanprotocol/secret-store-client && npm run build:watch",
"build": "npm run clean && npm run lint && tsc && npm run doc",
"build:watch": "tsc -w",
"doc": "typedoc --mode modules --out ./doc/ src/",
"doc": "typedoc --mode modules --out ./doc/ ./src/",
"run": "ts-node",
"release": "./node_modules/release-it/bin/release-it.js --src.tagName='v%s' --github.release --npm.publish --non-interactive",
"release-minor": "./node_modules/release-it/bin/release-it.js minor --src.tagName='v%s' --github.release --npm.publish --non-interactive",
"release-major": "./node_modules/release-it/bin/release-it.js major --src.tagName='v%s' --github.release --npm.publish --non-interactive",
@ -49,20 +51,23 @@
"node": ">=8 <10"
},
"dependencies": {
"@oceanprotocol/keeper-contracts": "^0.4.1",
"bignumber.js": "^7.2.1",
"eth-crypto": "^1.2.4",
"@oceanprotocol/keeper-contracts": "0.3.19",
"@oceanprotocol/secret-store-client": "0.0.7",
"bignumber.js": "^8.0.1",
"eth-crypto": "^1.2.5",
"eth-ecies": "^1.0.3",
"ethereumjs-util": "^6.0.0",
"jsonwebtoken": "^8.3.0",
"node-fetch": "^2.2.0",
"node-fetch": "^2.2.1",
"uuid": "^3.3.2",
"web3": "1.0.0-beta.36",
"web3-utils": "1.0.0-beta.36"
"web3-utils": "1.0.0-beta.36",
"whatwg-url": "^7.0.0"
},
"devDependencies": {
"@types/chai": "^4.1.6",
"@types/chai": "^4.1.7",
"@types/mocha": "^5.2.5",
"@types/node": "^8.10.36",
"@types/node": "^8.10.37",
"chai": "^4.2.0",
"mocha": "^5.2.0",
"nyc": "^13.1.0",
@ -70,6 +75,6 @@
"ts-node": "^7.0.1",
"tslint": "^5.11.0",
"typedoc": "^0.13.0",
"typescript": "^3.1.3"
"typescript": "^3.1.6"
}
}

View File

@ -1,6 +1,9 @@
import {URL} from "whatwg-url"
import DDO from "../ddo/DDO"
import Config from "../models/Config"
import Logger from "../utils/Logger"
import AquariusConnectorProvider from "./AquariusConnectorProvider"
import SearchQuery from "./query/SearchQuery"
export default class Aquarius {
@ -13,36 +16,37 @@ export default class Aquarius {
public async getAccessUrl(accessToken: any, payload: any): Promise<string> {
const accessUrl = await AquariusConnectorProvider.getConnector().post(
`${accessToken.service_endpoint}/${accessToken.resource_id}`,
payload)
.then((response: any) => {
const accessUrl: string = await AquariusConnectorProvider.getConnector()
.post(`${accessToken.service_endpoint}/${accessToken.resource_id}`, payload)
.then((response: any): string => {
if (response.ok) {
return response.text()
}
Logger.log("Failed: ", response.status, response.statusText)
Logger.error("Failed: ", response.status, response.statusText)
return null
})
.then((consumptionUrl: string) => {
Logger.log("Success accessing consume endpoint: ", consumptionUrl)
.then((consumptionUrl: string): string => {
Logger.error("Success accessing consume endpoint: ", consumptionUrl)
return consumptionUrl
})
.catch((error) => {
Logger.error("Error fetching the data asset consumption url: ", error)
return null
})
return accessUrl
}
public async queryMetadata(query): Promise<any[]> {
public async queryMetadata(query: SearchQuery): Promise<any[]> {
const result = await AquariusConnectorProvider.getConnector().post(
this.url + "/api/v1/aquarius/assets/ddo/query",
JSON.stringify(query))
const result = await AquariusConnectorProvider.getConnector()
.post(this.url + "/api/v1/aquarius/assets/ddo/query", JSON.stringify(query))
.then((response: any) => {
if (response.ok) {
return response.json()
}
Logger.log("Failed: ", response.status, response.statusText)
Logger.error("queryMetadata failed:", response.status, response.statusText)
return null
})
.catch((error) => {
Logger.error("Error fetching querying metadata: ", error)
@ -51,16 +55,21 @@ export default class Aquarius {
return result
}
public async queryMetadataByText(query): Promise<any[]> {
public async queryMetadataByText(query: SearchQuery): Promise<any[]> {
const result = await AquariusConnectorProvider.getConnector().get(
this.url + "/api/v1/aquarius/assets/ddo/query",
JSON.stringify(query))
const fullUrl = new URL(this.url + "/api/v1/aquarius/assets/ddo/query")
fullUrl.searchParams.append("text", query.text)
fullUrl.searchParams.append("sort", JSON.stringify(query.sort))
fullUrl.searchParams.append("offset", query.offset.toString())
fullUrl.searchParams.append("page", query.page.toString())
const result = await AquariusConnectorProvider.getConnector()
.get(fullUrl)
.then((response: any) => {
if (response.ok) {
return response.json()
}
Logger.log("Failed: ", response.status, response.statusText)
Logger.log("queryMetadataByText failed:", response.status, response.statusText)
return null
})
.catch((error) => {
Logger.error("Error fetching querying metadata: ", error)
@ -68,4 +77,44 @@ export default class Aquarius {
return result
}
public async storeDDO(ddo: DDO): Promise<DDO> {
const fullUrl = this.url + `/api/v1/aquarius/assets/ddo`
const result: DDO = await AquariusConnectorProvider.getConnector()
.post(fullUrl, DDO.serialize(ddo))
.then((response: any) => {
if (response.ok) {
return response.json()
}
Logger.error("storeDDO failed:", response.status, response.statusText)
return null
})
.catch((error) => {
Logger.error("Error fetching querying metadata: ", error)
})
return result
}
public async retrieveDDO(did: string): Promise<DDO> {
const fullUrl = this.url + `/api/v1/aquarius/assets/ddo/${did}`
const result = await AquariusConnectorProvider.getConnector()
.get(fullUrl)
.then((response: any) => {
if (response.ok) {
return response.json()
}
Logger.log("retrieveDDO failed:", response.status, response.statusText)
return null
})
.catch((error) => {
Logger.error("Error fetching querying metadata: ", error)
})
return result
}
public getServiceEndpoint(did) {
return `${this.url}/api/v1/provider/assets/metadata/${did}`
}
}

View File

@ -1,10 +1,9 @@
import fetch from "node-fetch"
import { URL } from "url"
export default class AquariusConnector {
public post(url, payload) {
return fetch(url, {
public async post(url, payload): Promise<any> {
return this.fetch(url, {
method: "POST",
body: payload,
headers: {
@ -13,17 +12,26 @@ export default class AquariusConnector {
})
}
public get(url, payload) {
const fullUrl = new URL(url)
for (const key of Object.keys(payload)) {
fullUrl.searchParams.append(key, payload[key])
}
return fetch(fullUrl, {
public async get(url): Promise<any> {
return this.fetch(url, {
method: "GET",
body: null,
headers: {
"Content-type": "application/json",
},
})
}
public async put(url, payload): Promise<any> {
return this.fetch(url, {
method: "PUT",
body: payload,
headers: {
"Content-type": "application/json",
},
})
}
private async fetch(url, opts): Promise<any> {
return fetch(url, opts)
}
}

View File

@ -1,21 +1,17 @@
import Logger from "../utils/Logger"
import AquariusConnector from "./AquariusConnector"
export default class AquariusConnectorProvider {
public static setConnector(connector: AquariusConnector) {
Logger.log("setting", typeof connector.constructor.name)
AquariusConnectorProvider.connector = connector
}
public static getConnector() {
public static getConnector(): AquariusConnector {
if (!AquariusConnectorProvider.connector) {
AquariusConnectorProvider.connector = new AquariusConnector()
}
Logger.log("getting", typeof AquariusConnectorProvider.connector.constructor.name)
return AquariusConnectorProvider.connector
}

View File

@ -0,0 +1,3 @@
export default class Query {
public value: number = 1
}

View File

@ -0,0 +1,14 @@
import Query from "./Query"
import Sort from "./Sort"
export default class SearchQuery {
public offset: number = 100
public page: number = 0
public query: Query = {
value: 1,
} as Query
public sort: Sort = {
value: 1,
} as Sort
public text: string = "Office"
}

View File

@ -0,0 +1,3 @@
export default class Sort {
public value: number = 1
}

View File

@ -0,0 +1,15 @@
import StructuredMarkup from "./StructuredMarkup"
export default class AdditionalInformation {
public updateFrecuency: string = "yearly"
public structuredMarkup: StructuredMarkup[] = [
{
uri: "http://skos.um.es/unescothes/C01194/jsonld",
mediaType: "application/ld+json",
} as StructuredMarkup,
{
uri: "http://skos.um.es/unescothes/C01194/turtle",
mediaType: "text/turtle",
}as StructuredMarkup,
]
}

View File

@ -0,0 +1,4 @@
export default class Authentication {
public type: string = "RsaSignatureAuthentication2018"
public publicKey: string = "did:op:123456789abcdefghi#keys-1"
}

8
src/ddo/Condition.ts Normal file
View File

@ -0,0 +1,8 @@
import Parameter from "./Parameter"
export default class Condition {
public name: string = "lockPayment"
public timeout: number = 0
public conditionKey: string
public parameters: Parameter[]
}

5
src/ddo/Curation.ts Normal file
View File

@ -0,0 +1,5 @@
export default class Curation {
public rating: number = 0.93
public numVotes: number = 123
public schema: string = "Binary Votting"
}

37
src/ddo/DDO.ts Normal file
View File

@ -0,0 +1,37 @@
import Authentication from "./Authentication"
import PublicKey from "./PublicKey"
import Service from "./Service"
export default class DDO {
public static serialize(ddo: DDO): string {
return JSON.stringify(ddo, null, 2)
}
public static deserialize(ddoString: string): DDO {
const ddo = JSON.parse(ddoString)
return ddo as DDO
}
public "@context": string = "https://w3id.org/future-method/v1"
public id: string
public publicKey: PublicKey[]
public authentication: Authentication[]
public service: Service[]
// @ts-ignore
private assa: string
public constructor(ddo?: {
id?: string,
publicKey?: PublicKey[],
authentication?: Authentication[],
service?: Service[],
}) {
this.id = ddo ? ddo.id ? ddo.id : null : null
this.publicKey = ddo ? ddo.publicKey ? ddo.publicKey : [] : []
this.authentication = ddo ? ddo.authentication ? ddo.authentication : [] : []
this.service = ddo ? ddo.service ? ddo.service : [] : []
}
}

54
src/ddo/MetaData.ts Normal file
View File

@ -0,0 +1,54 @@
import AdditionalInformation from "./AdditionalInformation"
import Curation from "./Curation"
import MetaDataBase from "./MetaDataBase"
import StructuredMarkup from "./StructuredMarkup"
export default class MetaData {
public base: MetaDataBase = {
name: "UK Weather information 2011",
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",
contentUrls: [
"https://testocnfiles.blob.core.windows.net/testfiles/testzkp.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,
} as MetaDataBase
public curation: Curation = {
rating: 0.93,
numVotes: 123,
schema: "Binary Votting",
} as Curation
public additionalInformation: AdditionalInformation = {
updateFrecuency: "yearly",
structuredMarkup: [
{
uri: "http://skos.um.es/unescothes/C01194/jsonld",
mediaType: "application/ld+json",
} as StructuredMarkup,
{
uri: "http://skos.um.es/unescothes/C01194/turtle",
mediaType: "text/turtle",
} as StructuredMarkup,
],
} as AdditionalInformation
}

31
src/ddo/MetaDataBase.ts Normal file
View File

@ -0,0 +1,31 @@
export default class MetaDataBase {
public name: string = "UK Weather information 2011"
public type: string = "dataset"
public description: string = "Weather information of UK including temperature and humidity"
public size: string = "3.1gb"
public dateCreated: string = "2012-10-10T17:00:000Z"
public author: string = "Met Office"
public license: string = "CC-BY"
public copyrightHolder: string = "Met Office"
public encoding: string = "UTF-8"
public compression: string = "zip"
public contentType: string = "text/csv"
public workExample: string = "423432fsd,51.509865,-0.118092,2011-01-01T10:55:11+00:00,7.2,68"
public contentUrls: string[] = [
"https://testocnfiles.blob.core.windows.net/testfiles/testzkp.zip",
]
public links: any[] = [
{
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/",
},
]
public inLanguage: string = "en"
public tags: string = "weather, uk, 2011, temperature, humidity"
public price: number = 10
}

5
src/ddo/Parameter.ts Normal file
View File

@ -0,0 +1,5 @@
export default class Parameter {
public name: string
public type: string
public value: any
}

7
src/ddo/PublicKey.ts Normal file
View File

@ -0,0 +1,7 @@
export default class PublicKey {
public id: string = "did:op:123456789abcdefghi#keys-1"
public type: string = "RsaVerificationKey2018"
public owner: string = "did:op:123456789abcdefghi"
public publicKeyPem?: string = "-----BEGIN PUBLIC KEY...END PUBLIC KEY-----\r\n"
public publicKeyBase58?: string = "H3C2AVvLMv6gmMNam3uVAjZpfkcJCwDwnZn6z3wXmqPV"
}

13
src/ddo/Service.ts Normal file
View File

@ -0,0 +1,13 @@
import Condition from "./Condition"
import MetaData from "./MetaData"
export default class Service {
public type: string = "OpenIdConnectVersion1.0Service"
public serviceDefinitionId?: string
public templateId?: string
public serviceEndpoint: string = "https://openid.example.com/"
public purchaseEndpoint?: string
public description?: string = "My public social inbox"
public metadata?: MetaData = {} as MetaData
public conditions?: Condition[] = []
}

View File

@ -0,0 +1,4 @@
export default class StructuredMarkup {
public uri: string = "http://skos.um.es/unescothes/C01194/jsonld"
public mediaType: string = "application/ld+json"
}

20
src/examples/Register.ts Normal file
View File

@ -0,0 +1,20 @@
import DDO from "../ddo/DDO"
import MetaData from "../ddo/MetaData"
import {Account, Logger, Ocean} from "../squid"
(async () => {
const ocean: Ocean = await Ocean.getInstance({
nodeUri: "http://localhost:8545",
aquariusUri: "http://localhost:5000",
parityUri: "http://localhost:9545",
secretStoreUri: "https://secret-store.dev-ocean.com",
threshold: 2,
password: "unittest",
address: "0xed243adfb84a6626eba46178ccb567481c6e655d",
})
const publisher: Account = (await ocean.getAccounts())[0]
const ddo: DDO = await ocean.registerAsset(new MetaData(), publisher)
Logger.log(ddo.id)
})()

View File

@ -3,63 +3,28 @@ import Logger from "../utils/Logger"
import Keeper from "./Keeper"
import Web3Provider from "./Web3Provider"
const contracts: Map<string, Contract> = new Map<string, Contract>()
export default class ContractHandler {
public static async get(what: string): Contract {
const where = (await (await Keeper.getInstance()).getNetworkName()).toLowerCase()
try {
return contracts.get(what) || await ContractHandler.load(what, where)
return ContractHandler.contracts.get(what) || await ContractHandler.load(what, where)
} catch (err) {
Logger.error("Failed to load", what, "from", where, err)
throw err
}
}
public static async deployContracts() {
Logger.log("Trying to deploy contracts")
const web3 = Web3Provider.getWeb3()
const deployerAddress = (await web3.eth.getAccounts())[0]
// deploy libs
/* not part of trilobite
const dll = await ContractHandler.deployContract("DLL", deployerAddress)
const attributeStore = await ContractHandler.deployContract("AttributeStore", deployerAddress)
*/
// deploy contracts
const token = await ContractHandler.deployContract("OceanToken", deployerAddress)
/* not part of trilobite
const plcrVoting = await ContractHandler.deployContract("PLCRVoting", deployerAddress, {
args: [token.options.address],
tokens: [
{
name: "DLL", address: dll.options.address,
}, {
name: "AttributeStore", address: attributeStore.options.address,
},
],
})
/* not part of trilobite
const registry = await ContractHandler.deployContract("OceanRegistry", deployerAddress, {
args: [token.options.address, plcrVoting.options.address],
})
*/
const market = await ContractHandler.deployContract("OceanMarket", deployerAddress, {
args: [token.options.address],
})
/* not part of trilobite
const dispute = await ContractHandler.deployContract("OceanDispute", deployerAddress, {
args: [market.options.address, registry.options.address, plcrVoting.options.address],
})
*/
await ContractHandler.deployContract("OceanAuth", deployerAddress, {
args: [market.options.address],
})
public static set(name: string, contractInstance: Contract) {
ContractHandler.contracts.set(name, contractInstance)
}
public static has(name: string): boolean {
return ContractHandler.contracts.has(name)
}
private static contracts: Map<string, Contract> = new Map<string, Contract>()
private static async load(what: string, where: string): Promise<Contract> {
const web3 = Web3Provider.getWeb3()
// Logger.log("Loading", what, "from", where)
@ -73,56 +38,7 @@ export default class ContractHandler {
// Logger.log("Getting instance of", what, "from", where, "at", artifact.address)
const contract = new web3.eth.Contract(artifact.abi, artifact.address)
Logger.log("Loaded", what, "from", where)
contracts.set(what, contract)
return contracts.get(what)
}
// todo: reactivate for tethys
private static replaceTokens(bytecode: string, tokens: any[]) {
for (const token of tokens) {
bytecode = bytecode.replace(
new RegExp(`_+${token.name}_+`, "g"),
token.address.replace("0x", ""))
}
// Logger.log(bytecode)
return bytecode.toString()
}
private static async deployContract(name: string, from: string, params?): Promise<Contract> {
// dont redeploy if there is already something loaded
if (contracts.has(name)) {
return contracts.get(name)
}
const web3 = Web3Provider.getWeb3()
let contractInstance: Contract
try {
Logger.log("Deploying", name)
const artifact = require(`@oceanprotocol/keeper-contracts/artifacts/${name}.development.json`)
const tempContract = new web3.eth.Contract(artifact.abi, artifact.address)
contractInstance = await tempContract.deploy({
data: params && params.tokens ?
ContractHandler.replaceTokens(artifact.bytecode.toString(), params.tokens) :
artifact.bytecode,
arguments: params && params.args ? params.args : null,
}).send({
from,
gas: 3000000,
gasPrice: 10000000000,
})
contracts.set(name, contractInstance)
// Logger.log("Deployed", name, "at", contractInstance.options.address);
} catch (err) {
Logger.error("Deployment failed for", name, "with params", JSON.stringify(params, null, 2), err.message)
throw err
}
return contractInstance
ContractHandler.contracts.set(what, contract)
return ContractHandler.contracts.get(what)
}
}

View File

@ -0,0 +1,18 @@
import MethodReflection from "../models/MethodReflection"
import GenericContract from "./contracts/GenericContract"
export default class ContractReflector {
public static async reflectContractMethod(pathToMethod: string): Promise<MethodReflection> {
const parts: string[] = pathToMethod.split(".")
const contract = await GenericContract.getInstance(parts[0])
return {
contractName: parts[0],
methodName: parts[1],
address: contract.getAddress(),
signature: contract.getSignatureOfMethod(parts[1]),
inputs: contract.getInputsOfMethod(parts[1]),
} as MethodReflection
}
}

View File

@ -1,6 +1,9 @@
import OceanAuth from "./Auth"
import OceanMarket from "./Market"
import OceanToken from "./Token"
import OceanAuth from "./contracts/Auth"
import AccessConditions from "./contracts/conditions/AccessConditions"
import DIDRegistry from "./contracts/DIDRegistry"
import OceanMarket from "./contracts/Market"
import ServiceAgreement from "./contracts/ServiceAgreement"
import OceanToken from "./contracts/Token"
import Web3Provider from "./Web3Provider"
export default class Keeper {
@ -13,6 +16,9 @@ export default class Keeper {
Keeper.instance.market = await OceanMarket.getInstance()
Keeper.instance.auth = await OceanAuth.getInstance()
Keeper.instance.token = await OceanToken.getInstance()
Keeper.instance.serviceAgreement = await ServiceAgreement.getInstance()
Keeper.instance.accessConditions = await AccessConditions.getInstance()
Keeper.instance.didRegistry = await DIDRegistry.getInstance()
}
return Keeper.instance
}
@ -22,6 +28,9 @@ export default class Keeper {
public token: OceanToken
public market: OceanMarket
public auth: OceanAuth
public serviceAgreement: ServiceAgreement
public accessConditions: AccessConditions
public didRegistry: DIDRegistry
public async getNetworkName(): Promise<string> {
return Web3Provider.getWeb3().eth.net.getId()

View File

@ -1,8 +1,5 @@
import * as Web3 from "web3"
import ConfigProvider from "../ConfigProvider"
import Logger from "../utils/Logger"
Logger.log("using web3", Web3.version)
export default class Web3Provider {

View File

@ -1,7 +1,5 @@
import {Receipt} from "web3-utils"
import AccessStatus from "../models/AccessStatus"
import Asset from "../ocean/Asset"
import Order from "../ocean/Order"
import AccessStatus from "../../models/AccessStatus"
import ContractBase from "./ContractBase"
export default class OceanAuth extends ContractBase {
@ -25,23 +23,12 @@ export default class OceanAuth extends ContractBase {
return this.call("getEncryptedAccessToken", [orderId], consumerAddress)
}
public async initiateAccessRequest(asset: Asset, publicKey: string,
timeout: number, buyerAddress: string): Promise<Receipt> {
const args = [asset.getId(), asset.publisher.getId(), publicKey, timeout]
return this.sendTransaction("initiateAccessRequest", buyerAddress, args)
}
public async commitAccessRequest(order: Order, publisherAddress: string) {
const args = [order.getId(), true, 9999999999, "discovery", "read", "slaLink", "slaType"]
return this.sendTransaction("commitAccessRequest", publisherAddress, args)
}
public async getTempPubKey(orderId: string) {
return this.call("getTempPubKey", [orderId])
}
public async deliverAccessToken(orderId: string, accessToken: string, publisherAddress: string) {
return this.sendTransaction("deliverAccessToken", publisherAddress, [orderId, accessToken])
return this.send("deliverAccessToken", publisherAddress, [orderId, accessToken])
}
}

View File

@ -1,7 +1,8 @@
import Event from "web3"
import Contract from "web3-eth-contract"
import Logger from "../utils/Logger"
import ContractHandler from "./ContractHandler"
import {Receipt} from "web3-utils"
import Logger from "../../utils/Logger"
import ContractHandler from "../ContractHandler"
export default abstract class ContractBase {
@ -32,7 +33,7 @@ export default abstract class ContractBase {
public async getEventData(eventName: any, options: any): Promise<Event[]> {
if (!this.contract.events[eventName]) {
throw new Error(`Event ${eventName} not found on contract ${this.contractName}`)
throw new Error(`Event "${eventName}" not found on contract "${this.contractName}"`)
}
return this.contract.getPastEvents(eventName, options)
}
@ -41,13 +42,23 @@ export default abstract class ContractBase {
return this.contract.options.address
}
public getSignatureOfMethod(methodName: string): string {
const foundMethod = this.searchMethod(methodName)
return foundMethod.signature
}
public getInputsOfMethod(methodName: string): any[] {
const foundMethod = this.searchMethod(methodName)
return foundMethod.inputs
}
protected async init() {
this.contract = await ContractHandler.get(this.contractName)
}
protected async sendTransaction(name: string, from: string, args: any[]) {
protected async send(name: string, from: string, args: any[]): Promise<Receipt> {
if (!this.contract.methods[name]) {
throw new Error(`Method ${name} is not part of contract ${this.contractName}`)
throw new Error(`Method "${name}" is not part of contract "${this.contractName}"`)
}
try {
const tx = this.contract.methods[name](...args)
@ -60,13 +71,13 @@ export default abstract class ContractBase {
})
} catch (err) {
const argString = JSON.stringify(args, null, 2)
Logger.error(`Sending transaction ${name} on contract ${this.contractName} failed.`)
Logger.error(`Sending transaction "${name}" on contract "${this.contractName}" failed.`)
Logger.error(`Args: ${argString} From: ${from}`)
throw err
}
}
protected async call(name: string, args: any[], from?: string) {
protected async call(name: string, args: any[], from?: string): Promise<any> {
if (!this.contract.methods[name]) {
throw new Error(`Method ${name} is not part of contract ${this.contractName}`)
}
@ -74,9 +85,20 @@ export default abstract class ContractBase {
const method = this.contract.methods[name](...args)
return method.call(from ? {from} : null)
} catch (err) {
Logger.error(`Calling method ${name} on contract ${this.contractName} failed. Args: ${args}`, err)
Logger.error(`Calling method "${name}" on contract "${this.contractName}" failed. Args: ${args}`, err)
throw err
}
}
private searchMethod(methodName): any {
const foundMethod = this.contract.options.jsonInterface.find((method) => {
if (method.name === methodName) {
return method
}
})
if (!foundMethod) {
throw new Error(`Method "${methodName}" is not part of contract "${this.contractName}"`)
}
return foundMethod
}
}

View File

@ -0,0 +1,38 @@
import {Receipt} from "web3-utils"
import ValueType from "../../models/ValueType"
import Web3Provider from "../Web3Provider"
import ContractBase from "./ContractBase"
export default class DIDRegistry extends ContractBase {
public static async getInstance(): Promise<DIDRegistry> {
const didRegistry: DIDRegistry = new DIDRegistry("DIDRegistry")
await didRegistry.init()
return didRegistry
}
public async registerAttribute(did: string, type: ValueType, key: string,
value: string, ownerAddress: string): Promise<Receipt> {
return this.send("registerAttribute",
ownerAddress, ["0x" + did, type, Web3Provider.getWeb3().utils.fromAscii(key), value],
)
}
public async getOwner(did: string): Promise<string> {
return this.call("getOwner",
["0x" + did],
)
}
public async getUpdateAt(did: string): Promise<number> {
const blockNum = await this.call("getUpdateAt",
["0x" + did],
)
return parseInt(blockNum, 10)
}
}

View File

@ -0,0 +1,14 @@
import ContractBase from "./ContractBase"
export default class GenericContract extends ContractBase {
public static async getInstance(contractName: string): Promise<ContractBase> {
const contract: GenericContract = new GenericContract(contractName)
await contract.init()
return contract
}
private constructor(contractName: string) {
super(contractName)
}
}

View File

@ -1,6 +1,5 @@
import BigNumber from "bignumber.js"
import {Receipt} from "web3-utils"
import Order from "../ocean/Order"
import ContractBase from "./ContractBase"
export default class OceanMarket extends ContractBase {
@ -13,7 +12,7 @@ export default class OceanMarket extends ContractBase {
// call functions (costs no gas)
public async isAssetActive(assetId: string): Promise<boolean> {
return this.call("checkAsset", [assetId])
return this.call("checkAsset", ["0x" + assetId])
}
public async verifyOrderPayment(orderId: string): Promise<boolean> {
@ -21,12 +20,12 @@ export default class OceanMarket extends ContractBase {
}
public async getAssetPrice(assetId: string): Promise<number> {
return this.call("getAssetPrice", [assetId])
return this.call("getAssetPrice", ["0x" + assetId])
.then((price: string) => new BigNumber(price).toNumber())
}
public async requestTokens(amount: number, receiverAddress: string): Promise<Receipt> {
return this.sendTransaction("requestTokens", receiverAddress, [amount])
return this.send("requestTokens", receiverAddress, [amount])
}
public async generateId(input: string): Promise<string> {
@ -34,14 +33,6 @@ export default class OceanMarket extends ContractBase {
}
public async register(assetId: string, price: number, publisherAddress: string): Promise<Receipt> {
return this.sendTransaction("register", publisherAddress, [assetId, price])
}
public async payOrder(order: Order, publisherAddress: string,
price: number, consumerAddress: string,
timeout: number): Promise<Receipt> {
return this.sendTransaction("sendPayment", consumerAddress, [
order.getId(), publisherAddress, price, timeout,
])
return this.send("register", publisherAddress, ["0x" + assetId, price])
}
}

View File

@ -0,0 +1,48 @@
import {Receipt} from "web3-utils"
import MethodReflection from "../../models/MethodReflection"
import ContractBase from "./ContractBase"
export default class ServiceAgreement extends ContractBase {
public static async getInstance(): Promise<ServiceAgreement> {
const serviceAgreement: ServiceAgreement = new ServiceAgreement("ServiceAgreement")
await serviceAgreement.init()
return serviceAgreement
}
public async setupAgreementTemplate(templateId: string, methodReflections: MethodReflection[],
dependencyMatrix: number[], name: any, ownerAddress: string)
: Promise<Receipt> {
return this.send("setupAgreementTemplate", ownerAddress, [
templateId, methodReflections.map((r) => r.address),
methodReflections.map((r) => r.signature), dependencyMatrix, name, [0], 0,
])
}
public async getTemplateStatus(templateId: string) {
return this.call("getTemplateStatus", [templateId])
}
public async getTemplateOwner(templateId: string) {
return this.call("getTemplateOwner", [templateId])
}
public async getAgreementStatus(serviceDefinitionId: string) {
return this.call("getAgreementStatus", [serviceDefinitionId])
}
public async executeAgreement(serviceAgreementTemplateId: string, serviceAgreementSignatureHash: string,
consumerAddress: string, valueHashes: string[], timeoutValues: number[],
serviceAgreementId: string, did: string, publisherAddress: string):
Promise<Receipt> {
return this.send("executeAgreement", publisherAddress, [
serviceAgreementTemplateId, serviceAgreementSignatureHash, consumerAddress, valueHashes,
timeoutValues, "0x" + serviceAgreementId, "0x" + did.replace("did:op:", ""),
])
}
}

View File

@ -11,7 +11,7 @@ export default class OceanToken extends ContractBase {
}
public async approve(marketAddress: string, price: number, buyerAddress: string): Promise<Receipt> {
return this.sendTransaction("approve", buyerAddress, [marketAddress, price])
return this.send("approve", buyerAddress, [marketAddress, price])
}
public async balanceOf(address: string): Promise<number> {

View File

@ -0,0 +1,18 @@
import {Receipt} from "web3-utils"
import ContractBase from "../ContractBase"
export default class AccessConditions extends ContractBase {
public static async getInstance(): Promise<AccessConditions> {
const accessConditions: AccessConditions = new AccessConditions("AccessConditions")
await accessConditions.init()
return accessConditions
}
public async grantAccess(serviceAgreementId: any, assetId: any, documentKeyId: any, publisherAddress: string)
: Promise<Receipt> {
return this.send("grantAccess", publisherAddress, [
serviceAgreementId, "0x" + assetId, "0x" + documentKeyId,
])
}
}

View File

@ -0,0 +1,10 @@
import ContractBase from "../ContractBase"
export default class PaymentConditions extends ContractBase {
public static async getInstance(): Promise<PaymentConditions> {
const paymentConditions: PaymentConditions = new PaymentConditions("PaymentConditions")
await paymentConditions.init()
return paymentConditions
}
}

View File

@ -1,5 +1,23 @@
export default class Config {
/* Aquarius Config */
// the url to the aquarius
public aquariusUri: string
public nodeUri: string
public web3Provider: any
/* Keeper Config */
// the uri to the node we want to connect to, not need if web3Provider is set
public nodeUri?: string
// from outside eg. metamask
public web3Provider?: any
/* Secret Store Config */
// the uri of the secret store to connect to
public secretStoreUri: string
// the uri of the parity node to connect to
public parityUri: string
// the password of the account in the local parity node to sign the serverKeyId
public password: string
// the address of the account in the local parity node to sign the serverKeyId
public address: string
// the number of nodes in the secret store that have to agree on changes
public threshold: number
}

View File

@ -0,0 +1,7 @@
export default class MethodReflection {
public contractName: string
public methodName: string
public address: string
public signature: string
public inputs: any[]
}

4
src/models/ValuePair.ts Normal file
View File

@ -0,0 +1,4 @@
export default class ValuePair {
public type: string
public value: any
}

8
src/models/ValueType.ts Normal file
View File

@ -0,0 +1,8 @@
enum ValueType {
DID, // DID string e.g. 'did:op:xxx'
DIDRef, // hash of DID same as in parameter (bytes32 _did) in text 0x0123abc.. or 0123abc..
URL, // URL string e.g. 'http(s)://xx'
DDO, // DDO string in JSON e.g. '{ "id": "did:op:xxx"...
}
export default ValueType

View File

@ -1,56 +0,0 @@
import * as EthCrypto from "eth-crypto"
import * as EthjsUtil from "ethereumjs-util"
import Keeper from "../keeper/Keeper"
import Logger from "../utils/Logger"
import Account from "./Account"
import OceanBase from "./OceanBase"
import Order from "./Order"
export default class Asset extends OceanBase {
constructor(public name: string,
public description: string,
public price: number,
public publisher: Account) {
super()
}
public async purchase(consumer: Account, timeout: number): Promise<Order> {
const {token, market, auth} = await Keeper.getInstance()
const key = EthCrypto.createIdentity()
const publicKey = EthjsUtil.privateToPublic(key.privateKey).toString("hex")
const price = await market.getAssetPrice(this.getId())
const isValid = await market.isAssetActive(this.getId())
Logger.log("The asset:", this.getId(), "is it valid?", isValid, "it's price is:", price)
if (!isValid) {
throw new Error("The Asset is not valid!")
}
try {
const marketAddr = market.getAddress()
// Allow market contract to transfer funds on the consumer"s behalf
await token.approve(marketAddr, price, consumer.getId())
Logger.log(`${price} tokens approved on market with id: ${marketAddr}`)
} catch (err) {
Logger.error("token.approve failed", err)
}
let order: Order
try {
// Submit the access request
const initiateAccessRequestReceipt = await auth.initiateAccessRequest(this,
publicKey, timeout, consumer.getId())
const {returnValues} = initiateAccessRequestReceipt.events.AccessConsentRequested
Logger.log(`Keeper AccessConsentRequested event received on asset: ${this.getId()}`)
order = new Order(this, returnValues._timeout, returnValues._pubKey, key)
order.setId(returnValues._id)
} catch (err) {
Logger.error("auth.initiateAccessRequest failed", err)
}
return order
}
}

12
src/ocean/IdGenerator.ts Normal file
View File

@ -0,0 +1,12 @@
import * as v4 from "uuid/v4"
export default class IdGenerator {
public static generateId(): string {
const id = `${v4()}${v4()}`
return id.replace(/-/g, "")
}
public static generatePrefixedId() {
return "0x" + this.generateId()
}
}

View File

@ -1,29 +1,45 @@
import Aquarius from "../aquarius/Aquarius"
import AquariusProvider from "../aquarius/AquariusProvider"
import SearchQuery from "../aquarius/query/SearchQuery"
import ConfigProvider from "../ConfigProvider"
import DDOCondition from "../ddo/Condition"
import DDO from "../ddo/DDO"
import MetaData from "../ddo/MetaData"
import Parameter from "../ddo/Parameter"
import Service from "../ddo/Service"
import Keeper from "../keeper/Keeper"
import Web3Provider from "../keeper/Web3Provider"
import Config from "../models/Config"
import ValuePair from "../models/ValuePair"
import ValueType from "../models/ValueType"
import Logger from "../utils/Logger"
import Account from "./Account"
import Asset from "./Asset"
import Order from "./Order"
import IdGenerator from "./IdGenerator"
import Condition from "./ServiceAgreements/Condition"
import ServiceAgreement from "./ServiceAgreements/ServiceAgreement"
import ServiceAgreementTemplate from "./ServiceAgreements/ServiceAgreementTemplate"
import Access from "./ServiceAgreements/Templates/Access"
export default class Ocean {
public static async getInstance(config) {
public static async getInstance(config: Config) {
if (!Ocean.instance) {
ConfigProvider.setConfig(config)
Ocean.instance = new Ocean(await Keeper.getInstance())
Ocean.instance = new Ocean()
Ocean.instance.keeper = await Keeper.getInstance()
Ocean.instance.aquarius = await AquariusProvider.getAquarius()
}
return Ocean.instance
}
private static instance = null
private keeper: Keeper
private constructor(keeper: Keeper) {
this.keeper = keeper
private keeper: Keeper
private aquarius: Aquarius
private constructor() {
}
public async getAccounts(): Promise<Account[]> {
@ -34,62 +50,102 @@ export default class Ocean {
return ethAccounts.map((address: string) => new Account(address))
}
public async register(asset: Asset): Promise<string> {
const {market} = this.keeper
public async registerAsset(metadata: MetaData, publisher: Account): Promise<DDO> {
// generate an id
const assetId = await market.generateId(asset.name + asset.description)
Logger.log(`Registering: ${assetId} with price ${asset.price} for ${asset.publisher.getId()}`)
asset.setId(assetId)
const isAssetActive = await market.isAssetActive(assetId)
// register asset in the market
if (!isAssetActive) {
const result = await market.register(asset.getId(), asset.price, asset.publisher.getId())
Logger.log("Registered:", assetId, "in block", result.blockNumber)
} else {
throw new Error("Asset already registered")
}
return assetId
}
const {didRegistry} = this.keeper
public async getOrdersByAccount(consumer: Account): Promise<Order[]> {
const {auth} = this.keeper
const id: string = IdGenerator.generateId()
const did: string = `did:op:${id}`
const serviceDefinitionId: string = IdGenerator.generatePrefixedId()
Logger.log("Getting orders")
metadata.base.contentUrls = metadata.base.contentUrls.map((contentUrl) => {
const accessConsentRequestedData = await auth.getEventData(
"AccessConsentRequested", {
filter: {
_consumer: consumer.getId(),
},
fromBlock: 0,
toBlock: "latest",
})
// todo encrypt url in secret store
Logger.log(contentUrl)
return "0x00000"
})
const orders = await Promise.all(
accessConsentRequestedData
.map(async (event: any) => {
const template = new Access()
const serviceAgreementTemplate = new ServiceAgreementTemplate(template)
const {returnValues} = event
// get condition keys from template
const conditions: Condition[] = await serviceAgreementTemplate.getConditions()
const order: Order = new Order(
null,
parseInt(returnValues._timeout, 10),
null, null)
order.setId(returnValues._id)
return order
// create ddo conditions out of the keys
const ddoConditions: DDOCondition[] = conditions.map((condition: Condition): DDOCondition => {
return {
name: condition.methodReflection.methodName,
timeout: condition.timeout,
conditionKey: condition.condtionKey,
parameters: condition.methodReflection.inputs.map((input: ValuePair) => {
return {
...input,
value: "xxx",
} as Parameter
}),
)
// Logger.log("Got orders:", JSON.stringify(orders, null, 2))
Logger.log(`Got ${Object.keys(orders).length} orders`)
} as DDOCondition
})
const serviceEndpoint = this.aquarius.getServiceEndpoint(did)
return orders
// create ddo itself
const ddo: DDO = new DDO({
id: did,
service: [
{
type: template.templateName,
// tslint:disable-next-line
serviceEndpoint: "http://mybrizo.org/api/v1/brizo/services/consume?pubKey=${pubKey}&serviceId={serviceId}&url={url}",
purchaseEndpoint: "http://mybrizo.org/api/v1/brizo/services/access/purchase?",
// the id of the service agreement?
serviceDefinitionId,
// the id of the service agreement template
templateId: serviceAgreementTemplate.getId(),
conditions: ddoConditions,
} as Service,
{
serviceEndpoint,
metadata,
} as Service,
],
})
const storedDdo = await this.aquarius.storeDDO(ddo)
await didRegistry.registerAttribute(id, ValueType.DID, "Metadata", serviceEndpoint,
publisher.getId())
return storedDdo
}
public async searchAssets(query): Promise<any[]> {
return AquariusProvider.getAquarius().queryMetadata(query)
public async purchase(did: string, consumer: Account): Promise<ServiceAgreement> {
const ddo = await AquariusProvider.getAquarius().retrieveDDO(did)
const id = did.replace("did:op:", "")
const serviceAgreementId: string = IdGenerator.generateId()
const serviceAgreement: ServiceAgreement = await ServiceAgreement.signServiceAgreement(id,
// todo get publisher from ddo
ddo, serviceAgreementId, consumer, new Account())
return serviceAgreement
}
public async searchAssets(query: SearchQuery): Promise<any[]> {
return this.aquarius.queryMetadata(query)
}
public async searchAssetsByText(text: string): Promise<any[]> {
return this.aquarius.queryMetadataByText({
text,
page: 1,
offset: 100,
query: {
value: 1,
},
sort: {
value: 1,
},
} as SearchQuery)
}
}

View File

@ -1,97 +0,0 @@
import * as EthEcies from "eth-ecies"
import * as JWT from "jsonwebtoken"
import AquariusProvider from "../aquarius/AquariusProvider"
import Keeper from "../keeper/Keeper"
import Web3Provider from "../keeper/Web3Provider"
import AccessStatus from "../models/AccessStatus"
import Logger from "../utils/Logger"
import Account from "./Account"
import Asset from "./Asset"
import OceanBase from "./OceanBase"
export default class Order extends OceanBase {
constructor(private asset: Asset, private timeout: number,
private pubkey: string, private key: any) {
super()
}
public async getStatus(): Promise<AccessStatus> {
const {auth} = await Keeper.getInstance()
return auth.getOrderStatus(this.id)
}
public async pay(consumer: Account): Promise<string> {
const {market} = await Keeper.getInstance()
Logger.log(
`Sending payment: ${this.getId()} ${this.asset.publisher.getId()} ${this.asset.price} ${this.timeout}`,
)
const payReceipt =
await market.payOrder(this, this.asset.publisher.getId(), this.asset.price, consumer.getId(), this.timeout)
return payReceipt.events.PaymentReceived.returnValues._paymentId
}
public async commit(accessToken: string): Promise<boolean> {
const {auth} = await Keeper.getInstance()
const commitAccessRequestReceipt = await auth.commitAccessRequest(this, this.asset.publisher.getId())
if (commitAccessRequestReceipt.events.AccessRequestRejected) {
const {returnValues} = commitAccessRequestReceipt.events.AccessRequestRejected
throw new Error(`commitAccessRequest failed ${JSON.stringify(returnValues, null, 2)}`)
}
const pubKey = await auth.getTempPubKey(this.getId())
if (this.pubkey !== pubKey) {
throw new Error("Pubkey missmatch")
}
const encryptedAccessToken =
EthEcies.encrypt(new Buffer(pubKey, "hex"), new Buffer(accessToken)).toString("hex")
await auth.deliverAccessToken(this.getId(), `0x${encryptedAccessToken}`, this.asset.publisher.getId())
return true
}
public async consume(consumer: Account): Promise<string> {
const {auth} = await Keeper.getInstance()
const encryptedAccessToken = await auth.getEncryptedAccessToken(this.getId(), consumer.getId())
// grab the access token from acl contract
const tokenNo0x = encryptedAccessToken.slice(2)
const encryptedTokenBuffer = Buffer.from(tokenNo0x, "hex")
const privateKey = this.key.privateKey.slice(2)
const accessTokenEncoded: string =
EthEcies.decrypt(Buffer.from(privateKey, "hex"), encryptedTokenBuffer).toString()
const accessToken = JWT.decode(accessTokenEncoded) // Returns a json object
if (!accessToken) {
throw new Error(`AccessToken is not an jwt: ${accessTokenEncoded}`)
}
const signature = Web3Provider.getWeb3().eth.sign(encryptedAccessToken, consumer.getId())
const encryptedAccessTokenSha3 = Web3Provider.getWeb3().utils.sha3(encryptedAccessToken)
// Download the data set from the provider using the url in the access token
// decode the access token, grab the service_endpoint, request_id,
// payload keys: ['consumerId', 'fixed_msg', 'sigEncJWT', 'jwt']
const payload = JSON.stringify({
consumerId: consumer.getId(),
fixed_msg: encryptedAccessTokenSha3,
sigEncJWT: signature,
jwt: accessTokenEncoded,
})
const accessUrl = await AquariusProvider.getAquarius().getAccessUrl(accessToken, payload)
Logger.log("consume url: ", accessUrl)
return accessUrl
}
}

View File

@ -0,0 +1,7 @@
import MethodReflection from "../../models/MethodReflection"
export default class Condition {
public methodReflection: MethodReflection
public condtionKey: string
public timeout: number
}

View File

@ -0,0 +1,5 @@
export default class Method {
public path: string
public dependency: number
public timeout: number
}

View File

@ -0,0 +1,132 @@
import Condition from "../../ddo/Condition"
import DDO from "../../ddo/DDO"
import Keeper from "../../keeper/Keeper"
import Web3Provider from "../../keeper/Web3Provider"
import ValuePair from "../../models/ValuePair"
import Account from "../Account"
import OceanBase from "../OceanBase"
export default class ServiceAgreement extends OceanBase {
public static async signServiceAgreement(assetId: string, ddo: DDO, serviceAgreementId: string, consumer: Account,
publisher: Account):
Promise<ServiceAgreement> {
const values: ValuePair[] = ServiceAgreement.getValuesFromDDO(ddo, serviceAgreementId)
const valueHashes = ServiceAgreement.createValueHashes(values)
const timeoutValues: number[] = ServiceAgreement.getTimeoutValuesFromDDO(ddo)
const serviceAgreementHashSignature = await ServiceAgreement.createSAHashSignature(ddo, serviceAgreementId,
values, valueHashes, timeoutValues, consumer)
const serviceAgreement: ServiceAgreement = await ServiceAgreement.executeAgreement(ddo,
serviceAgreementId, values, valueHashes, timeoutValues, serviceAgreementHashSignature, consumer, publisher)
return serviceAgreement
}
public static async createSAHashSignature(ddo: DDO, serviceAgreementId: string, values: ValuePair[],
valueHashes: string[], timeoutValues: number[], consumer: Account):
Promise<string> {
const conditionKeys: string[] = ddo.service[0].conditions.map((condition) => {
return condition.conditionKey
})
const serviceAgreementHash = ServiceAgreement.hashServiceAgreement(ddo.service[0].templateId,
serviceAgreementId, conditionKeys, valueHashes, timeoutValues)
const serviceAgreementHashSignature =
await Web3Provider.getWeb3().eth.sign(serviceAgreementHash, consumer.getId())
return serviceAgreementHashSignature
}
private static async executeAgreement(ddo: DDO, serviceAgreementId: string, values: ValuePair[],
valueHashes: string[], timeoutValues: number[],
serviceAgreementHashSignature: string, consumer: Account,
publisher: Account): Promise<ServiceAgreement> {
const {serviceAgreement} = await Keeper.getInstance()
const executeAgreementReceipt = await serviceAgreement.executeAgreement(
ddo.service[0].templateId, serviceAgreementHashSignature, consumer.getId(), valueHashes,
timeoutValues, serviceAgreementId, ddo.id, publisher.getId())
if (executeAgreementReceipt.events.ExecuteAgreement.returnValues.state === false) {
throw new Error("signing service agreement failed.")
}
return new ServiceAgreement(
executeAgreementReceipt.events.ExecuteAgreement.returnValues.serviceAgreementId,
ddo,
publisher,
consumer,
executeAgreementReceipt.events.ExecuteAgreement.returnValues.state,
executeAgreementReceipt.events.ExecuteAgreement.returnValues.status,
)
}
private static createValueHashes(valuePairs: ValuePair[]): any[] {
return valuePairs.map((valuePair) => {
return ServiceAgreement.hashSingleValue(valuePair)
})
}
private static hashSingleValue(data: ValuePair): string {
return Web3Provider.getWeb3().utils.soliditySha3(data).toString("hex")
}
private static hashServiceAgreement(serviceAgreementTemplateId: string, serviceAgreementId: string,
conditionKeys: string[], valueHashes: string[], timeouts: number[])
: string {
const args = [
{type: "bytes32", value: serviceAgreementTemplateId} as ValuePair,
{type: "bytes32[]", value: conditionKeys} as ValuePair,
{type: "bytes32[]", value: valueHashes} as ValuePair,
{type: "uint256[]", value: timeouts} as ValuePair,
{type: "bytes32", value: serviceAgreementId} as ValuePair,
]
return Web3Provider.getWeb3().utils.soliditySha3(...args).toString("hex")
}
private static getTimeoutValuesFromDDO(ddo: DDO): number[] {
const timeoutValues: number[] = ddo.service[0].conditions.map((condition: Condition) => {
return condition.timeout
})
return timeoutValues
}
private static getValuesFromDDO(ddo: DDO, serviceAgreementId: string): ValuePair[] {
const values: ValuePair[] = [
{type: "bool", value: true} as ValuePair,
{type: "bool", value: false} as ValuePair,
{type: "bool", value: false} as ValuePair,
{type: "uint", value: 120} as ValuePair,
{type: "string", value: serviceAgreementId} as ValuePair,
]
return values
}
private constructor(serviceAgreementId: string, ddo: DDO, private publisher: Account, consumer: Account,
state: boolean, status: boolean) {
super(serviceAgreementId)
}
public async grantAccess(assetId: string, documentId: string): Promise<boolean> {
const {accessConditions} = await Keeper.getInstance()
const grantAccessReceipt =
await accessConditions.grantAccess(this.getId(), assetId, documentId,
this.publisher.getId())
return grantAccessReceipt.status
}
public async getStatus() {
const {serviceAgreement} = await Keeper.getInstance()
return serviceAgreement.getAgreementStatus(this.getId())
}
}

View File

@ -0,0 +1,105 @@
import ContractReflector from "../../keeper/ContractReflector"
import Keeper from "../../keeper/Keeper"
import Web3Provider from "../../keeper/Web3Provider"
import MethodReflection from "../../models/MethodReflection"
import ValuePair from "../../models/ValuePair"
import Logger from "../../utils/Logger"
import Account from "../Account"
import OceanBase from "../OceanBase"
import Condition from "./Condition"
import Method from "./Method"
import TemplateBase from "./Templates/TemplateBase"
export default class ServiceAgreementTemplate extends OceanBase {
private static generateConditionsKey(serviceAgreementTemplateId: string, methodReflection: MethodReflection)
: string {
const values = [
{type: "bytes32", value: serviceAgreementTemplateId} as ValuePair,
{type: "address", value: methodReflection.address} as ValuePair,
{type: "bytes4", value: methodReflection.signature} as ValuePair,
]
return Web3Provider.getWeb3().utils.soliditySha3(...values).toString("hex")
}
public constructor(private template: TemplateBase) {
super(template.id)
}
public async register(templateOwnerAddress: string)
: Promise<boolean> {
const dependencyMatrix: number[] =
await Promise.all(this.template.Methods.map(async (method: Method) => {
// tslint:disable-next-line
return method.dependency | method.timeout
}))
const {serviceAgreement} = await Keeper.getInstance()
const methodReflections = await this.getMethodReflections()
const owner = await this.getOwner()
if (!owner.getId().startsWith("0x0")) {
Logger.error(`Template with id "${this.template.id}" already registered.`)
return false
}
const receipt = await serviceAgreement.setupAgreementTemplate(
this.template.id, methodReflections, dependencyMatrix,
Web3Provider.getWeb3().utils.fromAscii(this.template.templateName),
templateOwnerAddress)
const templateId = receipt.events.SetupAgreementTemplate.returnValues.serviceTemplateId
if (templateId !== this.template.id) {
// tslint:disable-next-line
throw new Error(`TemplateId missmatch on ${this.template.templateName}! Should be "${this.template.id}" but is ${templateId}`)
}
if (receipt.status) {
Logger.error("Registering template failed")
}
return receipt.status
}
/**
* gets the status of a service agreement template
*/
public async getStatus(): Promise<boolean> {
const {serviceAgreement} = await Keeper.getInstance()
return serviceAgreement.getTemplateStatus(this.getId())
}
public async getOwner(): Promise<Account> {
const {serviceAgreement} = await Keeper.getInstance()
return new Account(await serviceAgreement.getTemplateOwner(this.id))
}
public async getConditions(): Promise<Condition[]> {
const methodReflections = await this.getMethodReflections()
const conditions: Condition[] = methodReflections.map((methodReflection, i) => {
return {
methodReflection,
timeout: this.template.Methods[i].timeout,
condtionKey: ServiceAgreementTemplate.generateConditionsKey(this.getId(),
methodReflection),
} as Condition
})
return conditions
}
private async getMethodReflections(): Promise<MethodReflection[]> {
const methodReflections: MethodReflection[] =
await Promise.all(this.template.Methods.map(async (method: Method) => {
const methodReflection = await ContractReflector.reflectContractMethod(method.path)
return methodReflection
}))
return methodReflections
}
}

View File

@ -0,0 +1,30 @@
import Method from "../Method"
import TemplateBase from "./TemplateBase"
export default class Access extends TemplateBase {
public templateName: string = "Access"
public id: string = "0x044852b2a670ade5407e78fb2863c51de9fcb96542a07186fe3aeda6bb8a116d"
public Methods: Method[] = [
{
path: "PaymentConditions.lockPayment",
dependency: 0,
timeout: 10,
} as Method,
{
path: "AccessConditions.grantAccess",
dependency: 1,
timeout: 500,
} as Method,
{
path: "PaymentConditions.releasePayment",
dependency: 4,
timeout: 17,
} as Method,
{
path: "PaymentConditions.refundPayment",
dependency: 1,
timeout: 40,
} as Method,
]
}

View File

@ -0,0 +1,30 @@
import Method from "../Method"
import TemplateBase from "./TemplateBase"
export default class FitchainCompute extends TemplateBase {
public templateName: string = "FitchainCompute"
public id: string = "0xc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc6"
public Methods: Method[] = [
{
path: "PaymentConditions.lockPayment",
dependency: 0,
timeout: 10,
} as Method,
{
path: "AccessConditions.grantAccess",
dependency: 1,
timeout: 500,
} as Method,
{
path: "PaymentConditions.releasePayment",
dependency: 4,
timeout: 17,
} as Method,
{
path: "PaymentConditions.refundPayment",
dependency: 1,
timeout: 40,
} as Method,
]
}

View File

@ -0,0 +1,7 @@
import Method from "../Method"
export default abstract class TemplateBase {
public Methods: Method[]
public templateName: string
public id: string = "0x00000000000000000000000000000000000000000000000000000000000000"
}

View File

@ -0,0 +1,21 @@
import SecretStore from "@oceanprotocol/secret-store-client"
import ConfigProvider from "../ConfigProvider"
export default class SecretStoreProvider {
public static setSecretStore(secretStore: SecretStore) {
SecretStoreProvider.secretStore = secretStore
}
public static getSecretStore(): SecretStore {
if (!SecretStoreProvider.secretStore) {
SecretStoreProvider.secretStore = new SecretStore(ConfigProvider.getConfig())
}
return SecretStoreProvider.secretStore
}
private static secretStore: SecretStore
}

View File

@ -1,11 +1,11 @@
import Asset from "./ocean/Asset"
import Account from "./ocean/Account"
import Ocean from "./ocean/Ocean"
import Order from "./ocean/Order"
import ServiceAgreement from "./ocean/ServiceAgreements/ServiceAgreement"
import Logger from "./utils/Logger"
export {
Ocean,
Order,
Asset,
ServiceAgreement,
Logger,
Account,
}

View File

@ -13,12 +13,8 @@ describe("Squid", () => {
assert(squid.Logger)
})
it("should expose Asset", async () => {
assert(squid.Asset)
})
it("should expose Order", async () => {
assert(squid.Order)
it("should expose ServiceAgreement", async () => {
assert(squid.ServiceAgreement)
})
})

View File

@ -1,21 +1,20 @@
import * as assert from "assert"
import Aquarius from "../../src/aquarius/Aquarius"
import AquariusConnectorProvider from "../../src/aquarius/AquariusConnectorProvider"
import SearchQuery from "../../src/aquarius/query/SearchQuery"
import DDO from "../../src/ddo/DDO"
import IdGenerator from "../../src/ocean/IdGenerator"
import config from "../config"
import AquariusConnectorMock from "../mocks/AquariusConnector.mock"
before(() => {
AquariusConnectorProvider.setConnector(new AquariusConnectorMock())
})
// import * as jsonDDO from "../testdata/ddo.json"
describe("Aquarius", () => {
const aquarius: Aquarius = new Aquarius(config)
describe("#queryMetadata()", () => {
it("should query metadata", async () => {
const aquarius: Aquarius = new Aquarius(config)
const query = {
offset: 100,
page: 0,
@ -26,11 +25,84 @@ describe("Aquarius", () => {
value: 1,
},
text: "Office",
}
} as SearchQuery
// @ts-ignore
AquariusConnectorProvider.setConnector(new AquariusConnectorMock())
const result: any[] = await aquarius.queryMetadata(query)
assert(result)
assert(result.length !== null)
})
})
describe("#queryMetadataByText()", () => {
it("should query metadata by text", async () => {
const query = {
offset: 100,
page: 0,
query: {
value: 1,
},
sort: {
value: 1,
},
text: "Office",
} as SearchQuery
// @ts-ignore
AquariusConnectorProvider.setConnector(new AquariusConnectorMock())
const result: any[] = await aquarius.queryMetadataByText(query)
assert(result)
assert(result.length !== null)
})
})
describe("#storeDDO()", () => {
it("should store a ddo", async () => {
const did: string = `did:op:${IdGenerator.generateId()}`
const ddo: DDO = new DDO({
id: did,
})
// @ts-ignore
AquariusConnectorProvider.setConnector(new AquariusConnectorMock(ddo))
const result: DDO = await aquarius.storeDDO(ddo)
assert(result)
assert(result.id === ddo.id)
})
})
describe("#retrieveDDO()", () => {
it("should store a ddo", async () => {
const did: string = `did:op:${IdGenerator.generateId()}`
const ddo: DDO = new DDO({
id: did,
})
// @ts-ignore
AquariusConnectorProvider.setConnector(new AquariusConnectorMock(ddo))
const storageResult: DDO = await aquarius.storeDDO(ddo)
assert(storageResult)
assert(storageResult.id === did)
const restrieveResult: DDO = await aquarius.retrieveDDO(did)
assert(restrieveResult)
assert(restrieveResult.id === did)
assert(restrieveResult.id === storageResult.id)
})
})
})

View File

@ -3,5 +3,10 @@ import Config from "../src/models/Config"
export default {
aquariusUri: "http://localhost:5000",
nodeUri: "http://localhost:8545",
parityUri: "http://localhost:9545",
secretStoreUri: "https://secret-store.dev-ocean.com",
threshold: 2,
password: "unittest",
address: "0xed243adfb84a6626eba46178ccb567481c6e655d",
web3Provider: null,
} as Config

216
test/ddo/DDO.test.ts Normal file
View File

@ -0,0 +1,216 @@
import {assert} from "chai"
import AdditionalInformation from "../../src/ddo/AdditionalInformation"
import Authentication from "../../src/ddo/Authentication"
import Curation from "../../src/ddo/Curation"
import DDO from "../../src/ddo/DDO"
import MetaData from "../../src/ddo/MetaData"
import MetaDataBase from "../../src/ddo/MetaDataBase"
import PublicKey from "../../src/ddo/PublicKey"
import Service from "../../src/ddo/Service"
import StructuredMarkup from "../../src/ddo/StructuredMarkup"
import * as jsonDDO from "../testdata/ddo.json"
describe("DDO", () => {
const testDDO: DDO = new DDO({
publicKey: [
{
id: "did:op:123456789abcdefghi#keys-1",
type: "RsaVerificationKey2018",
owner: "did:op:123456789abcdefghi",
publicKeyPem: "-----BEGIN PUBLIC KEY...END PUBLIC KEY-----\r\n",
} as PublicKey,
{
id: "did:op:123456789abcdefghi#keys-2",
type: "Ed25519VerificationKey2018",
owner: "did:op:123456789abcdefghi",
publicKeyBase58: "H3C2AVvLMv6gmMNam3uVAjZpfkcJCwDwnZn6z3wXmqPV",
} as PublicKey,
{
id: "did:op:123456789abcdefghi#keys-3",
type: "RsaPublicKeyExchangeKey2018",
owner: "did:op:123456789abcdefghi",
publicKeyPem: "-----BEGIN PUBLIC KEY...END PUBLIC KEY-----\r\n",
} as PublicKey,
],
authentication: [
{
type: "RsaSignatureAuthentication2018",
publicKey: "did:op:123456789abcdefghi#keys-1",
} as Authentication,
{
type: "ieee2410Authentication2018",
publicKey: "did:op:123456789abcdefghi#keys-2",
} as Authentication,
],
service: [
{
type: "OpenIdConnectVersion1.0Service",
serviceEndpoint: "https://openid.example.com/",
} as Service,
{
type: "CredentialRepositoryService",
serviceEndpoint: "https://repository.example.com/service/8377464",
} as Service,
{
type: "XdiService",
serviceEndpoint: "https://xdi.example.com/8377464",
} as Service,
{
type: "HubService",
serviceEndpoint: "https://hub.example.com/.identity/did:op:0123456789abcdef/",
} as Service,
{
type: "MessagingService",
serviceEndpoint: "https://example.com/messages/8377464",
} as Service,
{
type: "SocialWebInboxService",
serviceEndpoint: "https://social.example.com/83hfh37dj",
description: "My public social inbox",
spamCost: {
amount: "0.50",
currency: "USD",
},
} as Service,
{
id: "did:op:123456789abcdefghi;bops",
type: "BopsService",
serviceEndpoint: "https://bops.example.com/enterprise/",
} as Service,
{
type: "Consume",
// tslint:disable-next-line
serviceEndpoint: "http://mybrizo.org/api/v1/brizo/services/consume?pubKey=${pubKey}&serviceId={serviceId}&url={url}",
} as Service,
{
type: "Compute",
// tslint:disable-next-line
serviceEndpoint: "http://mybrizo.org/api/v1/brizo/services/compute?pubKey=${pubKey}&serviceId={serviceId}&algo={algo}&container={container}",
} as Service,
{
type: "Metadata",
serviceEndpoint: "http://myaquarius.org/api/v1/provider/assets/metadata/{did}",
metadata: {
base: {
name: "UK Weather information 2011",
type: "dataset",
description: "Weather information of UK including temperature and humidity",
size: "3.1gb",
dateCreated: "2012-10-10T17:00:000Z",
author: "Met Office",
license: "CC-BY",
copyrightHolder: "Met Office",
encoding: "UTF-8",
compression: "zip",
contentType: "text/csv",
workExample: "423432fsd,51.509865,-0.118092,2011-01-01T10:55:11+00:00,7.2,68",
contentUrls: [
"https://testocnfiles.blob.core.windows.net/testfiles/testzkp.zip",
],
links: [
{
// tslint:disable-next-line
sample1: "http://data.ceda.ac.uk/badc/ukcp09/data/gridded-land-obs/gridded-land-obs-daily/"
},
{
// tslint:disable-next-line
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,
} as MetaDataBase,
curation: {
rating: 0.93,
numVotes: 123,
schema: "Binary Votting",
} as Curation,
additionalInformation: {
updateFrecuency: "yearly",
structuredMarkup: [
{
uri: "http://skos.um.es/unescothes/C01194/jsonld",
mediaType: "application/ld+json",
} as StructuredMarkup,
{
uri: "http://skos.um.es/unescothes/C01194/turtle",
mediaType: "text/turtle",
} as StructuredMarkup,
],
} as AdditionalInformation,
} as MetaData,
},
],
})
describe("#serialize()", () => {
it("should properly serialize", async () => {
const ddoString = DDO.serialize(testDDO)
assert(ddoString)
assert(ddoString.startsWith("{"))
})
})
describe("#constructor()", () => {
it("should create an empty ddo", async () => {
const ddo = new DDO()
assert(ddo)
assert(ddo.service.length === 0)
assert(ddo.authentication.length === 0)
assert(ddo.publicKey.length === 0)
})
it("should create an predefined ddo", async () => {
const service: Service = {
serviceEndpoint: "http://",
description: "nice service",
} as Service
const ddo = new DDO({
service: [service],
})
assert(ddo)
assert(ddo.service.length === 1)
assert(ddo.service[0].description === service.description)
assert(ddo.authentication.length === 0)
assert(ddo.publicKey.length === 0)
})
})
describe("#deserialize()", () => {
it("should properly deserialize from serialized object", async () => {
const ddoString = DDO.serialize(testDDO)
assert(ddoString)
const ddo: DDO = DDO.deserialize(ddoString)
assert(ddo)
assert(ddo.id === testDDO.id)
assert(ddo.publicKey[0].publicKeyPem === testDDO.publicKey[0].publicKeyPem)
})
it("should properly deserialize from json file", async () => {
const ddo: DDO = DDO.deserialize(JSON.stringify(jsonDDO))
assert(ddo)
assert(ddo.id === jsonDDO.id)
assert(ddo.publicKey[0].publicKeyPem === jsonDDO.publicKey[0].publicKeyPem)
})
})
})

View File

@ -1,16 +1,22 @@
import {assert} from "chai"
import ConfigProvider from "../../src/ConfigProvider"
import ContractHandler from "../../src/keeper/ContractHandler"
import Account from "../../src/ocean/Account"
import Ocean from "../../src/ocean/Ocean"
import config from "../config"
import ContractBaseMock from "../mocks/ContractBase.Mock"
import TestContractHandler from "./TestContractHandler"
const wrappedContract = new ContractBaseMock("OceanToken")
let accounts: Account[]
describe("ContractWrapperBase", () => {
before(async () => {
ConfigProvider.setConfig(config)
await ContractHandler.deployContracts()
wrappedContract.initMock()
await TestContractHandler.prepareContracts()
await wrappedContract.initMock()
const ocean: Ocean = await Ocean.getInstance(config)
accounts = await ocean.getAccounts()
})
describe("#call()", () => {
@ -52,6 +58,29 @@ describe("ContractWrapperBase", () => {
})
})
describe("#send()", () => {
it("should fail to call on an unknown contract function", (done) => {
wrappedContract.sendMock("transferxxx", accounts[0].getId(), [])
.catch(() => {
done()
})
})
})
describe("#getSignatureOfMethod()", () => {
it("should a signature of the function", async () => {
const sig = wrappedContract.getSignatureOfMethod("name")
assert(sig)
assert(typeof sig === "string")
assert(sig.startsWith("0x"))
})
})
describe("#getEventData()", () => {
it("should fail on unknown event", (done) => {

View File

@ -7,7 +7,6 @@ describe("ContractHandler", () => {
before(async () => {
ConfigProvider.setConfig(config)
await ContractHandler.deployContracts()
})
describe("#get()", () => {

View File

@ -0,0 +1,101 @@
import {assert} from "chai"
import ConfigProvider from "../../src/ConfigProvider"
import DIDRegistry from "../../src/keeper/contracts/DIDRegistry"
import Web3Provider from "../../src/keeper/Web3Provider"
import ValueType from "../../src/models/ValueType"
import Account from "../../src/ocean/Account"
import IdGenerator from "../../src/ocean/IdGenerator"
import Ocean from "../../src/ocean/Ocean"
import Logger from "../../src/utils/Logger"
import config from "../config"
import TestContractHandler from "./TestContractHandler"
let ocean: Ocean
let didRegistry: DIDRegistry
describe("DIDRegistry", () => {
before(async () => {
ConfigProvider.setConfig(config)
await TestContractHandler.prepareContracts()
ocean = await Ocean.getInstance(config)
didRegistry = await DIDRegistry.getInstance()
})
describe("#registerAttribute()", () => {
it("should register an attribute in a new did", async () => {
const ownerAccount: Account = (await ocean.getAccounts())[0]
const did = IdGenerator.generateId()
const providerKey = Web3Provider.getWeb3().utils.fromAscii("provider")
const data = "my nice provider, is nice"
const receipt = await didRegistry.registerAttribute(did, ValueType.DID, providerKey,
data, ownerAccount.getId())
assert(receipt.status)
assert(receipt.events.DIDAttributeRegistered)
})
it("should register another attribute in the same did", async () => {
const ownerAccount: Account = (await ocean.getAccounts())[0]
const did = IdGenerator.generateId()
{
// register the first attribute
const providerKey = Web3Provider.getWeb3().utils.fromAscii("provider")
const data = "my nice provider, is nice"
await didRegistry.registerAttribute(did, ValueType.DID, providerKey,
data, ownerAccount.getId())
}
{
// register the second attribute with the same did
const providerKey = Web3Provider.getWeb3().utils.fromAscii("provider2")
const data = "asdsad"
const receipt = await didRegistry.registerAttribute(did, ValueType.DID, providerKey,
data, ownerAccount.getId())
assert(receipt.status)
assert(receipt.events.DIDAttributeRegistered)
}
})
})
describe("#getOwner()", () => {
it("should get the owner of a did properly", async () => {
const ownerAccount: Account = (await ocean.getAccounts())[0]
const did = IdGenerator.generateId()
const providerKey = Web3Provider.getWeb3().utils.fromAscii("provider")
const data = "my nice provider, is nice"
await didRegistry.registerAttribute(did, ValueType.DID, providerKey,
data, ownerAccount.getId())
const owner = await didRegistry.getOwner(did)
assert(owner === ownerAccount.getId(), `Got ${owner} but expected ${ownerAccount.getId()}`)
})
it("should get 0x00.. for a not registered did", async () => {
const owner = await didRegistry.getOwner("1234")
assert(owner === "0x0000000000000000000000000000000000000000")
})
})
describe("#getUpdateAt()", () => {
it("should the block number of the last update of the did attribute", async () => {
const ownerAccount: Account = (await ocean.getAccounts())[0]
const did = IdGenerator.generateId()
const providerKey = Web3Provider.getWeb3().utils.fromAscii("provider")
const data = "my nice provider, is nice"
await didRegistry.registerAttribute(did, ValueType.DID, providerKey,
data, ownerAccount.getId())
const updatedAt: number = await didRegistry.getUpdateAt(did)
assert(updatedAt > 0)
Logger.log(typeof updatedAt)
})
})
})

View File

@ -1,8 +1,8 @@
import {assert} from "chai"
import ConfigProvider from "../../src/ConfigProvider"
import ContractHandler from "../../src/keeper/ContractHandler"
import Keeper from "../../src/keeper/Keeper"
import config from "../config"
import TestContractHandler from "./TestContractHandler"
let keeper: Keeper
@ -10,10 +10,10 @@ describe("Keeper", () => {
before(async () => {
ConfigProvider.setConfig(config)
await ContractHandler.deployContracts()
await TestContractHandler.prepareContracts()
keeper = await Keeper.getInstance()
})
describe("public interface", () => {
it("should have market", () => {

View File

@ -0,0 +1,124 @@
import Contract from "web3-eth-contract"
import ContractHandler from "../../src/keeper/ContractHandler"
import Web3Provider from "../../src/keeper/Web3Provider"
import ServiceAgreementTemplate from "../../src/ocean/ServiceAgreements/ServiceAgreementTemplate"
import Access from "../../src/ocean/ServiceAgreements/Templates/Access"
import FitchainCompute from "../../src/ocean/ServiceAgreements/Templates/FitchainCompute"
import Logger from "../../src/utils/Logger"
export default class TestContractHandler extends ContractHandler {
public static async prepareContracts() {
const web3 = Web3Provider.getWeb3()
const deployerAddress = (await web3.eth.getAccounts())[0]
// deploy contracts
await TestContractHandler.deployContracts(deployerAddress)
// register templates
await new ServiceAgreementTemplate(new Access()).register(deployerAddress)
await new ServiceAgreementTemplate(new FitchainCompute()).register(deployerAddress)
}
private static async deployContracts(deployerAddress: string) {
Logger.log("Trying to deploy contracts")
// deploy libs
/* not part of trilobite
const dll = await ContractHandler.deployContract("DLL", deployerAddress)
const attributeStore = await ContractHandler.deployContract("AttributeStore", deployerAddress)
*/
// deploy contracts
const token = await TestContractHandler.deployContract("OceanToken", deployerAddress)
/* not part of trilobite
const plcrVoting = await ContractHandler.deployContract("PLCRVoting", deployerAddress, {
args: [token.options.address],
tokens: [
{
name: "DLL", address: dll.options.address,
}, {
name: "AttributeStore", address: attributeStore.options.address,
},
],
})
/* not part of trilobite
const registry = await ContractHandler.deployContract("OceanRegistry", deployerAddress, {
args: [token.options.address, plcrVoting.options.address],
})
*/
const market = await TestContractHandler.deployContract("OceanMarket", deployerAddress, {
args: [token.options.address],
})
const sa = await TestContractHandler.deployContract("ServiceAgreement", deployerAddress, {
args: [],
})
await TestContractHandler.deployContract("AccessConditions", deployerAddress, {
args: [sa.options.address],
})
await TestContractHandler.deployContract("PaymentConditions", deployerAddress, {
args: [sa.options.address, token.options.address],
})
await TestContractHandler.deployContract("DIDRegistry", deployerAddress, {})
/* not part of trilobite
const dispute = await ContractHandler.deployContract("OceanDispute", deployerAddress, {
args: [market.options.address, registry.options.address, plcrVoting.options.address],
})
*/
await TestContractHandler.deployContract("OceanAuth", deployerAddress, {
args: [market.options.address],
})
}
private static async deployContract(name: string, from: string, params?): Promise<Contract> {
// dont redeploy if there is already something loaded
if (ContractHandler.has(name)) {
return ContractHandler.get(name)
}
const web3 = Web3Provider.getWeb3()
let contractInstance: Contract
try {
Logger.log("Deploying", name)
const artifact = require(`@oceanprotocol/keeper-contracts/artifacts/${name}.development.json`)
const tempContract = new web3.eth.Contract(artifact.abi, artifact.address)
contractInstance = await tempContract.deploy({
data: params && params.tokens ?
TestContractHandler.replaceTokens(artifact.bytecode.toString(), params.tokens) :
artifact.bytecode,
arguments: params && params.args ? params.args : null,
}).send({
from,
gas: 3000000,
gasPrice: 10000000000,
})
TestContractHandler.set(name, contractInstance)
// Logger.log("Deployed", name, "at", contractInstance.options.address);
} catch (err) {
Logger.error("Deployment failed for", name, "with params", JSON.stringify(params, null, 2), err.message)
throw err
}
return contractInstance
}
private static replaceTokens(bytecode: string, tokens: any[]) {
for (const token of tokens) {
bytecode = bytecode.replace(
new RegExp(`_+${token.name}_+`, "g"),
token.address.replace("0x", ""))
}
// Logger.log(bytecode)
return bytecode.toString()
}
}

View File

@ -1,5 +1,6 @@
--require ts-node/register
--require source-map-support/register
--full-trace
--bail
test/**/*.test.ts
--require ts-node/register
--require source-map-support/register
--full-trace
--bail
--timeout 5000
test/**/*.test.ts

View File

@ -1,17 +1,25 @@
import AquariusConnector from "../../src/aquarius/AquariusConnector"
// @ts-ignore
export default class AquariusConnectorMock extends AquariusConnector {
public async post(url: string, payload: any) {
constructor(private returnData: any) {
super()
}
return {
ok: true,
json: () => {
return []
},
text: () => {
return ""
},
}
// @ts-ignore
private async fetch(url, opts): Promise<any> {
return new Promise((resolve, reject) => {
resolve({
ok: true,
json: () => {
return this.returnData ? this.returnData : []
},
text: () => {
return this.returnData ? this.returnData.toString() : ""
},
})
})
}
}

View File

@ -1,8 +1,8 @@
import ContractBase from "../../src/keeper/ContractBase"
import ContractBase from "../../src/keeper/contracts/ContractBase"
export default class ContractBaseMock extends ContractBase {
public async initMock() {
this.init()
await this.init()
}
public async callMock(name: string, args: any[], from?: string) {
@ -10,6 +10,6 @@ export default class ContractBaseMock extends ContractBase {
}
public async sendMock(name: string, from: string, args: any[]) {
return this.sendTransaction(name, from, args)
return this.send(name, from, args)
}
}

View File

@ -0,0 +1,16 @@
import SecretStore from "@oceanprotocol/secret-store-client"
export default class SecretStoreMock extends SecretStore {
public async encryptDocument(documentId, document: any) {
return "0x283asdgahd1t371t23h"
}
public async decryptDocument(documentId, encryptedDocument: any) {
return {
doc: "test",
}
}
}

View File

@ -1,10 +1,10 @@
import {assert} from "chai"
import ConfigProvider from "../../src/ConfigProvider"
import ContractHandler from "../../src/keeper/ContractHandler"
import Web3Provider from "../../src/keeper/Web3Provider"
import Account from "../../src/ocean/Account"
import Ocean from "../../src/ocean/Ocean"
import config from "../config"
import TestContractHandler from "../keeper/TestContractHandler"
let ocean: Ocean
let accounts: Account[]
@ -13,7 +13,7 @@ describe("Account", () => {
before(async () => {
ConfigProvider.setConfig(config)
await ContractHandler.deployContracts()
await TestContractHandler.prepareContracts()
ocean = await Ocean.getInstance(config)
accounts = await ocean.getAccounts()

View File

@ -1,47 +0,0 @@
import {assert} from "chai"
import AquariusProvider from "../../src/aquarius/AquariusProvider"
import ConfigProvider from "../../src/ConfigProvider"
import ContractHandler from "../../src/keeper/ContractHandler"
import Account from "../../src/ocean/Account"
import Asset from "../../src/ocean/Asset"
import Ocean from "../../src/ocean/Ocean"
import Order from "../../src/ocean/Order"
import config from "../config"
import AquariusMock from "../mocks/Aquarius.mock"
const testName = "Test Asset 2"
const testDescription = "This asset is pure owange"
const testPrice = 100
const timeout = 100000
let ocean: Ocean
let testAsset: Asset
let accounts: Account[]
let testPublisher: Account
describe("Asset", () => {
before(async () => {
ConfigProvider.setConfig(config)
AquariusProvider.setAquarius(new AquariusMock(config))
await ContractHandler.deployContracts()
ocean = await Ocean.getInstance(config)
accounts = await ocean.getAccounts()
testPublisher = accounts[0]
testAsset = new Asset(testName, testDescription, testPrice, testPublisher)
await ocean.register(testAsset)
})
describe("#purchase()", () => {
it("should purchase an asset", async () => {
// todo
const consumerAccount = accounts[5]
const order: Order = await testAsset.purchase(consumerAccount, timeout)
assert(order)
})
})
})

View File

@ -0,0 +1,53 @@
import * as assert from "assert"
import IdGenerator from "../../src/ocean/IdGenerator"
describe("IdGenerator", () => {
describe("#generateId()", () => {
it("should generate an id", async () => {
const id = IdGenerator.generateId()
assert(id)
})
it("should generate an id that is 64 chars long", async () => {
const id: string = IdGenerator.generateId()
assert(id.length === 64, id)
})
it("should not contain -", async () => {
const id: string = IdGenerator.generateId()
assert(id.indexOf("-") === -1)
})
})
describe("#generatePrefixedId()", () => {
it("should generate an id", async () => {
const id = IdGenerator.generatePrefixedId()
assert(id)
})
it("should generate an id that is 64 chars long", async () => {
const id: string = IdGenerator.generatePrefixedId()
assert(id.length === 66, id)
})
it("should be prefixed", async () => {
const id: string = IdGenerator.generatePrefixedId()
assert(id.startsWith("0x"))
})
it("should not contain -", async () => {
const id: string = IdGenerator.generatePrefixedId()
assert(id.indexOf("-") === -1)
})
})
})

View File

@ -1,46 +1,42 @@
import {assert} from "chai"
import AquariusProvider from "../../src/aquarius/AquariusProvider"
import SearchQuery from "../../src/aquarius/query/SearchQuery"
import ConfigProvider from "../../src/ConfigProvider"
import ContractHandler from "../../src/keeper/ContractHandler"
import DDO from "../../src/ddo/DDO"
import MetaData from "../../src/ddo/MetaData"
import Account from "../../src/ocean/Account"
import Asset from "../../src/ocean/Asset"
import Ocean from "../../src/ocean/Ocean"
import Order from "../../src/ocean/Order"
import SecretStoreProvider from "../../src/secretstore/SecretStoreProvider"
import config from "../config"
import TestContractHandler from "../keeper/TestContractHandler"
import AquariusMock from "../mocks/Aquarius.mock"
import SecretStoreMock from "../mocks/SecretStore.mock"
let ocean: Ocean
let accounts: Account[]
let testAsset: Asset
let testPublisher: Account
const name = "Test Asset 3"
const description = "This asset is pure owange"
const price = 100
const timeout = 100000000
describe("Ocean", () => {
before(async () => {
ConfigProvider.setConfig(config)
AquariusProvider.setAquarius(new AquariusMock(config))
await ContractHandler.deployContracts()
SecretStoreProvider.setSecretStore(new SecretStoreMock(config))
await TestContractHandler.prepareContracts()
ocean = await Ocean.getInstance(config)
accounts = await ocean.getAccounts()
testPublisher = accounts[0]
testAsset = new Asset(name, description, price, testPublisher)
})
describe("#getInstance()", () => {
it("should list accounts", async () => {
it("should get an instance of cean", async () => {
const ocn = Ocean.getInstance(config)
const oceanInstance: Ocean = await Ocean.getInstance(config)
assert(ocn)
assert(oceanInstance)
})
})
describe("#getAccounts()", () => {
@ -56,35 +52,16 @@ describe("Ocean", () => {
})
describe("#register()", () => {
describe("#registerAsset()", () => {
it("should register an asset", async () => {
const assetId: string = await ocean.register(testAsset)
const metaData: MetaData = new MetaData()
const ddo: DDO = await ocean.registerAsset(metaData, testPublisher)
assert(assetId.length === 66)
assert(assetId.startsWith("0x"))
assert(ddo)
assert(ddo.id.startsWith("did:op:"))
})
})
describe("#getOrdersByConsumer()", () => {
it("should list orders", async () => {
const testConsumer = accounts[1]
const asset: Asset = new Asset("getOrdersByConsumer test", description, price, testPublisher)
await ocean.register(asset)
const order: Order = await asset.purchase(testConsumer, timeout)
const orders = await ocean.getOrdersByAccount(testConsumer)
assert(orders.length === 1)
assert(orders[0].getId() === order.getId())
})
})
describe("#searchAssets()", () => {
@ -101,7 +78,7 @@ describe("Ocean", () => {
value: 1,
},
text: "Office",
}
} as SearchQuery
const assets: any[] = await ocean.searchAssets(query)
@ -109,4 +86,15 @@ describe("Ocean", () => {
})
})
describe("#searchAssetsByText()", () => {
it("should search for assets", async () => {
const text = "office"
const assets: any[] = await ocean.searchAssetsByText(text)
assert(assets)
})
})
})

View File

@ -1,104 +0,0 @@
import {assert} from "chai"
import AquariusProvider from "../../src/aquarius/AquariusProvider"
import ConfigProvider from "../../src/ConfigProvider"
import ContractHandler from "../../src/keeper/ContractHandler"
import AccessStatus from "../../src/models/AccessStatus"
import Account from "../../src/ocean/Account"
import Asset from "../../src/ocean/Asset"
import Ocean from "../../src/ocean/Ocean"
import Order from "../../src/ocean/Order"
import config from "../config"
import AquariusMock from "../mocks/Aquarius.mock"
const testName = "Order Test Asset"
const testDescription = "This asset is pure owange"
const testPrice = 100
const timeout = 1000000
const accessToken = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzM4NCJ9.eyJpc3MiOiJPbmxpbmUgSldUIEJ1aWxkZXIiLCJpYXQiOjE1Mzk3ODcxMDEsImV4cCI6NDcyNjk5NjcwNCwiYXVkIjoiIiwic3ViIjoiIiwic2VydmljZV9lbmRwb2ludCI6Imh0dHA6Ly9hZGFzZCIsInJlc291cmNlX2lkIjoiMTIzNDUifQ.2H3TRC3CAToVE9divSckwHi_HNvgOHKrtJPo8128qrKBHTk7YYb0UNfVCuYqwhGR"
let ocean: Ocean
let testAsset: Asset
let accounts: Account[]
let testPublisher: Account
let testConsumer: Account
describe("Order", () => {
before(async () => {
ConfigProvider.setConfig(config)
AquariusProvider.setAquarius(new AquariusMock(config))
await ContractHandler.deployContracts()
ocean = await Ocean.getInstance(config)
accounts = await ocean.getAccounts()
testPublisher = accounts[0]
testConsumer = accounts[1]
// register an asset to play around with
testAsset = new Asset(testName, testDescription, testPrice, testPublisher)
await ocean.register(testAsset)
})
describe("#pay()", async () => {
it("should pay for an order", async () => {
const order: Order = await testAsset.purchase(testConsumer, timeout)
assert(order)
await order.commit(accessToken)
await testConsumer.requestTokens(testAsset.price)
const paymentId: string = await order.pay(testConsumer)
assert(paymentId)
})
})
describe("#commit()", async () => {
it("should commit the order", async () => {
const order: Order = await testAsset.purchase(testConsumer, timeout)
assert(order)
await order.commit(accessToken)
})
})
describe("#getStatus()", async () => {
it("should get status Requested on new order", async () => {
const order: Order = await testAsset.purchase(testConsumer, timeout)
assert(order)
const status: AccessStatus = await order.getStatus()
assert(status === AccessStatus.Requested)
})
it("should get status Delivered on commited order", async () => {
const order: Order = await testAsset.purchase(testConsumer, timeout)
assert(order)
await order.commit(accessToken)
const status: AccessStatus = await order.getStatus()
assert(status === AccessStatus.Delivered)
})
})
describe("#consume()", () => {
it("should consume an asset", async () => {
const consumerAccount = accounts[5]
await consumerAccount.requestTokens(testAsset.price)
// place order - consumer
const order: Order = await testAsset.purchase(consumerAccount, timeout)
// commit order - provider
await order.commit(accessToken)
// pay order - consumer
await order.pay(consumerAccount)
const url = await order.consume(consumerAccount)
assert(url)
})
})
})

View File

@ -0,0 +1,131 @@
import {assert} from "chai"
import AquariusConnectorProvider from "../../src/aquarius/AquariusConnectorProvider"
import ConfigProvider from "../../src/ConfigProvider"
import DDOCondition from "../../src/ddo/Condition"
import DDO from "../../src/ddo/DDO"
import Parameter from "../../src/ddo/Parameter"
import Service from "../../src/ddo/Service"
import Account from "../../src/ocean/Account"
import IdGenerator from "../../src/ocean/IdGenerator"
import Ocean from "../../src/ocean/Ocean"
import Condition from "../../src/ocean/ServiceAgreements/Condition"
import ServiceAgreement from "../../src/ocean/ServiceAgreements/ServiceAgreement"
import ServiceAgreementTemplate from "../../src/ocean/ServiceAgreements/ServiceAgreementTemplate"
import Access from "../../src/ocean/ServiceAgreements/Templates/Access"
import config from "../config"
import TestContractHandler from "../keeper/TestContractHandler"
import AquariusConnectorMock from "../mocks/AquariusConnector.mock"
let ocean: Ocean
let accounts: Account[]
let publisherAccount: Account
let consumerAccount: Account
let serviceDefinition
describe("ServiceAgreement", () => {
before(async () => {
ConfigProvider.setConfig(config)
await TestContractHandler.prepareContracts()
ocean = await Ocean.getInstance(config)
accounts = await ocean.getAccounts()
publisherAccount = accounts[1]
consumerAccount = accounts[2]
const serviceAgreementTemplate: ServiceAgreementTemplate =
new ServiceAgreementTemplate(new Access())
// get condition keys from template
const conditions: Condition[] = await serviceAgreementTemplate.getConditions()
// create ddo conditions out of the keys
const ddoConditions: DDOCondition[] = conditions.map((condition): DDOCondition => {
return {
name: condition.methodReflection.methodName,
timeout: condition.timeout,
conditionKey: condition.condtionKey,
parameters: condition.methodReflection.inputs.map((input) => {
return {
...input,
value: "xx",
}as Parameter
}),
} as DDOCondition
})
serviceDefinition = [
{
serviceDefinitionId: IdGenerator.generateId(),
templateId: serviceAgreementTemplate.getId(),
conditions: ddoConditions,
} as Service,
]
})
describe("#signServiceAgreement()", () => {
it("should execute an service agreement", async () => {
const id: string = IdGenerator.generateId()
const did: string = `did:op:${id}`
const ddo = new DDO({id: did, service: serviceDefinition})
const assetId: string = IdGenerator.generateId()
const serviceAgreementId: string = IdGenerator.generateId()
// @ts-ignore
AquariusConnectorProvider.setConnector(new AquariusConnectorMock(ddo))
const serviceAgreement: ServiceAgreement =
await ServiceAgreement.signServiceAgreement(assetId, ddo, serviceAgreementId, consumerAccount,
publisherAccount)
assert(serviceAgreement)
const serviceDefinitionId = serviceAgreement.getId()
assert(serviceDefinitionId)
assert(serviceDefinitionId !== did)
})
})
describe("#getStatus()", () => {
it("should get the status of a newly created service agreement", async () => {
const id: string = IdGenerator.generateId()
const did: string = `did:op:${id}`
const ddo = new DDO({id: did, service: serviceDefinition})
const assetId: string = IdGenerator.generateId()
const serviceAgreementId: string = IdGenerator.generateId()
// @ts-ignore
AquariusConnectorProvider.setConnector(new AquariusConnectorMock(ddo))
const serviceAgreement: ServiceAgreement =
await ServiceAgreement.signServiceAgreement(assetId, ddo, serviceAgreementId, consumerAccount,
publisherAccount)
assert(serviceAgreement)
const status = await serviceAgreement.getStatus()
assert(status === false)
})
})
describe("#grantAccess()", () => {
it("should grant access in that service agreement", async () => {
const id: string = IdGenerator.generateId()
const did: string = `did:op:${id}`
const ddo = new DDO({id: did, service: serviceDefinition})
const assetId: string = IdGenerator.generateId()
const serviceAgreementId: string = IdGenerator.generateId()
// @ts-ignore
AquariusConnectorProvider.setConnector(new AquariusConnectorMock(ddo))
const serviceAgreement: ServiceAgreement =
await ServiceAgreement.signServiceAgreement(assetId, ddo, serviceAgreementId, consumerAccount,
publisherAccount)
assert(serviceAgreement)
const fulfilled: boolean = await serviceAgreement.grantAccess(assetId, IdGenerator.generateId())
assert(fulfilled)
})
})
})

View File

@ -0,0 +1,60 @@
import {assert} from "chai"
import ConfigProvider from "../../src/ConfigProvider"
import Account from "../../src/ocean/Account"
import IdGenerator from "../../src/ocean/IdGenerator"
import Ocean from "../../src/ocean/Ocean"
import ServiceAgreementTemplate from "../../src/ocean/ServiceAgreements/ServiceAgreementTemplate"
import Access from "../../src/ocean/ServiceAgreements/Templates/Access"
import TemplateBase from "../../src/ocean/ServiceAgreements/Templates/TemplateBase"
import config from "../config"
import TestContractHandler from "../keeper/TestContractHandler"
let ocean: Ocean
let accounts: Account[]
describe("ServiceAgreementTemplate", () => {
before(async () => {
ConfigProvider.setConfig(config)
await TestContractHandler.prepareContracts()
ocean = await Ocean.getInstance(config)
accounts = await ocean.getAccounts()
})
describe("#register()", () => {
it("should setup an Access agreement template correctly", async () => {
const templateOwner = accounts[0]
const access: TemplateBase = new Access()
access.id = IdGenerator.generatePrefixedId()
const serviceAgreementTemplate: ServiceAgreementTemplate =
new ServiceAgreementTemplate(access)
assert(serviceAgreementTemplate)
const registered: boolean = await serviceAgreementTemplate.register(templateOwner.getId())
assert(registered)
assert(serviceAgreementTemplate.getId())
assert((await serviceAgreementTemplate.getOwner()).getId() === templateOwner.getId())
})
})
describe("#getStatus()", () => {
it("should get the status of a newly deployed agreement template", async () => {
const publisherAccount = accounts[0]
const access: TemplateBase = new Access()
access.id = IdGenerator.generatePrefixedId()
const serviceAgreementTemplate: ServiceAgreementTemplate =
new ServiceAgreementTemplate(access)
assert(serviceAgreementTemplate)
const registered: boolean = await serviceAgreementTemplate.register(publisherAccount.getId())
assert(registered)
const templateStatus = await serviceAgreementTemplate.getStatus()
assert(templateStatus === true)
})
})
})

1
test/testdata/AccessToken.json vendored Normal file
View File

@ -0,0 +1 @@
"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzM4NCJ9.eyJpc3MiOiJPbmxpbmUgSldUIEJ1aWxkZXIiLCJpYXQiOjE1Mzk3ODcxMDEsImV4cCI6NDcyNjk5NjcwNCwiYXVkIjoiIiwic3ViIjoiIiwic2VydmljZV9lbmRwb2ludCI6Imh0dHA6Ly9hZGFzZCIsInJlc291cmNlX2lkIjoiMTIzNDUifQ.2H3TRC3CAToVE9divSckwHi_HNvgOHKrtJPo8128qrKBHTk7YYb0UNfVCuYqwhGR"

218
test/testdata/ddo.json vendored Normal file
View File

@ -0,0 +1,218 @@
{
"@context": "https://w3id.org/future-method/v1",
"id": "did:op:08a429b8529856d59867503f8056903a680935a76950bb9649785cc97869a43d",
"publicKey": [
{
"id": "did:op:123456789abcdefghi#keys-1",
"type": "RsaVerificationKey2018",
"owner": "did:op:123456789abcdefghi",
"publicKeyPem": "-----BEGIN PUBLIC KEY...END PUBLIC KEY-----\r\n"
},
{
"id": "did:op:123456789abcdefghi#keys-2",
"type": "Ed25519VerificationKey2018",
"owner": "did:op:123456789abcdefghi",
"publicKeyBase58": "H3C2AVvLMv6gmMNam3uVAjZpfkcJCwDwnZn6z3wXmqPV"
},
{
"id": "did:op:123456789abcdefghi#keys-3",
"type": "RsaPublicKeyExchangeKey2018",
"owner": "did:op:123456789abcdefghi",
"publicKeyPem": "-----BEGIN PUBLIC KEY...END PUBLIC KEY-----\r\n"
}
],
"authentication": [
{
"type": "RsaSignatureAuthentication2018",
"publicKey": "did:op:123456789abcdefghi#keys-1"
},
{
"type": "ieee2410Authentication2018",
"publicKey": "did:op:123456789abcdefghi#keys-2"
}
],
"proof": {
"type": "UUIDSignature",
"created": "2016-02-08T16:02:20Z",
"creator": "did:example:8uQhQMGzWxR8vw5P3UWH1ja",
"signatureValue": "QNB13Y7Q9...1tzjn4w=="
},
"service": [
{
"type": "Access",
"serviceDefinitionId": "0",
"serviceEndpoint": "http://mybrizo.org/api/v1/brizo/services/consume?pubKey=${pubKey}&serviceId={serviceId}&url={url}",
"purchaseEndpoint": "http://mybrizo.org/api/v1/brizo/services/access/purchase?",
"templateId": "044852b2a670ade5407e78fb2863c51000000000000000000000000000000000",
"conditions": [
{
"name": "lockPayment",
"timeout": 0,
"conditionKey": {
"contractAddress": "0x...",
"fingerprint": "0x..."
},
"parameters": {
"assetId": "bytes32",
"price": "integer"
},
"events": {
"PaymentLocked": {
"actorType": [
"publisher"
],
"handlers": [
{
"moduleName": "accessControl",
"functionName": "grantAccess",
"version": "0.1"
}
]
}
}
},
{
"name": "releasePayment",
"timeout": 0,
"conditionKey": {
"contractAddress": "0x...",
"fingerprint": "0xXXXXXXXX"
},
"parameters": {
"assetId": "bytes32",
"price": "integer"
},
"events": {
"PaymentReleased": {
"actorType": [
"publisher"
],
"handlers": [
{
"moduleName": "serviceAgreement",
"functionName": "fulfillAgreement",
"version": "0.1"
}
]
}
}
},
{
"name": "grantAccess",
"timeout": 0,
"conditionKey": {
"contractAddress": "0x",
"fingerprint": "0xXXXXXXXX"
},
"parameters": {
"assetId": "bytes32",
"documentKeyId": "bytes32"
},
"events": {
"AccessGranted": {
"actorType": [
"consumer"
],
"handlers": [
{
"moduleName": "asset",
"functionName": "consumeService",
"version": "0.1"
}
]
}
}
},
{
"name": "refundPayment",
"timeout": 1,
"condition_key": {
"contractAddress": "0x...",
"fingerprint": "0xXXXXXXXX"
},
"parameters": {
"assetId": "bytes32",
"price": "int"
},
"events": {
"PaymentRefund": {
"actorType": [
"consumer"
],
"handlers": [
{
"moduleName": "serviceAgreement",
"functionName": "fulfillAgreement",
"version": "0.1"
}
]
}
}
}
]
},
{
"type": "CloudCompute",
"serviceDefinitionId": "1",
"serviceEndpoint": "http://mybrizo.org/api/v1/brizo/services/compute?pubKey=${pubKey}&serviceId={serviceId}&algo={algo}&container={container}",
"templateId": "044852b2a670ade5407e78fb2863c51000000000000000000000000000000002"
},
{
"type": "Metadata",
"serviceDefinitionId": "2",
"serviceEndpoint": "http://myaquarius.org/api/v1/provider/assets/metadata/{did}",
"metadata": {
"base": {
"name": "UK Weather information 2011",
"type": "dataset",
"description": "Weather information of UK including temperature and humidity",
"size": "3.1gb",
"dateCreated": "2012-10-10T17:00:000Z",
"author": "Met Office",
"license": "CC-BY",
"copyrightHolder": "Met Office",
"encoding": "UTF-8",
"compression": "zip",
"contentType": "text/csv",
"workExample": "423432fsd,51.509865,-0.118092,2011-01-01T10:55:11+00:00,7.2,68",
"contentUrls": [
"https://testocnfiles.blob.core.windows.net/testfiles/testzkp.zip"
],
"links": [
{
"name": "Sample of Asset Data",
"type": "sample",
"url": "https://foo.com/sample.csv"
},
{
"name": "Data Format Definition",
"type": "format",
"AssetID": "4d517500da0acb0d65a716f61330969334630363ce4a6a9d39691026ac7908ea"
}
],
"inLanguage": "en",
"tags": "weather, uk, 2011, temperature, humidity",
"price": 10
},
"curation": {
"rating": 0.93,
"numVotes": 123,
"schema": "Binary Votting"
},
"additionalInformation": {
"updateFrecuency": "yearly",
"structuredMarkup": [
{
"uri": "http://skos.um.es/unescothes/C01194/jsonld",
"mediaType": "application/ld+json"
},
{
"uri": "http://skos.um.es/unescothes/C01194/turtle",
"mediaType": "text/turtle"
}
]
}
}
}
]
}

View File

@ -1,5 +1,6 @@
{
"compilerOptions": {
"resolveJsonModule": true,
"lib": [
"es6",
"es7"