format all the things

This commit is contained in:
Matthias Kretschmann 2019-06-20 00:20:09 +02:00 committed by Pedro Gutiérrez
parent 537b5a63ad
commit b61822e30c
117 changed files with 3246 additions and 2254 deletions

View File

@ -1,6 +1,6 @@
language: node_js
node_js:
- "10"
- '10'
services:
- docker
@ -42,9 +42,8 @@ notifications:
deploy:
- provider: npm
email: "devops@oceanprotocol.com"
email: 'devops@oceanprotocol.com'
api_key: ${NPM_TOKEN}
skip_cleanup: true
on:
tags: true

View File

@ -138,6 +138,8 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
> 8 April 2019
* First release
- Bump version 0.5.1 -> 0.5.2 [`#183`](https://github.com/oceanprotocol/squid-js/pull/183)
- Use the new Aquarius response type. [`b8fec2d`](https://github.com/oceanprotocol/squid-js/commit/b8fec2d0844009944f6492aa62049e806a4286a1)
- Add a integration test using the consumption of big files. [`6a98fc3`](https://github.com/oceanprotocol/squid-js/commit/6a98fc39cfc8b914c5c59f59242781fd56165856)

View File

@ -1,6 +1,6 @@
[![banner](https://raw.githubusercontent.com/oceanprotocol/art/master/github/repo-banner%402x.png)](https://oceanprotocol.com)
# squid-js
<h1 align="center">Squid-js</h1>
> 🦑 JavaScript client library for Ocean Protocol
> [oceanprotocol.com](https://oceanprotocol.com)
@ -9,7 +9,7 @@
[![Travis (.com)](https://img.shields.io/travis/com/oceanprotocol/squid-js.svg)](https://travis-ci.com/oceanprotocol/squid-js)
[![GitHub contributors](https://img.shields.io/github/contributors/oceanprotocol/squid-js.svg)](https://github.com/oceanprotocol/squid-js/graphs/contributors)
[![Codacy Badge](https://api.codacy.com/project/badge/Grade/8508313231b44b0997ec84898cd6f9db)](https://app.codacy.com/app/ocean-protocol/squid-js?utm_source=github.com&utm_medium=referral&utm_content=oceanprotocol/squid-js&utm_campaign=Badge_Grade_Settings)
[![js oceanprotocol](https://img.shields.io/badge/js-oceanprotocol-7b1173.svg)](https://github.com/oceanprotocol/eslint-config-oceanprotocol)
[![js oceanprotocol](https://img.shields.io/badge/js-oceanprotocol-7b1173.svg)](https://github.com/oceanprotocol/eslint-config-oceanprotocol)
[![Greenkeeper badge](https://badges.greenkeeper.io/oceanprotocol/squid-js.svg)](https://greenkeeper.io/)
---
@ -54,17 +54,17 @@ You can then connect to a running [Keeper](https://github.com/oceanprotocol/keep
```js
const ocean: Ocean = await Ocean.getInstance({
// the node of the blockchain to connect to, could also be infura
nodeUri: "http://localhost:8545",
nodeUri: 'http://localhost:8545',
// the uri of aquarius
aquariusUri: "http://localhost:5000",
aquariusUri: 'http://localhost:5000',
// the uri of brizo
brizoUri: "http://localhost:8030",
brizoUri: 'http://localhost:8030',
// address that brizo uses
brizoAddress: "0x00bd138abd70e2f00903268f3db08f2d25677c9e"
brizoAddress: '0x00bd138abd70e2f00903268f3db08f2d25677c9e'
// the uri to the parity node you want to use for encryption and decryption
parityUri: "http://localhost:9545",
parityUri: 'http://localhost:9545',
// the uri of the secret store that holds the keys
secretStoreUri: "http://localhost:12001"
secretStoreUri: 'http://localhost:12001'
})
```
@ -199,4 +199,4 @@ Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
limitations under the License.

View File

@ -1 +1 @@
this document has been moved to [here](https://github.com/oceanprotocol/dev-ocean/blob/master/doc/architecture/squid.md).
this document has been moved to [here](https://github.com/oceanprotocol/dev-ocean/blob/master/doc/architecture/squid.md).

View File

@ -1,32 +1,32 @@
import * as HDWalletProvider from "truffle-hdwallet-provider"
import { Config } from "../src"
import * as HDWalletProvider from 'truffle-hdwallet-provider'
import { Config } from '../src'
const configJson: Config = {
nodeUri: "http://localhost:8545",
aquariusUri: "http://172.15.0.15:5000",
brizoUri: "http://localhost:8030",
secretStoreUri: "http://localhost:12001",
brizoAddress: "0x00Bd138aBD70e2F00903268F3Db08f2D25677C9e",
verbose: false,
nodeUri: 'http://localhost:8545',
aquariusUri: 'http://172.15.0.15:5000',
brizoUri: 'http://localhost:8030',
secretStoreUri: 'http://localhost:12001',
brizoAddress: '0x00Bd138aBD70e2F00903268F3Db08f2D25677C9e',
verbose: false
}
if (process.env.NETWORK_NAME === "nile") {
if (process.env.NETWORK_NAME === 'nile') {
Object.assign(configJson, {
nodeUri: "https://nile.dev-ocean.com",
aquariusUri: "https://nginx-aquarius.dev-ocean.com",
brizoUri: "https://nginx-brizo.dev-ocean.com",
secretStoreUri: "https://secret-store.dev-ocean.com",
brizoAddress: "0x413c9ba0a05b8a600899b41b0c62dd661e689354",
nodeUri: 'https://nile.dev-ocean.com',
aquariusUri: 'https://nginx-aquarius.dev-ocean.com',
brizoUri: 'https://nginx-brizo.dev-ocean.com',
secretStoreUri: 'https://secret-store.dev-ocean.com',
brizoAddress: '0x413c9ba0a05b8a600899b41b0c62dd661e689354'
})
}
if (process.env.NETWORK_NAME === "duero") {
if (process.env.NETWORK_NAME === 'duero') {
Object.assign(configJson, {
nodeUri: "https://duero.dev-ocean.com",
aquariusUri: "https://aquarius.duero.dev-ocean.com",
brizoUri: "https://brizo.duero.dev-ocean.com",
secretStoreUri: "https://secret-store.duero.dev-ocean.com",
brizoAddress: "0x9d4ed58293f71122ad6a733c1603927a150735d0",
nodeUri: 'https://duero.dev-ocean.com',
aquariusUri: 'https://aquarius.duero.dev-ocean.com',
brizoUri: 'https://brizo.duero.dev-ocean.com',
secretStoreUri: 'https://secret-store.duero.dev-ocean.com',
brizoAddress: '0x9d4ed58293f71122ad6a733c1603927a150735d0'
})
}
@ -38,7 +38,7 @@ if (process.env.SEED_WORDS) {
seedphrase,
configJson.nodeUri,
0,
5,
5
)
}

View File

@ -1,12 +1,12 @@
import { assert } from "chai"
import { assert } from 'chai'
import { config } from "../config"
import { config } from '../config'
import { getMetadata } from "../utils"
import { getMetadata } from '../utils'
import { Ocean, Account } from "../../src" // @oceanprotocol/squid
import { Ocean, Account } from '../../src' // @oceanprotocol/squid
describe("Asset Owners", () => {
describe('Asset Owners', () => {
let ocean: Ocean
let account1: Account
@ -23,7 +23,7 @@ describe("Asset Owners", () => {
account2 = accounts[1]
})
it("should be set correctly the owner of a asset", async () => {
it('should be set correctly the owner of a asset', async () => {
const ddo = await ocean.assets.create(metadata as any, account1)
const owner = await ocean.assets.owner(ddo.id)
@ -31,33 +31,49 @@ describe("Asset Owners", () => {
assert.equal(owner, account1.getId())
})
it("should get the assets owned by a user", async () => {
const {length: initialLength} = await ocean.assets.ownerAssets(account2.getId())
it('should get the assets owned by a user', async () => {
const { length: initialLength } = await ocean.assets.ownerAssets(
account2.getId()
)
await ocean.assets.create(metadata as any, account1)
await ocean.assets.create(metadata as any, account1)
await ocean.assets.create(metadata as any, account2)
const {length: finalLength} = await ocean.assets.ownerAssets(account2.getId())
const { length: finalLength } = await ocean.assets.ownerAssets(
account2.getId()
)
assert.equal(finalLength - initialLength, 1)
})
it("should get the assets that can be consumer by a user", async () => {
const {length: initialLength} = await ocean.assets.consumerAssets(account2.getId())
it('should get the assets that can be consumer by a user', async () => {
const { length: initialLength } = await ocean.assets.consumerAssets(
account2.getId()
)
const ddo = await ocean.assets.create(metadata as any, account1)
const {length: finalLength1} = await ocean.assets.consumerAssets(account2.getId())
const { length: finalLength1 } = await ocean.assets.consumerAssets(
account2.getId()
)
assert.equal(finalLength1 - initialLength, 0)
// Granting access
await account2.requestTokens(+metadata.base.price * (10 ** -await ocean.keeper.token.decimals()))
await ocean.assets.order(ddo.id, ddo.findServiceByType("Access").serviceDefinitionId, account2)
await account2.requestTokens(
+metadata.base.price * 10 ** -(await ocean.keeper.token.decimals())
)
await ocean.assets.order(
ddo.id,
ddo.findServiceByType('Access').serviceDefinitionId,
account2
)
// Access granted
const {length: finalLength2} = await ocean.assets.consumerAssets(account2.getId())
const { length: finalLength2 } = await ocean.assets.consumerAssets(
account2.getId()
)
assert.equal(finalLength2 - initialLength, 1)
})
})

View File

@ -1,10 +1,10 @@
import { assert } from "chai"
import { assert } from 'chai'
import { config } from "../config"
import { config } from '../config'
import { Ocean, Account } from "../../src" // @oceanprotocol/squid
import { Ocean, Account } from '../../src' // @oceanprotocol/squid
describe("Authentication Token", () => {
describe('Authentication Token', () => {
let ocean: Ocean
let account1: Account
@ -13,7 +13,7 @@ describe("Authentication Token", () => {
before(async () => {
try {
localStorage.clear()
} catch { }
} catch {}
ocean = await Ocean.getInstance(config)
@ -23,13 +23,13 @@ describe("Authentication Token", () => {
account2 = accounts[1]
})
it("should generate a token", async () => {
it('should generate a token', async () => {
const token = await ocean.auth.get(account1)
assert.match(token, /^0x[a-f0-9]{130}-[0-9]{0,14}/i)
})
it("should return the account that signed the token", async () => {
it('should return the account that signed the token', async () => {
const token = await ocean.auth.get(account1)
const address = await ocean.auth.check(token)
@ -37,7 +37,7 @@ describe("Authentication Token", () => {
assert.equal(address, account1.getId())
})
it("should store the token for a user", async () => {
it('should store the token for a user', async () => {
assert.isUndefined(await account1.getToken())
await ocean.auth.store(account1)
@ -45,19 +45,19 @@ describe("Authentication Token", () => {
assert.match(await account1.getToken(), /^0x[a-f0-9]{130}-[0-9]{0,14}/i)
})
it("should restore the token for a user", async () => {
it('should restore the token for a user', async () => {
const token = await ocean.auth.restore(account1)
assert.match(token, /^0x[a-f0-9]{130}-[0-9]{0,14}/i)
})
it("should return undefined when is not stored", async () => {
it('should return undefined when is not stored', async () => {
const token = await ocean.auth.restore(account2)
assert.isUndefined(token)
})
it("should know if the token is stored", async () => {
it('should know if the token is stored', async () => {
let acc1Stored
let acc2Stored
acc1Stored = await ocean.auth.isStored(account1)

View File

@ -1,12 +1,12 @@
import { assert } from "chai"
import * as fs from "fs"
import { assert } from 'chai'
import * as fs from 'fs'
import { config } from "../config"
import { getMetadata } from "../utils"
import { config } from '../config'
import { getMetadata } from '../utils'
import { Ocean, DDO, Account, ConditionState } from "../../src" // @oceanprotocol/squid
import { Ocean, DDO, Account, ConditionState } from '../../src' // @oceanprotocol/squid
describe("Consume Asset", () => {
describe('Consume Asset', () => {
let ocean: Ocean
let publisher: Account
@ -15,7 +15,10 @@ describe("Consume Asset", () => {
const metadata = getMetadata()
let ddo: DDO
let serviceAgreementSignatureResult: {agreementId: string, signature: string}
let serviceAgreementSignatureResult: {
agreementId: string
signature: string
}
before(async () => {
ocean = await Ocean.getInstance(config)
@ -25,35 +28,59 @@ describe("Consume Asset", () => {
consumer = (await ocean.accounts.list())[1]
})
it("should regiester a asset", async () => {
it('should regiester a asset', async () => {
ddo = await ocean.assets.create(metadata as any, publisher)
assert.isDefined(ddo, "Register has not returned a DDO")
assert.match(ddo.id, /^did:op:[a-f0-9]{64}$/, "DDO id is not valid")
assert.isAtLeast(ddo.authentication.length, 1, "Default authentication not added")
assert.isDefined(ddo.findServiceByType("Access"), "DDO Access service doesn't exist")
assert.isDefined(ddo, 'Register has not returned a DDO')
assert.match(ddo.id, /^did:op:[a-f0-9]{64}$/, 'DDO id is not valid')
assert.isAtLeast(
ddo.authentication.length,
1,
'Default authentication not added'
)
assert.isDefined(
ddo.findServiceByType('Access'),
"DDO Access service doesn't exist"
)
})
it("should be able to request tokens for consumer", async () => {
it('should be able to request tokens for consumer', async () => {
const initialBalance = (await consumer.getBalance()).ocn
const claimedTokens = +metadata.base.price * (10 ** -await ocean.keeper.token.decimals())
const claimedTokens =
+metadata.base.price * 10 ** -(await ocean.keeper.token.decimals())
await consumer.requestTokens(claimedTokens)
assert.equal((await consumer.getBalance()).ocn, initialBalance + claimedTokens, "OCN Tokens not delivered")
assert.equal(
(await consumer.getBalance()).ocn,
initialBalance + claimedTokens,
'OCN Tokens not delivered'
)
})
it("should sign the service agreement", async () => {
const accessService = ddo.findServiceByType("Access")
it('should sign the service agreement', async () => {
const accessService = ddo.findServiceByType('Access')
serviceAgreementSignatureResult = await ocean.agreements.prepare(ddo.id, accessService.serviceDefinitionId, consumer)
serviceAgreementSignatureResult = await ocean.agreements.prepare(
ddo.id,
accessService.serviceDefinitionId,
consumer
)
const {agreementId, signature} = serviceAgreementSignatureResult
assert.match(agreementId, /^0x[a-f0-9]{64}$/, "Service agreement ID seems not valid")
assert.match(signature, /^0x[a-f0-9]{130}$/, "Service agreement signature seems not valid")
const { agreementId, signature } = serviceAgreementSignatureResult
assert.match(
agreementId,
/^0x[a-f0-9]{64}$/,
'Service agreement ID seems not valid'
)
assert.match(
signature,
/^0x[a-f0-9]{130}$/,
'Service agreement signature seems not valid'
)
})
it("should execute the service agreement", async () => {
const accessService = ddo.findServiceByType("Access")
it('should execute the service agreement', async () => {
const accessService = ddo.findServiceByType('Access')
const success = await ocean.agreements.create(
ddo.id,
@ -61,103 +88,115 @@ describe("Consume Asset", () => {
accessService.serviceDefinitionId,
serviceAgreementSignatureResult.signature,
consumer,
publisher,
publisher
)
assert.isTrue(success)
})
it("should get the agreement conditions status not fulfilled", async () => {
const status = await ocean.agreements.status(serviceAgreementSignatureResult.agreementId)
it('should get the agreement conditions status not fulfilled', async () => {
const status = await ocean.agreements.status(
serviceAgreementSignatureResult.agreementId
)
assert.deepEqual(status, {
lockReward: ConditionState.Unfulfilled,
accessSecretStore: ConditionState.Unfulfilled,
escrowReward: ConditionState.Unfulfilled,
escrowReward: ConditionState.Unfulfilled
})
})
it("should lock the payment by the consumer", async () => {
const paid = await ocean.agreements.conditions
.lockReward(
serviceAgreementSignatureResult.agreementId,
ddo.findServiceByType("Metadata").metadata.base.price,
consumer,
)
it('should lock the payment by the consumer', async () => {
const paid = await ocean.agreements.conditions.lockReward(
serviceAgreementSignatureResult.agreementId,
ddo.findServiceByType('Metadata').metadata.base.price,
consumer
)
assert.isTrue(paid, "The asset has not been paid correctly")
assert.isTrue(paid, 'The asset has not been paid correctly')
})
// The test will fail because Brizo grants the access faster
it("should grant the access by the publisher", async () => {
it('should grant the access by the publisher', async () => {
try {
const granted = await ocean.agreements.conditions
.grantAccess(serviceAgreementSignatureResult.agreementId, ddo.id, consumer.getId(), publisher)
const granted = await ocean.agreements.conditions.grantAccess(
serviceAgreementSignatureResult.agreementId,
ddo.id,
consumer.getId(),
publisher
)
assert.isTrue(granted, "The asset has not been granted correctly")
assert.isTrue(granted, 'The asset has not been granted correctly')
const accessGranted = await ocean.keeper.conditions
.accessSecretStoreCondition
.checkPermissions(consumer.getId(), ddo.id)
const accessGranted = await ocean.keeper.conditions.accessSecretStoreCondition.checkPermissions(
consumer.getId(),
ddo.id
)
assert.isTrue(accessGranted, "Consumer has been granted.")
} catch { }
assert.isTrue(accessGranted, 'Consumer has been granted.')
} catch {}
})
it("should get the agreement conditions status fulfilled", async () => {
const status = await ocean.agreements.status(serviceAgreementSignatureResult.agreementId)
it('should get the agreement conditions status fulfilled', async () => {
const status = await ocean.agreements.status(
serviceAgreementSignatureResult.agreementId
)
assert.deepEqual(status, {
lockReward: ConditionState.Fulfilled,
accessSecretStore: ConditionState.Fulfilled,
escrowReward: ConditionState.Unfulfilled,
escrowReward: ConditionState.Unfulfilled
})
})
it("should consume and store the assets", async () => {
const accessService = ddo.findServiceByType("Access")
it('should consume and store the assets', async () => {
const accessService = ddo.findServiceByType('Access')
const folder = "/tmp/ocean/squid-js-1"
const folder = '/tmp/ocean/squid-js-1'
const path = await ocean.assets.consume(
serviceAgreementSignatureResult.agreementId,
ddo.id,
accessService.serviceDefinitionId,
consumer,
folder
)
assert.include(path, folder, 'The storage path is not correct.')
const files = await new Promise<string[]>(resolve => {
fs.readdir(path, (err, fileList) => {
resolve(fileList)
})
})
assert.deepEqual(
files,
['README.md', 'package.json'],
'Stored files are not correct.'
)
})
it('should consume and store one assets', async () => {
const accessService = ddo.findServiceByType('Access')
const folder = '/tmp/ocean/squid-js-2'
const path = await ocean.assets.consume(
serviceAgreementSignatureResult.agreementId,
ddo.id,
accessService.serviceDefinitionId,
consumer,
folder,
1
)
assert.include(path, folder, "The storage path is not correct.")
assert.include(path, folder, 'The storage path is not correct.')
const files = await new Promise<string[]>((resolve) => {
const files = await new Promise<string[]>(resolve => {
fs.readdir(path, (err, fileList) => {
resolve(fileList)
})
})
assert.deepEqual(files, ["README.md", "package.json"], "Stored files are not correct.")
})
it("should consume and store one assets", async () => {
const accessService = ddo.findServiceByType("Access")
const folder = "/tmp/ocean/squid-js-2"
const path = await ocean.assets.consume(
serviceAgreementSignatureResult.agreementId,
ddo.id,
accessService.serviceDefinitionId,
consumer,
folder,
1,
)
assert.include(path, folder, "The storage path is not correct.")
const files = await new Promise<string[]>((resolve) => {
fs.readdir(path, (err, fileList) => {
resolve(fileList)
})
})
assert.deepEqual(files, ["README.md"], "Stored files are not correct.")
assert.deepEqual(files, ['README.md'], 'Stored files are not correct.')
})
})

View File

@ -1,12 +1,12 @@
import { assert } from "chai"
import * as fs from "fs"
import { assert } from 'chai'
import * as fs from 'fs'
import { config } from "../config"
import { getMetadata } from "../utils"
import { config } from '../config'
import { getMetadata } from '../utils'
import { Ocean, Account, DDO } from "../../src" // @oceanprotocol/squid
import { Ocean, Account, DDO } from '../../src' // @oceanprotocol/squid
describe("Consume Asset (Brizo)", () => {
describe('Consume Asset (Brizo)', () => {
let ocean: Ocean
let publisher: Account
@ -28,50 +28,64 @@ describe("Consume Asset (Brizo)", () => {
after(() => {
try {
localStorage.clear()
} catch { }
} catch {}
})
it("should authenticate the accounts", async () => {
it('should authenticate the accounts', async () => {
await publisher.authenticate()
await consumer.authenticate()
})
it("should regiester an asset", async () => {
it('should regiester an asset', async () => {
const steps = []
ddo = await ocean.assets.create(metadata as any, publisher)
.next((step) => steps.push(step))
ddo = await ocean.assets
.create(metadata as any, publisher)
.next(step => steps.push(step))
assert.instanceOf(ddo, DDO)
assert.deepEqual(steps, [0, 1, 2, 3, 4, 5, 6, 7])
})
it("should order the asset", async () => {
const accessService = ddo.findServiceByType("Access")
it('should order the asset', async () => {
const accessService = ddo.findServiceByType('Access')
await consumer.requestTokens(+metadata.base.price * (10 ** -await ocean.keeper.token.decimals()))
await consumer.requestTokens(
+metadata.base.price * 10 ** -(await ocean.keeper.token.decimals())
)
const steps = []
agreementId = await ocean.assets.order(ddo.id, accessService.serviceDefinitionId, consumer)
.next((step) => steps.push(step))
agreementId = await ocean.assets
.order(ddo.id, accessService.serviceDefinitionId, consumer)
.next(step => steps.push(step))
assert.isDefined(agreementId)
assert.deepEqual(steps, [0, 1, 2, 3])
})
it("should consume and store the assets", async () => {
const accessService = ddo.findServiceByType("Access")
it('should consume and store the assets', async () => {
const accessService = ddo.findServiceByType('Access')
const folder = "/tmp/ocean/squid-js"
const path = await ocean.assets.consume(agreementId, ddo.id, accessService.serviceDefinitionId, consumer, folder)
const folder = '/tmp/ocean/squid-js'
const path = await ocean.assets.consume(
agreementId,
ddo.id,
accessService.serviceDefinitionId,
consumer,
folder
)
assert.include(path, folder, "The storage path is not correct.")
assert.include(path, folder, 'The storage path is not correct.')
const files = await new Promise<string[]>((resolve) => {
const files = await new Promise<string[]>(resolve => {
fs.readdir(path, (err, fileList) => {
resolve(fileList)
})
})
assert.deepEqual(files, ["README.md", "package.json"], "Stored files are not correct.")
assert.deepEqual(
files,
['README.md', 'package.json'],
'Stored files are not correct.'
)
})
})

View File

@ -1,13 +1,13 @@
import { assert } from "chai"
import * as fs from "fs"
import { assert } from 'chai'
import * as fs from 'fs'
import { config } from "../config"
import { getMetadata } from "../utils"
import { config } from '../config'
import { getMetadata } from '../utils'
import { Ocean, Account, DDO } from "../../src" // @oceanprotocol/squid
import { Ocean, Account, DDO } from '../../src' // @oceanprotocol/squid
// Ensure that your network is fast enought and you have some free ram before run it.
xdescribe("Consume Asset (Large size)", () => {
xdescribe('Consume Asset (Large size)', () => {
let ocean: Ocean
let publisher: Account
@ -21,10 +21,12 @@ xdescribe("Consume Asset (Large size)", () => {
...baseMetadata,
base: {
...baseMetadata.base,
files: [{
url: "https://speed.hetzner.de/1GB.bin",
}],
},
files: [
{
url: 'https://speed.hetzner.de/1GB.bin'
}
]
}
}
before(async () => {
@ -35,36 +37,46 @@ xdescribe("Consume Asset (Large size)", () => {
consumer = (await ocean.accounts.list())[1]
})
it("should regiester an asset", async () => {
it('should regiester an asset', async () => {
ddo = await ocean.assets.create(metadata as any, publisher)
assert.instanceOf(ddo, DDO)
})
it("should order the asset", async () => {
const accessService = ddo.findServiceByType("Access")
it('should order the asset', async () => {
const accessService = ddo.findServiceByType('Access')
await consumer.requestTokens(metadata.base.price)
agreementId = await ocean.assets.order(ddo.id, accessService.serviceDefinitionId, consumer)
agreementId = await ocean.assets.order(
ddo.id,
accessService.serviceDefinitionId,
consumer
)
assert.isDefined(agreementId)
})
it("should consume and store the assets", async () => {
const accessService = ddo.findServiceByType("Access")
it('should consume and store the assets', async () => {
const accessService = ddo.findServiceByType('Access')
const folder = "/tmp/ocean/squid-js"
const path = await ocean.assets.consume(agreementId, ddo.id, accessService.serviceDefinitionId, consumer, folder)
const folder = '/tmp/ocean/squid-js'
const path = await ocean.assets.consume(
agreementId,
ddo.id,
accessService.serviceDefinitionId,
consumer,
folder
)
assert.include(path, folder, "The storage path is not correct.")
assert.include(path, folder, 'The storage path is not correct.')
const files = await new Promise<string[]>((resolve) => {
const files = await new Promise<string[]>(resolve => {
fs.readdir(path, (err, fileList) => {
resolve(fileList)
})
})
assert.deepEqual(files, ["1GB.bin"], "Stored files are not correct.")
assert.deepEqual(files, ['1GB.bin'], 'Stored files are not correct.')
})
})

View File

@ -1,19 +1,23 @@
import { assert } from "chai"
import { assert } from 'chai'
import { config } from "../config"
import { config } from '../config'
import { Ocean, templates, conditions, utils, Account, Keeper } from "../../src" // @oceanprotocol/squid
import { Ocean, templates, conditions, utils, Account, Keeper } from '../../src' // @oceanprotocol/squid
const { LockRewardCondition, EscrowReward, AccessSecretStoreCondition } = conditions
const {
LockRewardCondition,
EscrowReward,
AccessSecretStoreCondition
} = conditions
describe("Register Escrow Access Secret Store Template", () => {
describe('Register Escrow Access Secret Store Template', () => {
let ocean: Ocean
let keeper: Keeper
let template: templates.EscrowAccessSecretStoreTemplate
const url = "https://example.com/did/ocean/test-attr-example.txt"
const checksum = "b".repeat(32)
const url = 'https://example.com/did/ocean/test-attr-example.txt'
const checksum = 'b'.repeat(32)
const escrowAmount = 12
let templateManagerOwner: Account
@ -36,26 +40,35 @@ describe("Register Escrow Access Secret Store Template", () => {
consumer = (await ocean.accounts.list())[2]
// Conditions
accessSecretStoreCondition = keeper.conditions.accessSecretStoreCondition
accessSecretStoreCondition =
keeper.conditions.accessSecretStoreCondition
lockRewardCondition = keeper.conditions.lockRewardCondition
escrowReward = keeper.conditions.escrowReward
})
describe("Propose and approve template", () => {
it("should propose the template", async () => {
await keeper.templateStoreManager.proposeTemplate(template.getAddress(), consumer.getId(), true)
describe('Propose and approve template', () => {
it('should propose the template', async () => {
await keeper.templateStoreManager.proposeTemplate(
template.getAddress(),
consumer.getId(),
true
)
// TODO: Use a event to detect template mined
await new Promise((_) => setTimeout(_, 2 * 1000))
await new Promise(_ => setTimeout(_, 2 * 1000))
})
it("should approve the template", async () => {
await keeper.templateStoreManager.approveTemplate(template.getAddress(), templateManagerOwner.getId(), true)
it('should approve the template', async () => {
await keeper.templateStoreManager.approveTemplate(
template.getAddress(),
templateManagerOwner.getId(),
true
)
// TODO: Use a event to detect template mined
await new Promise((_) => setTimeout(_, 2 * 1000))
await new Promise(_ => setTimeout(_, 2 * 1000))
})
})
describe("Full flow", () => {
describe('Full flow', () => {
const agreementId = `0x${utils.generateId()}`
const did = `0x${utils.generateId()}`
@ -63,49 +76,76 @@ describe("Register Escrow Access Secret Store Template", () => {
let conditionIdLock: string
let conditionIdEscrow: string
it("should register a DID", async () => {
await keeper.didRegistry.registerAttribute(did, checksum, [], url, publisher.getId())
it('should register a DID', async () => {
await keeper.didRegistry.registerAttribute(
did,
checksum,
[],
url,
publisher.getId()
)
})
it("should generate the condition IDs", async () => {
conditionIdAccess = await accessSecretStoreCondition.generateIdHash(agreementId, did, consumer.getId())
conditionIdLock = await lockRewardCondition.generateIdHash(agreementId, await escrowReward.getAddress(), escrowAmount)
it('should generate the condition IDs', async () => {
conditionIdAccess = await accessSecretStoreCondition.generateIdHash(
agreementId,
did,
consumer.getId()
)
conditionIdLock = await lockRewardCondition.generateIdHash(
agreementId,
await escrowReward.getAddress(),
escrowAmount
)
conditionIdEscrow = await escrowReward.generateIdHash(
agreementId,
escrowAmount,
publisher.getId(),
consumer.getId(),
conditionIdLock,
conditionIdAccess,
conditionIdAccess
)
})
it("should have conditions types", async () => {
it('should have conditions types', async () => {
const conditionTypes = await template.getConditionTypes()
assert.equal(conditionTypes.length, 3, "Expected 3 conditions.")
assert.equal(conditionTypes.length, 3, 'Expected 3 conditions.')
assert.deepEqual(
[...conditionTypes].sort(),
[accessSecretStoreCondition.getAddress(), escrowReward.getAddress(), lockRewardCondition.getAddress()].sort(),
"The conditions doesn't match",
[
accessSecretStoreCondition.getAddress(),
escrowReward.getAddress(),
lockRewardCondition.getAddress()
].sort(),
"The conditions doesn't match"
)
})
it("should have condition instances asociated", async () => {
it('should have condition instances asociated', async () => {
const conditionInstances = await template.getConditions()
assert.equal(conditionInstances.length, 3, "Expected 3 conditions.")
assert.equal(conditionInstances.length, 3, 'Expected 3 conditions.')
const conditionClasses = [AccessSecretStoreCondition, EscrowReward, LockRewardCondition]
conditionClasses
.forEach((conditionClass) => {
if (!conditionInstances.find((condition) => condition instanceof conditionClass)) {
throw new Error(`${conditionClass.name} is not part of the conditions.`)
}
})
const conditionClasses = [
AccessSecretStoreCondition,
EscrowReward,
LockRewardCondition
]
conditionClasses.forEach(conditionClass => {
if (
!conditionInstances.find(
condition => condition instanceof conditionClass
)
) {
throw new Error(
`${conditionClass.name} is not part of the conditions.`
)
}
})
})
it("should create a new agreement", async () => {
it('should create a new agreement', async () => {
const agreement = await template.createAgreement(
agreementId,
did,
@ -113,35 +153,52 @@ describe("Register Escrow Access Secret Store Template", () => {
[0, 0, 0],
[0, 0, 0],
consumer.getId(),
publisher.getId(),
publisher.getId()
)
assert.isTrue(agreement.status)
})
it("should not grant the access to the consumer", async () => {
const accessGranted = await accessSecretStoreCondition.checkPermissions(consumer.getId(), did)
it('should not grant the access to the consumer', async () => {
const accessGranted = await accessSecretStoreCondition.checkPermissions(
consumer.getId(),
did
)
assert.isFalse(accessGranted, "Consumer has been granted.")
assert.isFalse(accessGranted, 'Consumer has been granted.')
})
it("should fulfill LockRewardCondition", async () => {
it('should fulfill LockRewardCondition', async () => {
await consumer.requestTokens(escrowAmount)
await keeper.token.approve(lockRewardCondition.getAddress(), escrowAmount, consumer.getId())
await keeper.token.approve(
lockRewardCondition.getAddress(),
escrowAmount,
consumer.getId()
)
const fulfill = await lockRewardCondition.fulfill(agreementId, escrowReward.getAddress(), escrowAmount, consumer.getId())
const fulfill = await lockRewardCondition.fulfill(
agreementId,
escrowReward.getAddress(),
escrowAmount,
consumer.getId()
)
assert.isDefined(fulfill.events.Fulfilled, "Not Fulfilled event.")
assert.isDefined(fulfill.events.Fulfilled, 'Not Fulfilled event.')
})
it("should fulfill AccessSecretStoreCondition", async () => {
const fulfill = await accessSecretStoreCondition.fulfill(agreementId, did, consumer.getId(), publisher.getId())
it('should fulfill AccessSecretStoreCondition', async () => {
const fulfill = await accessSecretStoreCondition.fulfill(
agreementId,
did,
consumer.getId(),
publisher.getId()
)
assert.isDefined(fulfill.events.Fulfilled, "Not Fulfilled event.")
assert.isDefined(fulfill.events.Fulfilled, 'Not Fulfilled event.')
})
it("should fulfill EscrowReward", async () => {
it('should fulfill EscrowReward', async () => {
const fulfill = await escrowReward.fulfill(
agreementId,
escrowAmount,
@ -149,56 +206,92 @@ describe("Register Escrow Access Secret Store Template", () => {
consumer.getId(),
conditionIdLock,
conditionIdAccess,
consumer.getId(),
consumer.getId()
)
assert.isDefined(fulfill.events.Fulfilled, "Not Fulfilled event.")
assert.isDefined(fulfill.events.Fulfilled, 'Not Fulfilled event.')
})
it("should grant the access to the consumer", async () => {
const accessGranted = await accessSecretStoreCondition.checkPermissions(consumer.getId(), did)
it('should grant the access to the consumer', async () => {
const accessGranted = await accessSecretStoreCondition.checkPermissions(
consumer.getId(),
did
)
assert.isTrue(accessGranted, "Consumer has not been granted.")
assert.isTrue(accessGranted, 'Consumer has not been granted.')
})
})
describe("Short flow", () => {
describe('Short flow', () => {
const did = utils.generateId()
let agreementId
it("should register a DID", async () => {
it('should register a DID', async () => {
// This part is executed inside Ocean.assets.create()
await keeper.didRegistry.registerAttribute(did, checksum, [], url, publisher.getId())
await keeper.didRegistry.registerAttribute(
did,
checksum,
[],
url,
publisher.getId()
)
})
it("should create a new agreement (short way)", async () => {
agreementId = await template.createFullAgreement(did, escrowAmount, consumer.getId(), publisher.getId())
it('should create a new agreement (short way)', async () => {
agreementId = await template.createFullAgreement(
did,
escrowAmount,
consumer.getId(),
publisher.getId()
)
assert.match(agreementId, /^0x[a-f0-9]{64}$/i)
})
it("should not grant the access to the consumer", async () => {
const accessGranted = await accessSecretStoreCondition.checkPermissions(consumer.getId(), did)
it('should not grant the access to the consumer', async () => {
const accessGranted = await accessSecretStoreCondition.checkPermissions(
consumer.getId(),
did
)
assert.isFalse(accessGranted, "Consumer has been granted.")
assert.isFalse(accessGranted, 'Consumer has been granted.')
})
it("should fulfill the conditions from consumer side", async () => {
it('should fulfill the conditions from consumer side', async () => {
await consumer.requestTokens(escrowAmount)
await ocean.agreements.conditions.lockReward(agreementId, escrowAmount, consumer)
await ocean.agreements.conditions.lockReward(
agreementId,
escrowAmount,
consumer
)
})
it("should fulfill the conditions from publisher side", async () => {
await ocean.agreements.conditions.grantAccess(agreementId, did, consumer.getId(), publisher)
await ocean.agreements.conditions.releaseReward(agreementId, escrowAmount, did, consumer.getId(), publisher.getId(), publisher)
it('should fulfill the conditions from publisher side', async () => {
await ocean.agreements.conditions.grantAccess(
agreementId,
did,
consumer.getId(),
publisher
)
await ocean.agreements.conditions.releaseReward(
agreementId,
escrowAmount,
did,
consumer.getId(),
publisher.getId(),
publisher
)
})
it("should grant the access to the consumer", async () => {
const accessGranted = await accessSecretStoreCondition.checkPermissions(consumer.getId(), did)
it('should grant the access to the consumer', async () => {
const accessGranted = await accessSecretStoreCondition.checkPermissions(
consumer.getId(),
did
)
assert.isTrue(accessGranted, "Consumer has not been granted.")
assert.isTrue(accessGranted, 'Consumer has not been granted.')
})
})
})

View File

@ -1,18 +1,21 @@
import { assert } from "chai"
import { assert } from 'chai'
import { config } from "../config"
import { config } from '../config'
import { generateMetadata } from "../utils"
import { generateMetadata } from '../utils'
import { Ocean, Account, DDO } from "../../src" // @oceanprotocol/squid
import { Ocean, Account, DDO } from '../../src' // @oceanprotocol/squid
describe("Search Asset", () => {
describe('Search Asset', () => {
let ocean: Ocean
let publisher: Account
const testHash = Math.random().toString(36).substr(2)
const metadataGenerator = (name: string) => generateMetadata(`${name}${testHash}`)
const testHash = Math.random()
.toString(36)
.substr(2)
const metadataGenerator = (name: string) =>
generateMetadata(`${name}${testHash}`)
let test1length
let test2length
@ -26,56 +29,92 @@ describe("Search Asset", () => {
publisher.setPassword(process.env.ACCOUNT_PASSWORD)
})
it("should be able to search the assets", async () => {
const {results: ddos} = await ocean.assets.search(`Test1${testHash}`)
it('should be able to search the assets', async () => {
const { results: ddos } = await ocean.assets.search(`Test1${testHash}`)
assert.isArray(ddos, "A search should return an array")
assert.isArray(ddos, 'A search should return an array')
test1length = ddos.length
test2length = (await ocean.assets.search(`Test2${testHash}`)).results.length
test3length = (await ocean.assets.search(`Test3${testHash}`)).results.length
test2length = (await ocean.assets.search(`Test2${testHash}`)).results
.length
test3length = (await ocean.assets.search(`Test3${testHash}`)).results
.length
})
it("should regiester some a asset", async () => {
assert.instanceOf(await ocean.assets.create(metadataGenerator("Test1") as any, publisher), DDO)
assert.instanceOf(await ocean.assets.create(metadataGenerator("Test2") as any, publisher), DDO)
assert.instanceOf(await ocean.assets.create(metadataGenerator("Test2") as any, publisher), DDO)
assert.instanceOf(await ocean.assets.create(metadataGenerator("Test3") as any, publisher), DDO)
it('should regiester some a asset', async () => {
assert.instanceOf(
await ocean.assets.create(
metadataGenerator('Test1') as any,
publisher
),
DDO
)
assert.instanceOf(
await ocean.assets.create(
metadataGenerator('Test2') as any,
publisher
),
DDO
)
assert.instanceOf(
await ocean.assets.create(
metadataGenerator('Test2') as any,
publisher
),
DDO
)
assert.instanceOf(
await ocean.assets.create(
metadataGenerator('Test3') as any,
publisher
),
DDO
)
})
it("should search by text and see the increment of DDOs", async () => {
it('should search by text and see the increment of DDOs', async () => {
assert.equal(
(await ocean.assets.search(`Test2${testHash}`)).results.length - test2length,
(await ocean.assets.search(`Test2${testHash}`)).results.length -
test2length,
2,
"Something was wrong searching the assets",
'Something was wrong searching the assets'
)
assert.equal(
(await ocean.assets.search(`Test3${testHash}`)).results.length - test3length,
(await ocean.assets.search(`Test3${testHash}`)).results.length -
test3length,
1,
"Something was wrong searching the assets",
'Something was wrong searching the assets'
)
})
it("should return a list of DDOs", async () => {
const {results: ddos} = await ocean.assets.search(`Test1${testHash}`)
it('should return a list of DDOs', async () => {
const { results: ddos } = await ocean.assets.search(`Test1${testHash}`)
assert.equal(ddos.length - test1length, 1, "Something was wrong searching the assets")
ddos.map((ddo) => assert.instanceOf(ddo, DDO, "The DDO is not an instance of a DDO"))
assert.equal(
ddos.length - test1length,
1,
'Something was wrong searching the assets'
)
ddos.map(ddo =>
assert.instanceOf(ddo, DDO, 'The DDO is not an instance of a DDO')
)
})
it("should be able to do a query to get a list of DDOs", async () => {
const {results: ddos} = await ocean.assets.query({
it('should be able to do a query to get a list of DDOs', async () => {
const { results: ddos } = await ocean.assets.query({
page: 1,
offset: 1,
query: {
text: [`Test2${testHash}`],
text: [`Test2${testHash}`]
},
sort: {
text: 1,
},
text: 1
}
})
assert.equal(ddos.length, 1, "Something was wrong searching the assets")
ddos.map((ddo) => assert.instanceOf(ddo, DDO, "The DDO is not an instance of a DDO"))
assert.equal(ddos.length, 1, 'Something was wrong searching the assets')
ddos.map(ddo =>
assert.instanceOf(ddo, DDO, 'The DDO is not an instance of a DDO')
)
})
})

View File

@ -1,16 +1,16 @@
import { assert } from "chai"
import { assert } from 'chai'
import { config } from "../config"
import { config } from '../config'
import { Ocean, Account, DID } from "../../src" // @oceanprotocol/squid
import { Ocean, Account, DID } from '../../src' // @oceanprotocol/squid
describe("Secret Store", () => {
describe('Secret Store', () => {
let ocean: Ocean
let account: Account
const did: DID = DID.generate()
const content = {content: "Test 123"}
const content = { content: 'Test 123' }
let encryptedContent
before(async () => {
@ -20,8 +20,12 @@ describe("Secret Store", () => {
account = (await ocean.accounts.list())[0]
})
it("should encrypt a text", async () => {
encryptedContent = await ocean.secretStore.encrypt(did.getId(), content, account)
it('should encrypt a text', async () => {
encryptedContent = await ocean.secretStore.encrypt(
did.getId(),
content,
account
)
assert.isDefined(encryptedContent)
assert.match(encryptedContent, /^0x[a-f0-9]{76}$/i)

View File

@ -1,13 +1,12 @@
import { assert } from "chai"
import { assert } from 'chai'
import { config } from "../config"
import { config } from '../config'
import { Ocean, Account, DDO } from "../../src" // @oceanprotocol/squid
import { Ocean, Account, DDO } from '../../src' // @oceanprotocol/squid
// WARN: not integration test. It has been done here because constant values
// depends on the first account on spree (only accessible from integration test)
describe("Signature", () => {
describe('Signature', () => {
let ocean: Ocean
let consumer: Account
@ -18,32 +17,36 @@ describe("Signature", () => {
consumer = (await ocean.accounts.list())[0]
})
it("should generate the correct signature", async () => {
const templateId = `0x${"f".repeat(40)}`
const agreementId = `0x${"e".repeat(64)}`
it('should generate the correct signature', async () => {
const templateId = `0x${'f'.repeat(40)}`
const agreementId = `0x${'e'.repeat(64)}`
const accessId = `0x${"a".repeat(64)}`
const lockId = `0x${"b".repeat(64)}`
const escrowId = `0x${"c".repeat(64)}`
const accessId = `0x${'a'.repeat(64)}`
const lockId = `0x${'b'.repeat(64)}`
const escrowId = `0x${'c'.repeat(64)}`
const hash = await ocean.utils.agreements.hashServiceAgreement(
templateId,
agreementId,
[accessId, lockId, escrowId],
[0, 0, 0],
[0, 0, 0],
[0, 0, 0]
)
assert.equal(hash, "0x67901517c18a3d23e05806fff7f04235cc8ae3b1f82345b8bfb3e4b02b5800c7", "The signatuere is not correct.")
assert.equal(
hash,
'0x67901517c18a3d23e05806fff7f04235cc8ae3b1f82345b8bfb3e4b02b5800c7',
'The signatuere is not correct.'
)
})
it("should generate the correct signature", async () => {
const templates = ocean.keeper.templates
it('should generate the correct signature', async () => {
const { templates } = ocean.keeper
const did = `did:op:${"c".repeat(64)}`
const templateId = `0x${"f".repeat(40)}`
const agreementId = `0x${"e".repeat(64)}`
const serviceDefinitionId = "0"
const did = `did:op:${'c'.repeat(64)}`
const templateId = `0x${'f'.repeat(40)}`
const agreementId = `0x${'e'.repeat(64)}`
const serviceDefinitionId = '0'
const serviceAgreementTemplate = await templates.escrowAccessSecretStoreTemplate.getServiceAgreementTemplate()
@ -51,37 +54,41 @@ describe("Signature", () => {
id: did,
service: [
{
type: "Access",
type: 'Access',
purchaseEndpoint: undefined,
serviceEndpoint: undefined,
serviceDefinitionId,
templateId,
serviceAgreementTemplate,
serviceAgreementTemplate
} as any,
{
type: "Metadata",
type: 'Metadata',
metadata: {
base: {
price: 10,
},
},
} as any,
],
price: 10
}
}
} as any
]
})
const signature = await ocean.utils.agreements.signServiceAgreement(
ddo,
serviceDefinitionId,
agreementId,
[`0x${"1".repeat(64)}`, `0x${"2".repeat(64)}`, `0x${"3".repeat(64)}`],
consumer,
[
`0x${'1'.repeat(64)}`,
`0x${'2'.repeat(64)}`,
`0x${'3'.repeat(64)}`
],
consumer
)
assert.equal(
signature,
// tslint:disable-next-line
"0x3aa8a1c48b8e582d694bbd4ba3a29fde573b78da9720dc48baeb831b2163e1fa6e10e983882ebf8a00f4124de2505136354fd146934053f0d58bba4eced5f8d000",
"The signatuere is not correct.",
'0x3aa8a1c48b8e582d694bbd4ba3a29fde573b78da9720dc48baeb831b2163e1fa6e10e983882ebf8a00f4124de2505136354fd146934053f0d58bba4eced5f8d000',
'The signatuere is not correct.'
)
})
})

View File

@ -1,24 +1,27 @@
import { assert } from "chai"
import { assert } from 'chai'
import { config } from "../config"
import { config } from '../config'
import { Ocean, OceanPlatformTechStatus } from "../../src" // @oceanprotocol/squid
describe("Versions", () => {
import { Ocean, OceanPlatformTechStatus } from '../../src' // @oceanprotocol/squid
describe('Versions', () => {
let ocean: Ocean
before(async () => {
ocean = await Ocean.getInstance(config)
})
it("should returns the versions", async () => {
it('should returns the versions', async () => {
const versions = await ocean.versions.get()
assert.equal(versions.aquarius.status, OceanPlatformTechStatus.Working)
assert.equal(versions.brizo.status, OceanPlatformTechStatus.Working)
assert.equal(versions.squid.status, OceanPlatformTechStatus.Working)
assert.deepEqual(versions.status, {ok: true, contracts: true, network: true})
assert.deepEqual(versions.status, {
ok: true,
contracts: true,
network: true
})
})
})

View File

@ -1,11 +1,7 @@
{
"compilerOptions": {
"resolveJsonModule": true,
"lib": [
"es6",
"es7",
"dom"
],
"lib": ["es6", "es7", "dom"],
"noUnusedLocals": true
}
}

View File

@ -1,51 +1,55 @@
import { MetaData } from "../../src" // @oceanprotocol/squid
import { MetaData } from '../../src' // @oceanprotocol/squid
const metadata: Partial<MetaData> = {
base: {
name: undefined,
type: "dataset",
description: "Weather information of UK including temperature and humidity",
dateCreated: "2012-10-10T17:00:00Z",
datePublished: "2012-10-10T17:00:00Z",
author: "Met Office",
license: "CC-BY",
copyrightHolder: "Met Office",
workExample: "423432fsd,51.509865,-0.118092,2011-01-01T10:55:11+00:00,7.2,68",
type: 'dataset',
description:
'Weather information of UK including temperature and humidity',
dateCreated: '2012-10-10T17:00:00Z',
datePublished: '2012-10-10T17:00:00Z',
author: 'Met Office',
license: 'CC-BY',
copyrightHolder: 'Met Office',
workExample:
'423432fsd,51.509865,-0.118092,2011-01-01T10:55:11+00:00,7.2,68',
links: [
{
name: "Sample of Asset Data",
type: "sample",
url: "https://foo.com/sample.csv",
name: 'Sample of Asset Data',
type: 'sample',
url: 'https://foo.com/sample.csv'
},
{
name: "Data Format Definition",
type: "format",
url: "https://foo.com/sample.csv",
},
name: 'Data Format Definition',
type: 'format',
url: 'https://foo.com/sample.csv'
}
],
inLanguage: "en",
categories: ["Economy", "Data Science"],
tags: ["weather", "uk", "2011", "temperature", "humidity"],
price: "21" + "0".repeat(18),
inLanguage: 'en',
categories: ['Economy', 'Data Science'],
tags: ['weather', 'uk', '2011', 'temperature', 'humidity'],
price: '21' + '0'.repeat(18),
files: [
{
index: 0,
url: "https://raw.githubusercontent.com/oceanprotocol/squid-js/develop/package.json",
url:
'https://raw.githubusercontent.com/oceanprotocol/squid-js/develop/package.json'
},
{
index: 1,
url: "https://raw.githubusercontent.com/oceanprotocol/squid-js/develop/README.md",
},
],
},
url:
'https://raw.githubusercontent.com/oceanprotocol/squid-js/develop/README.md'
}
]
}
}
export const generateMetadata = (name: string): Partial<MetaData> => ({
...metadata,
base: {
...metadata.base,
name,
},
name
}
})
export const getMetadata = () => generateMetadata("TestAsset")
export const getMetadata = () => generateMetadata('TestAsset')

View File

@ -1 +1 @@
export * from "./ddo-metadata-generator"
export * from './ddo-metadata-generator'

View File

@ -1,14 +1,19 @@
#!/usr/bin/env node
'use strict';
'use strict'
const packageInfo = require('../package.json');
const packageInfo = require('../package.json')
const execSync = require('child_process').execSync;
const execSync = require('child_process').execSync
process.stdout.write(
JSON
.stringify({
version: require('../package.json').version,
commit: execSync(`git rev-parse HEAD`).toString().trim(),
}, null, ' ')
);
JSON.stringify(
{
version: require('../package.json').version,
commit: execSync(`git rev-parse HEAD`)
.toString()
.trim()
},
null,
' '
)
)

View File

@ -1,8 +1,8 @@
import * as Web3 from "web3"
import Config from "./models/Config"
import { Logger, LoggerInstance, LogLevel } from "./utils"
import Web3Provider from "./keeper/Web3Provider"
import { Ocean } from "./ocean/Ocean"
import * as Web3 from 'web3'
import Config from './models/Config'
import { Logger, LoggerInstance, LogLevel } from './utils'
import Web3Provider from './keeper/Web3Provider'
import { Ocean } from './ocean/Ocean'
export interface InstantiableConfig {
ocean: Ocean
@ -11,30 +11,34 @@ export interface InstantiableConfig {
logger?: Logger
}
export function generateIntantiableConfigFromConfig(config: Config): Partial<InstantiableConfig> {
const logLevel = typeof config.verbose !== "number"
? (config.verbose ? LogLevel.Log : LogLevel.None)
: config.verbose as LogLevel
export function generateIntantiableConfigFromConfig(
config: Config
): Partial<InstantiableConfig> {
const logLevel =
typeof config.verbose !== 'number'
? config.verbose
? LogLevel.Log
: LogLevel.None
: (config.verbose as LogLevel)
return {
config,
web3: Web3Provider.getWeb3(config),
logger: new Logger(logLevel),
logger: new Logger(logLevel)
}
}
export abstract class Instantiable {
protected get ocean() {
if (!this._ocean) {
this.logger.error("Ocean instance is not defined.")
this.logger.error('Ocean instance is not defined.')
}
return this._ocean
}
protected get web3() {
if (!this._web3) {
this.logger.error("Web3 instance is not defined.")
this.logger.error("Using default instance.")
this.logger.error('Web3 instance is not defined.')
this.logger.error('Using default instance.')
return Web3Provider.getWeb3()
}
return this._web3
@ -42,31 +46,36 @@ export abstract class Instantiable {
protected get config() {
if (!this._config) {
this.logger.error("Config instance is not defined.")
this.logger.error('Config instance is not defined.')
}
return this._config
}
protected get logger() {
if (!this._logger) {
LoggerInstance.error("Logger instance is not defined.")
LoggerInstance.error("Using default instance.")
LoggerInstance.error('Logger instance is not defined.')
LoggerInstance.error('Using default instance.')
return LoggerInstance
}
return this._logger
}
protected get instanceConfig(): InstantiableConfig {
const {ocean, web3, config, logger} = this
return {ocean, web3, config, logger}
const { ocean, web3, config, logger } = this
return { ocean, web3, config, logger }
}
public static async getInstance(...args: any[]): Promise<any>
public static async getInstance(config: InstantiableConfig): Promise<any> {
LoggerInstance.warn("getInstance() methods has needs to be added to child class.")
LoggerInstance.warn(
'getInstance() methods has needs to be added to child class.'
)
}
protected static setInstanceConfig<T extends Instantiable>(instance: T, {ocean, config, web3, logger}: InstantiableConfig) {
protected static setInstanceConfig<T extends Instantiable>(
instance: T,
{ ocean, config, web3, logger }: InstantiableConfig
) {
instance._ocean = ocean
instance._config = config
instance._web3 = web3

View File

@ -1,9 +1,9 @@
import { URL } from "whatwg-url"
import { DDO } from "../ddo/DDO"
import DID from "../ocean/DID"
import { Instantiable, InstantiableConfig } from "../Instantiable.abstract"
import { URL } from 'whatwg-url'
import { DDO } from '../ddo/DDO'
import DID from '../ocean/DID'
import { Instantiable, InstantiableConfig } from '../Instantiable.abstract'
const apiPath = "/api/v1/aquarius/assets/ddo"
const apiPath = '/api/v1/aquarius/assets/ddo'
export interface QueryResult {
results: DDO[]
@ -16,8 +16,8 @@ export interface SearchQuery {
text?: string
offset?: number
page?: number
query: {[property: string]: string | number | string[] | number[]}
sort?: {[jsonPath: string]: number}
query: { [property: string]: string | number | string[] | number[] }
sort?: { [jsonPath: string]: number }
}
/**
@ -40,20 +40,33 @@ export class Aquarius extends Instantiable {
public async getAccessUrl(accessToken: any, payload: any): Promise<string> {
const accessUrl: string = await this.ocean.utils.fetch
.post(`${accessToken.service_endpoint}/${accessToken.resource_id}`, payload)
.post(
`${accessToken.service_endpoint}/${accessToken.resource_id}`,
payload
)
.then((response: any): string => {
if (response.ok) {
return response.text()
}
this.logger.error("Failed: ", response.status, response.statusText)
this.logger.error(
'Failed: ',
response.status,
response.statusText
)
return null
})
.then((consumptionUrl: string): string => {
this.logger.error("Success accessing consume endpoint: ", consumptionUrl)
this.logger.error(
'Success accessing consume endpoint: ',
consumptionUrl
)
return consumptionUrl
})
.catch((error) => {
this.logger.error("Error fetching the data asset consumption url: ", error)
.catch(error => {
this.logger.error(
'Error fetching the data asset consumption url: ',
error
)
return null
})
@ -72,14 +85,18 @@ export class Aquarius extends Instantiable {
if (response.ok) {
return response.json() as DDO[]
}
this.logger.error("queryMetadata failed:", response.status, response.statusText)
this.logger.error(
'queryMetadata failed:',
response.status,
response.statusText
)
return this.transformResult()
})
.then((results) => {
.then(results => {
return this.transformResult(results)
})
.catch((error) => {
this.logger.error("Error fetching querying metadata: ", error)
.catch(error => {
this.logger.error('Error fetching querying metadata: ', error)
return this.transformResult()
})
@ -93,24 +110,34 @@ export class Aquarius extends Instantiable {
*/
public async queryMetadataByText(query: SearchQuery): Promise<QueryResult> {
const fullUrl = new URL(`${this.url}${apiPath}/query`)
fullUrl.searchParams.append("text", query.text)
fullUrl.searchParams.append("sort", decodeURIComponent(JSON.stringify(query.sort)))
fullUrl.searchParams.append("offset", query.offset.toString())
fullUrl.searchParams.append("page", query.page.toString())
fullUrl.searchParams.append('text', query.text)
fullUrl.searchParams.append(
'sort',
decodeURIComponent(JSON.stringify(query.sort))
)
fullUrl.searchParams.append('offset', query.offset.toString())
fullUrl.searchParams.append('page', query.page.toString())
const result: QueryResult = await this.ocean.utils.fetch
.get(fullUrl)
.then((response: any) => {
if (response.ok) {
return response.json() as DDO[]
}
this.logger.log("queryMetadataByText failed:", response.status, response.statusText)
this.logger.log(
'queryMetadataByText failed:',
response.status,
response.statusText
)
return this.transformResult()
})
.then((results) => {
.then(results => {
return this.transformResult(results)
})
.catch((error) => {
this.logger.error("Error fetching querying metadata by text: ", error)
.catch(error => {
this.logger.error(
'Error fetching querying metadata by text: ',
error
)
return this.transformResult()
})
@ -130,14 +157,19 @@ export class Aquarius extends Instantiable {
if (response.ok) {
return response.json()
}
this.logger.error("storeDDO failed:", response.status, response.statusText, ddo)
this.logger.error(
'storeDDO failed:',
response.status,
response.statusText,
ddo
)
return null as DDO
})
.then((response: DDO) => {
return new DDO(response) as DDO
})
.catch((error) => {
this.logger.error("Error fetching querying metadata: ", error)
.catch(error => {
this.logger.error('Error fetching querying metadata: ', error)
return null as DDO
})
@ -157,14 +189,19 @@ export class Aquarius extends Instantiable {
if (response.ok) {
return response.json()
}
this.logger.log("retrieveDDO failed:", response.status, response.statusText, did)
this.logger.log(
'retrieveDDO failed:',
response.status,
response.statusText,
did
)
return null as DDO
})
.then((response: DDO) => {
return new DDO(response) as DDO
})
.catch((error) => {
this.logger.error("Error fetching querying metadata: ", error)
.catch(error => {
this.logger.error('Error fetching querying metadata: ', error)
return null as DDO
})
@ -176,14 +213,18 @@ export class Aquarius extends Instantiable {
}
private transformResult(
{results, page, total_pages, total_results}: any = {result: [], page: 0, total_pages: 0, total_results: 0},
{ results, page, total_pages, total_results }: any = {
result: [],
page: 0,
total_pages: 0,
total_results: 0
}
): QueryResult {
return {
results: (results || []).map((ddo) => new DDO(ddo as DDO)),
results: (results || []).map(ddo => new DDO(ddo as DDO)),
page,
totalPages: total_pages,
totalResults: total_results,
totalResults: total_results
}
}
}

View File

@ -1,18 +1,18 @@
import * as fs from "fs"
import save = require("save-file")
import * as fs from 'fs'
import { File } from "../ddo/MetaData"
import Account from "../ocean/Account"
import { noZeroX } from "../utils"
import { Instantiable, InstantiableConfig } from "../Instantiable.abstract"
import { File } from '../ddo/MetaData'
import Account from '../ocean/Account'
import { noZeroX } from '../utils'
import { Instantiable, InstantiableConfig } from '../Instantiable.abstract'
import save = require('save-file')
const apiPath = "/api/v1/brizo/services"
const apiPath = '/api/v1/brizo/services'
/**
* Provides a interface with Brizo.
* Brizo is the technical component executed by the Publishers allowing to them to provide extended data services.
*/
export class Brizo extends Instantiable {
export class Brizo extends Instantiable {
private get url() {
return this.config.brizoUri
}
@ -38,7 +38,12 @@ export class Brizo extends Instantiable {
return `${this.url}${apiPath}/publish`
}
public getComputeEndpoint(pubKey: string, serviceId: string, algo: string, container: string) {
public getComputeEndpoint(
pubKey: string,
serviceId: string,
algo: string,
container: string
) {
// tslint:disable-next-line
return `${this.url}${apiPath}/compute`
}
@ -48,26 +53,24 @@ export class Brizo extends Instantiable {
serviceAgreementId: string,
serviceDefinitionId: string,
signature: string,
consumerAddress: string,
consumerAddress: string
): Promise<any> {
const args = {
did,
serviceAgreementId,
serviceDefinitionId,
signature,
consumerAddress,
consumerAddress
}
try {
return await this.ocean.utils.fetch
.post(
this.getPurchaseEndpoint(),
decodeURI(JSON.stringify(args)),
)
return await this.ocean.utils.fetch.post(
this.getPurchaseEndpoint(),
decodeURI(JSON.stringify(args))
)
} catch (e) {
this.logger.error(e)
throw new Error("HTTP request failed")
throw new Error('HTTP request failed')
}
}
@ -77,12 +80,17 @@ export class Brizo extends Instantiable {
account: Account,
files: File[],
destination: string,
index: number = -1,
index: number = -1
): Promise<string> {
const signature = await account.getToken() || await this.ocean.utils.signature.signText(noZeroX(agreementId), account.getId())
const signature =
(await account.getToken()) ||
(await this.ocean.utils.signature.signText(
noZeroX(agreementId),
account.getId()
))
const filesPromises = files
.filter(({}, i) => index === -1 || i === index)
.map(async ({index: i}) => {
.map(async ({ index: i }) => {
let consumeUrl = serviceEndpoint
consumeUrl += `?index=${i}`
consumeUrl += `&serviceAgreementId=${noZeroX(agreementId)}`
@ -90,12 +98,9 @@ export class Brizo extends Instantiable {
consumeUrl += `&signature=${signature}`
try {
await this.downloadFile(
consumeUrl,
destination,
)
await this.downloadFile(consumeUrl, destination)
} catch (e) {
this.logger.error("Error consuming assets")
this.logger.error('Error consuming assets')
this.logger.error(e)
throw e
}
@ -108,52 +113,56 @@ export class Brizo extends Instantiable {
did: string,
signature: string,
document: any,
publisher: string,
publisher: string
): Promise<string> {
const args = {
documentId: did,
signature,
document: JSON.stringify(document),
publisherAddress: publisher,
publisherAddress: publisher
}
try {
const response = await this.ocean.utils.fetch
.post(
this.getEncryptEndpoint(),
decodeURI(JSON.stringify(args)),
)
const response = await this.ocean.utils.fetch.post(
this.getEncryptEndpoint(),
decodeURI(JSON.stringify(args))
)
if (!response.ok) {
throw new Error("HTTP request failed")
throw new Error('HTTP request failed')
}
return await response.text()
} catch (e) {
this.logger.error(e)
throw new Error("HTTP request failed")
throw new Error('HTTP request failed')
}
}
private async downloadFile(url: string, destination?: string): Promise<string> {
const response = await this.ocean.utils.fetch
.get(url)
private async downloadFile(
url: string,
destination?: string
): Promise<string> {
const response = await this.ocean.utils.fetch.get(url)
if (!response.ok) {
throw new Error("Response error.")
throw new Error('Response error.')
}
let filename
try {
filename = response.headers.get("content-disposition").match(/attachment;filename=(.+)/)[1]
filename = response.headers
.get('content-disposition')
.match(/attachment;filename=(.+)/)[1]
} catch {
throw new Error("Response is not containing file name.")
throw new Error('Response is not containing file name.')
}
if (destination) {
await new Promise(async (resolve, reject) => {
fs.mkdirSync(destination, {recursive: true})
const fileStream = fs.createWriteStream(`${destination}${filename}`)
fs.mkdirSync(destination, { recursive: true })
const fileStream = fs.createWriteStream(
`${destination}${filename}`
)
response.body.pipe(fileStream)
response.body.on("error", reject)
fileStream.on("finish", resolve)
response.body.on('error', reject)
fileStream.on('finish', resolve)
})
return destination

View File

@ -1,18 +1,17 @@
import * as Web3 from "web3"
import Web3Provider from "../keeper/Web3Provider"
import LoggerInstance from "../utils/Logger"
import { Ocean } from "../ocean/Ocean"
import { Authentication } from "./Authentication"
import { Proof } from "./Proof"
import { PublicKey } from "./PublicKey"
import { Service, ServiceType } from "./Service"
import * as Web3 from 'web3'
import Web3Provider from '../keeper/Web3Provider'
import LoggerInstance from '../utils/Logger'
import { Ocean } from '../ocean/Ocean'
import { Authentication } from './Authentication'
import { Proof } from './Proof'
import { PublicKey } from './PublicKey'
import { Service, ServiceType } from './Service'
/**
* DID Descriptor Object.
* Contains all the data related to an asset.
*/
export class DDO {
/**
* Serializes the DDO object.
* @param {DDO} DDO to be serialized.
@ -33,7 +32,7 @@ export class DDO {
return new DDO(ddo)
}
public "@context": string = "https://w3id.org/did/v1"
public '@context': string = 'https://w3id.org/did/v1'
/**
* DID, descentralized ID.
@ -48,12 +47,14 @@ export class DDO {
public constructor(ddo: Partial<DDO> = {}) {
Object.assign(this, ddo, {
created: (ddo && ddo.created) || new Date().toISOString().replace(/\.[0-9]{3}/, ""),
created:
(ddo && ddo.created) ||
new Date().toISOString().replace(/\.[0-9]{3}/, '')
})
}
public shortId(): string {
return this.id.replace("did:op:", "")
return this.id.replace('did:op:', '')
}
/**
@ -61,12 +62,16 @@ export class DDO {
* @param {string} serviceDefinitionId Service ID.
* @return {Service} Service.
*/
public findServiceById<T extends ServiceType>(serviceDefinitionId: string): Service<T> {
public findServiceById<T extends ServiceType>(
serviceDefinitionId: string
): Service<T> {
if (!serviceDefinitionId) {
throw new Error("serviceDefinitionId not set")
throw new Error('serviceDefinitionId not set')
}
const service = this.service.find((s) => s.serviceDefinitionId === serviceDefinitionId)
const service = this.service.find(
s => s.serviceDefinitionId === serviceDefinitionId
)
return service as Service<T>
}
@ -76,12 +81,14 @@ export class DDO {
* @param {string} serviceType Service type.
* @return {Service} Service.
*/
public findServiceByType<T extends ServiceType>(serviceType: T): Service<T> {
public findServiceByType<T extends ServiceType>(
serviceType: T
): Service<T> {
if (!serviceType) {
throw new Error("serviceType not set")
throw new Error('serviceType not set')
}
return this.service.find((s) => s.type === serviceType) as Service<T>
return this.service.find(s => s.type === serviceType) as Service<T>
}
/**
@ -89,20 +96,20 @@ export class DDO {
* @return {string[]} DDO checksum.
*/
public getChecksum(): string {
const {metadata} = this.findServiceByType("Metadata")
const {files, name, author, license} = metadata.base
const { metadata } = this.findServiceByType('Metadata')
const { files, name, author, license } = metadata.base
const values = [
...(files || [])
.map(({checksum}) => checksum)
.filter((_) => !!_),
...(files || []).map(({ checksum }) => checksum).filter(_ => !!_),
name,
author,
license,
this.id,
this.id
]
return Web3Provider.getWeb3().utils.sha3(values.join("")).replace(/^0x([a-f0-9]{64})(:!.+)?$/i, "0x$1")
return Web3Provider.getWeb3()
.utils.sha3(values.join(''))
.replace(/^0x([a-f0-9]{64})(:!.+)?$/i, '0x$1')
}
/**
@ -112,16 +119,24 @@ export class DDO {
* @param {string} password Password if it's requirted.
* @return {Promise<Proof>} Proof object.
*/
public async generateProof(ocean: Ocean, publicKey: string, password?: string): Promise<Proof> {
public async generateProof(
ocean: Ocean,
publicKey: string,
password?: string
): Promise<Proof> {
const checksum = this.getChecksum()
const signature = await ocean.utils.signature.signText(checksum, publicKey, password)
const signature = await ocean.utils.signature.signText(
checksum,
publicKey,
password
)
return {
created: new Date().toISOString().replace(/\.[0-9]{3}/, ""),
created: new Date().toISOString().replace(/\.[0-9]{3}/, ''),
creator: publicKey,
type: "DDOIntegritySignature",
signatureValue: signature,
type: 'DDOIntegritySignature',
signatureValue: signature
}
}
@ -129,9 +144,9 @@ export class DDO {
* Generated and adds the checksum.
*/
public addChecksum(): void {
const metadataService = this.findServiceByType("Metadata")
const metadataService = this.findServiceByType('Metadata')
if (metadataService.metadata.base.checksum) {
LoggerInstance.log("Checksum already exists")
LoggerInstance.log('Checksum already exists')
return
}
metadataService.metadata.base.checksum = this.getChecksum()
@ -144,9 +159,13 @@ export class DDO {
* @param {string} password Password if it's requirted.
* @return {Promise<Proof>} Proof object.
*/
public async addProof(web3: Web3, publicKey: string, password?: string): Promise<void> {
public async addProof(
web3: Web3,
publicKey: string,
password?: string
): Promise<void> {
if (this.proof) {
throw new Error("Proof already exists")
throw new Error('Proof already exists')
}
this.proof = await this.generateProof(web3, publicKey, password)
}

View File

@ -62,7 +62,6 @@ export interface File {
* @see https://github.com/oceanprotocol/OEPs/tree/master/8#base-attributes
*/
export interface MetaDataBase {
/**
* Descriptive name of the Asset.
* @type {string}
@ -76,7 +75,7 @@ export interface MetaDataBase {
* @type {string}
* @example "dataset"
*/
type: "dataset" | "algorithm" | "container" | "workflow" | "other"
type: 'dataset' | 'algorithm' | 'container' | 'workflow' | 'other'
/**
* Details of what the resource is. For a dataset, this attribute
@ -150,7 +149,7 @@ export interface MetaDataBase {
* },
* ]
*/
links?: Array<{[name: string]: string}>
links?: Array<{ [name: string]: string }>
/**
* The language of the content. Please use one of the language
@ -244,7 +243,7 @@ export interface AdditionalInformation {
*/
structuredMarkup: Array<{
uri: string
mediaType: string,
mediaType: string
}>
/**

View File

@ -13,7 +13,11 @@ export interface PublicKey {
* Type of key.
* @type {string}
*/
type: "Ed25519VerificationKey2018" | "RsaVerificationKey2018" | "EdDsaSAPublicKeySecp256k1" | "EthereumECDSAKey"
type:
| 'Ed25519VerificationKey2018'
| 'RsaVerificationKey2018'
| 'EdDsaSAPublicKeySecp256k1'
| 'EthereumECDSAKey'
/**
* Key owner.

View File

@ -1,7 +1,12 @@
import { MetaData } from "./MetaData"
import { ServiceAgreementTemplate } from "./ServiceAgreementTemplate"
import { MetaData } from './MetaData'
import { ServiceAgreementTemplate } from './ServiceAgreementTemplate'
export type ServiceType = "Authorization" | "Metadata" | "Access" | "Compute" | "FitchainCompute"
export type ServiceType =
| 'Authorization'
| 'Metadata'
| 'Access'
| 'Compute'
| 'FitchainCompute'
export interface ServiceCommon {
type: ServiceType
@ -10,18 +15,18 @@ export interface ServiceCommon {
}
export interface ServiceAuthorization extends ServiceCommon {
type: "Authorization"
service: "SecretStore" | "None" | "RSAES-OAEP"
type: 'Authorization'
service: 'SecretStore' | 'None' | 'RSAES-OAEP'
}
export interface ServiceMetadata extends ServiceCommon {
type: "Metadata"
type: 'Metadata'
metadata: MetaData
}
export interface ServiceAccess extends ServiceCommon {
type: "Access"
name?: string,
type: 'Access'
name?: string
description?: string
creator?: string
templateId?: string
@ -33,10 +38,16 @@ export interface ServiceCompute extends ServiceCommon {
templateId?: string
}
export type Service<T extends ServiceType | "default" = "default"> =
T extends "Authorization" ? ServiceAuthorization :
T extends "Metadata" ? ServiceMetadata :
T extends "Access" ? ServiceAccess :
T extends "Compute" ? ServiceCompute :
T extends "default" ? ServiceCommon :
ServiceCommon
export type Service<
T extends ServiceType | 'default' = 'default'
> = T extends 'Authorization'
? ServiceAuthorization
: T extends 'Metadata'
? ServiceMetadata
: T extends 'Access'
? ServiceAccess
: T extends 'Compute'
? ServiceCompute
: T extends 'default'
? ServiceCommon
: ServiceCommon

View File

@ -10,7 +10,7 @@ export interface ServiceAgreementTemplateEvent {
handler: {
moduleName: string
functionName: string
version: string,
version: string
}
}
@ -28,6 +28,6 @@ export interface ServiceAgreementTemplate {
contractName: string
events: ServiceAgreementTemplateEvent[]
fulfillmentOrder: string[]
conditionDependency: {[condition: string]: string[]}
conditionDependency: { [condition: string]: string[] }
conditions: ServiceAgreementTemplateCondition[]
}

View File

@ -1 +1 @@
export * from "./squid"
export * from './squid'

View File

@ -1,4 +1,4 @@
import ContractBase from "./contracts/ContractBase"
import ContractBase from './contracts/ContractBase'
interface EventEmitter {
// tslint:disable-next-line
@ -16,15 +16,17 @@ export class ContractEvent {
private eventEmitter: EventEmitter,
private contract: ContractBase,
private eventName: string,
private filter: {[key: string]: any},
) { }
private filter: { [key: string]: any }
) {}
public subscribe(callback: (events: any[]) => void): ContractEventSubscription {
const onEvent = async (blockNumber) => {
public subscribe(
callback: (events: any[]) => void
): ContractEventSubscription {
const onEvent = async blockNumber => {
const events = await this.contract.getEventData(this.eventName, {
filter: this.filter,
fromBlock: blockNumber,
toBlock: "latest",
toBlock: 'latest'
})
if (events.length) {
callback(events)
@ -33,13 +35,13 @@ export class ContractEvent {
this.eventEmitter.subscribe(onEvent)
return {
unsubscribe: () => this.eventEmitter.unsubscribe(onEvent),
unsubscribe: () => this.eventEmitter.unsubscribe(onEvent)
}
}
public once(callback?: (events: any[]) => void) {
return new Promise((resolve) => {
const subscription = this.subscribe((events) => {
return new Promise(resolve => {
const subscription = this.subscribe(events => {
subscription.unsubscribe()
if (callback) {
callback(events)

View File

@ -1,21 +1,30 @@
import { Contract } from "web3-eth-contract"
import { Instantiable, InstantiableConfig } from "../Instantiable.abstract"
import { Contract } from 'web3-eth-contract'
import { Instantiable, InstantiableConfig } from '../Instantiable.abstract'
export default class ContractHandler extends Instantiable {
protected static getContract(what: string, networkId: number) {
return ContractHandler.contracts.get(this.getHash(what, networkId))
}
protected static setContract(what: string, networkId: number, contractInstance: Contract) {
ContractHandler.contracts.set(this.getHash(what, networkId), contractInstance)
protected static setContract(
what: string,
networkId: number,
contractInstance: Contract
) {
ContractHandler.contracts.set(
this.getHash(what, networkId),
contractInstance
)
}
protected static hasContract(what: string, networkId: number): boolean {
return ContractHandler.contracts.has(this.getHash(what, networkId))
}
private static contracts: Map<string, Contract> = new Map<string, Contract>()
private static contracts: Map<string, Contract> = new Map<
string,
Contract
>()
private static getHash(what: string, networkId: number): string {
return `${what}/#${networkId}`
@ -30,25 +39,44 @@ export default class ContractHandler extends Instantiable {
const where = (await this.ocean.keeper.getNetworkName()).toLowerCase()
const networkId = await this.ocean.keeper.getNetworkId()
try {
return ContractHandler.getContract(what, networkId) || await this.load(what, where, networkId)
return (
ContractHandler.getContract(what, networkId) ||
(await this.load(what, where, networkId))
)
} catch (err) {
this.logger.error("Failed to load", what, "from", where, err)
this.logger.error('Failed to load', what, 'from', where, err)
throw err
}
}
private async load(what: string, where: string, networkId: number): Promise<Contract> {
this.logger.debug("Loading", what, "from", where)
private async load(
what: string,
where: string,
networkId: number
): Promise<Contract> {
this.logger.debug('Loading', what, 'from', where)
const artifact = require(`@oceanprotocol/keeper-contracts/artifacts/${what}.${where}.json`)
// Logger.log('Loaded artifact', artifact)
const code = await this.web3.eth.getCode(artifact.address)
if (code === "0x0") {
if (code === '0x0') {
// no code in the blockchain dude
throw new Error(`No code deployed at address ${artifact.address}, sorry.`)
throw new Error(
`No code deployed at address ${artifact.address}, sorry.`
)
}
const contract = new this.web3.eth.Contract(artifact.abi, artifact.address)
const contract = new this.web3.eth.Contract(
artifact.abi,
artifact.address
)
this.logger.debug("Getting instance of", what, "from", where, "at address", artifact.address)
this.logger.debug(
'Getting instance of',
what,
'from',
where,
'at address',
artifact.address
)
ContractHandler.setContract(what, networkId, contract)
return ContractHandler.getContract(what, networkId)
}

View File

@ -1,10 +1,9 @@
import { ContractEvent } from "./ContractEvent"
import ContractBase from "./contracts/ContractBase"
import { ContractEvent } from './ContractEvent'
import ContractBase from './contracts/ContractBase'
import { Instantiable, InstantiableConfig } from "../Instantiable.abstract"
import { Instantiable, InstantiableConfig } from '../Instantiable.abstract'
export class EventHandler extends Instantiable {
get count() {
return this.events.size
}
@ -24,7 +23,7 @@ export class EventHandler extends Instantiable {
this.checkBlock()
return {
unsubscribe: () => this.unsubscribe(callback),
unsubscribe: () => this.unsubscribe(callback)
}
}
@ -37,7 +36,11 @@ export class EventHandler extends Instantiable {
}
}
public getEvent(contract: ContractBase, eventName: string, filter: {[key: string]: any}) {
public getEvent(
contract: ContractBase,
eventName: string,
filter: { [key: string]: any }
) {
return new ContractEvent(this, contract, eventName, filter)
}
@ -54,9 +57,12 @@ export class EventHandler extends Instantiable {
}
if (this.lastBlock !== blockNumber) {
this.events.forEach((fn) => fn(this.lastBlock + 1))
this.events.forEach(fn => fn(this.lastBlock + 1))
this.lastBlock = blockNumber
}
this.lastTimeout = global.setTimeout(() => this.checkBlock(true, n++), this.interval)
this.lastTimeout = global.setTimeout(
() => this.checkBlock(true, n++),
this.interval
)
}
}

View File

@ -1,16 +1,28 @@
import { ContractBase } from "./contracts/ContractBase"
import { ContractBase } from './contracts/ContractBase'
import DIDRegistry from "./contracts/DIDRegistry"
import Dispenser from "./contracts/Dispenser"
import OceanToken from "./contracts/Token"
import { Condition, LockRewardCondition, EscrowReward, AccessSecretStoreCondition } from "./contracts/conditions"
import { AgreementTemplate, EscrowAccessSecretStoreTemplate } from "./contracts/templates"
import { TemplateStoreManager, AgreementStoreManager, ConditionStoreManager } from "./contracts/managers"
import DIDRegistry from './contracts/DIDRegistry'
import Dispenser from './contracts/Dispenser'
import OceanToken from './contracts/Token'
import {
Condition,
LockRewardCondition,
EscrowReward,
AccessSecretStoreCondition
} from './contracts/conditions'
import {
AgreementTemplate,
EscrowAccessSecretStoreTemplate
} from './contracts/templates'
import {
TemplateStoreManager,
AgreementStoreManager,
ConditionStoreManager
} from './contracts/managers'
import { objectPromiseAll } from "../utils"
import { EventHandler } from "./EventHandler"
import { objectPromiseAll } from '../utils'
import { EventHandler } from './EventHandler'
import { Instantiable, InstantiableConfig } from "../Instantiable.abstract"
import { Instantiable, InstantiableConfig } from '../Instantiable.abstract'
/**
* Interface with Ocean Keeper contracts.
@ -20,12 +32,13 @@ import { Instantiable, InstantiableConfig } from "../Instantiable.abstract"
* - Marketplace: the core marketplace where people can transact with each other with Ocean tokens.
*/
export class Keeper extends Instantiable {
/**
* Returns Keeper instance.
* @return {Promise<Keeper>}
*/
public static async getInstance(config: InstantiableConfig): Promise<Keeper> {
public static async getInstance(
config: InstantiableConfig
): Promise<Keeper> {
const keeper = new Keeper()
keeper.setInstanceConfig(config)
@ -41,14 +54,22 @@ export class Keeper extends Instantiable {
didRegistry: DIDRegistry.getInstance(config),
// Managers
templateStoreManager: TemplateStoreManager.getInstance(config),
agreementStoreManager: AgreementStoreManager.getInstance(config),
conditionStoreManager: ConditionStoreManager.getInstance(config),
agreementStoreManager: AgreementStoreManager.getInstance(
config
),
conditionStoreManager: ConditionStoreManager.getInstance(
config
),
// Conditions
lockRewardCondition: LockRewardCondition.getInstance(config),
escrowReward: EscrowReward.getInstance(config),
accessSecretStoreCondition: AccessSecretStoreCondition.getInstance(config),
accessSecretStoreCondition: AccessSecretStoreCondition.getInstance(
config
),
// Templates
escrowAccessSecretStoreTemplate: EscrowAccessSecretStoreTemplate.getInstance(config),
escrowAccessSecretStoreTemplate: EscrowAccessSecretStoreTemplate.getInstance(
config
)
})
keeper.connected = true
@ -69,16 +90,18 @@ export class Keeper extends Instantiable {
keeper.conditions = {
lockRewardCondition: keeper.instances.lockRewardCondition,
escrowReward: keeper.instances.escrowReward,
accessSecretStoreCondition: keeper.instances.accessSecretStoreCondition,
accessSecretStoreCondition:
keeper.instances.accessSecretStoreCondition
}
// Conditions
keeper.templates = {
escrowAccessSecretStoreTemplate: keeper.instances.escrowAccessSecretStoreTemplate,
escrowAccessSecretStoreTemplate:
keeper.instances.escrowAccessSecretStoreTemplate
}
// Utils
keeper.utils = {
eventHandler: new EventHandler(config),
eventHandler: new EventHandler(config)
}
return keeper
@ -130,26 +153,26 @@ export class Keeper extends Instantiable {
* Conditions instances.
*/
public conditions: {
lockRewardCondition: LockRewardCondition,
escrowReward: EscrowReward,
accessSecretStoreCondition: AccessSecretStoreCondition,
lockRewardCondition: LockRewardCondition
escrowReward: EscrowReward
accessSecretStoreCondition: AccessSecretStoreCondition
}
/**
* Templates instances.
*/
public templates: {
escrowAccessSecretStoreTemplate: EscrowAccessSecretStoreTemplate,
escrowAccessSecretStoreTemplate: EscrowAccessSecretStoreTemplate
}
/**
* Helpers for contracts.
*/
public utils: {
eventHandler: EventHandler,
eventHandler: EventHandler
}
private instances: {[contractRef: string]: ContractBase & any}
private instances: { [contractRef: string]: ContractBase & any }
/**
* Returns a condition by address.
@ -157,8 +180,9 @@ export class Keeper extends Instantiable {
* @return {Condition} Condition instance.
*/
public getConditionByAddress(address: string): Condition {
return Object.values(this.conditions)
.find((condition) => condition.getAddress() === address)
return Object.values(this.conditions).find(
condition => condition.getAddress() === address
)
}
/**
@ -167,8 +191,9 @@ export class Keeper extends Instantiable {
* @return {AgreementTemplate} Agreement template instance.
*/
public getTemplateByName(name: string): AgreementTemplate {
return Object.values(this.templates)
.find((template) => template.contractName === name)
return Object.values(this.templates).find(
template => template.contractName === name
)
}
/**
@ -177,8 +202,9 @@ export class Keeper extends Instantiable {
* @return {AgreementTemplate} Agreement template instance.
*/
public getTemplateByAddress(address: string): AgreementTemplate {
return Object.values(this.templates)
.find((template) => template.getAddress() === address)
return Object.values(this.templates).find(
template => template.getAddress() === address
)
}
/**
@ -194,22 +220,32 @@ export class Keeper extends Instantiable {
* @return {Promise<string>} Network name.
*/
public getNetworkName(): Promise<string> {
return this.web3.eth.net.getId()
.then((networkId) => {
switch (networkId) {
case 1: return "Main"
case 2: return "Morden"
case 3: return "Ropsten"
case 4: return "Rinkeby"
case 77: return "POA_Sokol"
case 99: return "POA_Core"
case 42: return "Kovan"
case 2199: return "Duero"
case 8996: return "Spree"
case 8995: return "Nile"
default: return "Development"
}
})
return this.web3.eth.net.getId().then(networkId => {
switch (networkId) {
case 1:
return 'Main'
case 2:
return 'Morden'
case 3:
return 'Ropsten'
case 4:
return 'Rinkeby'
case 77:
return 'POA_Sokol'
case 99:
return 'POA_Core'
case 42:
return 'Kovan'
case 2199:
return 'Duero'
case 8996:
return 'Spree'
case 8995:
return 'Nile'
default:
return 'Development'
}
})
}
public getAllInstances() {

View File

@ -1,17 +1,16 @@
import * as Web3 from "web3"
import Config from "../models/Config"
import * as Web3 from 'web3'
import Config from '../models/Config'
export default class Web3Provider {
/**
* Returns Web3 instance.
* @return {Web3}
*/
public static getWeb3(config: Partial<Config> = {}): Web3 {
return new Web3(
config.web3Provider
|| Web3.givenProvider
|| new Web3.providers.HttpProvider(config.nodeUri),
config.web3Provider ||
Web3.givenProvider ||
new Web3.providers.HttpProvider(config.nodeUri)
)
}
}

View File

@ -1,11 +1,10 @@
import { Contract } from "web3-eth-contract"
import { TransactionReceipt } from "web3-core"
import ContractHandler from "../ContractHandler"
import { Contract } from 'web3-eth-contract'
import { TransactionReceipt } from 'web3-core'
import ContractHandler from '../ContractHandler'
import { Instantiable, InstantiableConfig } from "../../Instantiable.abstract"
import { Instantiable, InstantiableConfig } from '../../Instantiable.abstract'
export abstract class ContractBase extends Instantiable {
protected static instance = null
public contractName: string
@ -22,16 +21,18 @@ export abstract class ContractBase extends Instantiable {
public async getEventData(eventName: string, options: any) {
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)
}
public getPastEvents(eventName: string, filter: {[key: string]: any}) {
public getPastEvents(eventName: string, filter: { [key: string]: any }) {
return this.getEventData(eventName, {
filter,
fromBlock: 0,
toBlock: "latest",
toBlock: 'latest'
})
}
@ -62,72 +63,110 @@ export abstract class ContractBase extends Instantiable {
return from
}
protected async sendFrom(name: string, args: any[], from?: string): Promise<TransactionReceipt> {
protected async sendFrom(
name: string,
args: any[],
from?: string
): Promise<TransactionReceipt> {
from = await this.getFromAddress(from)
return this.send(name, from, args)
}
protected async send(name: string, from: string, args: any[]): Promise<TransactionReceipt> {
protected async send(
name: string,
from: string,
args: any[]
): Promise<TransactionReceipt> {
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}"`
)
}
// Logger.log(name, args)
const method = this.contract.methods[name]
try {
const methodInstance = method(...args)
const estimatedGas = await methodInstance.estimateGas(args, {
from,
from
})
const tx = methodInstance.send({
from,
gas: estimatedGas,
gas: estimatedGas
})
return tx
} catch (err) {
const mappedArgs = this.searchMethod(name, args).inputs.map((input, i) => {
return {
name: input.name,
value: args[i],
const mappedArgs = this.searchMethod(name, args).inputs.map(
(input, i) => {
return {
name: input.name,
value: args[i]
}
}
})
this.logger.error("-".repeat(40))
this.logger.error(`Sending transaction "${name}" on contract "${this.contractName}" failed.`)
)
this.logger.error('-'.repeat(40))
this.logger.error(
`Sending transaction "${name}" on contract "${this.contractName}" failed.`
)
this.logger.error(`Error: ${err.message}`)
this.logger.error(`From: ${from}`)
this.logger.error(`Parameters: ${JSON.stringify(mappedArgs, null, 2)}`)
this.logger.error("-".repeat(40))
this.logger.error(
`Parameters: ${JSON.stringify(mappedArgs, null, 2)}`
)
this.logger.error('-'.repeat(40))
throw err
}
}
protected async call<T extends any>(name: string, args: any[], from?: string): Promise<T> {
protected async call<T extends any>(
name: string,
args: any[],
from?: string
): Promise<T> {
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}`
)
}
// Logger.log(name)
try {
const method = this.contract.methods[name](...args)
return method.call(from ? {from} : null)
return method.call(from ? { from } : null)
} catch (err) {
this.logger.error(`Calling method "${name}" on contract "${this.contractName}" failed. Args: ${args}`, err)
this.logger.error(
`Calling method "${name}" on contract "${this.contractName}" failed. Args: ${args}`,
err
)
throw err
}
}
protected getEvent(eventName: string, filter: {[key: string]: any}) {
protected getEvent(eventName: string, filter: { [key: string]: any }) {
if (!this.contract.events[eventName]) {
throw new Error(`Event ${eventName} is not part of contract ${this.contractName}`)
throw new Error(
`Event ${eventName} is not part of contract ${this.contractName}`
)
}
return this.ocean.keeper.utils.eventHandler.getEvent(this, eventName, filter)
return this.ocean.keeper.utils.eventHandler.getEvent(
this,
eventName,
filter
)
}
private searchMethod(methodName: string, args: any[] = []) {
const methods = this.contract.options.jsonInterface
.map((method) => ({...method, signature: (method as any).signature}))
.map(method => ({
...method,
signature: (method as any).signature
}))
.filter((method: any) => method.name === methodName)
const foundMethod = methods.find(({inputs}) => inputs.length === args.length) || methods[0]
const foundMethod =
methods.find(({ inputs }) => inputs.length === args.length) ||
methods[0]
if (!foundMethod) {
throw new Error(`Method "${methodName}" is not part of contract "${this.contractName}"`)
throw new Error(
`Method "${methodName}" is not part of contract "${this.contractName}"`
)
}
return foundMethod
}

View File

@ -1,35 +1,45 @@
import Web3Provider from "../Web3Provider"
import ContractBase from "./ContractBase"
import { zeroX, didPrefixed } from "../../utils"
import { InstantiableConfig } from "../../Instantiable.abstract"
import Web3Provider from '../Web3Provider'
import ContractBase from './ContractBase'
import { zeroX, didPrefixed } from '../../utils'
import { InstantiableConfig } from '../../Instantiable.abstract'
export default class DIDRegistry extends ContractBase {
public static async getInstance(config: InstantiableConfig): Promise<DIDRegistry> {
const didRegistry: DIDRegistry = new DIDRegistry("DIDRegistry")
public static async getInstance(
config: InstantiableConfig
): Promise<DIDRegistry> {
const didRegistry: DIDRegistry = new DIDRegistry('DIDRegistry')
await didRegistry.init(config)
return didRegistry
}
public async registerAttribute(did: string, checksum: string, providers: string[], value: string, ownerAddress: string) {
return this.send(
"registerAttribute",
ownerAddress,
[zeroX(did), zeroX(checksum), providers.map(zeroX), value],
)
public async registerAttribute(
did: string,
checksum: string,
providers: string[],
value: string,
ownerAddress: string
) {
return this.send('registerAttribute', ownerAddress, [
zeroX(did),
zeroX(checksum),
providers.map(zeroX),
value
])
}
public async getDIDOwner(did: string): Promise<string> {
return this.call("getDIDOwner", [zeroX(did)])
return this.call('getDIDOwner', [zeroX(did)])
}
public async getBlockNumberUpdated(did: string): Promise<number> {
return +await this.call("getBlockNumberUpdated", [zeroX(did)])
return +(await this.call('getBlockNumberUpdated', [zeroX(did)]))
}
public async getAttributesByOwner(owner: string): Promise<string[]> {
return (await this.getPastEvents("DIDAttributeRegistered", {_owner: zeroX(owner)}))
.map(({returnValues}) => returnValues._did)
return (await this.getPastEvents('DIDAttributeRegistered', {
_owner: zeroX(owner)
}))
.map(({ returnValues }) => returnValues._did)
.map(didPrefixed)
}
}

View File

@ -1,15 +1,19 @@
import ContractBase from "./ContractBase"
import { InstantiableConfig } from "../../Instantiable.abstract"
import ContractBase from './ContractBase'
import { InstantiableConfig } from '../../Instantiable.abstract'
export default class Dispenser extends ContractBase {
public static async getInstance(config: InstantiableConfig): Promise<Dispenser> {
const dispenser: Dispenser = new Dispenser("Dispenser")
public static async getInstance(
config: InstantiableConfig
): Promise<Dispenser> {
const dispenser: Dispenser = new Dispenser('Dispenser')
await dispenser.init(config)
return dispenser
}
public async requestTokens(amount: number | string, receiverAddress: string) {
return this.send("requestTokens", receiverAddress, [String(amount)])
public async requestTokens(
amount: number | string,
receiverAddress: string
) {
return this.send('requestTokens', receiverAddress, [String(amount)])
}
}

View File

@ -1,9 +1,11 @@
import ContractBase from "./ContractBase"
import { InstantiableConfig } from "../../Instantiable.abstract"
import ContractBase from './ContractBase'
import { InstantiableConfig } from '../../Instantiable.abstract'
export default class GenericContract extends ContractBase {
public static async getInstance(config: InstantiableConfig, contractName: string): Promise<ContractBase> {
public static async getInstance(
config: InstantiableConfig,
contractName: string
): Promise<ContractBase> {
const contract: GenericContract = new GenericContract(contractName)
await contract.init(config)
return contract

View File

@ -1,29 +1,31 @@
import BigNumber from "bignumber.js"
import ContractBase from "./ContractBase"
import { InstantiableConfig } from "../../Instantiable.abstract"
import BigNumber from 'bignumber.js'
import ContractBase from './ContractBase'
import { InstantiableConfig } from '../../Instantiable.abstract'
export default class OceanToken extends ContractBase {
public static async getInstance(config: InstantiableConfig): Promise<OceanToken> {
const token: OceanToken = new OceanToken("OceanToken")
public static async getInstance(
config: InstantiableConfig
): Promise<OceanToken> {
const token: OceanToken = new OceanToken('OceanToken')
await token.init(config)
return token
}
public async approve(to: string, price: number | string, from?: string) {
return this.sendFrom("approve", [to, String(price)], from)
return this.sendFrom('approve', [to, String(price)], from)
}
public async decimals(): Promise<number> {
return this.call("decimals", [])
return this.call('decimals', [])
}
public async balanceOf(address: string): Promise<number> {
return this.call("balanceOf", [address])
.then((balance: string) => new BigNumber(balance).toNumber())
return this.call('balanceOf', [address]).then((balance: string) =>
new BigNumber(balance).toNumber()
)
}
public async transfer(to: string, amount: number, from: string) {
return this.send("transfer", from, [to, amount])
return this.send('transfer', from, [to, amount])
}
}

View File

@ -1,30 +1,51 @@
import { Condition } from "./Condition.abstract"
import { zeroX, didZeroX, didPrefixed } from "../../../utils"
import { InstantiableConfig } from "../../../Instantiable.abstract"
import { Condition } from './Condition.abstract'
import { zeroX, didZeroX, didPrefixed } from '../../../utils'
import { InstantiableConfig } from '../../../Instantiable.abstract'
export class AccessSecretStoreCondition extends Condition {
public static async getInstance(config: InstantiableConfig): Promise<AccessSecretStoreCondition> {
return Condition.getInstance(config, "AccessSecretStoreCondition", AccessSecretStoreCondition)
public static async getInstance(
config: InstantiableConfig
): Promise<AccessSecretStoreCondition> {
return Condition.getInstance(
config,
'AccessSecretStoreCondition',
AccessSecretStoreCondition
)
}
public hashValues(did: string, grantee: string) {
return super.hashValues(didZeroX(did), zeroX(grantee))
}
public fulfill(agreementId: string, did: string, grantee: string, from?: string) {
return super.fulfill(agreementId, [didZeroX(did), grantee].map(zeroX), from)
public fulfill(
agreementId: string,
did: string,
grantee: string,
from?: string
) {
return super.fulfill(
agreementId,
[didZeroX(did), grantee].map(zeroX),
from
)
}
public checkPermissions(grantee: string, did: string, from?: string) {
return this.call<boolean>("checkPermissions", [grantee, didZeroX(did)].map(zeroX), from)
return this.call<boolean>(
'checkPermissions',
[grantee, didZeroX(did)].map(zeroX),
from
)
}
public async getGrantedDidByConsumer(consumer: string): Promise<Array<{did: string, agreementId: string}>> {
return (await this.getPastEvents("Fulfilled", {_grantee: zeroX(consumer)}))
.map(({returnValues}) => ({
did: didPrefixed(returnValues._documentId),
agreementId: zeroX(returnValues._agreementId),
}))
public async getGrantedDidByConsumer(
consumer: string
): Promise<Array<{ did: string; agreementId: string }>> {
return (await this.getPastEvents('Fulfilled', {
_grantee: zeroX(consumer)
})).map(({ returnValues }) => ({
did: didPrefixed(returnValues._documentId),
agreementId: zeroX(returnValues._agreementId)
}))
}
}

View File

@ -1,19 +1,27 @@
import ContractBase from "../ContractBase"
import { zeroX } from "../../../utils"
import { InstantiableConfig } from "../../../Instantiable.abstract"
import ContractBase from '../ContractBase'
import { zeroX } from '../../../utils'
import { InstantiableConfig } from '../../../Instantiable.abstract'
export enum ConditionState {
Uninitialized = 0,
Unfulfilled = 1,
Fulfilled = 2,
Aborted = 3,
Aborted = 3
}
export const conditionStateNames = ["Uninitialized", "Unfulfilled", "Fulfilled", "Aborted"]
export const conditionStateNames = [
'Uninitialized',
'Unfulfilled',
'Fulfilled',
'Aborted'
]
export abstract class Condition extends ContractBase {
public static async getInstance(config: InstantiableConfig, conditionName: string, conditionsClass: any): Promise<Condition & any> {
public static async getInstance(
config: InstantiableConfig,
conditionName: string,
conditionsClass: any
): Promise<Condition & any> {
const condition: Condition = new (conditionsClass as any)(conditionName)
await condition.init(config)
return condition
@ -24,12 +32,12 @@ export abstract class Condition extends ContractBase {
}
public hashValues(...args: any[]): Promise<string> {
return this.call("hashValues", args)
return this.call('hashValues', args)
}
public fulfill(agreementId: string, ...args: any[])
public fulfill(agreementId: string, args: any[], from?: string) {
return this.sendFrom("fulfill", [zeroX(agreementId), ...args], from)
return this.sendFrom('fulfill', [zeroX(agreementId), ...args], from)
}
public async generateIdHash(agreementId: string, ...values: any[]) {
@ -37,14 +45,14 @@ export abstract class Condition extends ContractBase {
}
public generateId(agreementId: string, valueHash: string) {
return this.call<string>("generateId", [zeroX(agreementId), valueHash])
return this.call<string>('generateId', [zeroX(agreementId), valueHash])
}
public abortByTimeOut(agreementId: string, from?: string) {
return this.sendFrom("abortByTimeOut", [zeroX(agreementId)], from)
return this.sendFrom('abortByTimeOut', [zeroX(agreementId)], from)
}
public getConditionFulfilledEvent(agreementId: string) {
return this.getEvent("Fulfilled", {agreementId: zeroX(agreementId)})
return this.getEvent('Fulfilled', { agreementId: zeroX(agreementId) })
}
}

View File

@ -1,15 +1,25 @@
import { Condition } from "./Condition.abstract"
import { zeroX } from "../../../utils"
import { InstantiableConfig } from "../../../Instantiable.abstract"
import { Condition } from './Condition.abstract'
import { zeroX } from '../../../utils'
import { InstantiableConfig } from '../../../Instantiable.abstract'
export class EscrowReward extends Condition {
public static async getInstance(config: InstantiableConfig): Promise<EscrowReward> {
return Condition.getInstance(config, "EscrowReward", EscrowReward)
public static async getInstance(
config: InstantiableConfig
): Promise<EscrowReward> {
return Condition.getInstance(config, 'EscrowReward', EscrowReward)
}
public hashValues(amount: number, receiver: string, sender: string, lockCondition: string, releaseCondition: string) {
return super.hashValues(amount, ...[receiver, sender, lockCondition, releaseCondition].map(zeroX))
public hashValues(
amount: number,
receiver: string,
sender: string,
lockCondition: string,
releaseCondition: string
) {
return super.hashValues(
amount,
...[receiver, sender, lockCondition, releaseCondition].map(zeroX)
)
}
public fulfill(
@ -19,8 +29,17 @@ export class EscrowReward extends Condition {
sender: string,
lockCondition: string,
releaseCondition: string,
from?: string,
from?: string
) {
return super.fulfill(agreementId, [amount, ...[receiver, sender, lockCondition, releaseCondition].map(zeroX)], from)
return super.fulfill(
agreementId,
[
amount,
...[receiver, sender, lockCondition, releaseCondition].map(
zeroX
)
],
from
)
}
}

View File

@ -1,18 +1,32 @@
import { Condition } from "./Condition.abstract"
import { zeroX } from "../../../utils"
import { InstantiableConfig } from "../../../Instantiable.abstract"
import { Condition } from './Condition.abstract'
import { zeroX } from '../../../utils'
import { InstantiableConfig } from '../../../Instantiable.abstract'
export class LockRewardCondition extends Condition {
public static async getInstance(config: InstantiableConfig): Promise<LockRewardCondition> {
return Condition.getInstance(config, "LockRewardCondition", LockRewardCondition)
public static async getInstance(
config: InstantiableConfig
): Promise<LockRewardCondition> {
return Condition.getInstance(
config,
'LockRewardCondition',
LockRewardCondition
)
}
public hashValues(rewardAddress: string, amount: number | string) {
return super.hashValues(zeroX(rewardAddress), String(amount))
}
public fulfill(agreementId: string, rewardAddress: string, amount: number | string, from?: string) {
return super.fulfill(agreementId, [zeroX(rewardAddress), String(amount)], from)
public fulfill(
agreementId: string,
rewardAddress: string,
amount: number | string,
from?: string
) {
return super.fulfill(
agreementId,
[zeroX(rewardAddress), String(amount)],
from
)
}
}

View File

@ -1,4 +1,4 @@
export * from "./Condition.abstract"
export { AccessSecretStoreCondition } from "./AccessSecretStoreCondition"
export { EscrowReward } from "./EscrowReward"
export { LockRewardCondition } from "./LockRewardCondition"
export * from './Condition.abstract'
export { AccessSecretStoreCondition } from './AccessSecretStoreCondition'
export { EscrowReward } from './EscrowReward'
export { LockRewardCondition } from './LockRewardCondition'

View File

@ -1,6 +1,6 @@
import ContractBase from "../ContractBase"
import { zeroX } from "../../../utils"
import { InstantiableConfig } from "../../../Instantiable.abstract"
import ContractBase from '../ContractBase'
import { zeroX } from '../../../utils'
import { InstantiableConfig } from '../../../Instantiable.abstract'
export interface AgreementData {
did: string
@ -12,20 +12,36 @@ export interface AgreementData {
}
export class AgreementStoreManager extends ContractBase {
public static async getInstance(config: InstantiableConfig): Promise<AgreementStoreManager> {
const templateStoreManeger: AgreementStoreManager = new AgreementStoreManager("AgreementStoreManager")
public static async getInstance(
config: InstantiableConfig
): Promise<AgreementStoreManager> {
const templateStoreManeger: AgreementStoreManager = new AgreementStoreManager(
'AgreementStoreManager'
)
await templateStoreManeger.init(config)
return templateStoreManeger
}
public getOwner(): Promise<string> {
return this.call("owner", [])
return this.call('owner', [])
}
public async getAgreement(agreementId: string) {
const {did, didOwner, templateId, conditionIds, lastUpdatedBy, blockNumberUpdated} =
await this.call("getAgreement", [zeroX(agreementId)])
return {did, didOwner, templateId, conditionIds, lastUpdatedBy, blockNumberUpdated: +blockNumberUpdated} as AgreementData
const {
did,
didOwner,
templateId,
conditionIds,
lastUpdatedBy,
blockNumberUpdated
} = await this.call('getAgreement', [zeroX(agreementId)])
return {
did,
didOwner,
templateId,
conditionIds,
lastUpdatedBy,
blockNumberUpdated: +blockNumberUpdated
} as AgreementData
}
}

View File

@ -1,7 +1,7 @@
import ContractBase from "../ContractBase"
import { ConditionState } from "../conditions/Condition.abstract"
import { zeroX } from "../../../utils"
import { InstantiableConfig } from "../../../Instantiable.abstract"
import ContractBase from '../ContractBase'
import { ConditionState } from '../conditions/Condition.abstract'
import { zeroX } from '../../../utils'
import { InstantiableConfig } from '../../../Instantiable.abstract'
export interface ConditionData {
typeRef: string
@ -14,20 +14,30 @@ export interface ConditionData {
}
export class ConditionStoreManager extends ContractBase {
public static async getInstance(config: InstantiableConfig): Promise<ConditionStoreManager> {
const templateStoreManeger: ConditionStoreManager = new ConditionStoreManager("ConditionStoreManager")
public static async getInstance(
config: InstantiableConfig
): Promise<ConditionStoreManager> {
const templateStoreManeger: ConditionStoreManager = new ConditionStoreManager(
'ConditionStoreManager'
)
await templateStoreManeger.init(config)
return templateStoreManeger
}
public getOwner(): Promise<string> {
return this.call("owner", [])
return this.call('owner', [])
}
public async getCondition(conditionId: string) {
const {typeRef, state, timeLock, timeOut, blockNumber, lastUpdatedBy, blockNumberUpdated} =
await this.call("getCondition", [zeroX(conditionId)])
const {
typeRef,
state,
timeLock,
timeOut,
blockNumber,
lastUpdatedBy,
blockNumberUpdated
} = await this.call('getCondition', [zeroX(conditionId)])
return {
typeRef,
state: +state,
@ -35,7 +45,7 @@ export class ConditionStoreManager extends ContractBase {
timeOut: +timeOut,
blockNumber: +blockNumber,
lastUpdatedBy,
blockNumberUpdated: +blockNumberUpdated,
blockNumberUpdated: +blockNumberUpdated
} as ConditionData
}
}

View File

@ -1,63 +1,86 @@
import ContractBase from "../ContractBase"
import { zeroX } from "../../../utils"
import { InstantiableConfig } from "../../../Instantiable.abstract"
import ContractBase from '../ContractBase'
import { zeroX } from '../../../utils'
import { InstantiableConfig } from '../../../Instantiable.abstract'
export enum TemplateState {
Uninitialized = 0,
Proposed = 1,
Approved = 2,
Revoked = 3,
Revoked = 3
}
export interface TemplateMetadata {
state: TemplateState,
owner: string,
lastUpdatedBy: string,
blockNumberUpdated: number
state: TemplateState
owner: string
lastUpdatedBy: string
blockNumberUpdated: number
}
export class TemplateStoreManager extends ContractBase {
public static async getInstance(config: InstantiableConfig): Promise<TemplateStoreManager> {
const templateStoreManeger: TemplateStoreManager = new TemplateStoreManager("TemplateStoreManager")
public static async getInstance(
config: InstantiableConfig
): Promise<TemplateStoreManager> {
const templateStoreManeger: TemplateStoreManager = new TemplateStoreManager(
'TemplateStoreManager'
)
await templateStoreManeger.init(config)
return templateStoreManeger
}
public getOwner(): Promise<string> {
return this.call("owner", [])
return this.call('owner', [])
}
public async proposeTemplate(address: string, from?: string, ignoreExists?: boolean) {
public async proposeTemplate(
address: string,
from?: string,
ignoreExists?: boolean
) {
const template = await this.getTemplate(address)
if (template.blockNumberUpdated !== 0) {
this.logger.warn(`Template "${address}" already exist.`)
if (!ignoreExists) {
throw new Error("Template already exist.")
throw new Error('Template already exist.')
}
} else {
return this.sendFrom("proposeTemplate", [zeroX(address)], from)
return this.sendFrom('proposeTemplate', [zeroX(address)], from)
}
}
public async approveTemplate(address: string, from?: string, ignoreApproved?: boolean) {
public async approveTemplate(
address: string,
from?: string,
ignoreApproved?: boolean
) {
const template = await this.getTemplate(address)
if (template.state !== TemplateState.Proposed) {
this.logger.warn(`Template "${address}" is not in "proposed" state.`)
this.logger.warn(
`Template "${address}" is not in "proposed" state.`
)
if (!ignoreApproved) {
throw new Error(`Template not in "proposed" state.`)
}
} else {
return this.sendFrom("approveTemplate", [zeroX(address)], from)
return this.sendFrom('approveTemplate', [zeroX(address)], from)
}
}
public revokeTemplate(address: string, from?: string) {
return this.sendFrom("revokeTemplate", [zeroX(address)], from)
return this.sendFrom('revokeTemplate', [zeroX(address)], from)
}
public async getTemplate(address: string) {
const {state, owner, lastUpdatedBy, blockNumberUpdated} = await this.call("getTemplate", [zeroX(address)])
return {state: +state, owner, lastUpdatedBy, blockNumberUpdated: +blockNumberUpdated} as TemplateMetadata
const {
state,
owner,
lastUpdatedBy,
blockNumberUpdated
} = await this.call('getTemplate', [zeroX(address)])
return {
state: +state,
owner,
lastUpdatedBy,
blockNumberUpdated: +blockNumberUpdated
} as TemplateMetadata
}
}

View File

@ -1,3 +1,3 @@
export * from "./AgreementStoreManager"
export * from "./ConditionStoreManager"
export * from "./TemplateStoreManager"
export * from './AgreementStoreManager'
export * from './ConditionStoreManager'
export * from './TemplateStoreManager'

View File

@ -1,28 +1,33 @@
import ContractBase from "../ContractBase"
import { Condition, ConditionState, conditionStateNames } from "../conditions/Condition.abstract"
import { DDO } from "../../../ddo/DDO"
import { ServiceAgreementTemplate } from "../../../ddo/ServiceAgreementTemplate"
import { zeroX } from "../../../utils"
import { InstantiableConfig } from "../../../Instantiable.abstract"
import ContractBase from '../ContractBase'
import {
Condition,
ConditionState,
conditionStateNames
} from '../conditions/Condition.abstract'
import { DDO } from '../../../ddo/DDO'
import { ServiceAgreementTemplate } from '../../../ddo/ServiceAgreementTemplate'
import { zeroX } from '../../../utils'
import { InstantiableConfig } from '../../../Instantiable.abstract'
export interface AgreementConditionsStatus {
[condition: string]: {
condition: string,
contractName: string,
state: ConditionState,
blocked: boolean,
blockedBy: string[],
},
condition: string
contractName: string
state: ConditionState
blocked: boolean
blockedBy: string[]
}
}
export abstract class AgreementTemplate extends ContractBase {
public static async getInstance(
config: InstantiableConfig,
conditionName: string,
templateClass: any,
templateClass: any
): Promise<AgreementTemplate & any> {
const condition: AgreementTemplate = new (templateClass as any)(conditionName)
const condition: AgreementTemplate = new (templateClass as any)(
conditionName
)
await condition.init(config)
return condition
}
@ -32,7 +37,14 @@ export abstract class AgreementTemplate extends ContractBase {
}
// tslint:disable-next-line
public createAgreement(agreementId: string, did: string, conditionIds: string[], timeLocks: number[], timeOuts: number[], ...args: any[])
public createAgreement(
agreementId: string,
did: string,
conditionIds: string[],
timeLocks: number[],
timeOuts: number[],
...args: any[]
)
public createAgreement(
agreementId: string,
did: string,
@ -40,19 +52,19 @@ export abstract class AgreementTemplate extends ContractBase {
timeLocks: number[],
timeOuts: number[],
extraArgs: any[],
from?: string,
from?: string
) {
return this.sendFrom(
"createAgreement",
'createAgreement',
[
zeroX(agreementId),
zeroX(did),
conditionIds.map(zeroX),
timeLocks,
timeOuts,
...extraArgs,
...extraArgs
],
from,
from
)
}
@ -61,7 +73,7 @@ export abstract class AgreementTemplate extends ContractBase {
* @return {Promise<string[]>} Conditions address.
*/
public getConditionTypes(): Promise<string[]> {
return this.call("getConditionTypes", [])
return this.call('getConditionTypes', [])
}
/**
@ -69,8 +81,9 @@ export abstract class AgreementTemplate extends ContractBase {
* @return {Promise<Condition[]>} Conditions contracts.
*/
public async getConditions(): Promise<Condition[]> {
return (await this.getConditionTypes())
.map((address) => this.ocean.keeper.getConditionByAddress(address))
return (await this.getConditionTypes()).map(address =>
this.ocean.keeper.getConditionByAddress(address)
)
}
/**
@ -80,7 +93,12 @@ export abstract class AgreementTemplate extends ContractBase {
* @param {string} from Consumer address.
* @return {Promise<string[]>} Condition IDs.
*/
public abstract getAgreementIdsFromDDO(agreementId: string, ddo: DDO, consumer: string, from?: string): Promise<string[]>
public abstract getAgreementIdsFromDDO(
agreementId: string,
ddo: DDO,
consumer: string,
from?: string
): Promise<string[]>
/**
* Create a new agreement using the data of a DDO.
@ -89,9 +107,16 @@ export abstract class AgreementTemplate extends ContractBase {
* @param {string} from Creator address.
* @return {Promise<boolean>} Success.
*/
public abstract createAgreementFromDDO(agreementId: string, ddo: DDO, consumer: string, from?: string): Promise<boolean>
public abstract createAgreementFromDDO(
agreementId: string,
ddo: DDO,
consumer: string,
from?: string
): Promise<boolean>
public abstract async getServiceAgreementTemplate(): Promise<ServiceAgreementTemplate>
public abstract async getServiceAgreementTemplate(): Promise<
ServiceAgreementTemplate
>
public async getServiceAgreementTemplateConditions() {
const serviceAgreementTemplate = await this.getServiceAgreementTemplate()
@ -99,11 +124,12 @@ export abstract class AgreementTemplate extends ContractBase {
}
public async getServiceAgreementTemplateConditionByRef(ref: string) {
const name = (await this.getServiceAgreementTemplateConditions())
.find(({name: conditionRef}) => conditionRef === ref)
.contractName
return (await this.getConditions())
.find((condition) => condition.contractName === name)
const name = (await this.getServiceAgreementTemplateConditions()).find(
({ name: conditionRef }) => conditionRef === ref
).contractName
return (await this.getConditions()).find(
condition => condition.contractName === name
)
}
public async getServiceAgreementTemplateDependencies() {
@ -117,49 +143,58 @@ export abstract class AgreementTemplate extends ContractBase {
* @return {Promise} Conditions status.
*/
public async getAgreementStatus(
agreementId: string,
agreementId: string
): Promise<AgreementConditionsStatus | false> {
const agreementStore = this.ocean.keeper.agreementStoreManager
const conditionStore = this.ocean.keeper.conditionStoreManager
const dependencies = await this.getServiceAgreementTemplateDependencies()
const {conditionIds} = await agreementStore.getAgreement(agreementId)
const { conditionIds } = await agreementStore.getAgreement(agreementId)
if (!conditionIds.length) {
this.logger.error(`Agreement not creeated yet: "${agreementId}"`)
return false
}
const conditionIdByConddition = (await this.getConditions())
.reduce((acc, {contractName}, i) => ({...acc, [contractName]: conditionIds[i]}), {})
const conditionIdByConddition = (await this.getConditions()).reduce(
(acc, { contractName }, i) => ({
...acc,
[contractName]: conditionIds[i]
}),
{}
)
const statesPromises = Object.keys(dependencies)
.map(async (ref, i) => {
const {contractName} = await this.getServiceAgreementTemplateConditionByRef(ref)
return {
ref,
contractName,
state: (await conditionStore.getCondition(conditionIdByConddition[contractName])).state,
}
})
const statesPromises = Object.keys(dependencies).map(async (ref, i) => {
const {
contractName
} = await this.getServiceAgreementTemplateConditionByRef(ref)
return {
ref,
contractName,
state: (await conditionStore.getCondition(
conditionIdByConddition[contractName]
)).state
}
})
const states = await Promise.all(statesPromises)
return states
.reduce((acc, {contractName, ref, state}) => {
const blockers = dependencies[ref]
.map((dependency) => states.find((_) => _.ref === dependency))
.filter((condition) => condition.state !== ConditionState.Fulfilled)
return {
...acc,
[ref]: {
condition: ref,
contractName,
state,
blocked: !!blockers.length,
blockedBy: blockers.map((_) => _.ref),
},
return states.reduce((acc, { contractName, ref, state }) => {
const blockers = dependencies[ref]
.map(dependency => states.find(_ => _.ref === dependency))
.filter(
condition => condition.state !== ConditionState.Fulfilled
)
return {
...acc,
[ref]: {
condition: ref,
contractName,
state,
blocked: !!blockers.length,
blockedBy: blockers.map(_ => _.ref)
}
}, {})
}
}, {})
}
/**
@ -169,25 +204,30 @@ export abstract class AgreementTemplate extends ContractBase {
public async printAgreementStatus(agreementId: string) {
const status = await this.getAgreementStatus(agreementId)
this.logger.bypass("-".repeat(80))
this.logger.bypass("Template:", this.contractName)
this.logger.bypass("Agreement ID:", agreementId)
this.logger.bypass("-".repeat(40))
this.logger.bypass('-'.repeat(80))
this.logger.bypass('Template:', this.contractName)
this.logger.bypass('Agreement ID:', agreementId)
this.logger.bypass('-'.repeat(40))
if (!status) {
this.logger.bypass("Agreement not created yet!")
this.logger.bypass('Agreement not created yet!')
}
Object.values(status || [])
.forEach(({condition, contractName, state, blocked, blockedBy}, i) => {
Object.values(status || []).forEach(
({ condition, contractName, state, blocked, blockedBy }, i) => {
if (i) {
this.logger.bypass("-".repeat(20))
this.logger.bypass('-'.repeat(20))
}
this.logger.bypass(`${condition} (${contractName})`)
this.logger.bypass(" Status:", state, `(${conditionStateNames[state]})`)
this.logger.bypass(
' Status:',
state,
`(${conditionStateNames[state]})`
)
if (blocked) {
this.logger.bypass(" Blocked by:", blockedBy)
this.logger.bypass(' Blocked by:', blockedBy)
}
})
this.logger.bypass("-".repeat(80))
}
)
this.logger.bypass('-'.repeat(80))
}
/**
@ -196,6 +236,8 @@ export abstract class AgreementTemplate extends ContractBase {
* @return {Event} Agreement created event.
*/
public getAgreementCreatedEvent(agreementId: string) {
return this.getEvent("AgreementCreated", {agreementId: zeroX(agreementId)})
return this.getEvent('AgreementCreated', {
agreementId: zeroX(agreementId)
})
}
}

View File

@ -1,145 +1,142 @@
import { ServiceAgreementTemplate } from "../../../ddo/ServiceAgreementTemplate"
import { ServiceAgreementTemplate } from '../../../ddo/ServiceAgreementTemplate'
export const escrowAccessSecretStoreTemplateServiceAgreementTemplate: ServiceAgreementTemplate = {
contractName: "EscrowAccessSecretStoreTemplate",
contractName: 'EscrowAccessSecretStoreTemplate',
events: [
{
name: "AgreementCreated",
actorType: "consumer",
name: 'AgreementCreated',
actorType: 'consumer',
handler: {
moduleName: "escrowAccessSecretStoreTemplate",
functionName: "fulfillLockRewardCondition",
version: "0.1",
},
},
moduleName: 'escrowAccessSecretStoreTemplate',
functionName: 'fulfillLockRewardCondition',
version: '0.1'
}
}
],
fulfillmentOrder: [
"lockReward.fulfill",
"accessSecretStore.fulfill",
"escrowReward.fulfill",
'lockReward.fulfill',
'accessSecretStore.fulfill',
'escrowReward.fulfill'
],
conditionDependency: {
lockReward: [],
accessSecretStore: [],
escrowReward: [
"lockReward",
"accessSecretStore",
],
escrowReward: ['lockReward', 'accessSecretStore']
},
conditions: [
{
name: "lockReward",
name: 'lockReward',
timelock: 0,
timeout: 0,
contractName: "LockRewardCondition",
functionName: "fulfill",
contractName: 'LockRewardCondition',
functionName: 'fulfill',
parameters: [
{
name: "_rewardAddress",
type: "address",
value: "",
name: '_rewardAddress',
type: 'address',
value: ''
},
{
name: "_amount",
type: "uint256",
value: "",
},
name: '_amount',
type: 'uint256',
value: ''
}
],
events: [
{
name: "Fulfilled",
actorType: "publisher",
name: 'Fulfilled',
actorType: 'publisher',
handler: {
moduleName: "lockRewardCondition",
functionName: "fulfillAccessSecretStoreCondition",
version: "0.1",
},
},
],
moduleName: 'lockRewardCondition',
functionName: 'fulfillAccessSecretStoreCondition',
version: '0.1'
}
}
]
},
{
name: "accessSecretStore",
name: 'accessSecretStore',
timelock: 0,
timeout: 0,
contractName: "AccessSecretStoreCondition",
functionName: "fulfill",
contractName: 'AccessSecretStoreCondition',
functionName: 'fulfill',
parameters: [
{
name: "_documentId",
type: "bytes32",
value: "",
name: '_documentId',
type: 'bytes32',
value: ''
},
{
name: "_grantee",
type: "address",
value: "",
},
name: '_grantee',
type: 'address',
value: ''
}
],
events: [
{
name: "Fulfilled",
actorType: "publisher",
name: 'Fulfilled',
actorType: 'publisher',
handler: {
moduleName: "accessSecretStore",
functionName: "fulfillEscrowRewardCondition",
version: "0.1",
},
moduleName: 'accessSecretStore',
functionName: 'fulfillEscrowRewardCondition',
version: '0.1'
}
},
{
name: "TimedOut",
actorType: "consumer",
name: 'TimedOut',
actorType: 'consumer',
handler: {
moduleName: "accessSecretStore",
functionName: "fulfillEscrowRewardCondition",
version: "0.1",
},
},
],
moduleName: 'accessSecretStore',
functionName: 'fulfillEscrowRewardCondition',
version: '0.1'
}
}
]
},
{
name: "escrowReward",
name: 'escrowReward',
timelock: 0,
timeout: 0,
contractName: "EscrowReward",
functionName: "fulfill",
contractName: 'EscrowReward',
functionName: 'fulfill',
parameters: [
{
name: "_amount",
type: "uint256",
value: "",
name: '_amount',
type: 'uint256',
value: ''
},
{
name: "_receiver",
type: "address",
value: "",
name: '_receiver',
type: 'address',
value: ''
},
{
name: "_sender",
type: "address",
value: "",
name: '_sender',
type: 'address',
value: ''
},
{
name: "_lockCondition",
type: "bytes32",
value: "",
name: '_lockCondition',
type: 'bytes32',
value: ''
},
{
name: "_releaseCondition",
type: "bytes32",
value: "",
},
name: '_releaseCondition',
type: 'bytes32',
value: ''
}
],
events: [
{
name: "Fulfilled",
actorType: "publisher",
name: 'Fulfilled',
actorType: 'publisher',
handler: {
moduleName: "escrowRewardCondition",
functionName: "verifyRewardTokens",
version: "0.1",
},
},
],
},
],
moduleName: 'escrowRewardCondition',
functionName: 'verifyRewardTokens',
version: '0.1'
}
}
]
}
]
}

View File

@ -1,14 +1,19 @@
import { AgreementTemplate } from "./AgreementTemplate.abstract"
import { DDO } from "../../../ddo/DDO"
import { generateId, zeroX } from "../../../utils"
import { InstantiableConfig } from "../../../Instantiable.abstract"
import { AgreementTemplate } from './AgreementTemplate.abstract'
import { DDO } from '../../../ddo/DDO'
import { generateId, zeroX } from '../../../utils'
import { InstantiableConfig } from '../../../Instantiable.abstract'
import { escrowAccessSecretStoreTemplateServiceAgreementTemplate } from "./EscrowAccessSecretStoreTemplate.serviceAgreementTemplate"
import { escrowAccessSecretStoreTemplateServiceAgreementTemplate } from './EscrowAccessSecretStoreTemplate.serviceAgreementTemplate'
export class EscrowAccessSecretStoreTemplate extends AgreementTemplate {
public static async getInstance(config: InstantiableConfig): Promise<EscrowAccessSecretStoreTemplate> {
return AgreementTemplate.getInstance(config, "EscrowAccessSecretStoreTemplate", EscrowAccessSecretStoreTemplate)
public static async getInstance(
config: InstantiableConfig
): Promise<EscrowAccessSecretStoreTemplate> {
return AgreementTemplate.getInstance(
config,
'EscrowAccessSecretStoreTemplate',
EscrowAccessSecretStoreTemplate
)
}
public async getServiceAgreementTemplate() {
@ -33,7 +38,7 @@ export class EscrowAccessSecretStoreTemplate extends AgreementTemplate {
timeLocks: number[],
timeOuts: number[],
accessConsumer: string,
from?: string,
from?: string
) {
return super.createAgreement(
agreementId,
@ -42,24 +47,46 @@ export class EscrowAccessSecretStoreTemplate extends AgreementTemplate {
timeLocks,
timeOuts,
[accessConsumer],
from,
from
)
}
public async createAgreementFromDDO(agreementId: string, ddo: DDO, consumer: string, from?: string) {
return !!await this.createFullAgreement(
public async createAgreementFromDDO(
agreementId: string,
ddo: DDO,
consumer: string,
from?: string
) {
return !!(await this.createFullAgreement(
ddo.shortId(),
ddo.findServiceByType("Metadata").metadata.base.price,
ddo.findServiceByType('Metadata').metadata.base.price,
consumer,
from,
agreementId,
)
agreementId
))
}
public async getAgreementIdsFromDDO(agreementId: string, ddo: DDO, consumer: string, from?: string) {
const {accessSecretStoreConditionId, lockRewardConditionId, escrowRewardId} =
await this.createFullAgreementData(agreementId, ddo.shortId(), ddo.findServiceByType("Metadata").metadata.base.price, consumer)
return [accessSecretStoreConditionId, lockRewardConditionId, escrowRewardId]
public async getAgreementIdsFromDDO(
agreementId: string,
ddo: DDO,
consumer: string,
from?: string
) {
const {
accessSecretStoreConditionId,
lockRewardConditionId,
escrowRewardId
} = await this.createFullAgreementData(
agreementId,
ddo.shortId(),
ddo.findServiceByType('Metadata').metadata.base.price,
consumer
)
return [
accessSecretStoreConditionId,
lockRewardConditionId,
escrowRewardId
]
}
/**
@ -74,47 +101,75 @@ export class EscrowAccessSecretStoreTemplate extends AgreementTemplate {
amount: number | string,
consumer: string,
from?: string,
agreementId: string = generateId(),
agreementId: string = generateId()
): Promise<string> {
const {accessSecretStoreConditionId, lockRewardConditionId, escrowRewardId} =
await this.createFullAgreementData(agreementId, did, amount, consumer)
const {
accessSecretStoreConditionId,
lockRewardConditionId,
escrowRewardId
} = await this.createFullAgreementData(
agreementId,
did,
amount,
consumer
)
await this.createAgreement(
agreementId,
did,
[accessSecretStoreConditionId, lockRewardConditionId, escrowRewardId],
[
accessSecretStoreConditionId,
lockRewardConditionId,
escrowRewardId
],
[0, 0, 0],
[0, 0, 0],
consumer,
from,
from
)
return zeroX(agreementId)
}
private async createFullAgreementData(agreementId: string, did: string, amount: number | string, consumer: string) {
const {didRegistry, conditions} = this.ocean.keeper
private async createFullAgreementData(
agreementId: string,
did: string,
amount: number | string,
consumer: string
) {
const { didRegistry, conditions } = this.ocean.keeper
const {accessSecretStoreCondition, lockRewardCondition, escrowReward} = conditions
const {
accessSecretStoreCondition,
lockRewardCondition,
escrowReward
} = conditions
const publisher = await didRegistry.getDIDOwner(did)
const lockRewardConditionId = await lockRewardCondition.generateIdHash(agreementId, await escrowReward.getAddress(), amount)
const accessSecretStoreConditionId = await accessSecretStoreCondition.generateIdHash(agreementId, did, consumer)
const lockRewardConditionId = await lockRewardCondition.generateIdHash(
agreementId,
await escrowReward.getAddress(),
amount
)
const accessSecretStoreConditionId = await accessSecretStoreCondition.generateIdHash(
agreementId,
did,
consumer
)
const escrowRewardId = await escrowReward.generateIdHash(
agreementId,
String(amount),
publisher,
consumer,
lockRewardConditionId,
accessSecretStoreConditionId,
accessSecretStoreConditionId
)
return {
lockRewardConditionId,
accessSecretStoreConditionId,
escrowRewardId,
escrowRewardId
}
}
}

View File

@ -1,2 +1,4 @@
export * from "./AgreementTemplate.abstract"
export { EscrowAccessSecretStoreTemplate } from "./EscrowAccessSecretStoreTemplate"
export * from './AgreementTemplate.abstract'
export {
EscrowAccessSecretStoreTemplate
} from './EscrowAccessSecretStoreTemplate'

View File

@ -3,7 +3,7 @@ enum AccessStatus {
Committed,
Delivered,
Verified,
Revoked,
Revoked
}
export default AccessStatus

View File

@ -1,5 +1,5 @@
import { LogLevel } from "../utils/Logger"
export { LogLevel } from "../utils/Logger"
import { LogLevel } from '../utils/Logger'
export { LogLevel } from '../utils/Logger'
export class Config {
/**

View File

@ -1,4 +1,4 @@
import InputType from "./InputType"
import InputType from './InputType'
export default class MethodReflection {
public contractName: string

View File

@ -1,8 +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"...
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,7 +1,7 @@
import BigNumber from "bignumber.js"
import Balance from "../models/Balance"
import BigNumber from 'bignumber.js'
import Balance from '../models/Balance'
import { Instantiable, InstantiableConfig } from "../Instantiable.abstract"
import { Instantiable, InstantiableConfig } from '../Instantiable.abstract'
/**
* Account information.
@ -10,7 +10,7 @@ export default class Account extends Instantiable {
private password?: string
private token?: string
constructor(private id: string = "0x0", config?: InstantiableConfig) {
constructor(private id: string = '0x0', config?: InstantiableConfig) {
super()
if (config) {
this.setInstanceConfig(config)
@ -54,7 +54,7 @@ export default class Account extends Instantiable {
* @return {Promise<string>} Account token.
*/
public async getToken(): Promise<string> {
return this.token || await this.ocean.auth.restore(this)
return this.token || (await this.ocean.auth.restore(this))
}
/**
@ -77,8 +77,8 @@ export default class Account extends Instantiable {
* @return {Promise<number>}
*/
public async getOceanBalance(): Promise<number> {
const token = this.ocean.keeper.token
return await token.balanceOf(this.id) / (10 ** await token.decimals())
const { token } = this.ocean.keeper
return (await token.balanceOf(this.id)) / 10 ** (await token.decimals())
}
/**
@ -86,9 +86,8 @@ export default class Account extends Instantiable {
* @return {Promise<number>}
*/
public async getEtherBalance(): Promise<number> {
return this.web3
.eth
.getBalance(this.id, "latest")
return this.web3.eth
.getBalance(this.id, 'latest')
.then((balance: string): number => {
return new BigNumber(balance).toNumber()
})
@ -101,7 +100,7 @@ export default class Account extends Instantiable {
public async getBalance(): Promise<Balance> {
return {
eth: await this.getEtherBalance(),
ocn: await this.getOceanBalance(),
ocn: await this.getOceanBalance()
}
}
@ -113,13 +112,10 @@ export default class Account extends Instantiable {
public async requestTokens(amount: number | string): Promise<string> {
amount = String(amount)
try {
await this.ocean.keeper
.dispenser
.requestTokens(amount, this.id)
await this.ocean.keeper.dispenser.requestTokens(amount, this.id)
} catch (e) {
this.logger.error(e)
throw new Error("Error requesting tokens")
throw new Error('Error requesting tokens')
}
return amount
}

View File

@ -1,12 +1,11 @@
import { generateId } from "../utils/GeneratorHelpers"
import { generateId } from '../utils/GeneratorHelpers'
const prefix = "did:op:"
const prefix = 'did:op:'
/**
* Decentralized ID.
*/
export default class DID {
/**
* Parses a DID from a string.
* @param {string} didString DID in string.

View File

@ -1,26 +1,28 @@
import { OceanAccounts } from "./OceanAccounts"
import { OceanAgreements } from "./OceanAgreements"
import { OceanAssets } from "./OceanAssets"
import { OceanAuth } from "./OceanAuth"
import { OceanSecretStore } from "./OceanSecretStore"
import { OceanTokens } from "./OceanTokens"
import { OceanVersions } from "./OceanVersions"
import { OceanUtils } from "./utils/OceanUtils"
import { OceanAccounts } from './OceanAccounts'
import { OceanAgreements } from './OceanAgreements'
import { OceanAssets } from './OceanAssets'
import { OceanAuth } from './OceanAuth'
import { OceanSecretStore } from './OceanSecretStore'
import { OceanTokens } from './OceanTokens'
import { OceanVersions } from './OceanVersions'
import { OceanUtils } from './utils/OceanUtils'
import { Aquarius } from "../aquarius/Aquarius"
import { Brizo } from "../brizo/Brizo"
import { Aquarius } from '../aquarius/Aquarius'
import { Brizo } from '../brizo/Brizo'
import Keeper from "../keeper/Keeper"
import Keeper from '../keeper/Keeper'
import { Config } from "../models/Config"
import { Config } from '../models/Config'
import { Instantiable, generateIntantiableConfigFromConfig } from "../Instantiable.abstract"
import {
Instantiable,
generateIntantiableConfigFromConfig
} from '../Instantiable.abstract'
/**
* Main interface for Ocean Protocol.
*/
export class Ocean extends Instantiable {
/**
* Returns the instance of Ocean.
* @param {Config} config Ocean instance configuration.
@ -31,7 +33,7 @@ export class Ocean extends Instantiable {
const instanceConfig = {
...generateIntantiableConfigFromConfig(config),
ocean: instance,
ocean: instance
}
instance.setInstanceConfig(instanceConfig)
@ -44,7 +46,9 @@ export class Ocean extends Instantiable {
instance.auth = await OceanAuth.getInstance(instanceConfig)
instance.assets = await OceanAssets.getInstance(instanceConfig)
instance.agreements = await OceanAgreements.getInstance(instanceConfig)
instance.secretStore = await OceanSecretStore.getInstance(instanceConfig)
instance.secretStore = await OceanSecretStore.getInstance(
instanceConfig
)
instance.tokens = await OceanTokens.getInstance(instanceConfig)
instance.versions = await OceanVersions.getInstance(instanceConfig)

View File

@ -1,17 +1,18 @@
import Balance from "../models/Balance"
import Account from "./Account"
import { Instantiable, InstantiableConfig } from "../Instantiable.abstract"
import Balance from '../models/Balance'
import Account from './Account'
import { Instantiable, InstantiableConfig } from '../Instantiable.abstract'
/**
* Account submodule of Ocean Protocol.
*/
export class OceanAccounts extends Instantiable {
/**
* Returns the instance of OceanAccounts.
* @return {Promise<OceanAccounts>}
*/
public static async getInstance(config: InstantiableConfig): Promise<OceanAccounts> {
public static async getInstance(
config: InstantiableConfig
): Promise<OceanAccounts> {
const instance = new OceanAccounts()
instance.setInstanceConfig(config)
@ -23,12 +24,12 @@ export class OceanAccounts extends Instantiable {
* @return {Promise<Account[]>}
*/
public async list(): Promise<Account[]> {
// retrieve eth accounts
const ethAccounts: string[] = await this.web3.eth.getAccounts()
const accountPromises = ethAccounts
.map((address) => new Account(address, this.instanceConfig))
const accountPromises = ethAccounts.map(
address => new Account(address, this.instanceConfig)
)
return Promise.all(accountPromises)
}
@ -47,7 +48,10 @@ export class OceanAccounts extends Instantiable {
* @param {number} amount Token amount.
* @return {Promise<boolean>} Success.
*/
public async requestTokens(account: Account, amount: number): Promise<boolean> {
public async requestTokens(
account: Account,
amount: number
): Promise<boolean> {
try {
await account.requestTokens(amount)
return true

View File

@ -1,12 +1,12 @@
import { generateId } from "../utils/GeneratorHelpers"
import Account from "./Account"
import DID from "./DID"
import { zeroX, didPrefixed } from "../utils"
import { Instantiable, InstantiableConfig } from "../Instantiable.abstract"
import { AgreementConditionsStatus } from "../keeper/contracts/templates/AgreementTemplate.abstract"
import { ConditionState } from "../keeper/contracts/conditions/Condition.abstract"
import { generateId } from '../utils/GeneratorHelpers'
import Account from './Account'
import DID from './DID'
import { zeroX, didPrefixed } from '../utils'
import { Instantiable, InstantiableConfig } from '../Instantiable.abstract'
import { AgreementConditionsStatus } from '../keeper/contracts/templates/AgreementTemplate.abstract'
import { ConditionState } from '../keeper/contracts/conditions/Condition.abstract'
import { OceanAgreementsConditions } from "./OceanAgreementsConditions"
import { OceanAgreementsConditions } from './OceanAgreementsConditions'
export interface AgreementPrepareResult {
agreementId: string
@ -17,15 +17,18 @@ export interface AgreementPrepareResult {
* Agreements submodule of Ocean Protocol.
*/
export class OceanAgreements extends Instantiable {
/**
* Returns the instance of OceanAgreements.
* @return {Promise<OceanAgreements>}
*/
public static async getInstance(config: InstantiableConfig): Promise<OceanAgreements> {
public static async getInstance(
config: InstantiableConfig
): Promise<OceanAgreements> {
const instance = new OceanAgreements()
instance.setInstanceConfig(config)
instance.conditions = await OceanAgreementsConditions.getInstance(config)
instance.conditions = await OceanAgreementsConditions.getInstance(
config
)
return instance
}
@ -46,27 +49,32 @@ export class OceanAgreements extends Instantiable {
public async prepare(
did: string,
serviceDefinitionId: string,
consumer: Account,
consumer: Account
): Promise<AgreementPrepareResult> {
const d: DID = DID.parse(did as string)
const ddo = await this.ocean.aquarius.retrieveDDO(d)
const agreementId: string = zeroX(generateId())
const templateName = ddo.findServiceByType("Access").serviceAgreementTemplate.contractName
const templateName = ddo.findServiceByType('Access')
.serviceAgreementTemplate.contractName
const agreementConditionsIds = await this.ocean.keeper
.getTemplateByName(templateName)
.getAgreementIdsFromDDO(agreementId, ddo, consumer.getId(), consumer.getId())
.getAgreementIdsFromDDO(
agreementId,
ddo,
consumer.getId(),
consumer.getId()
)
const signature = await this.ocean.utils.agreements.signServiceAgreement(
ddo,
serviceDefinitionId,
agreementId,
agreementConditionsIds,
consumer,
consumer
)
return {agreementId, signature}
return { agreementId, signature }
}
/**
@ -81,20 +89,20 @@ export class OceanAgreements extends Instantiable {
agreementId: string,
serviceDefinitionId: string,
signature: string,
consumer: Account,
consumer: Account
): Promise<void> {
const result = await this.ocean.brizo
.initializeServiceAgreement(
didPrefixed(did),
zeroX(agreementId),
serviceDefinitionId,
zeroX(signature),
consumer.getId(),
)
const result = await this.ocean.brizo.initializeServiceAgreement(
didPrefixed(did),
zeroX(agreementId),
serviceDefinitionId,
zeroX(signature),
consumer.getId()
)
if (!result.ok) {
throw new Error("Error on initialize agreement: " + await result.text())
throw new Error(
'Error on initialize agreement: ' + (await result.text())
)
}
}
@ -116,15 +124,21 @@ export class OceanAgreements extends Instantiable {
serviceDefinitionId: string,
signature: string,
consumer: Account,
publisher: Account,
publisher: Account
) {
const d: DID = DID.parse(did)
const ddo = await this.ocean.aquarius.retrieveDDO(d)
const templateName = ddo.findServiceById<"Access">(serviceDefinitionId).serviceAgreementTemplate.contractName
const templateName = ddo.findServiceById<'Access'>(serviceDefinitionId)
.serviceAgreementTemplate.contractName
await this.ocean.keeper
.getTemplateByName(templateName)
.createAgreementFromDDO(agreementId, ddo, consumer.getId(), publisher.getId())
.createAgreementFromDDO(
agreementId,
ddo,
consumer.getId(),
publisher.getId()
)
return true
}
@ -137,13 +151,20 @@ export class OceanAgreements extends Instantiable {
* @param {boolean} extended Returns a complete status with dependencies.
* @return {Promise<any>}
*/
public async status(agreementId: string, extended?: false): Promise<{[condition: string]: ConditionState}>
public async status(agreementId: string, extended: true): Promise<AgreementConditionsStatus>
public async status(
agreementId: string,
extended: boolean = false,
) {
const {templateId} = await this.ocean.keeper.agreementStoreManager.getAgreement(agreementId)
extended?: false
): Promise<{ [condition: string]: ConditionState }>
public async status(
agreementId: string,
extended: true
): Promise<AgreementConditionsStatus>
public async status(agreementId: string, extended: boolean = false) {
const {
templateId
} = await this.ocean.keeper.agreementStoreManager.getAgreement(
agreementId
)
const fullStatus = await this.ocean.keeper
.getTemplateByAddress(templateId)
.getAgreementStatus(agreementId)
@ -155,10 +176,9 @@ export class OceanAgreements extends Instantiable {
return fullStatus
}
const simpleStatus = {}
Object.entries(fullStatus)
.forEach(([condition, {state}]) => {
simpleStatus[condition] = state
})
Object.entries(fullStatus).forEach(([condition, { state }]) => {
simpleStatus[condition] = state
})
return simpleStatus as any
}
}

View File

@ -1,16 +1,17 @@
import Account from "./Account"
import { Instantiable, InstantiableConfig } from "../Instantiable.abstract"
import Account from './Account'
import { Instantiable, InstantiableConfig } from '../Instantiable.abstract'
/**
* Agreements Conditions submodule of Ocean Protocol.
*/
export class OceanAgreementsConditions extends Instantiable {
/**
* Returns the instance of OceanAgreementsConditions.
* @return {Promise<OceanAgreementsConditions>}
*/
public static async getInstance(config: InstantiableConfig): Promise<OceanAgreementsConditions> {
public static async getInstance(
config: InstantiableConfig
): Promise<OceanAgreementsConditions> {
const instance = new OceanAgreementsConditions()
instance.setInstanceConfig(config)
@ -24,12 +25,28 @@ export class OceanAgreementsConditions extends Instantiable {
* @param {number} amount Asset amount.
* @param {Account} from Account of sender.
*/
public async lockReward(agreementId: string, amount: number | string, from?: Account) {
const {lockRewardCondition, escrowReward} = this.ocean.keeper.conditions
public async lockReward(
agreementId: string,
amount: number | string,
from?: Account
) {
const {
lockRewardCondition,
escrowReward
} = this.ocean.keeper.conditions
await this.ocean.keeper.token.approve(lockRewardCondition.getAddress(), amount, from.getId())
await this.ocean.keeper.token.approve(
lockRewardCondition.getAddress(),
amount,
from.getId()
)
const receipt = await lockRewardCondition.fulfill(agreementId, escrowReward.getAddress(), amount, from && from.getId())
const receipt = await lockRewardCondition.fulfill(
agreementId,
escrowReward.getAddress(),
amount,
from && from.getId()
)
return !!receipt.events.Fulfilled
}
@ -40,10 +57,20 @@ export class OceanAgreementsConditions extends Instantiable {
* @param {string} grantee Consumer address.
* @param {Account} from Account of sender.
*/
public async grantAccess(agreementId: string, did: string, grantee: string, from?: Account) {
const {accessSecretStoreCondition} = this.ocean.keeper.conditions
public async grantAccess(
agreementId: string,
did: string,
grantee: string,
from?: Account
) {
const { accessSecretStoreCondition } = this.ocean.keeper.conditions
const receipt = await accessSecretStoreCondition.fulfill(agreementId, did, grantee, from && from.getId())
const receipt = await accessSecretStoreCondition.fulfill(
agreementId,
did,
grantee,
from && from.getId()
)
return !!receipt.events.Fulfilled
}
@ -66,12 +93,24 @@ export class OceanAgreementsConditions extends Instantiable {
did: string,
consumer: string,
publisher: string,
from?: Account,
from?: Account
) {
const {escrowReward, accessSecretStoreCondition, lockRewardCondition} = this.ocean.keeper.conditions
const {
escrowReward,
accessSecretStoreCondition,
lockRewardCondition
} = this.ocean.keeper.conditions
const conditionIdAccess = await accessSecretStoreCondition.generateIdHash(agreementId, did, consumer)
const conditionIdLock = await lockRewardCondition.generateIdHash(agreementId, escrowReward.getAddress(), amount)
const conditionIdAccess = await accessSecretStoreCondition.generateIdHash(
agreementId,
did,
consumer
)
const conditionIdLock = await lockRewardCondition.generateIdHash(
agreementId,
escrowReward.getAddress(),
amount
)
const receipt = await escrowReward.fulfill(
agreementId,
@ -80,7 +119,7 @@ export class OceanAgreementsConditions extends Instantiable {
consumer,
conditionIdLock,
conditionIdAccess,
from && from.getId(),
from && from.getId()
)
return !!receipt.events.Fulfilled
}

View File

@ -1,11 +1,16 @@
import { SearchQuery } from "../aquarius/Aquarius"
import { DDO } from "../ddo/DDO"
import { MetaData } from "../ddo/MetaData"
import { Service } from "../ddo/Service"
import Account from "./Account"
import DID from "./DID"
import { fillConditionsWithDDO, SubscribablePromise, generateId, zeroX } from "../utils"
import { Instantiable, InstantiableConfig } from "../Instantiable.abstract"
import { SearchQuery } from '../aquarius/Aquarius'
import { DDO } from '../ddo/DDO'
import { MetaData } from '../ddo/MetaData'
import { Service } from '../ddo/Service'
import Account from './Account'
import DID from './DID'
import {
fillConditionsWithDDO,
SubscribablePromise,
generateId,
zeroX
} from '../utils'
import { Instantiable, InstantiableConfig } from '../Instantiable.abstract'
export enum CreateProgressStep {
EncryptingFiles,
@ -15,26 +20,27 @@ export enum CreateProgressStep {
RegisteringDid,
DidRegistred,
StoringDdo,
DdoStored,
DdoStored
}
export enum OrderProgressStep {
CreatingAgreement,
AgreementInitialized,
LockingPayment,
LockedPayment,
LockedPayment
}
/**
* Assets submodule of Ocean Protocol.
*/
export class OceanAssets extends Instantiable {
/**
* Returns the instance of OceanAssets.
* @return {Promise<OceanAssets>}
*/
public static async getInstance(config: InstantiableConfig): Promise<OceanAssets> {
public static async getInstance(
config: InstantiableConfig
): Promise<OceanAssets> {
const instance = new OceanAssets()
instance.setInstanceConfig(config)
@ -57,18 +63,26 @@ export class OceanAssets extends Instantiable {
* @param {Account} publisher Publisher account.
* @return {Promise<DDO>}
*/
public create(metadata: MetaData, publisher: Account, services: Service[] = []): SubscribablePromise<CreateProgressStep, DDO> {
this.logger.log("Creating asset")
return new SubscribablePromise(async (observer) => {
const {secretStoreUri} = this.config
const {didRegistry, templates} = this.ocean.keeper
public create(
metadata: MetaData,
publisher: Account,
services: Service[] = []
): SubscribablePromise<CreateProgressStep, DDO> {
this.logger.log('Creating asset')
return new SubscribablePromise(async observer => {
const { secretStoreUri } = this.config
const { didRegistry, templates } = this.ocean.keeper
const did: DID = DID.generate()
this.logger.log("Encrypting files")
this.logger.log('Encrypting files')
observer.next(CreateProgressStep.EncryptingFiles)
const encryptedFiles = await this.ocean.secretStore.encrypt(did.getId(), metadata.base.files, publisher)
this.logger.log("Files encrypted")
const encryptedFiles = await this.ocean.secretStore.encrypt(
did.getId(),
metadata.base.files,
publisher
)
this.logger.log('Files encrypted')
observer.next(CreateProgressStep.FilesEncrypted)
const serviceAgreementTemplate = await templates.escrowAccessSecretStoreTemplate.getServiceAgreementTemplate()
@ -79,40 +93,42 @@ export class OceanAssets extends Instantiable {
// create ddo itself
const ddo: DDO = new DDO({
id: did.getDid(),
authentication: [{
type: "RsaSignatureAuthentication2018",
publicKey: did.getDid(),
}],
authentication: [
{
type: 'RsaSignatureAuthentication2018',
publicKey: did.getDid()
}
],
publicKey: [
{
id: did.getDid(),
type: "EthereumECDSAKey",
owner: publisher.getId(),
},
type: 'EthereumECDSAKey',
owner: publisher.getId()
}
],
service: [
{
type: "Access",
creator: "",
type: 'Access',
creator: '',
purchaseEndpoint: this.ocean.brizo.getPurchaseEndpoint(),
serviceEndpoint: this.ocean.brizo.getConsumeEndpoint(),
name: "dataAssetAccessServiceAgreement",
name: 'dataAssetAccessServiceAgreement',
templateId: templates.escrowAccessSecretStoreTemplate.getAddress(),
serviceAgreementTemplate,
serviceAgreementTemplate
},
{
type: "Authorization",
service: "SecretStore",
serviceEndpoint: secretStoreUri,
type: 'Authorization',
service: 'SecretStore',
serviceEndpoint: secretStoreUri
},
{
type: "Metadata",
type: 'Metadata',
serviceEndpoint,
metadata: {
// Default values
curation: {
rating: 0,
numVotes: 0,
numVotes: 0
},
// Overwrites defaults
...metadata,
@ -121,23 +137,30 @@ export class OceanAssets extends Instantiable {
...metadata.base,
contentUrls: undefined,
encryptedFiles,
files: metadata.base.files
.map((file, index) => ({
files: metadata.base.files.map(
(file, index) => ({
...file,
index,
url: undefined,
})),
} as any,
},
url: undefined
})
)
} as any
}
},
...services,
...services
]
// Remove duplications
.reverse()
.filter(({type}, i, list) => list.findIndex(({type: t}) => t === type) === i)
.filter(
({ type }, i, list) =>
list.findIndex(({ type: t }) => t === type) === i
)
.reverse()
// Adding ID
.map((_) => ({..._, serviceDefinitionId: String(serviceDefinitionIdCount++)})) as Service[],
.map(_ => ({
..._,
serviceDefinitionId: String(serviceDefinitionIdCount++)
})) as Service[]
})
// Overwritte initial service agreement conditions
@ -146,72 +169,93 @@ export class OceanAssets extends Instantiable {
serviceAgreementTemplate.conditions = conditions
ddo.addChecksum()
this.logger.log("Generating proof")
this.logger.log('Generating proof')
observer.next(CreateProgressStep.GeneratingProof)
await ddo.addProof(this.ocean, publisher.getId(), publisher.getPassword())
this.logger.log("Proof generated")
await ddo.addProof(
this.ocean,
publisher.getId(),
publisher.getPassword()
)
this.logger.log('Proof generated')
observer.next(CreateProgressStep.ProofGenerated)
this.logger.log("Registering DID")
this.logger.log('Registering DID')
observer.next(CreateProgressStep.RegisteringDid)
await didRegistry.registerAttribute(
did.getId(),
ddo.getChecksum(),
[this.config.brizoAddress],
serviceEndpoint,
publisher.getId(),
publisher.getId()
)
this.logger.log("DID registred")
this.logger.log('DID registred')
observer.next(CreateProgressStep.DidRegistred)
this.logger.log("Storing DDO")
this.logger.log('Storing DDO')
observer.next(CreateProgressStep.StoringDdo)
const storedDdo = await this.ocean.aquarius.storeDDO(ddo)
this.logger.log("DDO stored")
this.logger.log('DDO stored')
observer.next(CreateProgressStep.DdoStored)
return storedDdo
})
}
// tslint:disable-next-line
public async consume(agreementId: string, did: string, serviceDefinitionId: string, consumerAccount: Account, resultPath: string, index?: number): Promise<string>
// tslint:disable-next-line
public async consume(agreementId: string, did: string, serviceDefinitionId: string, consumerAccount: Account, resultPath?: undefined | null, index?: number): Promise<true>
public async consume(
agreementId: string,
did: string,
serviceDefinitionId: string,
consumerAccount: Account,
resultPath: string,
index?: number
): Promise<string>
public async consume(
agreementId: string,
did: string,
serviceDefinitionId: string,
consumerAccount: Account,
resultPath?: undefined | null,
index?: number
): Promise<true>
public async consume(
agreementId: string,
did: string,
serviceDefinitionId: string,
consumerAccount: Account,
resultPath?: string,
index: number = -1,
index: number = -1
): Promise<string | true> {
const ddo = await this.resolve(did)
const {metadata} = ddo.findServiceByType("Metadata")
const { metadata } = ddo.findServiceByType('Metadata')
const accessService = ddo.findServiceById(serviceDefinitionId)
const files = metadata.base.files
const { files } = metadata.base
const {serviceEndpoint} = accessService
const { serviceEndpoint } = accessService
if (!serviceEndpoint) {
throw new Error("Consume asset failed, service definition is missing the `serviceEndpoint`.")
throw new Error(
'Consume asset failed, service definition is missing the `serviceEndpoint`.'
)
}
this.logger.log("Consuming files")
this.logger.log('Consuming files')
resultPath = resultPath ? `${resultPath}/datafile.${ddo.shortId()}.${serviceDefinitionId}/` : undefined
resultPath = resultPath
? `${resultPath}/datafile.${ddo.shortId()}.${serviceDefinitionId}/`
: undefined
await this.ocean.brizo.consumeService(
agreementId,
serviceEndpoint,
consumerAccount,
files,
resultPath,
index,
index
)
this.logger.log("Files consumed")
this.logger.log('Files consumed')
if (resultPath) {
return resultPath
@ -230,60 +274,73 @@ export class OceanAssets extends Instantiable {
public order(
did: string,
serviceDefinitionId: string,
consumer: Account,
consumer: Account
): SubscribablePromise<OrderProgressStep, string> {
return new SubscribablePromise(async (observer) => {
return new SubscribablePromise(async observer => {
const oceanAgreements = this.ocean.agreements
const agreementId = zeroX(generateId())
const ddo = await this.resolve(did)
const keeper = this.ocean.keeper
const templateName = ddo.findServiceByType("Access").serviceAgreementTemplate.contractName
const { keeper } = this.ocean
const templateName = ddo.findServiceByType('Access')
.serviceAgreementTemplate.contractName
const template = keeper.getTemplateByName(templateName)
const accessCondition = keeper.conditions.accessSecretStoreCondition
const paymentFlow = new Promise(async (resolve, reject) => {
await template.getAgreementCreatedEvent(agreementId).once()
this.logger.log("Agreement initialized")
this.logger.log('Agreement initialized')
observer.next(OrderProgressStep.AgreementInitialized)
const {metadata} = ddo.findServiceByType("Metadata")
const { metadata } = ddo.findServiceByType('Metadata')
this.logger.log("Locking payment")
this.logger.log('Locking payment')
const accessGranted = accessCondition.getConditionFulfilledEvent(agreementId).once()
const accessGranted = accessCondition
.getConditionFulfilledEvent(agreementId)
.once()
observer.next(OrderProgressStep.LockingPayment)
const paid = await oceanAgreements.conditions.lockReward(agreementId, metadata.base.price, consumer)
const paid = await oceanAgreements.conditions.lockReward(
agreementId,
metadata.base.price,
consumer
)
observer.next(OrderProgressStep.LockedPayment)
if (paid) {
this.logger.log("Payment was OK")
this.logger.log('Payment was OK')
} else {
this.logger.error("Payment was KO")
this.logger.error("Agreement ID: ", agreementId)
this.logger.error("DID: ", ddo.id)
reject("Error on payment")
this.logger.error('Payment was KO')
this.logger.error('Agreement ID: ', agreementId)
this.logger.error('DID: ', ddo.id)
reject('Error on payment')
}
await accessGranted
this.logger.log("Access granted")
this.logger.log('Access granted')
resolve()
})
observer.next(OrderProgressStep.CreatingAgreement)
this.logger.log("Creating agreement")
await oceanAgreements.create(did, agreementId, serviceDefinitionId, undefined, consumer, consumer)
this.logger.log("Agreement created")
this.logger.log('Creating agreement')
await oceanAgreements.create(
did,
agreementId,
serviceDefinitionId,
undefined,
consumer,
consumer
)
this.logger.log('Agreement created')
try {
await paymentFlow
} catch (e) {
throw new Error("Error paying the asset.")
throw new Error('Error paying the asset.')
}
return agreementId
@ -298,11 +355,16 @@ export class OceanAssets extends Instantiable {
public async owner(did: string): Promise<string> {
const ddo = await this.resolve(did)
const checksum = ddo.getChecksum()
const {creator, signatureValue} = ddo.proof
const signer = await this.ocean.utils.signature.verifyText(checksum, signatureValue)
const { creator, signatureValue } = ddo.proof
const signer = await this.ocean.utils.signature.verifyText(
checksum,
signatureValue
)
if (signer.toLowerCase() !== creator.toLowerCase()) {
this.logger.warn(`Owner of ${ddo.id} doesn't match. Expected ${creator} instead of ${signer}.`)
this.logger.warn(
`Owner of ${ddo.id} doesn't match. Expected ${creator} instead of ${signer}.`
)
}
return creator
@ -323,8 +385,9 @@ export class OceanAssets extends Instantiable {
* @return {Promise<string[]>} List of DIDs.
*/
public async consumerAssets(consumer: string) {
return (await this.ocean.keeper.conditions.accessSecretStoreCondition.getGrantedDidByConsumer(consumer))
.map(({did}) => did)
return (await this.ocean.keeper.conditions.accessSecretStoreCondition.getGrantedDidByConsumer(
consumer
)).map(({ did }) => did)
}
/**
@ -347,11 +410,11 @@ export class OceanAssets extends Instantiable {
page: 1,
offset: 100,
query: {
value: 1,
value: 1
},
sort: {
value: 1,
},
value: 1
}
} as SearchQuery)
}
}

View File

@ -1,20 +1,21 @@
import Account from "./Account"
import { Instantiable, InstantiableConfig } from "../Instantiable.abstract"
import Account from './Account'
import { Instantiable, InstantiableConfig } from '../Instantiable.abstract'
const defaultAuthMessage = "Ocean Protocol Authentication"
const defaultAuthMessage = 'Ocean Protocol Authentication'
const defaultExpirationTime = 30 * 24 * 60 * 60 * 1000 // 30 days
const localStorageKey = "SquidTokens"
const localStorageKey = 'SquidTokens'
/**
* Tokens submodule of Ocean Protocol.
*/
export class OceanAuth extends Instantiable {
/**
* Returns the instance of OceanAuth.
* @return {Promise<OceanAuth>}
*/
public static async getInstance(config: InstantiableConfig): Promise<OceanAuth> {
public static async getInstance(
config: InstantiableConfig
): Promise<OceanAuth> {
const instance = new OceanAuth()
instance.setInstanceConfig(config)
@ -31,16 +32,15 @@ export class OceanAuth extends Instantiable {
const message = `${this.getMessage()}\n${time}`
try {
const signature = await this.ocean.utils.signature
.signText(
message,
account.getId(),
account.getPassword(),
)
const signature = await this.ocean.utils.signature.signText(
message,
account.getId(),
account.getPassword()
)
return `${signature}-${time}`
} catch {
throw new Error("User denied the signature.")
throw new Error('User denied the signature.')
}
}
@ -51,16 +51,16 @@ export class OceanAuth extends Instantiable {
*/
public async check(token: string): Promise<string> {
const expiration = this.getExpiration()
const [signature, timestamp] = token.split("-")
const [signature, timestamp] = token.split('-')
const message = `${this.getMessage()}\n${timestamp}`
if (((+timestamp * 1000) + expiration) < Date.now()) {
return `0x${"0".repeat(40)}`
if (+timestamp * 1000 + expiration < Date.now()) {
return `0x${'0'.repeat(40)}`
}
return this.web3.utils.toChecksumAddress(
await this.ocean.utils.signature.verifyText(message, signature),
await this.ocean.utils.signature.verifyText(message, signature)
)
}
@ -100,7 +100,7 @@ export class OceanAuth extends Instantiable {
* @return {Promise<boolean>} Is stored and valid.
*/
public async isStored(account: Account): Promise<boolean> {
return !!await this.restore(account)
return !!(await this.restore(account))
}
private writeToken(address: string, token: string) {
@ -108,10 +108,13 @@ export class OceanAuth extends Instantiable {
const storedTokens = localStorage.getItem(localStorageKey)
const tokens = storedTokens ? JSON.parse(storedTokens) : {}
localStorage.setItem(localStorageKey, JSON.stringify({
...tokens,
[address]: token,
}))
localStorage.setItem(
localStorageKey,
JSON.stringify({
...tokens,
[address]: token
})
)
}
private readToken(address: string) {
@ -124,9 +127,11 @@ export class OceanAuth extends Instantiable {
private getLocalStorage() {
try {
localStorage.getItem("")
localStorage.getItem('')
} catch {
throw new Error("LocalStorage is not supported. This feature is only available on browsers.")
throw new Error(
'LocalStorage is not supported. This feature is only available on browsers.'
)
}
return localStorage
}

View File

@ -1,18 +1,18 @@
import Account from "./Account"
import { noDidPrefixed } from "../utils"
import { File } from "../ddo/MetaData"
import { Instantiable, InstantiableConfig } from "../Instantiable.abstract"
import Account from './Account'
import { noDidPrefixed } from '../utils'
import { Instantiable, InstantiableConfig } from '../Instantiable.abstract'
/**
* SecretStore submodule of Ocean Protocol.
*/
export class OceanSecretStore extends Instantiable {
/**
* Returns the instance of OceanSecretStore.
* @return {Promise<OceanSecretStore>}
*/
public static async getInstance(config: InstantiableConfig): Promise<OceanSecretStore> {
public static async getInstance(
config: InstantiableConfig
): Promise<OceanSecretStore> {
const instance = new OceanSecretStore()
instance.setInstanceConfig(config)
@ -27,11 +27,24 @@ export class OceanSecretStore extends Instantiable {
* @param {string} publisher Publisher account.
* @return {Promise<string>} Encrypted text.
*/
public async encrypt(did: string, document: any, publisher: Account): Promise<string> {
public async encrypt(
did: string,
document: any,
publisher: Account
): Promise<string> {
const signature =
await publisher.getToken()
|| await this.ocean.utils.signature.signText(noDidPrefixed(did), publisher.getId(), publisher.getPassword())
(await publisher.getToken()) ||
(await this.ocean.utils.signature.signText(
noDidPrefixed(did),
publisher.getId(),
publisher.getPassword()
))
return await this.ocean.brizo.encrypt(noDidPrefixed(did), signature, document, publisher.getId())
return this.ocean.brizo.encrypt(
noDidPrefixed(did),
signature,
document,
publisher.getId()
)
}
}

View File

@ -1,16 +1,17 @@
import Account from "./Account"
import { Instantiable, InstantiableConfig } from "../Instantiable.abstract"
import Account from './Account'
import { Instantiable, InstantiableConfig } from '../Instantiable.abstract'
/**
* Tokens submodule of Ocean Protocol.
*/
export class OceanTokens extends Instantiable {
/**
* Returns the instance of OceanTokens.
* @return {Promise<OceanTokens>}
*/
public static async getInstance(config: InstantiableConfig): Promise<OceanTokens> {
public static async getInstance(
config: InstantiableConfig
): Promise<OceanTokens> {
const instance = new OceanTokens()
instance.setInstanceConfig(config)
@ -24,10 +25,12 @@ export class OceanTokens extends Instantiable {
* @param {Account} from Sender account address.
* @return {Promise<boolean>} Success,
*/
public async transfer(to: string, amount: number, from: Account): Promise<boolean> {
this.ocean.keeper
.token
.transfer(to, amount, from.getId())
public async transfer(
to: string,
amount: number,
from: Account
): Promise<boolean> {
this.ocean.keeper.token.transfer(to, amount, from.getId())
return true
}

View File

@ -1,13 +1,13 @@
import * as keeperPackageJson from "@oceanprotocol/keeper-contracts/package.json"
import * as metadata from "../metadata.json"
import * as keeperPackageJson from '@oceanprotocol/keeper-contracts/package.json'
import * as metadata from '../metadata.json'
import { Instantiable, InstantiableConfig } from "../Instantiable.abstract"
import { Instantiable, InstantiableConfig } from '../Instantiable.abstract'
export enum OceanPlatformTechStatus {
Loading = "Loading",
Unknown = "Unknown",
Stopped = "Stopped",
Working = "Working",
Loading = 'Loading',
Unknown = 'Unknown',
Stopped = 'Stopped',
Working = 'Working'
}
export interface OceanPlatformTech {
@ -20,7 +20,7 @@ export interface OceanPlatformTech {
export interface OceanPlatformKeeperTech extends OceanPlatformTech {
network?: string
keeperVersion?: string
contracts?: {[contractName: string]: string}
contracts?: { [contractName: string]: string }
}
export interface OceanPlatformVersions {
@ -30,7 +30,7 @@ export interface OceanPlatformVersions {
status: {
ok: boolean
contracts: boolean
network: boolean,
network: boolean
}
}
@ -38,12 +38,13 @@ export interface OceanPlatformVersions {
* Versions submodule of Ocean Protocol.
*/
export class OceanVersions extends Instantiable {
/**
* Returns the instance of OceanVersions.
* @return {Promise<OceanVersions>}
*/
public static async getInstance(config: InstantiableConfig): Promise<OceanVersions> {
public static async getInstance(
config: InstantiableConfig
): Promise<OceanVersions> {
const instance = new OceanVersions()
instance.setInstanceConfig(config)
@ -55,50 +56,62 @@ export class OceanVersions extends Instantiable {
// Squid
versions.squid = {
name: "Squid-js",
name: 'Squid-js',
version: metadata.version,
commit: metadata.commit,
status: OceanPlatformTechStatus.Working,
network: (await this.ocean.keeper.getNetworkName()).toLowerCase(),
keeperVersion: keeperPackageJson.version,
contracts: Object.values(await this.ocean.keeper.getAllInstances())
.reduce((acc, {contractName, address}) => ({
contracts: Object.values(
await this.ocean.keeper.getAllInstances()
).reduce(
(acc, { contractName, address }) => ({
...acc,
[contractName]: address,
}), {}),
[contractName]: address
}),
{}
)
}
// Brizo
try {
const {contracts, "keeper-version": keeperVersion, network, software: name, version} =
await this.ocean.brizo.getVersionInfo()
const {
contracts,
'keeper-version': keeperVersion,
network,
software: name,
version
} = await this.ocean.brizo.getVersionInfo()
versions.brizo = {
name,
status: OceanPlatformTechStatus.Working,
version,
contracts,
network,
keeperVersion: keeperVersion.replace(/^v/, ""),
keeperVersion: keeperVersion.replace(/^v/, '')
}
} catch {
versions.brizo = {
name: "Brizo",
status: OceanPlatformTechStatus.Stopped,
name: 'Brizo',
status: OceanPlatformTechStatus.Stopped
}
}
// Aquarius
try {
const {software: name, version} = await this.ocean.aquarius.getVersionInfo()
const {
software: name,
version
} = await this.ocean.aquarius.getVersionInfo()
versions.aquarius = {
name,
status: OceanPlatformTechStatus.Working,
version,
version
}
} catch {
versions.aquarius = {
name: "Aquarius",
status: OceanPlatformTechStatus.Stopped,
name: 'Aquarius',
status: OceanPlatformTechStatus.Stopped
}
}
@ -106,22 +119,22 @@ export class OceanVersions extends Instantiable {
const techs: OceanPlatformKeeperTech[] = Object.values(versions as any)
const networks = techs
.map(({network}) => network)
.filter((_) => !!_)
.reduce((acc, network) => ({...acc, [network]: true}), {})
.map(({ network }) => network)
.filter(_ => !!_)
.reduce((acc, network) => ({ ...acc, [network]: true }), {})
let contractStatus = true
const contractList = techs
.map(({contracts}) => contracts)
.filter((_) => !!_)
.map(({ contracts }) => contracts)
.filter(_ => !!_)
Array.from(contractList.map(Object.keys))
.reduce((acc, _) => [...acc, ..._], [])
.filter((_, i, list) => list.indexOf(_) === i)
.forEach((name) => {
.forEach(name => {
let address
contractList
.map((_) => _[name])
.forEach((_) => {
.map(_ => _[name])
.forEach(_ => {
if (!address) {
address = _
return
@ -133,9 +146,11 @@ export class OceanVersions extends Instantiable {
})
versions.status = {
ok: !techs.find(({status}) => status !== OceanPlatformTechStatus.Working),
ok: !techs.find(
({ status }) => status !== OceanPlatformTechStatus.Working
),
network: Object.keys(networks).length === 1,
contracts: contractStatus,
contracts: contractStatus
}
return versions

View File

@ -1,19 +1,20 @@
import { Instantiable, InstantiableConfig } from "../../Instantiable.abstract"
import { Instantiable, InstantiableConfig } from '../../Instantiable.abstract'
import { ServiceAgreement } from "./ServiceAgreement"
import { SignatureUtils } from "./SignatureUtils"
import { WebServiceConnector } from "./WebServiceConnector"
import { ServiceAgreement } from './ServiceAgreement'
import { SignatureUtils } from './SignatureUtils'
import { WebServiceConnector } from './WebServiceConnector'
/**
* Utils internal submodule of Ocean Protocol.
*/
export class OceanUtils extends Instantiable {
/**
* Returns the instance of OceanUtils.
* @return {Promise<OceanUtils>}
*/
public static async getInstance(config: InstantiableConfig): Promise<OceanUtils> {
public static async getInstance(
config: InstantiableConfig
): Promise<OceanUtils> {
const instance = new OceanUtils()
instance.setInstanceConfig(config)

View File

@ -1,13 +1,11 @@
import * as Web3 from "web3"
import { ServiceAgreementTemplateCondition } from "../../ddo/ServiceAgreementTemplate"
import { DDO } from "../../ddo/DDO"
import { ServiceAccess } from "../../ddo/Service"
import Account from "../Account"
import { zeroX } from "../../utils"
import { Instantiable, InstantiableConfig } from "../../Instantiable.abstract"
import { ServiceAgreementTemplateCondition } from '../../ddo/ServiceAgreementTemplate'
import { DDO } from '../../ddo/DDO'
import { ServiceAccess } from '../../ddo/Service'
import Account from '../Account'
import { zeroX } from '../../utils'
import { Instantiable, InstantiableConfig } from '../../Instantiable.abstract'
export class ServiceAgreement extends Instantiable {
constructor(config: InstantiableConfig) {
super()
this.setInstanceConfig(config)
@ -18,15 +16,20 @@ export class ServiceAgreement extends Instantiable {
serviceDefinitionId: string,
serviceAgreementId: string,
agreementConditionsIds: string[],
consumer: Account,
consumer: Account
): Promise<string> {
const service = ddo.findServiceById<"Access">(serviceDefinitionId)
const timelockValues: number[] = this.getTimeValuesFromService(service, "timelock")
const timeoutValues: number[] = this.getTimeValuesFromService(service, "timeout")
const service = ddo.findServiceById<'Access'>(serviceDefinitionId)
const timelockValues: number[] = this.getTimeValuesFromService(
service,
'timelock'
)
const timeoutValues: number[] = this.getTimeValuesFromService(
service,
'timeout'
)
if (!service.templateId) {
throw new Error("TemplateId not found in DDO.")
throw new Error('TemplateId not found in DDO.')
}
const serviceAgreementHashSignature = await this.createHashSignature(
@ -35,10 +38,10 @@ export class ServiceAgreement extends Instantiable {
agreementConditionsIds,
timelockValues,
timeoutValues,
consumer,
consumer
)
this.logger.debug("SA hash signature:", serviceAgreementHashSignature)
this.logger.debug('SA hash signature:', serviceAgreementHashSignature)
return serviceAgreementHashSignature
}
@ -49,19 +52,21 @@ export class ServiceAgreement extends Instantiable {
valueHashes: string[],
timelockValues: number[],
timeoutValues: number[],
consumer: Account,
consumer: Account
): Promise<string> {
const serviceAgreementHash = this.hashServiceAgreement(
templateId,
serviceAgreementId,
valueHashes,
timelockValues,
timeoutValues,
timeoutValues
)
const serviceAgreementHashSignature = await this.ocean.utils.signature
.signText(serviceAgreementHash, consumer.getId(), consumer.getPassword())
const serviceAgreementHashSignature = await this.ocean.utils.signature.signText(
serviceAgreementHash,
consumer.getId(),
consumer.getPassword()
)
return serviceAgreementHashSignature
}
@ -71,23 +76,26 @@ export class ServiceAgreement extends Instantiable {
serviceAgreementId: string,
valueHashes: string[],
timelocks: number[],
timeouts: number[],
timeouts: number[]
): string {
const args = [
{type: "address", value: zeroX(serviceAgreementTemplateId)},
{type: "bytes32[]", value: valueHashes.map(zeroX)},
{type: "uint256[]", value: timelocks},
{type: "uint256[]", value: timeouts},
{type: "bytes32", value: zeroX(serviceAgreementId)},
{ type: 'address', value: zeroX(serviceAgreementTemplateId) },
{ type: 'bytes32[]', value: valueHashes.map(zeroX) },
{ type: 'uint256[]', value: timelocks },
{ type: 'uint256[]', value: timeouts },
{ type: 'bytes32', value: zeroX(serviceAgreementId) }
]
return this.web3.utils.soliditySha3(...args).toString("hex")
return this.web3.utils.soliditySha3(...args).toString('hex')
}
private getTimeValuesFromService(service: ServiceAccess, type: "timeout" | "timelock"): number[] {
const timeoutValues: number[] = service.serviceAgreementTemplate.conditions
.map((condition: ServiceAgreementTemplateCondition) => condition[type])
private getTimeValuesFromService(
service: ServiceAccess,
type: 'timeout' | 'timelock'
): number[] {
const timeoutValues: number[] = service.serviceAgreementTemplate.conditions.map(
(condition: ServiceAgreementTemplateCondition) => condition[type]
)
return timeoutValues
}

View File

@ -1,28 +1,34 @@
import { Instantiable, InstantiableConfig } from "../../Instantiable.abstract"
import { Instantiable, InstantiableConfig } from '../../Instantiable.abstract'
export class SignatureUtils extends Instantiable {
constructor(config: InstantiableConfig) {
super()
this.setInstanceConfig(config)
}
public async signText(text: string, publicKey: string, password?: string): Promise<string> {
const isMetaMask = this.web3 && this.web3.currentProvider && this.web3.currentProvider.isMetaMask
public async signText(
text: string,
publicKey: string,
password?: string
): Promise<string> {
const isMetaMask =
this.web3 &&
this.web3.currentProvider &&
this.web3.currentProvider.isMetaMask
try {
return await this.web3.eth.personal.sign(text, publicKey, password)
} catch (e) {
if (isMetaMask) {
throw e
}
this.logger.warn("Error on personal sign.")
this.logger.warn('Error on personal sign.')
this.logger.warn(e)
try {
return await this.web3.eth.sign(text, publicKey, password)
} catch (e2) {
this.logger.error("Error on sign.")
this.logger.error('Error on sign.')
this.logger.error(e2)
throw new Error("Error executing personal sign")
throw new Error('Error executing personal sign')
}
}
}

View File

@ -1,11 +1,10 @@
import fetch, { BodyInit, RequestInit, Response } from "node-fetch"
import { Instantiable, InstantiableConfig } from "../../Instantiable.abstract"
import fetch, { BodyInit, RequestInit, Response } from 'node-fetch'
import { Instantiable, InstantiableConfig } from '../../Instantiable.abstract'
/**
* Provides a common interface to web services.
*/
export class WebServiceConnector extends Instantiable {
constructor(config: InstantiableConfig) {
super()
this.setInstanceConfig(config)
@ -13,30 +12,30 @@ export class WebServiceConnector extends Instantiable {
public post(url: string, payload: BodyInit): Promise<Response> {
return this.fetch(url, {
method: "POST",
method: 'POST',
body: payload,
headers: {
"Content-type": "application/json",
},
'Content-type': 'application/json'
}
})
}
public get(url: string): Promise<Response> {
return this.fetch(url, {
method: "GET",
method: 'GET',
headers: {
"Content-type": "application/json",
},
'Content-type': 'application/json'
}
})
}
public put(url: string, payload: BodyInit): Promise<Response> {
return this.fetch(url, {
method: "PUT",
method: 'PUT',
body: payload,
headers: {
"Content-type": "application/json",
},
'Content-type': 'application/json'
}
})
}

View File

@ -1,34 +1,37 @@
import Config from "./models/Config"
import Account from "./ocean/Account"
import DID from "./ocean/DID"
import { Ocean } from "./ocean/Ocean"
import { LoggerInstance as Logger} from "./utils/Logger"
import Keeper from "./keeper/Keeper"
import Config from './models/Config'
import Account from './ocean/Account'
import DID from './ocean/DID'
import { Ocean } from './ocean/Ocean'
import { LoggerInstance as Logger } from './utils/Logger'
import Keeper from './keeper/Keeper'
import * as templates from "./keeper/contracts/templates"
import * as conditions from "./keeper/contracts/conditions"
import * as utils from "./utils"
import * as templates from './keeper/contracts/templates'
import * as conditions from './keeper/contracts/conditions'
import * as utils from './utils'
// Exports
export * from "./ddo/DDO"
export * from "./ddo/MetaData"
export * from './ddo/DDO'
export * from './ddo/MetaData'
export { OrderProgressStep, CreateProgressStep } from "./ocean/OceanAssets"
export { OceanPlatformTechStatus, OceanPlatformTech, OceanPlatformKeeperTech, OceanPlatformVersions } from "./ocean/OceanVersions"
export { OrderProgressStep, CreateProgressStep } from './ocean/OceanAssets'
export {
OceanPlatformTechStatus,
OceanPlatformTech,
OceanPlatformKeeperTech,
OceanPlatformVersions
} from './ocean/OceanVersions'
export { AgreementTemplate } from "./keeper/contracts/templates"
export { Condition, ConditionState } from "./keeper/contracts/conditions"
export { AgreementTemplate } from './keeper/contracts/templates'
export { Condition, ConditionState } from './keeper/contracts/conditions'
export {
Ocean,
Account,
Config,
DID,
Logger,
Keeper,
conditions,
templates,
utils,
utils
}

View File

@ -1,35 +1,49 @@
import { LoggerInstance } from "./Logger"
import { LoggerInstance } from './Logger'
// Ox transformer
export const zeroX = (input: string) => zeroXTransformer(input, true)
export const noZeroX = (input: string) => zeroXTransformer(input, false)
export function zeroXTransformer(input: string = "", zeroOutput: boolean) {
const {valid, output} = inputMatch(input, /^(?:0x)*([a-f0-9]+)$/i, "zeroXTransformer")
return (zeroOutput && valid ? "0x" : "") + output
export function zeroXTransformer(input: string = '', zeroOutput: boolean) {
const { valid, output } = inputMatch(
input,
/^(?:0x)*([a-f0-9]+)$/i,
'zeroXTransformer'
)
return (zeroOutput && valid ? '0x' : '') + output
}
// did:op: transformer
export const didPrefixed = (input: string) => didTransformer(input, true)
export const noDidPrefixed = (input: string) => didTransformer(input, false)
export function didTransformer(input: string = "", prefixOutput: boolean) {
const {valid, output} = inputMatch(input, /^(?:0x|did:op:)*([a-f0-9]{64})$/i, "didTransformer")
return (prefixOutput && valid ? "did:op:" : "") + output
export function didTransformer(input: string = '', prefixOutput: boolean) {
const { valid, output } = inputMatch(
input,
/^(?:0x|did:op:)*([a-f0-9]{64})$/i,
'didTransformer'
)
return (prefixOutput && valid ? 'did:op:' : '') + output
}
// 0x + did:op: transformer
export const didZeroX = (input: string) => zeroX(didTransformer(input, false))
// Shared functions
function inputMatch(input: string, regexp: RegExp, conversorName: string): {valid: boolean, output: string} {
if (typeof input !== "string") {
LoggerInstance.debug("Not input string:")
function inputMatch(
input: string,
regexp: RegExp,
conversorName: string
): { valid: boolean; output: string } {
if (typeof input !== 'string') {
LoggerInstance.debug('Not input string:')
LoggerInstance.debug(input)
throw new Error(`[${conversorName}] Expected string, input type: ${typeof input}`)
throw new Error(
`[${conversorName}] Expected string, input type: ${typeof input}`
)
}
const match = input.match(regexp)
if (!match) {
const match = input.match(regexp)
if (!match) {
LoggerInstance.warn(`[${conversorName}] Input transformation failed.`)
return {valid: false, output: input}
return { valid: false, output: input }
}
return {valid: true, output: match[1]}
return { valid: true, output: match[1] }
}

View File

@ -1,25 +1,33 @@
import { DDO } from "../ddo/DDO"
import { ServiceAgreementTemplateCondition, ServiceAgreementTemplateParameter } from "../ddo/ServiceAgreementTemplate"
import { DDO } from '../ddo/DDO'
import {
ServiceAgreementTemplateCondition,
ServiceAgreementTemplateParameter
} from '../ddo/ServiceAgreementTemplate'
function fillParameterWithDDO(parameter: ServiceAgreementTemplateParameter, ddo: DDO): ServiceAgreementTemplateParameter {
const getValue = (name) => {
function fillParameterWithDDO(
parameter: ServiceAgreementTemplateParameter,
ddo: DDO
): ServiceAgreementTemplateParameter {
const getValue = name => {
switch (name) {
case "amount":
case "price":
return String(ddo.findServiceByType("Metadata").metadata.base.price)
case "assetId":
case "documentId":
case "documentKeyId":
case 'amount':
case 'price':
return String(
ddo.findServiceByType('Metadata').metadata.base.price
)
case 'assetId':
case 'documentId':
case 'documentKeyId':
return ddo.shortId()
case "rewardAddress":
case 'rewardAddress':
return ddo.publicKey[0].owner
}
return ""
return ''
}
const value = getValue(parameter.name.replace(/^_/, ""))
const value = getValue(parameter.name.replace(/^_/, ''))
return {...parameter, value}
return { ...parameter, value }
}
/**
@ -28,13 +36,14 @@ function fillParameterWithDDO(parameter: ServiceAgreementTemplateParameter, ddo:
* @param {DDO} ddo DDO related to this conditions.
* @return {ServiceAgreementTemplateCondition[]} Filled conditions.
*/
export function fillConditionsWithDDO(conditions: ServiceAgreementTemplateCondition[], ddo: DDO): ServiceAgreementTemplateCondition[] {
return conditions
.map((condition) => ({
...condition,
parameters: condition.parameters
.map((parameter) => ({
...fillParameterWithDDO(parameter, ddo),
})),
export function fillConditionsWithDDO(
conditions: ServiceAgreementTemplateCondition[],
ddo: DDO
): ServiceAgreementTemplateCondition[] {
return conditions.map(condition => ({
...condition,
parameters: condition.parameters.map(parameter => ({
...fillParameterWithDDO(parameter, ddo)
}))
}))
}

View File

@ -1,9 +1,9 @@
import {v4} from "uuid"
import { v4 } from 'uuid'
export function generateId(length = 64) {
let id = ""
let id = ''
while (id.length < length) {
id += v4().replace(/-/g, "")
id += v4().replace(/-/g, '')
}
return id.substr(0, length)
}

View File

@ -3,35 +3,34 @@ export enum LogLevel {
Error = 0,
Warn = 1,
Log = 2,
Verbose = 3,
Verbose = 3
}
export class Logger {
constructor(private logLevel: LogLevel = LogLevel.Verbose) { }
constructor(private logLevel: LogLevel = LogLevel.Verbose) {}
public setLevel(logLevel: LogLevel) {
this.logLevel = logLevel
}
public bypass(...args: any[]) {
this.dispatch("log", -Infinity as any, ...args)
this.dispatch('log', -Infinity as any, ...args)
}
public debug(...args: any[]) {
this.dispatch("debug", LogLevel.Verbose, ...args)
this.dispatch('debug', LogLevel.Verbose, ...args)
}
public log(...args: any[]) {
this.dispatch("log", LogLevel.Log, ...args)
this.dispatch('log', LogLevel.Log, ...args)
}
public warn(...args: any[]) {
this.dispatch("warn", LogLevel.Warn, ...args)
this.dispatch('warn', LogLevel.Warn, ...args)
}
public error(...args: any[]) {
this.dispatch("error", LogLevel.Error, ...args)
this.dispatch('error', LogLevel.Error, ...args)
}
private dispatch(verb: string, level: LogLevel, ...args: any[]) {

View File

@ -1,12 +1,17 @@
const zipObject = (keys = [], values = []) => {
return keys.reduce((acc, key, index) => ({
...acc,
[key]: values[index],
}), {})
return keys.reduce(
(acc, key, index) => ({
...acc,
[key]: values[index]
}),
{}
)
}
export const objectPromiseAll = async (obj: {[key: string]: Promise<any>}) => {
const keys = Object.keys(obj)
const result = await Promise.all(Object.values(obj))
return zipObject(keys, result)
export const objectPromiseAll = async (obj: {
[key: string]: Promise<any>
}) => {
const keys = Object.keys(obj)
const result = await Promise.all(Object.values(obj))
return zipObject(keys, result)
}

View File

@ -1,37 +1,47 @@
export class SubscribableObserver<T, P> {
public completed: boolean = false
private subscriptions = new Set<{onNext?: (next: T) => void, onComplete?: (complete: P) => void, onError?: (error: any) => void}>()
private subscriptions = new Set<{
onNext?: (next: T) => void
onComplete?: (complete: P) => void
onError?: (error: any) => void
}>()
public subscribe(onNext?: (next: T) => void, onComplete?: (complete: P) => void, onError?: (error: any) => void) {
public subscribe(
onNext?: (next: T) => void,
onComplete?: (complete: P) => void,
onError?: (error: any) => void
) {
if (this.completed) {
throw new Error("Observer completed.")
throw new Error('Observer completed.')
}
const subscription = {onNext, onComplete, onError}
const subscription = { onNext, onComplete, onError }
this.subscriptions.add(subscription)
return {
unsubscribe: () => this.subscriptions.delete(subscription),
unsubscribe: () => this.subscriptions.delete(subscription)
}
}
public next(next?: T): void {
this.emit("onNext", next)
this.emit('onNext', next)
}
public complete(resolve?: P): void {
this.emit("onComplete", resolve)
this.emit('onComplete', resolve)
this.unsubscribe()
}
public error(error?: any): void {
this.emit("onError", error)
this.emit('onError', error)
this.unsubscribe()
}
private emit(type: "onNext" | "onComplete" | "onError", value: any) {
private emit(type: 'onNext' | 'onComplete' | 'onError', value: any) {
Array.from(this.subscriptions)
.map((subscription) => subscription[type])
.filter((callback: any) => callback && typeof callback === "function")
.map(subscription => subscription[type])
.filter(
(callback: any) => callback && typeof callback === 'function'
)
.forEach((callback: any) => callback(value))
}

View File

@ -1,18 +1,19 @@
import { SubscribableObserver } from "./SubscribableObserver"
import { SubscribableObserver } from './SubscribableObserver'
export class SubscribablePromise<T extends any, P extends any> {
private observer = new SubscribableObserver<T, P>()
private promise = Object.assign(
new Promise<P>((resolve, reject) => {
setTimeout(() => {
this.observer
.subscribe(undefined, resolve, reject)
this.observer.subscribe(undefined, resolve, reject)
}, 0)
}),
this,
this
)
constructor(executor: (observer: SubscribableObserver<T, P>) => void | Promise<P>) {
constructor(
executor: (observer: SubscribableObserver<T, P>) => void | Promise<P>
) {
// Defear
setTimeout(() => this.init(executor), 1)
}
@ -26,7 +27,10 @@ export class SubscribablePromise<T extends any, P extends any> {
return this
}
public then(onfulfilled?: (value: P) => any, onrejected?: (error: any) => any) {
public then(
onfulfilled?: (value: P) => any,
onrejected?: (error: any) => any
) {
return Object.assign(this.promise.then(onfulfilled, onrejected), this)
}
@ -38,17 +42,19 @@ export class SubscribablePromise<T extends any, P extends any> {
return Object.assign(this.promise.finally(onfinally), this)
}
private init(executor: (observer: SubscribableObserver<T, P>) => void | Promise<P>) {
private init(
executor: (observer: SubscribableObserver<T, P>) => void | Promise<P>
) {
const execution = executor(this.observer)
Promise.resolve(execution as any)
.then((result) => {
if (typeof (execution as any).then === "function") {
.then(result => {
if (typeof (execution as any).then === 'function') {
this.observer.complete(result)
}
})
.catch((result) => {
if (typeof (execution as any).then === "function") {
.catch(result => {
if (typeof (execution as any).then === 'function') {
this.observer.error(result)
}
})

View File

@ -1,7 +1,7 @@
export * from "./PromiseResolver"
export * from "./Logger"
export * from "./ConversionTypeHelpers"
export * from "./GeneratorHelpers"
export * from "./DDOHelpers"
export * from "./SubscribablePromise"
export * from "./SubscribableObserver"
export * from './PromiseResolver'
export * from './Logger'
export * from './ConversionTypeHelpers'
export * from './GeneratorHelpers'
export * from './DDOHelpers'
export * from './SubscribablePromise'
export * from './SubscribableObserver'

View File

@ -1,11 +1,9 @@
import * as assert from "assert"
import * as squid from "../src/squid"
import * as assert from 'assert'
import * as squid from '../src/squid'
describe("Squid", () => {
describe("interface", () => {
it("should expose Ocean", async () => {
describe('Squid', () => {
describe('interface', () => {
it('should expose Ocean', async () => {
assert(squid.Ocean)
})
})

View File

@ -1,7 +1,7 @@
import { generateId } from "../src/utils/GeneratorHelpers"
import { generateId } from '../src/utils/GeneratorHelpers'
export default class TestIdGenerator {
public static generatePrefixedId() {
return "0x" + generateId()
return '0x' + generateId()
}
}

View File

@ -1,118 +1,124 @@
import { assert, spy, use } from "chai"
import * as spies from "chai-spies"
import { assert, spy, use } from 'chai'
import * as spies from 'chai-spies'
import { Ocean } from "../../src/ocean/Ocean"
import { Aquarius } from "../../src/aquarius/Aquarius"
import { SearchQuery } from "../../src/aquarius/Aquarius"
import { DDO } from "../../src/ddo/DDO"
import DID from "../../src/ocean/DID"
import config from "../config"
import { Ocean } from '../../src/ocean/Ocean'
import { Aquarius, SearchQuery } from '../../src/aquarius/Aquarius'
import { DDO } from '../../src/ddo/DDO'
import DID from '../../src/ocean/DID'
import config from '../config'
use(spies)
const reponsify = async (data) => ({ok: true, json: () => Promise.resolve(data)})
describe("Aquarius", () => {
const reponsify = async data => ({
ok: true,
json: () => Promise.resolve(data)
})
describe('Aquarius', () => {
let ocean: Ocean
let aquarius: Aquarius
// tslint:disable-next-line
const getResults = (results: DDO[], page = 0, total_pages = 1, total_results = 1) =>
({results, page, total_pages, total_results})
/* eslint-disable @typescript-eslint/camelcase */
const getResults = (
results: DDO[],
page = 0,
total_pages = 1,
total_results = 1
) => ({ results, page, total_pages, total_results })
/* eslint-enable @typescript-eslint/camelcase */
beforeEach(async () => {
ocean = await Ocean.getInstance(config)
aquarius = ocean.aquarius
aquarius = ocean.aquarius // eslint-disable-line prefer-destructuring
})
afterEach(() => {
spy.restore()
})
describe("#queryMetadata()", () => {
describe('#queryMetadata()', () => {
const query = {
offset: 100,
page: 1,
query: {
value: 1,
value: 1
},
sort: {
value: 1,
value: 1
},
text: "Office",
text: 'Office'
} as SearchQuery
it("should query metadata", async () => {
spy.on(ocean.utils.fetch, "post", () => reponsify(getResults([new DDO()])))
it('should query metadata', async () => {
spy.on(ocean.utils.fetch, 'post', () =>
reponsify(getResults([new DDO()]))
)
const result = await aquarius.queryMetadata(query)
assert.typeOf(result.results, "array")
assert.typeOf(result.results, 'array')
assert.lengthOf(result.results, 1)
assert.equal(result.page, 0)
assert.equal(result.totalPages, 1)
assert.equal(result.totalResults, 1)
})
it("should query metadata and return real ddo", async () => {
spy.on(ocean.utils.fetch, "post", () => reponsify(getResults([new DDO()])))
it('should query metadata and return real ddo', async () => {
spy.on(ocean.utils.fetch, 'post', () =>
reponsify(getResults([new DDO()]))
)
const result = await aquarius.queryMetadata(query)
assert.typeOf(result.results, "array")
assert.typeOf(result.results, 'array')
assert.lengthOf(result.results, 1)
assert.isDefined(result.results[0].findServiceById)
})
})
describe("#queryMetadataByText()", () => {
describe('#queryMetadataByText()', () => {
const query = {
offset: 100,
page: 1,
query: {
value: 1,
value: 1
},
sort: {
value: 1,
value: 1
},
text: "Office",
text: 'Office'
} as SearchQuery
it("should query metadata by text", async () => {
spy.on(ocean.utils.fetch, "get", () => reponsify(getResults([new DDO()])))
it('should query metadata by text', async () => {
spy.on(ocean.utils.fetch, 'get', () =>
reponsify(getResults([new DDO()]))
)
const result = await aquarius.queryMetadataByText(query)
assert.typeOf(result.results, "array")
assert.typeOf(result.results, 'array')
assert.lengthOf(result.results, 1)
assert.equal(result.page, 0)
assert.equal(result.totalPages, 1)
assert.equal(result.totalResults, 1)
})
it("should query metadata and return real ddo", async () => {
spy.on(ocean.utils.fetch, "get", () => reponsify(getResults([new DDO()])))
it('should query metadata and return real ddo', async () => {
spy.on(ocean.utils.fetch, 'get', () =>
reponsify(getResults([new DDO()]))
)
const result = await aquarius.queryMetadataByText(query)
assert.typeOf(result.results, "array")
assert.typeOf(result.results, 'array')
assert.lengthOf(result.results, 1)
assert.isDefined(result.results[0].findServiceById)
})
})
describe("#storeDDO()", () => {
it("should store a ddo", async () => {
describe('#storeDDO()', () => {
it('should store a ddo', async () => {
const did: DID = DID.generate()
const ddo: DDO = new DDO({
id: did.getId(),
id: did.getId()
})
spy.on(ocean.utils.fetch, "post", () => reponsify(ddo))
spy.on(ocean.utils.fetch, 'post', () => reponsify(ddo))
const result: DDO = await aquarius.storeDDO(ddo)
assert(result)
@ -120,17 +126,15 @@ describe("Aquarius", () => {
})
})
describe("#retrieveDDO()", () => {
it("should store a ddo", async () => {
describe('#retrieveDDO()', () => {
it('should store a ddo', async () => {
const did: DID = DID.generate()
const ddo: DDO = new DDO({
id: did.getId(),
id: did.getId()
})
spy.on(ocean.utils.fetch, "post", () => reponsify(ddo))
spy.on(ocean.utils.fetch, "get", () => reponsify(ddo))
spy.on(ocean.utils.fetch, 'post', () => reponsify(ddo))
spy.on(ocean.utils.fetch, 'get', () => reponsify(ddo))
const storageResult: DDO = await aquarius.storeDDO(ddo)
assert(storageResult)

View File

@ -1,13 +1,13 @@
import { Config, LogLevel } from "../src/models/Config"
import { LoggerInstance } from "../src/utils"
import { Config, LogLevel } from '../src/models/Config'
import { LoggerInstance } from '../src/utils'
LoggerInstance.setLevel(LogLevel.Error)
export default {
aquariusUri: "http://localhost:5000",
brizoUri: "http://localhost:3000",
aquariusUri: 'http://localhost:5000',
brizoUri: 'http://localhost:3000',
nodeUri: `http://localhost:${process.env.ETH_PORT || 8545}`,
parityUri: "http://localhost:9545",
secretStoreUri: "http://localhost:12001",
verbose: LogLevel.Error,
parityUri: 'http://localhost:9545',
secretStoreUri: 'http://localhost:12001',
verbose: LogLevel.Error
} as Config

View File

@ -1,157 +1,175 @@
import { assert, expect, spy, use } from "chai"
import * as spies from "chai-spies"
import * as Web3 from "web3"
import { assert, expect, spy, use } from 'chai'
import * as spies from 'chai-spies'
import * as Web3 from 'web3'
import { DDO } from "../../src/ddo/DDO"
import { Service } from "../../src/ddo/Service"
import { Ocean } from "../../src/ocean/Ocean"
import config from "../config"
import TestContractHandler from "../keeper/TestContractHandler"
import { DDO } from '../../src/ddo/DDO'
import { Service } from '../../src/ddo/Service'
import { Ocean } from '../../src/ocean/Ocean'
import config from '../config'
import TestContractHandler from '../keeper/TestContractHandler'
import * as jsonDDO from "../testdata/ddo.json"
import * as jsonDDO from '../testdata/ddo.json'
use(spies)
describe("DDO", () => {
describe('DDO', () => {
const testDDO: DDO = new DDO({
id: `did:op:${"a".repeat(64)}`,
id: `did:op:${'a'.repeat(64)}`,
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-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-2',
type: 'Ed25519VerificationKey2018',
owner: 'did:op:123456789abcdefghi',
publicKeyBase58: 'H3C2AVvLMv6gmMNam3uVAjZpfkcJCwDwnZn6z3wXmqPV'
}
],
authentication: [
{
type: "RsaSignatureAuthentication2018",
publicKey: "did:op:123456789abcdefghi#keys-1",
type: 'RsaSignatureAuthentication2018',
publicKey: 'did:op:123456789abcdefghi#keys-1'
},
{
type: "ieee2410Authentication2018",
publicKey: "did:op:123456789abcdefghi#keys-2",
},
type: 'ieee2410Authentication2018',
publicKey: 'did:op:123456789abcdefghi#keys-2'
}
],
service: [
{
type: "OpenIdConnectVersion1.0Service",
serviceEndpoint: "https://openid.example.com/",
type: 'OpenIdConnectVersion1.0Service',
serviceEndpoint: 'https://openid.example.com/'
},
{
type: "CredentialRepositoryService",
serviceEndpoint: "https://repository.example.com/service/8377464",
type: 'CredentialRepositoryService',
serviceEndpoint:
'https://repository.example.com/service/8377464'
},
{
type: "XdiService",
serviceEndpoint: "https://xdi.example.com/8377464",
type: 'XdiService',
serviceEndpoint: 'https://xdi.example.com/8377464'
},
{
type: "HubService",
serviceEndpoint: "https://hub.example.com/.identity/did:op:0123456789abcdef/",
type: 'HubService',
serviceEndpoint:
'https://hub.example.com/.identity/did:op:0123456789abcdef/'
},
{
type: "MessagingService",
serviceEndpoint: "https://example.com/messages/8377464",
type: 'MessagingService',
serviceEndpoint: 'https://example.com/messages/8377464'
},
{
type: "SocialWebInboxService",
serviceEndpoint: "https://social.example.com/83hfh37dj",
description: "My public social inbox",
type: 'SocialWebInboxService',
serviceEndpoint: 'https://social.example.com/83hfh37dj',
description: 'My public social inbox',
spamCost: {
amount: "0.50",
currency: "USD",
},
amount: '0.50',
currency: 'USD'
}
} as any,
{
id: "did:op:123456789abcdefghi;bops",
type: "BopsService",
serviceEndpoint: "https://bops.example.com/enterprise/",
id: 'did:op:123456789abcdefghi;bops',
type: 'BopsService',
serviceEndpoint: 'https://bops.example.com/enterprise/'
},
{
type: "Consume",
serviceEndpoint: "http://mybrizo.org/api/v1/brizo/services/consume?pubKey=${pubKey}&serviceId={serviceId}&url={url}",
type: 'Consume',
serviceEndpoint:
'http://mybrizo.org/api/v1/brizo/services/consume?pubKey=${pubKey}&serviceId={serviceId}&url={url}'
},
{
type: "Compute",
type: 'Compute',
// tslint:disable-next-line
serviceEndpoint: "http://mybrizo.org/api/v1/brizo/services/compute?pubKey=${pubKey}&serviceId={serviceId}&algo={algo}&container={container}",
serviceEndpoint:
'http://mybrizo.org/api/v1/brizo/services/compute?pubKey=${pubKey}&serviceId={serviceId}&algo={algo}&container={container}'
},
{
type: "Metadata",
serviceEndpoint: "http://myaquarius.org/api/v1/provider/assets/metadata/{did}",
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",
dateCreated: "2012-10-10T17:00:000Z",
datePublished: "2012-10-10T17:00:000Z",
author: "Met Office",
license: "CC-BY",
copyrightHolder: "Met Office",
workExample: "423432fsd,51.509865,-0.118092,2011-01-01T10:55:11+00:00,7.2,68",
name: 'UK Weather information 2011',
type: 'dataset',
description:
'Weather information of UK including temperature and humidity',
dateCreated: '2012-10-10T17:00:000Z',
datePublished: '2012-10-10T17:00:000Z',
author: 'Met Office',
license: 'CC-BY',
copyrightHolder: 'Met Office',
workExample:
'423432fsd,51.509865,-0.118092,2011-01-01T10:55:11+00:00,7.2,68',
links: [
{
sample1: "http://data.ceda.ac.uk/badc/ukcp09/data/gridded-land-obs/gridded-land-obs-daily/",
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/",
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/",
},
fieldsDescription:
'http://data.ceda.ac.uk/badc/ukcp09/'
}
],
inLanguage: 'en',
categories: ['Economy', 'Data Science'],
tags: [
'weather',
'uk',
'2011',
'temperature',
'humidity'
],
inLanguage: "en",
categories: ["Economy", "Data Science"],
tags: ["weather", "uk", "2011", "temperature", "humidity"],
price: 10,
files: [
{
index: 0,
checksum: "efb2c764274b745f5fc37f97c6b0e761",
checksum: 'efb2c764274b745f5fc37f97c6b0e761',
contentLength: 4535431,
resourceId: "access-log2018-02-13-15-17-29-18386C502CAEA932",
resourceId:
'access-log2018-02-13-15-17-29-18386C502CAEA932'
},
{
index: 1,
checksum: "085340abffh21495345af97c6b0e761",
contentLength: 12324,
checksum: '085340abffh21495345af97c6b0e761',
contentLength: 12324
},
{
index: 2,
},
index: 2
}
],
checksum: "",
checksum: ''
},
curation: {
rating: 0.93,
numVotes: 123,
schema: "Binary Voting",
schema: 'Binary Voting'
},
additionalInformation: {
updateFrecuency: "yearly",
updateFrecuency: 'yearly',
structuredMarkup: [
{
uri: "http://skos.um.es/unescothes/C01194/jsonld",
mediaType: "application/ld+json",
uri:
'http://skos.um.es/unescothes/C01194/jsonld',
mediaType: 'application/ld+json'
},
{
uri: "http://skos.um.es/unescothes/C01194/turtle",
mediaType: "text/turtle",
},
],
},
},
},
],
uri:
'http://skos.um.es/unescothes/C01194/turtle',
mediaType: 'text/turtle'
}
]
}
}
}
]
})
let web3: Web3
@ -167,20 +185,16 @@ describe("DDO", () => {
spy.restore()
})
describe("#serialize()", () => {
it("should properly serialize", async () => {
describe('#serialize()', () => {
it('should properly serialize', async () => {
const ddoString = DDO.serialize(testDDO)
assert(ddoString)
assert(ddoString.startsWith("{"))
assert(ddoString.startsWith('{'))
})
})
describe("#constructor()", () => {
it("should create an empty ddo", async () => {
describe('#constructor()', () => {
it('should create an empty ddo', async () => {
const ddo = new DDO()
assert(ddo)
@ -189,15 +203,14 @@ describe("DDO", () => {
assert(ddo.publicKey.length === 0)
})
it("should create an predefined ddo", async () => {
it('should create an predefined ddo', async () => {
const service: Partial<Service> & any = {
serviceEndpoint: "http://",
description: "nice service",
serviceEndpoint: 'http://',
description: 'nice service'
}
const ddo = new DDO({
service: [service as any],
service: [service as any]
})
assert(ddo)
@ -209,72 +222,84 @@ describe("DDO", () => {
})
})
describe("#deserialize()", () => {
it("should properly deserialize from serialized object", async () => {
describe('#deserialize()', () => {
it('should properly deserialize from serialized object', async () => {
const ddoString = DDO.serialize(testDDO)
assert.typeOf(ddoString, "string")
assert.typeOf(ddoString, 'string')
const ddo: DDO = DDO.deserialize(ddoString)
assert.instanceOf(ddo, DDO)
assert.equal(ddo.id, testDDO.id)
assert.equal(ddo.publicKey[0].publicKeyPem, testDDO.publicKey[0].publicKeyPem)
assert.equal(
ddo.publicKey[0].publicKeyPem,
testDDO.publicKey[0].publicKeyPem
)
})
it("should properly deserialize from json file", async () => {
it('should properly deserialize from json file', async () => {
const ddo: DDO = DDO.deserialize(JSON.stringify(jsonDDO))
assert(ddo)
assert.equal(ddo.id, jsonDDO.id)
assert.equal(ddo.publicKey[0].publicKeyPem, jsonDDO.publicKey[0].publicKeyPem)
assert.equal(
ddo.publicKey[0].publicKeyPem,
jsonDDO.publicKey[0].publicKeyPem
)
})
})
describe("#getChecksum()", () => {
it("should properly generate a the checksum DDO", async () => {
describe('#getChecksum()', () => {
it('should properly generate a the checksum DDO', async () => {
const ddo = new DDO(testDDO)
const checksum = ddo.getChecksum()
assert.equal(checksum, "0x15f27a7a3c7b15d2b06dec7347c6b8da168adddd7df51a8ebbbe87b59b80049b")
assert.equal(
checksum,
'0x15f27a7a3c7b15d2b06dec7347c6b8da168adddd7df51a8ebbbe87b59b80049b'
)
})
})
describe("#generateProof()", () => {
describe('#generateProof()', () => {
const publicKey = `0x${'a'.repeat(40)}`
const signature = `0x${'a'.repeat(130)}`
const publicKey = `0x${"a".repeat(40)}`
const signature = `0x${"a".repeat(130)}`
it("should properly generate the proof", async () => {
const signTextSpy = spy.on(ocean.utils.signature, "signText", () => signature)
it('should properly generate the proof', async () => {
const signTextSpy = spy.on(
ocean.utils.signature,
'signText',
() => signature
)
const ddo = new DDO(testDDO)
const checksum = ddo.getChecksum()
const proof = await ddo.generateProof(ocean, publicKey)
assert.include(proof as any, {
creator: publicKey,
type: "DDOIntegritySignature",
signatureValue: signature,
type: 'DDOIntegritySignature',
signatureValue: signature
})
expect(signTextSpy).to.have.been.called.with(checksum, publicKey)
})
})
describe("#addProof()", () => {
describe('#addProof()', () => {
const publicKey = `0x${'a'.repeat(40)}`
const publicKey = `0x${"a".repeat(40)}`
it("should properly add the proof on the DDO", async () => {
it('should properly add the proof on the DDO', async () => {
const fakeProof = {
creation: Date.now(),
creator: "test",
type: "test",
signaturValue: "test",
creator: 'test',
type: 'test',
signaturValue: 'test'
} as any
const ddo = new DDO(testDDO)
const generateProofSpy = spy.on(ddo, "generateProof", () => fakeProof)
const generateProofSpy = spy.on(
ddo,
'generateProof',
() => fakeProof
)
await ddo.addProof(web3, publicKey)
assert.equal(ddo.proof, fakeProof)

View File

@ -1,15 +1,14 @@
import {assert} from "chai"
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"
import { assert } from 'chai'
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")
const wrappedContract = new ContractBaseMock('OceanToken')
let accounts: Account[]
describe("ContractWrapperBase", () => {
describe('ContractWrapperBase', () => {
before(async () => {
await TestContractHandler.prepareContracts()
const ocean: Ocean = await Ocean.getInstance(config)
@ -17,79 +16,58 @@ describe("ContractWrapperBase", () => {
await wrappedContract.initMock((ocean as any).instanceConfig)
})
describe("#call()", () => {
describe('#call()', () => {
it('should fail to call on an unknown contract function', done => {
wrappedContract.callMock('balanceOfxxx', []).catch(() => {
done()
})
})
it("should fail to call on an unknown contract function", (done) => {
it('should fail to call on an contract function with wrong set of parameters', done => {
wrappedContract.callMock('balanceOf', []).catch(() => {
done()
})
})
wrappedContract.callMock("balanceOfxxx", [])
it('should fail to call on an unknown contract function', done => {
wrappedContract
.sendMock('balanceOfxxx', '0x00', ['0x00'])
.catch(() => {
done()
})
})
it("should fail to call on an contract function with wrong set of parameters", (done) => {
wrappedContract.callMock("balanceOf", [])
.catch(() => {
done()
})
it('should fail to call on an contract function with wrong set of parameters', done => {
wrappedContract.sendMock('approve', '0x000', []).catch(() => {
done()
})
})
})
it("should fail to call on an unknown contract function", (done) => {
wrappedContract.sendMock("balanceOfxxx", "0x00", ["0x00"])
describe('#send()', () => {
it('should fail to call on an unknown contract function', done => {
wrappedContract
.sendMock('transferxxx', accounts[0].getId(), [])
.catch(() => {
done()
})
})
it("should fail to call on an contract function with wrong set of parameters", (done) => {
wrappedContract.sendMock("approve", "0x000", [])
.catch(() => {
done()
})
})
})
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")
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"))
assert(typeof sig === 'string')
assert(sig.startsWith('0x'))
})
})
describe("#getEventData()", () => {
it("should fail on unknown event", (done) => {
wrappedContract.getEventData("crazyevent", {})
.catch(() => {
done()
})
describe('#getEventData()', () => {
it('should fail on unknown event', done => {
wrappedContract.getEventData('crazyevent', {}).catch(() => {
done()
})
})
})
})

View File

@ -1,12 +1,11 @@
import { assert } from "chai"
import { EventHandler } from "../../src/keeper/EventHandler"
import { ContractEventSubscription } from "../../src/keeper/ContractEvent"
import { Ocean } from "../../src/ocean/Ocean"
import config from "../config"
import TestContractHandler from "./TestContractHandler"
describe("ContractEvent", () => {
import { assert } from 'chai'
import { EventHandler } from '../../src/keeper/EventHandler'
import { ContractEventSubscription } from '../../src/keeper/ContractEvent'
import { Ocean } from '../../src/ocean/Ocean'
import config from '../config'
import TestContractHandler from './TestContractHandler'
describe('ContractEvent', () => {
let ocean: Ocean
let account: string
let eventHandler: EventHandler
@ -18,17 +17,22 @@ describe("ContractEvent", () => {
eventHandler = new EventHandler((ocean as any).instanceConfig)
account = (await ocean.accounts.list())[0].getId()
executeTransaction = () => ocean.keeper.dispenser.requestTokens(10, account)
executeTransaction = () =>
ocean.keeper.dispenser.requestTokens(10, account)
})
describe("#subscribe()", () => {
it("should listen the events", async () => {
const event = eventHandler.getEvent(ocean.keeper.token, "Transfer", {to: account})
describe('#subscribe()', () => {
it('should listen the events', async () => {
const event = eventHandler.getEvent(
ocean.keeper.token,
'Transfer',
{ to: account }
)
let validResolve = false
let subscription: ContractEventSubscription
const waitUntilEvent = new Promise((resolve) => {
subscription = event.subscribe((events) => {
const waitUntilEvent = new Promise(resolve => {
subscription = event.subscribe(events => {
assert.isDefined(events)
assert.lengthOf(events, 2)
if (validResolve) {
@ -37,18 +41,12 @@ describe("ContractEvent", () => {
})
})
await Promise.all([
executeTransaction(),
executeTransaction(),
])
await Promise.all([executeTransaction(), executeTransaction()])
await new Promise((_) => setTimeout(_, 2000))
await new Promise(_ => setTimeout(_, 2000))
validResolve = true
await Promise.all([
executeTransaction(),
executeTransaction(),
])
await Promise.all([executeTransaction(), executeTransaction()])
await waitUntilEvent
@ -56,14 +54,18 @@ describe("ContractEvent", () => {
})
})
describe("#once()", () => {
it("should listen only once", async () => {
describe('#once()', () => {
it('should listen only once', async () => {
const to = account
const event = eventHandler.getEvent(ocean.keeper.token, "Transfer", {to})
const event = eventHandler.getEvent(
ocean.keeper.token,
'Transfer',
{ to }
)
let canBeRejected = false
const waitUntilEvent = new Promise((resolve, reject) => {
event.once((events) => {
event.once(events => {
if (canBeRejected) {
reject()
}
@ -73,7 +75,7 @@ describe("ContractEvent", () => {
await executeTransaction()
await new Promise((_) => setTimeout(_, 2000))
await new Promise(_ => setTimeout(_, 2000))
canBeRejected = true
await executeTransaction()
@ -81,13 +83,17 @@ describe("ContractEvent", () => {
await waitUntilEvent
})
it("should get the event like a promise", async () => {
it('should get the event like a promise', async () => {
const to = account
const event = eventHandler.getEvent(ocean.keeper.token, "Transfer", {to})
const event = eventHandler.getEvent(
ocean.keeper.token,
'Transfer',
{ to }
)
const waitUntilEvent = event.once()
await new Promise((_) => setTimeout(_, 400))
await new Promise(_ => setTimeout(_, 400))
await executeTransaction()

View File

@ -1,29 +1,27 @@
import {assert} from "chai"
import ContractHandler from "../../src/keeper/ContractHandler"
import { Ocean } from "../../src/ocean/Ocean"
import config from "../config"
import { assert } from 'chai'
import ContractHandler from '../../src/keeper/ContractHandler'
import { Ocean } from '../../src/ocean/Ocean'
import config from '../config'
describe("ContractHandler", () => {
describe('ContractHandler', () => {
let contractHandler: ContractHandler
before(async () => {
const instanceConfig = (await Ocean.getInstance(config) as any).instanceConfig
const instanceConfig = ((await Ocean.getInstance(config)) as any)
.instanceConfig
contractHandler = new ContractHandler(instanceConfig)
})
describe("#get()", () => {
it("should load and get OceanToken correctly", async () => {
assert(await contractHandler.get("OceanToken"))
describe('#get()', () => {
it('should load and get OceanToken correctly', async () => {
assert(await contractHandler.get('OceanToken'))
})
it("should fail to load an unknown contract", (done) => {
contractHandler.get("OceanXXX")
.catch(() => {
done()
})
it('should fail to load an unknown contract', done => {
contractHandler.get('OceanXXX').catch(() => {
done()
})
})
})
})

View File

@ -1,67 +1,92 @@
import {assert} from "chai"
import DIDRegistry from "../../src/keeper/contracts/DIDRegistry"
import Account from "../../src/ocean/Account"
import { Ocean } from "../../src/ocean/Ocean"
import { generateId } from "../../src/utils/GeneratorHelpers"
import config from "../config"
import TestContractHandler from "./TestContractHandler"
import { assert } from 'chai'
import DIDRegistry from '../../src/keeper/contracts/DIDRegistry'
import Account from '../../src/ocean/Account'
import { Ocean } from '../../src/ocean/Ocean'
import { generateId } from '../../src/utils/GeneratorHelpers'
import config from '../config'
import TestContractHandler from './TestContractHandler'
let ocean: Ocean
let didRegistry: DIDRegistry
describe("DIDRegistry", () => {
describe('DIDRegistry', () => {
before(async () => {
await TestContractHandler.prepareContracts()
ocean = await Ocean.getInstance(config)
didRegistry = ocean.keeper.didRegistry
})
describe("#registerAttribute()", () => {
it("should register an attribute in a new did", async () => {
describe('#registerAttribute()', () => {
it('should register an attribute in a new did', async () => {
const ownerAccount: Account = (await ocean.accounts.list())[0]
const did = generateId()
const data = "my nice provider, is nice"
const receipt = await didRegistry.registerAttribute(did, `0123456789abcdef`, [], data, ownerAccount.getId())
const data = 'my nice provider, is nice'
const receipt = await didRegistry.registerAttribute(
did,
`0123456789abcdef`,
[],
data,
ownerAccount.getId()
)
assert(receipt.status)
assert(receipt.events.DIDAttributeRegistered)
})
it("should register another attribute in the same did", async () => {
it('should register another attribute in the same did', async () => {
const ownerAccount: Account = (await ocean.accounts.list())[0]
const did = generateId()
{
// register the first attribute
const data = "my nice provider, is nice"
await didRegistry.registerAttribute(did, "0123456789abcdef", [], data, ownerAccount.getId())
const data = 'my nice provider, is nice'
await didRegistry.registerAttribute(
did,
'0123456789abcdef',
[],
data,
ownerAccount.getId()
)
}
{
// register the second attribute with the same did
const data = "asdsad"
const receipt = await didRegistry.registerAttribute(did, "0123456789abcdef", [], data, ownerAccount.getId())
const data = 'asdsad'
const receipt = await didRegistry.registerAttribute(
did,
'0123456789abcdef',
[],
data,
ownerAccount.getId()
)
assert.isTrue(receipt.status)
assert.isDefined(receipt.events.DIDAttributeRegistered)
}
})
})
describe("#getDIDOwner()", () => {
it("should get the owner of a did properly", async () => {
describe('#getDIDOwner()', () => {
it('should get the owner of a did properly', async () => {
const ownerAccount: Account = (await ocean.accounts.list())[0]
const did = generateId()
const data = "my nice provider, is nice"
await didRegistry.registerAttribute(did, "0123456789abcdef", [], data, ownerAccount.getId())
const data = 'my nice provider, is nice'
await didRegistry.registerAttribute(
did,
'0123456789abcdef',
[],
data,
ownerAccount.getId()
)
const owner = await didRegistry.getDIDOwner(did)
assert.equal(owner, ownerAccount.getId(), `Got ${owner} but expected ${ownerAccount.getId()}`)
assert.equal(
owner,
ownerAccount.getId(),
`Got ${owner} but expected ${ownerAccount.getId()}`
)
})
it("should get 0x0 for a not registered did", async () => {
const owner = await didRegistry.getDIDOwner("1234")
assert.equal(owner, `0x${"0".repeat(40)}`)
it('should get 0x0 for a not registered did', async () => {
const owner = await didRegistry.getDIDOwner('1234')
assert.equal(owner, `0x${'0'.repeat(40)}`)
})
})
})

View File

@ -1,13 +1,12 @@
import { assert, expect, spy, use } from "chai"
import * as spies from "chai-spies"
import { EventHandler } from "../../src/keeper/EventHandler"
import { Ocean } from "../../src/ocean/Ocean"
import config from "../config"
import { assert, expect, spy, use } from 'chai'
import * as spies from 'chai-spies'
import { EventHandler } from '../../src/keeper/EventHandler'
import { Ocean } from '../../src/ocean/Ocean'
import config from '../config'
use(spies)
describe("EventHandler", () => {
describe('EventHandler', () => {
let ocean: Ocean
let eventHandler: EventHandler
@ -20,20 +19,24 @@ describe("EventHandler", () => {
spy.restore()
})
describe("#subscribe()", () => {
it("should subscribe to an event", async () => {
describe('#subscribe()', () => {
it('should subscribe to an event', async () => {
const countBefore = eventHandler.count
const subscription = eventHandler.subscribe(() => null)
assert.isDefined(subscription)
const countAfter = eventHandler.count
assert.equal(countBefore + 1, countAfter, "The event seems not added.")
assert.equal(
countBefore + 1,
countAfter,
'The event seems not added.'
)
subscription.unsubscribe()
})
it("should unsubscribe using the subscription", async () => {
it('should unsubscribe using the subscription', async () => {
const countBefore = eventHandler.count
const subscription = eventHandler.subscribe(() => null)
@ -42,12 +45,12 @@ describe("EventHandler", () => {
subscription.unsubscribe()
const countAfter = eventHandler.count
assert.equal(countBefore, countAfter, "The event seems not added.")
assert.equal(countBefore, countAfter, 'The event seems not added.')
})
})
describe("#unsubscribe()", () => {
it("should unsubscribe from an event", async () => {
describe('#unsubscribe()', () => {
it('should unsubscribe from an event', async () => {
const countBefore = eventHandler.count
const callback = () => null
@ -55,25 +58,29 @@ describe("EventHandler", () => {
eventHandler.unsubscribe(callback)
const countAfter = eventHandler.count
assert.equal(countBefore, countAfter, "The event seems not removed.")
assert.equal(
countBefore,
countAfter,
'The event seems not removed.'
)
})
})
describe("#checkBlock()", () => {
it("should call the callback on each new block", async () => {
describe('#checkBlock()', () => {
it('should call the callback on each new block', async () => {
let blockNumber = 100000000000
const callbackSpy = spy()
spy.on((ocean as any).web3.eth, "getBlockNumber", () => blockNumber)
spy.on((ocean as any).web3.eth, 'getBlockNumber', () => blockNumber)
const subscription = eventHandler.subscribe(callbackSpy)
await new Promise((_) => setTimeout(_, 300))
await new Promise(_ => setTimeout(_, 300))
expect(callbackSpy).not.to.has.been.called()
blockNumber++
await new Promise((_) => setTimeout(_, 300))
await new Promise(_ => setTimeout(_, 300))
expect(callbackSpy).to.has.been.called.with(blockNumber)

View File

@ -1,36 +1,32 @@
import {assert} from "chai"
import config from "../config"
import TestContractHandler from "./TestContractHandler"
import Keeper from "../../src/keeper/Keeper"
import { Ocean } from "../../src/ocean/Ocean"
import { assert } from 'chai'
import config from '../config'
import TestContractHandler from './TestContractHandler'
import Keeper from '../../src/keeper/Keeper'
import { Ocean } from '../../src/ocean/Ocean'
let keeper: Keeper
describe("Keeper", () => {
describe('Keeper', () => {
before(async () => {
await TestContractHandler.prepareContracts()
const ocean = await Ocean.getInstance(config)
keeper = ocean.keeper
})
describe("public interface", () => {
it("should have dispenser", () => {
describe('public interface', () => {
it('should have dispenser', () => {
assert(keeper.dispenser !== null)
})
it("should have token", () => {
it('should have token', () => {
assert(keeper.token !== null)
})
})
describe("#getNetworkName()", () => {
it("should get development as default", async () => {
describe('#getNetworkName()', () => {
it('should get development as default', async () => {
const networkName: string = await keeper.getNetworkName()
assert(networkName === "Development")
assert(networkName === 'Development')
})
})
})

View File

@ -1,11 +1,10 @@
import Contract from "web3-eth-contract"
import ContractHandler from "../../src/keeper/ContractHandler"
import Web3Provider from "../../src/keeper/Web3Provider"
import Logger from "../../src/utils/Logger"
import config from "../config"
import Contract from 'web3-eth-contract'
import ContractHandler from '../../src/keeper/ContractHandler'
import Web3Provider from '../../src/keeper/Web3Provider'
import Logger from '../../src/utils/Logger'
import config from '../config'
export default class TestContractHandler extends ContractHandler {
public static async prepareContracts() {
const web3 = Web3Provider.getWeb3(config)
const deployerAddress = (await web3.eth.getAccounts())[0]
@ -18,77 +17,131 @@ export default class TestContractHandler extends ContractHandler {
private static networkId: number
private static async deployContracts(deployerAddress: string) {
Logger.log("Trying to deploy contracts")
Logger.log('Trying to deploy contracts')
// Libraries
const epochLibrary = await TestContractHandler.deployContract("EpochLibrary", deployerAddress)
const didRegistryLibrary = await TestContractHandler.deployContract("DIDRegistryLibrary", deployerAddress)
const epochLibrary = await TestContractHandler.deployContract(
'EpochLibrary',
deployerAddress
)
const didRegistryLibrary = await TestContractHandler.deployContract(
'DIDRegistryLibrary',
deployerAddress
)
// Contracts
const token = await TestContractHandler.deployContract("OceanToken", deployerAddress, [deployerAddress, deployerAddress])
const token = await TestContractHandler.deployContract(
'OceanToken',
deployerAddress,
[deployerAddress, deployerAddress]
)
const dispenser = await TestContractHandler.deployContract("Dispenser", deployerAddress, [token.options.address, deployerAddress])
const dispenser = await TestContractHandler.deployContract(
'Dispenser',
deployerAddress,
[token.options.address, deployerAddress]
)
// Add dispenser as Token minter
if (!token.$initialized) {
await token.methods.addMinter(dispenser.options.address)
.send({from: deployerAddress})
await token.methods
.addMinter(dispenser.options.address)
.send({ from: deployerAddress })
}
const didRegistry = await TestContractHandler.deployContract("DIDRegistry", deployerAddress, [deployerAddress], {
DIDRegistryLibrary: didRegistryLibrary.options.address,
})
const didRegistry = await TestContractHandler.deployContract(
'DIDRegistry',
deployerAddress,
[deployerAddress],
{
DIDRegistryLibrary: didRegistryLibrary.options.address
}
)
// Managers
const templateStoreManager = await TestContractHandler.deployContract("TemplateStoreManager", deployerAddress, [
const templateStoreManager = await TestContractHandler.deployContract(
'TemplateStoreManager',
deployerAddress,
])
const conditionStoreManager = await TestContractHandler.deployContract("ConditionStoreManager", deployerAddress, [
[deployerAddress]
)
const conditionStoreManager = await TestContractHandler.deployContract(
'ConditionStoreManager',
deployerAddress,
], {
EpochLibrary: epochLibrary.options.address,
})
const agreementStoreManager = await TestContractHandler.deployContract("AgreementStoreManager", deployerAddress, [
deployerAddress, conditionStoreManager.options.address, templateStoreManager.options.address, didRegistry.options.address,
])
[deployerAddress],
{
EpochLibrary: epochLibrary.options.address
}
)
const agreementStoreManager = await TestContractHandler.deployContract(
'AgreementStoreManager',
deployerAddress,
[
deployerAddress,
conditionStoreManager.options.address,
templateStoreManager.options.address,
didRegistry.options.address
]
)
// Conditions
const lockRewardCondition = await TestContractHandler.deployContract("LockRewardCondition", deployerAddress, [
deployerAddress, conditionStoreManager.options.address, token.options.address,
])
const accessSecretStoreCondition = await TestContractHandler.deployContract("AccessSecretStoreCondition", deployerAddress, [
deployerAddress, conditionStoreManager.options.address, agreementStoreManager.options.address,
])
const lockRewardCondition = await TestContractHandler.deployContract(
'LockRewardCondition',
deployerAddress,
[
deployerAddress,
conditionStoreManager.options.address,
token.options.address
]
)
const accessSecretStoreCondition = await TestContractHandler.deployContract(
'AccessSecretStoreCondition',
deployerAddress,
[
deployerAddress,
conditionStoreManager.options.address,
agreementStoreManager.options.address
]
)
// Conditions rewards
const escrowReward = await TestContractHandler.deployContract("EscrowReward", deployerAddress, [
deployerAddress, conditionStoreManager.options.address, token.options.address,
])
const escrowReward = await TestContractHandler.deployContract(
'EscrowReward',
deployerAddress,
[
deployerAddress,
conditionStoreManager.options.address,
token.options.address
]
)
// Templates
await TestContractHandler.deployContract("EscrowAccessSecretStoreTemplate", deployerAddress, [
await TestContractHandler.deployContract(
'EscrowAccessSecretStoreTemplate',
deployerAddress,
agreementStoreManager.options.address,
didRegistry.options.address,
accessSecretStoreCondition.options.address,
lockRewardCondition.options.address,
escrowReward.options.address,
])
[
deployerAddress,
agreementStoreManager.options.address,
didRegistry.options.address,
accessSecretStoreCondition.options.address,
lockRewardCondition.options.address,
escrowReward.options.address
]
)
}
private static async deployContract(
name: string,
from: string,
args: any[] = [],
tokens: {[name: string]: string} = {},
): Promise<Contract & {$initialized: boolean}> {
tokens: { [name: string]: string } = {}
): Promise<Contract & { $initialized: boolean }> {
const where = this.networkId
// dont redeploy if there is already something loaded
if (TestContractHandler.hasContract(name, where)) {
const contract = await ContractHandler.getContract(name, where)
if (contract.testContract) {
return {...contract, $initialized: true}
return { ...contract, $initialized: true }
}
}
@ -96,50 +149,70 @@ export default class TestContractHandler extends ContractHandler {
let contractInstance: Contract
try {
Logger.log("Deploying", name)
Logger.log('Deploying', name)
const sendConfig = {
from,
gas: 3000000,
gasPrice: 10000000000,
gasPrice: 10000000000
}
const artifact = require(`@oceanprotocol/keeper-contracts/artifacts/${name}.development.json`)
const tempContract = new web3.eth.Contract(artifact.abi, artifact.address)
const tempContract = new web3.eth.Contract(
artifact.abi,
artifact.address
)
const isZos = !!tempContract.methods.initialize
Logger.debug({
name, from, isZos, args,
name,
from,
isZos,
args,
libraries: artifact.bytecode
.replace(/(0x)?[a-f0-9]{8}/gi, "")
.replace(/__([^_]+)_*[0-9a-f]{2}/g, "|$1")
.split("|")
.splice(1),
.replace(/(0x)?[a-f0-9]{8}/gi, '')
.replace(/__([^_]+)_*[0-9a-f]{2}/g, '|$1')
.split('|')
.splice(1)
})
contractInstance = await tempContract
.deploy({
data: TestContractHandler.replaceTokens(artifact.bytecode.toString(), tokens),
arguments: isZos ? undefined : args,
data: TestContractHandler.replaceTokens(
artifact.bytecode.toString(),
tokens
),
arguments: isZos ? undefined : args
})
.send(sendConfig)
if (isZos) {
await contractInstance.methods.initialize(...args).send(sendConfig)
await contractInstance.methods
.initialize(...args)
.send(sendConfig)
}
contractInstance.testContract = true
ContractHandler.setContract(name, where, contractInstance)
// Logger.log("Deployed", name, "at", contractInstance.options.address);
} catch (err) {
Logger.error("Deployment failed for", name, "with args", JSON.stringify(args, null, 2), err.message)
Logger.error(
'Deployment failed for',
name,
'with args',
JSON.stringify(args, null, 2),
err.message
)
throw err
}
return contractInstance
}
private static replaceTokens(bytecode: string, tokens: {[name: string]: string}): string {
return Object.entries(tokens)
.reduce(
(acc, [token, address]) => acc.replace(new RegExp(`_+${token}_+`, "g"), address.substr(2)),
bytecode,
)
private static replaceTokens(
bytecode: string,
tokens: { [name: string]: string }
): string {
return Object.entries(tokens).reduce(
(acc, [token, address]) =>
acc.replace(new RegExp(`_+${token}_+`, 'g'), address.substr(2)),
bytecode
)
}
}

View File

@ -1,33 +1,37 @@
import {assert} from "chai"
import { AccessSecretStoreCondition } from "../../../src/keeper/contracts/conditions"
import { Ocean } from "../../../src/ocean/Ocean"
import config from "../../config"
import TestContractHandler from "../TestContractHandler"
import { assert } from 'chai'
import { AccessSecretStoreCondition } from '../../../src/keeper/contracts/conditions'
import { Ocean } from '../../../src/ocean/Ocean'
import config from '../../config'
import TestContractHandler from '../TestContractHandler'
let condition: AccessSecretStoreCondition
describe("AccessSecretStoreCondition", () => {
const agreementId = `0x${"a".repeat(64)}`
const did = `did:op:${"a".repeat(64)}`
const address = `0x${"a".repeat(40)}`
describe('AccessSecretStoreCondition', () => {
const agreementId = `0x${'a'.repeat(64)}`
const did = `did:op:${'a'.repeat(64)}`
const address = `0x${'a'.repeat(40)}`
before(async () => {
await TestContractHandler.prepareContracts()
condition = (await Ocean.getInstance(config)).keeper.conditions.accessSecretStoreCondition
condition = (await Ocean.getInstance(config)).keeper.conditions
.accessSecretStoreCondition
})
describe("#hashValues()", () => {
it("should hash the values", async () => {
describe('#hashValues()', () => {
it('should hash the values', async () => {
const hash = await condition.hashValues(did, address)
assert.match(hash, /^0x[a-f0-9]{64}$/i)
assert.equal(hash, "0x1abbd7e58bc32bff739ee1e756a4108882322f2ec939d5e2f251e6b8424947fb", "The hash is not the expected.")
assert.equal(
hash,
'0x1abbd7e58bc32bff739ee1e756a4108882322f2ec939d5e2f251e6b8424947fb',
'The hash is not the expected.'
)
})
})
describe("#generateId()", () => {
it("should generate an ID", async () => {
describe('#generateId()', () => {
it('should generate an ID', async () => {
const hash = await condition.hashValues(did, address)
const id = await condition.generateId(agreementId, hash)

View File

@ -1,18 +1,17 @@
import {assert} from "chai"
import { EscrowReward } from "../../../src/keeper/contracts/conditions"
import { Ocean } from "../../../src/ocean/Ocean"
import config from "../../config"
import TestContractHandler from "../TestContractHandler"
import { assert } from 'chai'
import { EscrowReward } from '../../../src/keeper/contracts/conditions'
import { Ocean } from '../../../src/ocean/Ocean'
import config from '../../config'
import TestContractHandler from '../TestContractHandler'
let condition: EscrowReward
describe("EscrowReward", () => {
const agreementId = `0x${"a".repeat(64)}`
const did = `0x${"a".repeat(64)}`
describe('EscrowReward', () => {
const agreementId = `0x${'a'.repeat(64)}`
const did = `0x${'a'.repeat(64)}`
const amount = 15
const publisher = `0x${"a".repeat(40)}`
const consumer = `0x${"b".repeat(40)}`
const publisher = `0x${'a'.repeat(40)}`
const consumer = `0x${'b'.repeat(40)}`
let lockCondition
let releaseCondition
@ -22,21 +21,41 @@ describe("EscrowReward", () => {
await TestContractHandler.prepareContracts()
condition = keeper.conditions.escrowReward
lockCondition = await keeper.conditions.lockRewardCondition.generateIdHash(agreementId, publisher, amount)
releaseCondition = await keeper.conditions.accessSecretStoreCondition.generateIdHash(agreementId, did, consumer)
lockCondition = await keeper.conditions.lockRewardCondition.generateIdHash(
agreementId,
publisher,
amount
)
releaseCondition = await keeper.conditions.accessSecretStoreCondition.generateIdHash(
agreementId,
did,
consumer
)
})
describe("#hashValues()", () => {
it("should hash the values", async () => {
const hash = await condition.hashValues(amount, consumer, publisher, lockCondition, releaseCondition)
describe('#hashValues()', () => {
it('should hash the values', async () => {
const hash = await condition.hashValues(
amount,
consumer,
publisher,
lockCondition,
releaseCondition
)
assert.match(hash, /^0x[a-f0-9]{64}$/i)
})
})
describe("#generateId()", () => {
it("should generate an ID", async () => {
const hash = await condition.hashValues(amount, consumer, publisher, lockCondition, releaseCondition)
describe('#generateId()', () => {
it('should generate an ID', async () => {
const hash = await condition.hashValues(
amount,
consumer,
publisher,
lockCondition,
releaseCondition
)
const id = await condition.generateId(agreementId, hash)
assert.match(id, /^0x[a-f0-9]{64}$/i)

View File

@ -1,33 +1,37 @@
import {assert} from "chai"
import { LockRewardCondition } from "../../../src/keeper/contracts/conditions"
import { Ocean } from "../../../src/ocean/Ocean"
import config from "../../config"
import TestContractHandler from "../TestContractHandler"
import { assert } from 'chai'
import { LockRewardCondition } from '../../../src/keeper/contracts/conditions'
import { Ocean } from '../../../src/ocean/Ocean'
import config from '../../config'
import TestContractHandler from '../TestContractHandler'
let condition: LockRewardCondition
describe("LockRewardCondition", () => {
const agreementId = `0x${"a".repeat(64)}`
const address = `0x${"a".repeat(40)}`
describe('LockRewardCondition', () => {
const agreementId = `0x${'a'.repeat(64)}`
const address = `0x${'a'.repeat(40)}`
const amount = 15
before(async () => {
await TestContractHandler.prepareContracts()
condition = (await Ocean.getInstance(config)).keeper.conditions.lockRewardCondition
condition = (await Ocean.getInstance(config)).keeper.conditions
.lockRewardCondition
})
describe("#hashValues()", () => {
it("should hash the values", async () => {
describe('#hashValues()', () => {
it('should hash the values', async () => {
const hash = await condition.hashValues(address, amount)
assert.match(hash, /^0x[a-f0-9]{64}$/i)
assert.equal(hash, "0x2543c2ea4b9403bb3e5df1145c70731454748e72a37acc80d025f85e03267973", "The hash is not the expected.")
assert.equal(
hash,
'0x2543c2ea4b9403bb3e5df1145c70731454748e72a37acc80d025f85e03267973',
'The hash is not the expected.'
)
})
})
describe("#generateId()", () => {
it("should generate an ID", async () => {
describe('#generateId()', () => {
it('should generate an ID', async () => {
const hash = await condition.hashValues(address, amount)
const id = await condition.generateId(agreementId, hash)

View File

@ -1,18 +1,16 @@
import {assert} from "chai"
import { EscrowAccessSecretStoreTemplate } from "../../../src/keeper/contracts/templates"
import config from "../../config"
import TestContractHandler from "../TestContractHandler"
import { Ocean } from "../../../src/ocean/Ocean"
import { assert } from 'chai'
import { EscrowAccessSecretStoreTemplate } from '../../../src/keeper/contracts/templates'
import config from '../../config'
import TestContractHandler from '../TestContractHandler'
import { Ocean } from '../../../src/ocean/Ocean'
let condition: EscrowAccessSecretStoreTemplate
describe("EscrowAccessSecretStoreTemplate", () => {
describe('EscrowAccessSecretStoreTemplate', () => {
before(async () => {
const ocean: Ocean = await Ocean.getInstance(config)
await TestContractHandler.prepareContracts()
condition = ocean.keeper.templates.escrowAccessSecretStoreTemplate
})
// describe("#hashValues()", () => {
@ -23,5 +21,4 @@ describe("EscrowAccessSecretStoreTemplate", () => {
// assert.match(hash, /^0x[a-f0-9]{64}$/i)
// })
// })
})

View File

@ -1,13 +1,12 @@
import { Aquarius } from "../../src/aquarius/Aquarius"
import { DDO } from "../../src/ddo/DDO"
import DID from "../../src/ocean/DID"
import { Aquarius } from '../../src/aquarius/Aquarius'
import { DDO } from '../../src/ddo/DDO'
import DID from '../../src/ocean/DID'
const ddoStore: Map<string, any> = new Map<string, any>()
export default class AquariusMock extends Aquarius {
public async getAccessUrl(accessToken: any, payload: any): Promise<string> {
return "http://test/test"
return 'http://test/test'
}
public async storeDDO(ddo: DDO): Promise<DDO> {

View File

@ -1,10 +1,13 @@
import { Brizo } from "../../src/brizo/Brizo"
import { Brizo } from '../../src/brizo/Brizo'
export default class BrizoMock extends Brizo {
public async initializeServiceAgreement(did: string, serviceAgreementId: string, serviceDefinitionId: string,
signature: string, consumerPublicKey: string): Promise<any> {
public async initializeServiceAgreement(
did: string,
serviceAgreementId: string,
serviceDefinitionId: string,
signature: string,
consumerPublicKey: string
): Promise<any> {
return true
}
}

View File

@ -1,4 +1,4 @@
import ContractBase from "../../src/keeper/contracts/ContractBase"
import ContractBase from '../../src/keeper/contracts/ContractBase'
export default class ContractBaseMock extends ContractBase {
public async initMock(config: any) {

View File

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

View File

@ -1,15 +1,13 @@
import WebServiceConnector from "../../src/utils/WebServiceConnector"
import WebServiceConnector from '../../src/utils/WebServiceConnector'
// @ts-ignore
export default class WebServiceConnectorMock extends WebServiceConnector {
constructor(private returnData: any) {
super()
}
// @ts-ignore
private async fetch(url, opts): Promise<any> {
return new Promise((resolve, reject) => {
resolve({
ok: true,
@ -17,8 +15,10 @@ export default class WebServiceConnectorMock extends WebServiceConnector {
return this.returnData ? this.returnData : {}
},
text: () => {
return this.returnData ? JSON.stringify(this.returnData.toString()) : ""
},
return this.returnData
? JSON.stringify(this.returnData.toString())
: ''
}
})
})
}

Some files were not shown because too many files have changed in this diff Show More