From 7a13ad8daa353ac6f05ff9c1f3e925142c8284fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pedro=20Guti=C3=A9rrez?= Date: Thu, 21 Mar 2019 02:56:58 +0100 Subject: [PATCH] Be able to create different Ocean instances with different config. --- src/ConfigProvider.ts | 34 --- src/Instantiable.abstract.ts | 81 +++++++ src/aquarius/Aquarius.ts | 36 +-- src/aquarius/AquariusProvider.ts | 33 --- src/brizo/Brizo.ts | 20 +- src/brizo/BrizoProvider.ts | 33 --- src/ddo/DDO.ts | 14 +- src/keeper/ContractEvent.ts | 49 ++++ src/keeper/ContractHandler.ts | 68 +++--- src/keeper/ContractReflector.ts | 16 -- src/keeper/Event.ts | 61 ----- src/keeper/EventHandler.ts | 62 +++++ src/keeper/EventListener.ts | 29 --- src/keeper/Keeper.ts | 94 +++++--- src/keeper/Web3Provider.ts | 18 +- src/keeper/contracts/ContractBase.ts | 36 ++- src/keeper/contracts/DIDRegistry.ts | 5 +- src/keeper/contracts/Dispenser.ts | 9 +- src/keeper/contracts/GenericContract.ts | 6 +- src/keeper/contracts/Token.ts | 5 +- .../conditions/AccessSecretStoreCondition.ts | 5 +- .../conditions/Condition.abstract.ts | 16 +- .../contracts/conditions/EscrowReward.ts | 5 +- .../conditions/LockRewardCondition.ts | 5 +- .../managers/AgreementStoreManager.ts | 6 +- .../managers/ConditionStoreManager.ts | 6 +- .../managers/TemplateStoreManager.ts | 11 +- .../templates/AgreementTemplate.abstract.ts | 49 ++-- .../EscrowAccessSecretStoreTemplate.ts | 11 +- src/ocean/Account.ts | 32 ++- src/ocean/Ocean.ts | 225 +++--------------- src/ocean/OceanAccounts.ts | 23 +- src/ocean/OceanAgreements.ts | 38 +-- src/ocean/OceanAgreementsConditions.ts | 42 ++-- src/ocean/OceanAssets.ts | 134 +++++------ src/ocean/OceanSecretStore.ts | 45 ++-- src/ocean/OceanTokens.ts | 20 +- .../ServiceAgreements/ServiceAgreement.ts | 9 +- src/secretstore/SecretStoreProvider.ts | 38 +-- src/squid.ts | 5 +- src/utils/Logger.ts | 1 - src/utils/SignatureHelpers.ts | 9 +- test/aquarius/Aquarius.test.ts | 4 +- test/config.ts | 5 +- test/ddo/DDO.test.ts | 13 +- test/keeper/ContractBase.test.ts | 6 +- test/keeper/ContractEvent.test.ts | 97 ++++++++ test/keeper/ContractHandler.test.ts | 13 +- test/keeper/DIDRegistry.test.ts | 13 +- test/keeper/Event.test.ts | 85 ------- test/keeper/EventHandler.test.ts | 89 +++++++ test/keeper/EventListener.test.ts | 69 ------ test/keeper/Keeper.test.ts | 8 +- test/keeper/TestContractHandler.ts | 20 +- .../AccessSecretStoreCondition.test.ts | 9 +- test/keeper/conditions/EscrowReward.test.ts | 7 +- .../conditions/LockRewardCondition.test.ts | 7 +- .../EscrowAccessSecretStoreTemplate.test.ts | 8 +- test/mocha.opts | 2 +- test/mocks/Aquarius.mock.ts | 2 +- test/mocks/Brizo.mock.ts | 2 +- test/mocks/ContractBase.Mock.ts | 4 +- test/ocean/Account.test.ts | 11 +- test/ocean/Ocean.test.ts | 72 +----- test/ocean/OceanAccounts.test.ts | 12 +- test/ocean/OceanSecretStore.test.ts | 25 +- test/ocean/ServiceAgreement.test.ts | 4 +- test/utils/SignatureHelpers.test.ts | 14 +- 68 files changed, 898 insertions(+), 1147 deletions(-) delete mode 100644 src/ConfigProvider.ts create mode 100644 src/Instantiable.abstract.ts delete mode 100644 src/aquarius/AquariusProvider.ts delete mode 100644 src/brizo/BrizoProvider.ts create mode 100644 src/keeper/ContractEvent.ts delete mode 100644 src/keeper/ContractReflector.ts delete mode 100644 src/keeper/Event.ts create mode 100644 src/keeper/EventHandler.ts delete mode 100644 src/keeper/EventListener.ts create mode 100644 test/keeper/ContractEvent.test.ts delete mode 100644 test/keeper/Event.test.ts create mode 100644 test/keeper/EventHandler.test.ts delete mode 100644 test/keeper/EventListener.test.ts diff --git a/src/ConfigProvider.ts b/src/ConfigProvider.ts deleted file mode 100644 index b12888a..0000000 --- a/src/ConfigProvider.ts +++ /dev/null @@ -1,34 +0,0 @@ -import Config from "./models/Config" -import LoggerInstance, { LogLevel } from "./utils/Logger" - -/** - * Stores the configuration of the library. - */ -export default class ConfigProvider { - - /** - * @return {Config} Library config. - */ - public static getConfig(): Config { - return ConfigProvider.config - } - - /** - * @param {Config} Library config. - */ - public static setConfig(config: Config) { - LoggerInstance.setLevel( - typeof config.verbose !== "number" - ? (config.verbose ? LogLevel.Log : LogLevel.None) - : config.verbose as LogLevel, - ) - - ConfigProvider.config = config - } - - /** - * Library config. - * @type {Config} - */ - private static config: Config -} diff --git a/src/Instantiable.abstract.ts b/src/Instantiable.abstract.ts new file mode 100644 index 0000000..3d850f8 --- /dev/null +++ b/src/Instantiable.abstract.ts @@ -0,0 +1,81 @@ +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 + config?: Config + web3?: Web3 + logger?: Logger +} + +export function generateIntantiableConfigFromConfig(config: Config): Partial { + 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), + } +} + +export abstract class Instantiable { + private _ocean: Ocean + private _web3: Web3 + private _config: Config + private _logger: Logger + + protected get ocean() { + if (!this._ocean) { + 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.") + return Web3Provider.getWeb3() + } + return this._web3 + } + + protected get config() { + if (!this._config) { + 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.") + return LoggerInstance + } + return this._logger + } + + protected get instanceConfig(): InstantiableConfig { + const {ocean, web3, config, logger} = this + return {ocean, web3, config, logger} + } + + protected static setInstanceConfig(instance: T, {ocean, config, web3, logger}: InstantiableConfig) { + instance._ocean = ocean + instance._config = config + instance._web3 = web3 + instance._logger = logger + } + + protected setInstanceConfig(config: InstantiableConfig) { + Instantiable.setInstanceConfig(this, config) + } + + public static async getInstance(...args: any[]): Promise + public static async getInstance(config: InstantiableConfig): Promise { } +} diff --git a/src/aquarius/Aquarius.ts b/src/aquarius/Aquarius.ts index be653ab..48d00ed 100644 --- a/src/aquarius/Aquarius.ts +++ b/src/aquarius/Aquarius.ts @@ -1,10 +1,9 @@ import { URL } from "whatwg-url" import { DDO } from "../ddo/DDO" -import Config from "../models/Config" import DID from "../ocean/DID" -import LoggerInstance from "../utils/Logger" import WebServiceConnectorProvider from "../utils/WebServiceConnectorProvider" import { SearchQuery } from "./query/SearchQuery" +import { Instantiable, InstantiableConfig } from "../Instantiable.abstract" const apiPath = "/api/v1/aquarius/assets/ddo" @@ -12,11 +11,14 @@ const apiPath = "/api/v1/aquarius/assets/ddo" * Provides a interface with Aquarius. * Aquarius provides an off-chain database store for metadata about data assets. */ -export default class Aquarius { - private url: string +export class Aquarius extends Instantiable { + private get url() { + return this.config.aquariusUri + } - constructor(config: Config) { - this.url = config.aquariusUri + constructor(config: InstantiableConfig) { + super() + this.setInstanceConfig(config) } public async getAccessUrl(accessToken: any, payload: any): Promise { @@ -26,15 +28,15 @@ export default class Aquarius { if (response.ok) { return response.text() } - LoggerInstance.error("Failed: ", response.status, response.statusText) + this.logger.error("Failed: ", response.status, response.statusText) return null }) .then((consumptionUrl: string): string => { - LoggerInstance.error("Success accessing consume endpoint: ", consumptionUrl) + this.logger.error("Success accessing consume endpoint: ", consumptionUrl) return consumptionUrl }) .catch((error) => { - LoggerInstance.error("Error fetching the data asset consumption url: ", error) + this.logger.error("Error fetching the data asset consumption url: ", error) return null }) @@ -53,7 +55,7 @@ export default class Aquarius { if (response.ok) { return response.json() as DDO[] } - LoggerInstance.error("queryMetadata failed:", response.status, response.statusText) + this.logger.error("queryMetadata failed:", response.status, response.statusText) return [] as DDO[] }) .then((ddos) => { @@ -62,7 +64,7 @@ export default class Aquarius { }) }) .catch((error) => { - LoggerInstance.error("Error fetching querying metadata: ", error) + this.logger.error("Error fetching querying metadata: ", error) return [] as DDO[] }) @@ -86,7 +88,7 @@ export default class Aquarius { if (response.ok) { return response.json() as DDO[] } - LoggerInstance.log("queryMetadataByText failed:", response.status, response.statusText) + this.logger.log("queryMetadataByText failed:", response.status, response.statusText) return [] as DDO[] }) .then((ddos) => { @@ -95,7 +97,7 @@ export default class Aquarius { }) }) .catch((error) => { - LoggerInstance.error("Error fetching querying metadata by text: ", error) + this.logger.error("Error fetching querying metadata by text: ", error) return [] as DDO[] }) @@ -115,14 +117,14 @@ export default class Aquarius { if (response.ok) { return response.json() } - LoggerInstance.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) => { - LoggerInstance.error("Error fetching querying metadata: ", error) + this.logger.error("Error fetching querying metadata: ", error) return null as DDO }) @@ -142,14 +144,14 @@ export default class Aquarius { if (response.ok) { return response.json() } - LoggerInstance.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) => { - LoggerInstance.error("Error fetching querying metadata: ", error) + this.logger.error("Error fetching querying metadata: ", error) return null as DDO }) diff --git a/src/aquarius/AquariusProvider.ts b/src/aquarius/AquariusProvider.ts deleted file mode 100644 index 3422aa7..0000000 --- a/src/aquarius/AquariusProvider.ts +++ /dev/null @@ -1,33 +0,0 @@ -import ConfigProvider from "../ConfigProvider" -import Aquarius from "./Aquarius" - -/** - * Provides the Aquarius instance. - */ -export default class AquariusProvider { - - /** - * Set an Aquarius instance. - * @param {Aquarius} aquarius New Aquarius instance. - */ - public static setAquarius(aquarius: Aquarius) { - AquariusProvider.aquarius = aquarius - } - - /** - * Returns Acuarius instance. It creates a new one if it's not defined. - * @returns {Aquarius} Aquarius instance. - */ - public static getAquarius() { - if (!AquariusProvider.aquarius) { - AquariusProvider.aquarius = new Aquarius(ConfigProvider.getConfig()) - } - return AquariusProvider.aquarius - } - - /** - * Aquarius instance. - * @type {Aquarius} - */ - private static aquarius: Aquarius = null -} diff --git a/src/brizo/Brizo.ts b/src/brizo/Brizo.ts index bf9432a..a6629ff 100644 --- a/src/brizo/Brizo.ts +++ b/src/brizo/Brizo.ts @@ -1,9 +1,8 @@ import save = require("save-file") import { File } from "../ddo/MetaData" -import Config from "../models/Config" import Account from "../ocean/Account" -import LoggerInstance from "../utils/Logger" import WebServiceConnectorProvider from "../utils/WebServiceConnectorProvider" +import { Instantiable, InstantiableConfig } from "../Instantiable.abstract" const apiPath = "/api/v1/brizo/services" @@ -11,11 +10,14 @@ 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 default class Brizo { - private url: string +export class Brizo extends Instantiable { + private get url() { + return this.config.brizoUri + } - constructor(config: Config) { - this.url = config.brizoUri + constructor(config: InstantiableConfig) { + super() + this.setInstanceConfig(config) } public getPurchaseEndpoint() { @@ -55,7 +57,7 @@ export default class Brizo { decodeURI(JSON.stringify(args)), ) } catch (e) { - LoggerInstance.error(e) + this.logger.error(e) throw new Error("HTTP request failed") } } @@ -81,8 +83,8 @@ export default class Brizo { destination, ) } catch (e) { - LoggerInstance.error("Error consuming assets") - LoggerInstance.error(e) + this.logger.error("Error consuming assets") + this.logger.error(e) throw new Error("Error consuming assets") } }) diff --git a/src/brizo/BrizoProvider.ts b/src/brizo/BrizoProvider.ts deleted file mode 100644 index 1584e70..0000000 --- a/src/brizo/BrizoProvider.ts +++ /dev/null @@ -1,33 +0,0 @@ -import ConfigProvider from "../ConfigProvider" -import Brizo from "./Brizo" - -/** - * Provides the Brizo instance. - */ -export default class BrizoProvider { - - /** - * Set an Brizo instance. - * @param {Brizo} brizo New Brizo instance. - */ - public static setBrizo(brizo: Brizo) { - BrizoProvider.brizo = brizo - } - - /** - * Returns Acuarius instance. It creates a new one if it's not defined. - * @returns {Brizo} brizo instance. - */ - public static getBrizo() { - if (!BrizoProvider.brizo) { - BrizoProvider.brizo = new Brizo(ConfigProvider.getConfig()) - } - return BrizoProvider.brizo - } - - /** - * Brizo instance. - * @type {Brizo} - */ - private static brizo: Brizo = null -} diff --git a/src/ddo/DDO.ts b/src/ddo/DDO.ts index 27aa255..79f2552 100644 --- a/src/ddo/DDO.ts +++ b/src/ddo/DDO.ts @@ -1,3 +1,4 @@ +import * as Web3 from "web3" import Web3Provider from "../keeper/Web3Provider" import LoggerInstance from "../utils/Logger" import * as signatureHelpers from "../utils/SignatureHelpers" @@ -88,7 +89,6 @@ export class DDO { * @return {string[]} DDO checksum. */ public getChecksum(): string { - const web3 = Web3Provider.getWeb3() const {metadata} = this.findServiceByType("Metadata") const {files, name, author, license} = metadata.base @@ -102,19 +102,20 @@ export class DDO { this.id, ] - return web3.utils.sha3(values.join("")).replace(/^0x([a-f0-9]{32}).+$/i, "$1") + return Web3Provider.getWeb3().utils.sha3(values.join("")).replace(/^0x([a-f0-9]{32}).+$/i, "$1") } /** * Generates proof using personal sing. + * @param {Web3} web3 Web3 instance. * @param {string} publicKey Public key to be used on personal sign. * @param {string} password Password if it's requirted. * @return {Promise} Proof object. */ - public async generateProof(publicKey: string, password?: string): Promise { + public async generateProof(web3: Web3, publicKey: string, password?: string): Promise { const checksum = this.getChecksum() - const signature = await signatureHelpers.signText(checksum, publicKey, password) + const signature = await signatureHelpers.signText(web3, checksum, publicKey, password) return { created: (new Date()).toISOString(), @@ -138,14 +139,15 @@ export class DDO { /** * Generates and adds a proof using personal sing on the DDO. + * @param {Web3} web3 Web3 instance. * @param {string} publicKey Public key to be used on personal sign. * @param {string} password Password if it's requirted. * @return {Promise} Proof object. */ - public async addProof(publicKey: string, password?: string): Promise { + public async addProof(web3: Web3, publicKey: string, password?: string): Promise { if (this.proof) { throw new Error("Proof already exists") } - this.proof = await this.generateProof(publicKey, password) + this.proof = await this.generateProof(web3, publicKey, password) } } diff --git a/src/keeper/ContractEvent.ts b/src/keeper/ContractEvent.ts new file mode 100644 index 0000000..2993265 --- /dev/null +++ b/src/keeper/ContractEvent.ts @@ -0,0 +1,49 @@ +import ContractBase from "./contracts/ContractBase" + +interface EventEmitter { + subscribe: Function + unsubscribe: Function +} + +export interface ContractEventSubscription { + unsubscribe: Function +} + +export class ContractEvent { + constructor( + private eventEmitter: EventEmitter, + private contract: ContractBase, + private eventName: string, + private filter: {[key: string]: any}, + ) { } + + 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", + }) + if (events.length) { + callback(events) + } + } + + this.eventEmitter.subscribe(onEvent) + return { + unsubscribe: () => this.eventEmitter.unsubscribe(onEvent), + } + } + + once(callback?: (events: any[]) => void) { + return new Promise(resolve => { + const subscription = this.subscribe(events => { + subscription.unsubscribe() + if (callback) { + callback(events) + } + resolve(events) + }) + }) + } +} diff --git a/src/keeper/ContractHandler.ts b/src/keeper/ContractHandler.ts index 05348c0..4b54834 100644 --- a/src/keeper/ContractHandler.ts +++ b/src/keeper/ContractHandler.ts @@ -1,44 +1,56 @@ import { Contract } from "web3-eth-contract" -import LoggerInstance from "../utils/Logger" -import Keeper from "./Keeper" -import Web3Provider from "./Web3Provider" +import { Instantiable, InstantiableConfig } from "../Instantiable.abstract" -export default class ContractHandler { +export default class ContractHandler extends Instantiable { - public static async get(what: string): Promise { - const where = (await (await Keeper.getInstance()).getNetworkName()).toLowerCase() - try { - return ContractHandler.contracts.get(what) || await ContractHandler.load(what, where) - } catch (err) { - LoggerInstance.error("Failed to load", what, "from", where, err) - throw err - } - } - - protected static set(name: string, contractInstance: Contract) { - ContractHandler.contracts.set(name, contractInstance) - } - - protected static has(name: string): boolean { - return ContractHandler.contracts.has(name) + constructor(config: InstantiableConfig) { + super() + this.setInstanceConfig(config) } private static contracts: Map = new Map() - private static async load(what: string, where: string): Promise { - const web3 = Web3Provider.getWeb3() - LoggerInstance.debug("Loading", what, "from", where) + private static getHash(what: string, networkId: number): string { + return `${what}/#${networkId}` + } + + 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 hasContract(what: string, networkId: number): boolean { + return ContractHandler.contracts.has(this.getHash(what, networkId)) + } + + + public async get(what: string): Promise { + 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) + } catch (err) { + this.logger.error("Failed to load", what, "from", where, err) + throw err + } + } + + private async load(what: string, where: string, networkId: number): Promise { + 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 web3.eth.getCode(artifact.address) + const code = await this.web3.eth.getCode(artifact.address) if (code === "0x0") { // no code in the blockchain dude throw new Error(`No code deployed at address ${artifact.address}, sorry.`) } - const contract = new web3.eth.Contract(artifact.abi, artifact.address) + const contract = new this.web3.eth.Contract(artifact.abi, artifact.address) - LoggerInstance.debug("Getting instance of", what, "from", where, "at address", artifact.address) - ContractHandler.contracts.set(what, contract) - return ContractHandler.contracts.get(what) + this.logger.debug("Getting instance of", what, "from", where, "at address", artifact.address) + ContractHandler.setContract(what, networkId, contract) + return ContractHandler.getContract(what, networkId) } } diff --git a/src/keeper/ContractReflector.ts b/src/keeper/ContractReflector.ts deleted file mode 100644 index 3fa63db..0000000 --- a/src/keeper/ContractReflector.ts +++ /dev/null @@ -1,16 +0,0 @@ -import MethodReflection from "../models/MethodReflection" -import GenericContract from "./contracts/GenericContract" - -export default class ContractReflector { - - public static async reflectContractMethod(contractName: string, methodName: string): Promise { - const contract = await GenericContract.getInstance(contractName) - return { - contractName, - methodName, - address: contract.getAddress(), - signature: contract.getSignatureOfMethod(methodName), - inputs: contract.getInputsOfMethod(methodName), - } as MethodReflection - } -} diff --git a/src/keeper/Event.ts b/src/keeper/Event.ts deleted file mode 100644 index c77d3d8..0000000 --- a/src/keeper/Event.ts +++ /dev/null @@ -1,61 +0,0 @@ -import LoggerInstance from "../utils/Logger" -import GenericContract from "./contracts/GenericContract" -import EventListener from "./EventListener" -import Web3Provider from "./Web3Provider" - -export default class Event { - - private poller = null - private lastBlock: number = 0 - private interval: number = 200 - - constructor(private contractName: string, - private eventName: string, - private filter: any) { - - } - - public stopListen() { - clearInterval(this.poller) - this.poller = null - } - - public async listen(callback: any) { - this.lastBlock = await Web3Provider.getWeb3().eth.getBlockNumber() + 1 - - this.poller = setInterval( - () => this.handler(callback), - this.interval) - } - - public listenOnce(callback: any) { - this.listen((events: any[]) => { - if (events) { - EventListener.unsubscribe(this) - callback(events[0]) - } - }) - } - - private async handler(callback: any) { - const contract = await GenericContract.getInstance(this.contractName) - - if (this.lastBlock > await Web3Provider.getWeb3().eth.getBlockNumber()) { - return - } - try { - const events = await contract.getEventData(this.eventName, { - filter: this.filter, - fromBlock: this.lastBlock, - toBlock: "latest", - }) - - if (events.length > 0) { - this.lastBlock = events[events.length - 1].blockNumber + 1 - callback(events) - } - } catch (err) { - LoggerInstance.log(err) - } - } -} diff --git a/src/keeper/EventHandler.ts b/src/keeper/EventHandler.ts new file mode 100644 index 0000000..0c700de --- /dev/null +++ b/src/keeper/EventHandler.ts @@ -0,0 +1,62 @@ +import { ContractEvent } from "./ContractEvent" +import ContractBase from "./contracts/ContractBase" + +import { Instantiable, InstantiableConfig } from "../Instantiable.abstract" + +export class EventHandler extends Instantiable { + private events = new Set<(blockNumber) => void>() + private lastBlock: number + private interval = 200 + private polling: boolean = false + private lastTimeout: NodeJS.Timeout + + get count() { + return this.events.size + } + + constructor(config: InstantiableConfig) { + super() + this.setInstanceConfig(config) + } + + private async checkBlock(isInterval?: boolean, n = 0) { + const blockNumber = await this.web3.eth.getBlockNumber() + + if ((this.polling && !isInterval) || !this.count) { + return + } + this.polling = true + + if (!this.lastBlock) { + this.lastBlock = blockNumber + } + + if (this.lastBlock !== blockNumber) { + this.events.forEach(fn => fn(this.lastBlock + 1)) + this.lastBlock = blockNumber + } + this.lastTimeout = setTimeout(() => this.checkBlock(true, n++), this.interval) + } + + public subscribe(callback: (number) => void) { + this.events.add(callback) + this.checkBlock() + + return { + unsubscribe: () => this.unsubscribe(callback), + } + } + + public unsubscribe(callback: (number) => void) { + this.events.delete(callback) + if (!this.count) { + clearTimeout(this.lastTimeout) + delete this.lastBlock + this.polling = false + } + } + + public getEvent(contract: ContractBase, eventName: string, filter: {[key: string]: any}) { + return new ContractEvent(this, contract, eventName, filter) + } +} diff --git a/src/keeper/EventListener.ts b/src/keeper/EventListener.ts deleted file mode 100644 index d150c58..0000000 --- a/src/keeper/EventListener.ts +++ /dev/null @@ -1,29 +0,0 @@ -import Event from "./Event" - -export default class EventListener { - - public static subscribe(contractName: string, - eventName: string, - filter: any): Event { - - const event = new Event(contractName, eventName, filter) - EventListener.events.push(event) - - return event - } - - public static unsubscribe(event): boolean { - event.stopListen() - const i = EventListener.events.indexOf(event) - if (i > -1) { - EventListener.events.splice(i, 1) - } - return true - } - - public static count() { - return EventListener.events.length - } - - private static events: Event[] = [] -} diff --git a/src/keeper/Keeper.ts b/src/keeper/Keeper.ts index d1d33a8..1157f90 100644 --- a/src/keeper/Keeper.ts +++ b/src/keeper/Keeper.ts @@ -3,9 +3,11 @@ 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 } from "./contracts/managers" +import { TemplateStoreManager, AgreementStoreManager, ConditionStoreManager } from "./contracts/managers" -import Web3Provider from "./Web3Provider" +import { EventHandler } from "./EventHandler" + +import { Instantiable, InstantiableConfig } from "../Instantiable.abstract" /** * Interface with Ocean Keeper contracts. @@ -14,45 +16,48 @@ import Web3Provider from "./Web3Provider" * - Ocean Tokens: the intrinsic tokens circulated inside Ocean network, which is used in the voting of TCRs. * - Marketplace: the core marketplace where people can transact with each other with Ocean tokens. */ -export class Keeper { +export class Keeper extends Instantiable { /** * Returns Keeper instance. * @return {Promise} */ - public static async getInstance(): Promise { - if (Keeper.instance === null) { - Keeper.instance = new Keeper() + public static async getInstance(config: InstantiableConfig): Promise { + const keeper = new Keeper() + keeper.setInstanceConfig(config) - // Main contracts - Keeper.instance.dispenser = await Dispenser.getInstance() - Keeper.instance.token = await OceanToken.getInstance() - Keeper.instance.didRegistry = await DIDRegistry.getInstance() + // Adding keeper inside Ocean to prevent `Keeper not defined yet` error + config.ocean.keeper = keeper - // Managers - Keeper.instance.templateStoreManager = await TemplateStoreManager.getInstance() + // Main contracts + keeper.dispenser = await Dispenser.getInstance(config) + keeper.token = await OceanToken.getInstance(config) + keeper.didRegistry = await DIDRegistry.getInstance(config) - // Conditions - Keeper.instance.conditions = { - lockRewardCondition: await LockRewardCondition.getInstance(), - escrowReward: await EscrowReward.getInstance(), - accessSecretStoreCondition: await AccessSecretStoreCondition.getInstance(), - } + // Managers + keeper.templateStoreManager = await TemplateStoreManager.getInstance(config) + keeper.agreementStoreManager = await AgreementStoreManager.getInstance(config) + keeper.conditionStoreManager = await ConditionStoreManager.getInstance(config) - // Conditions - Keeper.instance.templates = { - escrowAccessSecretStoreTemplate: await EscrowAccessSecretStoreTemplate.getInstance(), - } + // Conditions + keeper.conditions = { + lockRewardCondition: await LockRewardCondition.getInstance(config), + escrowReward: await EscrowReward.getInstance(config), + accessSecretStoreCondition: await AccessSecretStoreCondition.getInstance(config), } - return Keeper.instance - } + // Conditions + keeper.templates = { + escrowAccessSecretStoreTemplate: await EscrowAccessSecretStoreTemplate.getInstance(config), + } - /** - * Keeper instance. - * @type {Keeper} - */ - private static instance: Keeper = null + // Utils + keeper.utils = { + eventHandler: new EventHandler(config), + } + + return keeper + } /** * Ocean Token smart contract instance. @@ -78,6 +83,18 @@ export class Keeper { */ public templateStoreManager: TemplateStoreManager + /** + * Template store manager smart contract instance. + * @type {AgreementStoreManager} + */ + public agreementStoreManager: AgreementStoreManager + + /** + * Template store manager smart contract instance. + * @type {ConditionStoreManager} + */ + public conditionStoreManager: ConditionStoreManager + /** * Conditions instances. */ @@ -94,6 +111,13 @@ export class Keeper { escrowAccessSecretStoreTemplate: EscrowAccessSecretStoreTemplate, } + /** + * Helpers for contracts. + */ + public utils: { + eventHandler: EventHandler + } + /** * Returns a condition by address. * @param {string} address Address of deployed condition. @@ -109,12 +133,20 @@ export class Keeper { .find((template) => template.contractName === name) } + /** + * Returns network id. + * @return {Promise} Network ID. + */ + public getNetworkId(): Promise { + return this.web3.eth.net.getId() + } + /** * Returns the network by name. * @return {Promise} Network name. */ - public async getNetworkName(): Promise { - return Web3Provider.getWeb3().eth.net.getId() + public getNetworkName(): Promise { + return this.web3.eth.net.getId() .then((networkId) => { let network: string = "Unknown" diff --git a/src/keeper/Web3Provider.ts b/src/keeper/Web3Provider.ts index be0472c..ebeff7a 100644 --- a/src/keeper/Web3Provider.ts +++ b/src/keeper/Web3Provider.ts @@ -1,5 +1,5 @@ import * as Web3 from "web3" -import ConfigProvider from "../ConfigProvider" +import Config from "../models/Config" export default class Web3Provider { @@ -7,18 +7,14 @@ export default class Web3Provider { * Returns Web3 instance. * @return {Web3} */ - public static getWeb3(): Web3 { - if (Web3Provider.web3 === null) { - const config = ConfigProvider.getConfig() + public static getWeb3(config: Partial = {}): Web3 { + if (!this.instances.has(config.nodeUri)) { const web3Provider = config.web3Provider || new Web3.providers.HttpProvider(config.nodeUri) - Web3Provider.web3 = new Web3(Web3.givenProvider || web3Provider) + this.instances.set(config.nodeUri, new Web3(Web3.givenProvider || web3Provider)) } - return Web3Provider.web3 + + return this.instances.get(config.nodeUri) } - /** - * Web3 instance. - * @type {Web3} - */ - private static web3: Web3 = null + private static instances = new Map() } diff --git a/src/keeper/contracts/ContractBase.ts b/src/keeper/contracts/ContractBase.ts index be88705..77cc6ca 100644 --- a/src/keeper/contracts/ContractBase.ts +++ b/src/keeper/contracts/ContractBase.ts @@ -1,10 +1,10 @@ import { Contract } from "web3-eth-contract" import { TransactionReceipt } from "web3-core" -import LoggerInstance from "../../utils/Logger" import ContractHandler from "../ContractHandler" -import Web3Provider from "../Web3Provider" -export default abstract class ContractBase { +import { Instantiable, InstantiableConfig } from "../../Instantiable.abstract" + +export default abstract class ContractBase extends Instantiable { protected static instance = null public contractName: string @@ -12,6 +12,7 @@ export default abstract class ContractBase { private contract: Contract = null constructor(contractName) { + super() this.contractName = contractName } @@ -36,13 +37,15 @@ export default abstract class ContractBase { return foundMethod.inputs } - protected async init() { - this.contract = await ContractHandler.get(this.contractName) + protected async init(config: InstantiableConfig) { + this.setInstanceConfig(config) + const contractHandler = new ContractHandler(config) + this.contract = await contractHandler.get(this.contractName) } protected async getFromAddress(from?: string): Promise { if (!from) { - from = (await Web3Provider.getWeb3().eth.getAccounts())[0] + from = (await this.web3.eth.getAccounts())[0] } return from } @@ -75,12 +78,12 @@ export default abstract class ContractBase { value: args[i], } }) - LoggerInstance.error("-".repeat(40)) - LoggerInstance.error(`Sending transaction "${name}" on contract "${this.contractName}" failed.`) - LoggerInstance.error(`Error: ${err.message}`) - LoggerInstance.error(`From: ${from}`) - LoggerInstance.error(`Parameters: ${JSON.stringify(mappedArgs, null, 2)}`) - LoggerInstance.error("-".repeat(40)) + 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)) throw err } } @@ -94,7 +97,7 @@ export default abstract class ContractBase { const method = this.contract.methods[name](...args) return method.call(from ? {from} : null) } catch (err) { - LoggerInstance.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 } } @@ -109,4 +112,11 @@ export default abstract class ContractBase { } return foundMethod } + + 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}`) + } + return this.ocean.keeper.utils.eventHandler.getEvent(this, eventName, filter) + } } diff --git a/src/keeper/contracts/DIDRegistry.ts b/src/keeper/contracts/DIDRegistry.ts index d23bc60..cd5ac68 100644 --- a/src/keeper/contracts/DIDRegistry.ts +++ b/src/keeper/contracts/DIDRegistry.ts @@ -1,12 +1,13 @@ import Web3Provider from "../Web3Provider" import ContractBase from "./ContractBase" import { zeroX } from "../../utils" +import { InstantiableConfig } from "../../Instantiable.abstract" export default class DIDRegistry extends ContractBase { - public static async getInstance(): Promise { + public static async getInstance(config: InstantiableConfig): Promise { const didRegistry: DIDRegistry = new DIDRegistry("DIDRegistry") - await didRegistry.init() + await didRegistry.init(config) return didRegistry } diff --git a/src/keeper/contracts/Dispenser.ts b/src/keeper/contracts/Dispenser.ts index e440f1a..71eb00d 100644 --- a/src/keeper/contracts/Dispenser.ts +++ b/src/keeper/contracts/Dispenser.ts @@ -1,11 +1,12 @@ import ContractBase from "./ContractBase" +import { InstantiableConfig } from "../../Instantiable.abstract" export default class Dispenser extends ContractBase { - public static async getInstance(): Promise { - const market: Dispenser = new Dispenser("Dispenser") - await market.init() - return market + public static async getInstance(config: InstantiableConfig): Promise { + const dispenser: Dispenser = new Dispenser("Dispenser") + await dispenser.init(config) + return dispenser } public async requestTokens(amount: number, receiverAddress: string) { diff --git a/src/keeper/contracts/GenericContract.ts b/src/keeper/contracts/GenericContract.ts index 2949a73..2171647 100644 --- a/src/keeper/contracts/GenericContract.ts +++ b/src/keeper/contracts/GenericContract.ts @@ -1,10 +1,12 @@ import ContractBase from "./ContractBase" +import { InstantiableConfig } from "../../Instantiable.abstract" + export default class GenericContract extends ContractBase { - public static async getInstance(contractName: string): Promise { + public static async getInstance(config: InstantiableConfig, contractName: string): Promise { const contract: GenericContract = new GenericContract(contractName) - await contract.init() + await contract.init(config) return contract } diff --git a/src/keeper/contracts/Token.ts b/src/keeper/contracts/Token.ts index 93d96fa..9b58da7 100644 --- a/src/keeper/contracts/Token.ts +++ b/src/keeper/contracts/Token.ts @@ -1,11 +1,12 @@ import BigNumber from "bignumber.js" import ContractBase from "./ContractBase" +import { InstantiableConfig } from "../../Instantiable.abstract" export default class OceanToken extends ContractBase { - public static async getInstance(): Promise { + public static async getInstance(config: InstantiableConfig): Promise { const token: OceanToken = new OceanToken("OceanToken") - await token.init() + await token.init(config) return token } diff --git a/src/keeper/contracts/conditions/AccessSecretStoreCondition.ts b/src/keeper/contracts/conditions/AccessSecretStoreCondition.ts index 738fb9c..a517098 100644 --- a/src/keeper/contracts/conditions/AccessSecretStoreCondition.ts +++ b/src/keeper/contracts/conditions/AccessSecretStoreCondition.ts @@ -1,10 +1,11 @@ import { Condition } from "./Condition.abstract" import { zeroX, didZeroX } from "../../../utils" +import { InstantiableConfig } from "../../../Instantiable.abstract" export class AccessSecretStoreCondition extends Condition { - public static async getInstance(): Promise { - return Condition.getInstance("AccessSecretStoreCondition", AccessSecretStoreCondition) + public static async getInstance(config: InstantiableConfig): Promise { + return Condition.getInstance(config, "AccessSecretStoreCondition", AccessSecretStoreCondition) } public hashValues(did: string, grantee: string) { diff --git a/src/keeper/contracts/conditions/Condition.abstract.ts b/src/keeper/contracts/conditions/Condition.abstract.ts index d5bcff8..4821dcb 100644 --- a/src/keeper/contracts/conditions/Condition.abstract.ts +++ b/src/keeper/contracts/conditions/Condition.abstract.ts @@ -1,7 +1,6 @@ import ContractBase from "../ContractBase" import { zeroX } from "../../../utils" -import EventListener from "../../../keeper/EventListener" -import Event from "../../../keeper/Event" +import { InstantiableConfig } from "../../../Instantiable.abstract" export enum ConditionState { Uninitialized = 0, @@ -14,9 +13,9 @@ export const conditionStateNames = ["Uninitialized", "Unfulfilled", "Fulfilled", export abstract class Condition extends ContractBase { - public static async getInstance(conditionName: string, conditionsClass: any): Promise { + public static async getInstance(config: InstantiableConfig, conditionName: string, conditionsClass: any): Promise { const condition: Condition = new (conditionsClass as any)(conditionName) - await condition.init() + await condition.init(config) return condition } @@ -45,12 +44,7 @@ export abstract class Condition extends ContractBase { return this.sendFrom("abortByTimeOut", [zeroX(agreementId)], from) } - public getConditionFulfilledEvent(agreementId: string): Event { - return EventListener - .subscribe( - this.contractName, - "Fulfilled", - {agreementId: zeroX(agreementId)}, - ) + public getConditionFulfilledEvent(agreementId: string) { + return this.getEvent("Fulfilled", {agreementId: zeroX(agreementId)}) } } diff --git a/src/keeper/contracts/conditions/EscrowReward.ts b/src/keeper/contracts/conditions/EscrowReward.ts index 6b8f7bc..c3ba86b 100644 --- a/src/keeper/contracts/conditions/EscrowReward.ts +++ b/src/keeper/contracts/conditions/EscrowReward.ts @@ -1,10 +1,11 @@ import { Condition } from "./Condition.abstract" import { zeroX } from "../../../utils" +import { InstantiableConfig } from "../../../Instantiable.abstract" export class EscrowReward extends Condition { - public static async getInstance(): Promise { - return Condition.getInstance("EscrowReward", EscrowReward) + public static async getInstance(config: InstantiableConfig): Promise { + return Condition.getInstance(config, "EscrowReward", EscrowReward) } public hashValues(amount: number, receiver: string, sender: string, lockCondition: string, releaseCondition: string) { diff --git a/src/keeper/contracts/conditions/LockRewardCondition.ts b/src/keeper/contracts/conditions/LockRewardCondition.ts index 0b608df..cb7519c 100644 --- a/src/keeper/contracts/conditions/LockRewardCondition.ts +++ b/src/keeper/contracts/conditions/LockRewardCondition.ts @@ -1,10 +1,11 @@ import { Condition } from "./Condition.abstract" import { zeroX } from "../../../utils" +import { InstantiableConfig } from "../../../Instantiable.abstract" export class LockRewardCondition extends Condition { - public static async getInstance(): Promise { - return Condition.getInstance("LockRewardCondition", LockRewardCondition) + public static async getInstance(config: InstantiableConfig): Promise { + return Condition.getInstance(config, "LockRewardCondition", LockRewardCondition) } public hashValues(rewardAddress: string, amount: number) { diff --git a/src/keeper/contracts/managers/AgreementStoreManager.ts b/src/keeper/contracts/managers/AgreementStoreManager.ts index 51892ea..e8aef9a 100644 --- a/src/keeper/contracts/managers/AgreementStoreManager.ts +++ b/src/keeper/contracts/managers/AgreementStoreManager.ts @@ -1,6 +1,6 @@ -import LoggerInstance from "../../../utils/Logger" import ContractBase from "../ContractBase" import { zeroX } from "../../../utils" +import { InstantiableConfig } from "../../../Instantiable.abstract" export interface AgreementData { did: string @@ -13,9 +13,9 @@ export interface AgreementData { export class AgreementStoreManager extends ContractBase { - public static async getInstance(): Promise { + public static async getInstance(config: InstantiableConfig): Promise { const templateStoreManeger: AgreementStoreManager = new AgreementStoreManager("AgreementStoreManager") - await templateStoreManeger.init() + await templateStoreManeger.init(config) return templateStoreManeger } diff --git a/src/keeper/contracts/managers/ConditionStoreManager.ts b/src/keeper/contracts/managers/ConditionStoreManager.ts index baccdad..95dcbe8 100644 --- a/src/keeper/contracts/managers/ConditionStoreManager.ts +++ b/src/keeper/contracts/managers/ConditionStoreManager.ts @@ -1,7 +1,7 @@ -import LoggerInstance from "../../../utils/Logger" import ContractBase from "../ContractBase" import { ConditionState } from "../conditions/Condition.abstract" import { zeroX } from "../../../utils" +import { InstantiableConfig } from "../../../Instantiable.abstract" export interface ConditionData { typeRef: string @@ -15,9 +15,9 @@ export interface ConditionData { export class ConditionStoreManager extends ContractBase { - public static async getInstance(): Promise { + public static async getInstance(config: InstantiableConfig): Promise { const templateStoreManeger: ConditionStoreManager = new ConditionStoreManager("ConditionStoreManager") - await templateStoreManeger.init() + await templateStoreManeger.init(config) return templateStoreManeger } diff --git a/src/keeper/contracts/managers/TemplateStoreManager.ts b/src/keeper/contracts/managers/TemplateStoreManager.ts index 7c7f6ab..782e519 100644 --- a/src/keeper/contracts/managers/TemplateStoreManager.ts +++ b/src/keeper/contracts/managers/TemplateStoreManager.ts @@ -1,6 +1,7 @@ -import LoggerInstance from "../../../utils/Logger" import ContractBase from "../ContractBase" import { zeroX } from "../../../utils" +import { InstantiableConfig } from "../../../Instantiable.abstract" + export enum TemplateState { Uninitialized = 0, @@ -18,9 +19,9 @@ export interface TemplateMetadata { export class TemplateStoreManager extends ContractBase { - public static async getInstance(): Promise { + public static async getInstance(config: InstantiableConfig): Promise { const templateStoreManeger: TemplateStoreManager = new TemplateStoreManager("TemplateStoreManager") - await templateStoreManeger.init() + await templateStoreManeger.init(config) return templateStoreManeger } @@ -31,7 +32,7 @@ export class TemplateStoreManager extends ContractBase { public async proposeTemplate(address: string, from?: string, ignoreExists?: boolean) { const template = await this.getTemplate(address) if (template.blockNumberUpdated !== 0) { - LoggerInstance.warn(`Template "${address}" already exist.`) + this.logger.warn(`Template "${address}" already exist.`) if (!ignoreExists) { throw new Error("Template already exist.") } @@ -43,7 +44,7 @@ export class TemplateStoreManager extends ContractBase { public async approveTemplate(address: string, from?: string, ignoreApproved?: boolean) { const template = await this.getTemplate(address) if (template.state !== TemplateState.Proposed) { - LoggerInstance.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.`) } diff --git a/src/keeper/contracts/templates/AgreementTemplate.abstract.ts b/src/keeper/contracts/templates/AgreementTemplate.abstract.ts index c7fbe28..276b0a9 100644 --- a/src/keeper/contracts/templates/AgreementTemplate.abstract.ts +++ b/src/keeper/contracts/templates/AgreementTemplate.abstract.ts @@ -1,18 +1,15 @@ import ContractBase from "../ContractBase" -import { AgreementStoreManager, ConditionStoreManager } from "../managers" import { Condition, ConditionState, conditionStateNames } from "../conditions/Condition.abstract" -import Keeper from "../../Keeper" import { DDO } from "../../../ddo/DDO" import { ServiceAgreementTemplate } from "../../../ddo/ServiceAgreementTemplate" -import { zeroX, LoggerInstance } from "../../../utils" -import EventListener from "../../../keeper/EventListener" -import Event from "../../../keeper/Event" +import { zeroX } from "../../../utils" +import { InstantiableConfig } from "../../../Instantiable.abstract" export abstract class AgreementTemplate extends ContractBase { - public static async getInstance(conditionName: string, templateClass: any): Promise { + public static async getInstance(config: InstantiableConfig, conditionName: string, templateClass: any): Promise { const condition: AgreementTemplate = new (templateClass as any)(conditionName) - await condition.init() + await condition.init(config) return condition } @@ -58,9 +55,8 @@ export abstract class AgreementTemplate extends ContractBase { * @return {Promise} Conditions contracts. */ public async getConditions(): Promise { - const keeper = await Keeper.getInstance() return (await this.getConditionTypes()) - .map((address) => keeper.getConditionByAddress(address)) + .map((address) => this.ocean.keeper.getConditionByAddress(address)) } /** @@ -117,14 +113,14 @@ export abstract class AgreementTemplate extends ContractBase { blockedBy: string[], }, } | false> { - const agreementStore = await AgreementStoreManager.getInstance() - const conditionStore = await ConditionStoreManager.getInstance() + const agreementStore = this.ocean.keeper.agreementStoreManager + const conditionStore = this.ocean.keeper.conditionStoreManager const dependencies = await this.getServiceAgreementTemplateDependencies() const {conditionIds} = await agreementStore.getAgreement(agreementId) if (!conditionIds.length) { - LoggerInstance.error(`Agreement not creeated yet: "${agreementId}"`) + this.logger.error(`Agreement not creeated yet: "${agreementId}"`) return false } @@ -167,25 +163,25 @@ export abstract class AgreementTemplate extends ContractBase { public async printAgreementStatus(agreementId: string) { const status = await this.getAgreementStatus(agreementId) - LoggerInstance.bypass("-".repeat(80)) - LoggerInstance.bypass("Template:", this.contractName) - LoggerInstance.bypass("Agreement ID:", agreementId) - LoggerInstance.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) { - LoggerInstance.bypass("Agreement not created yet!") + this.logger.bypass("Agreement not created yet!") } Object.values(status || []) .forEach(({condition, contractName, state, blocked, blockedBy}, i) => { if (i) { - LoggerInstance.bypass("-".repeat(20)) + this.logger.bypass("-".repeat(20)) } - LoggerInstance.bypass(`${condition} (${contractName})`) - LoggerInstance.bypass(" Status:", state, `(${conditionStateNames[state]})`) + this.logger.bypass(`${condition} (${contractName})`) + this.logger.bypass(" Status:", state, `(${conditionStateNames[state]})`) if (blocked) { - LoggerInstance.bypass(" Blocked by:", blockedBy) + this.logger.bypass(" Blocked by:", blockedBy) } }) - LoggerInstance.bypass("-".repeat(80)) + this.logger.bypass("-".repeat(80)) } /** @@ -193,12 +189,7 @@ export abstract class AgreementTemplate extends ContractBase { * @param {string} agreementId Agreement ID. * @return {Event} Agreement created event. */ - public getAgreementCreatedEvent(agreementId: string): Event { - return EventListener - .subscribe( - this.contractName, - "AgreementCreated", - {agreementId: zeroX(agreementId)}, - ) + public getAgreementCreatedEvent(agreementId: string) { + return this.getEvent("AgreementCreated", {agreementId: zeroX(agreementId)}) } } diff --git a/src/keeper/contracts/templates/EscrowAccessSecretStoreTemplate.ts b/src/keeper/contracts/templates/EscrowAccessSecretStoreTemplate.ts index 79b6733..3c9c982 100644 --- a/src/keeper/contracts/templates/EscrowAccessSecretStoreTemplate.ts +++ b/src/keeper/contracts/templates/EscrowAccessSecretStoreTemplate.ts @@ -3,13 +3,14 @@ import { LockRewardCondition, EscrowReward, AccessSecretStoreCondition } from ". import DIDRegistry from "../DIDRegistry" import { DDO } from "../../../ddo/DDO" import { generateId, zeroX } from "../../../utils" +import { InstantiableConfig } from "../../../Instantiable.abstract" import { escrowAccessSecretStoreTemplateServiceAgreementTemplate } from "./EscrowAccessSecretStoreTemplate.serviceAgreementTemplate" export class EscrowAccessSecretStoreTemplate extends AgreementTemplate { - public static async getInstance(): Promise { - return AgreementTemplate.getInstance("EscrowAccessSecretStoreTemplate", EscrowAccessSecretStoreTemplate) + public static async getInstance(config: InstantiableConfig): Promise { + return AgreementTemplate.getInstance(config, "EscrowAccessSecretStoreTemplate", EscrowAccessSecretStoreTemplate) } public async getServiceAgreementTemplate() { @@ -89,11 +90,9 @@ export class EscrowAccessSecretStoreTemplate extends AgreementTemplate { } private async createFullAgreementData(agreementId: string, did: string, amount: number, consumer: string) { - const didRegistry = await DIDRegistry.getInstance() + const {didRegistry, conditions} = this.ocean.keeper - const accessSecretStoreCondition = await AccessSecretStoreCondition.getInstance() - const lockRewardCondition = await LockRewardCondition.getInstance() - const escrowReward = await EscrowReward.getInstance() + const {accessSecretStoreCondition, lockRewardCondition, escrowReward} = conditions const publisher = await didRegistry.getDIDOwner(did) diff --git a/src/ocean/Account.ts b/src/ocean/Account.ts index 736f7cf..c24a216 100644 --- a/src/ocean/Account.ts +++ b/src/ocean/Account.ts @@ -1,17 +1,21 @@ import BigNumber from "bignumber.js" import * as EthJsUtils from "ethereumjs-util" -import Keeper from "../keeper/Keeper" -import Web3Provider from "../keeper/Web3Provider" import Balance from "../models/Balance" -import LoggerInstance from "../utils/Logger" + +import { Instantiable, InstantiableConfig } from "../Instantiable.abstract" /** * Account information. */ -export default class Account { +export default class Account extends Instantiable { private password?: string - constructor(private id: string = "0x0") { } + constructor(private id: string = "0x0", config?: InstantiableConfig) { + super() + if (config) { + this.setInstanceConfig(config) + } + } public getId() { return this.id @@ -42,7 +46,7 @@ export default class Account { * @return {Promise} */ public async getOceanBalance(): Promise { - const token = (await Keeper.getInstance()).token + const token = this.ocean.keeper.token return await token.balanceOf(this.id) / (10 ** await token.decimals()) } @@ -51,13 +55,10 @@ export default class Account { * @return {Promise} */ public async getEtherBalance(): Promise { - // Logger.log("getting balance for", account); - return Web3Provider - .getWeb3() + return this.web3 .eth .getBalance(this.id, "latest") .then((balance: string): number => { - // Logger.log("balance", balance); return new BigNumber(balance).toNumber() }) } @@ -80,11 +81,11 @@ export default class Account { */ public async requestTokens(amount: number): Promise { try { - await (await Keeper.getInstance()) + await this.ocean.keeper .dispenser .requestTokens(amount, this.id) } catch (e) { - LoggerInstance.error(e) + this.logger.error(e) throw new Error("Error requesting tokens") } @@ -96,11 +97,8 @@ export default class Account { * @return {Promise} */ public async getPublicKey(): Promise { - - const web3 = Web3Provider.getWeb3() - - const msg = web3.utils.sha3(this.getId()) - const sig = await web3.eth.sign(msg, this.getId()) + const msg = this.web3.utils.sha3(this.getId()) + const sig = await this.web3.eth.sign(msg, this.getId()) const {v, r, s} = EthJsUtils.fromRpcSig(sig) return EthJsUtils.ecrecover(EthJsUtils.toBuffer(msg), v, r, s).toString("hex") diff --git a/src/ocean/Ocean.ts b/src/ocean/Ocean.ts index 751f421..64c5676 100644 --- a/src/ocean/Ocean.ts +++ b/src/ocean/Ocean.ts @@ -1,33 +1,22 @@ -import deprecated from "deprecated-decorator" - import { OceanAccounts } from "./OceanAccounts" import { OceanAgreements } from "./OceanAgreements" import { OceanAssets } from "./OceanAssets" import { OceanSecretStore } from "./OceanSecretStore" import { OceanTokens } from "./OceanTokens" -import AquariusProvider from "../aquarius/AquariusProvider" -import { SearchQuery } from "../aquarius/query/SearchQuery" -import BrizoProvider from "../brizo/BrizoProvider" -import ConfigProvider from "../ConfigProvider" -import { DDO } from "../ddo/DDO" -import { MetaData } from "../ddo/MetaData" -import { Service } from "../ddo/Service" -import ContractEvent from "../keeper/Event" -import Config from "../models/Config" -import SecretStoreProvider from "../secretstore/SecretStoreProvider" -import { LoggerInstance, LogLevel } from "../utils/Logger" -import Account from "./Account" -import DID from "./DID" -import ServiceAgreement from "./ServiceAgreements/ServiceAgreement" +import { Aquarius } from "../aquarius/Aquarius" +import { Brizo } from "../brizo/Brizo" import Keeper from "../keeper/Keeper" -import EventListener from "../keeper/EventListener" + +import { Config } from "../models/Config" + +import { Instantiable, generateIntantiableConfigFromConfig } from "../Instantiable.abstract" /** * Main interface for Ocean Protocol. */ -export class Ocean { +export class Ocean extends Instantiable { /** * Returns the instance of Ocean. @@ -35,33 +24,46 @@ export class Ocean { * @return {Promise} */ public static async getInstance(config: Config): Promise { - ConfigProvider.setConfig(config) + const instance = new Ocean() - if (!Ocean.instance) { - Ocean.instance = new Ocean() - Ocean.instance.keeper = await Keeper.getInstance() - Ocean.instance.accounts = await OceanAccounts.getInstance() - Ocean.instance.assets = await OceanAssets.getInstance() - Ocean.instance.agreements = await OceanAgreements.getInstance() - Ocean.instance.secretStore = await OceanSecretStore.getInstance() - Ocean.instance.tokens = await OceanTokens.getInstance() + const instanceConfig = { + ...generateIntantiableConfigFromConfig(config), + ocean: instance, } + instance.setInstanceConfig(instanceConfig) - return Ocean.instance + instance.keeper = await Keeper.getInstance(instanceConfig) + + instance.brizo = new Brizo(instanceConfig) + instance.aquarius = new Aquarius(instanceConfig) + + instance.accounts = await OceanAccounts.getInstance(instanceConfig) + instance.assets = await OceanAssets.getInstance(instanceConfig) + instance.agreements = await OceanAgreements.getInstance(instanceConfig) + instance.secretStore = await OceanSecretStore.getInstance(instanceConfig) + instance.tokens = await OceanTokens.getInstance(instanceConfig) + + return instance } - /** - * Ocean instance. - * @type {Ocean} - */ - private static instance: Ocean = null - /** * Keeper instance. * @type {Keeper} */ public keeper: Keeper + /** + * Brizo instance. + * @type {Brizo} + */ + public brizo: Brizo + + /** + * Aquarius instance. + * @type {Aquarius} + */ + public aquarius: Aquarius + /** * Ocean account submodule * @type {OceanAccounts} @@ -92,158 +94,7 @@ export class Ocean { */ public tokens: OceanTokens - private constructor() { } - - /** - * Returns the list of accounts. - * @deprecated Replace by [Ocean.accounts.list]{@link #OceanAccounts.list} - * @return {Promise} - */ - @deprecated("OceanAccounts.list") - public async getAccounts(): Promise { - return await this.accounts.list() - } - - /** - * Returns a DDO by DID. - * @deprecated Replace by [Ocean.assets.resolve]{@link #OceanAssets.resolve} - * @param {string} did Decentralized ID. - * @return {Promise} - */ - @deprecated("OceanAssets.resolve") - public async resolveDID(did: string): Promise { - return await this.assets.resolve(did) - } - - /** - * Returns a DDO by DID. - * @deprecated Replace by [Ocean.assets.resolve]{@link #OceanAssets.resolve} - * @param {string} did Decentralized ID. - * @return {Promise} - */ - @deprecated("OceanAssets.resolve") - public async resolveAssetDID(did: string): Promise { - return await this.assets.resolve(did) - } - - /** - * Registers a new DDO. - * @deprecated Replace by [Ocean.assets.create]{@link #OceanAssets.create} - * @param {MetaData} metadata DDO metadata. - * @param {Account} publisher Publisher account. - * @return {Promise} - */ - @deprecated("OceanAssets.create") - public async registerAsset(metadata: MetaData, publisher: Account, services?: Service[]): Promise { - return await this.assets.create(metadata, publisher, services) - } - - /** - * Signs a service agreement by DID. - * @deprecated Replace by [Ocean.agreement.prepare]{@link #OceanAgreement.prepare} - * @param {string} did Decentralized ID. - * @param {string} serviceDefinitionId Service definition ID. - * @param {Account} consumer Consumer account. - * @return {Promise} - * - */ - @deprecated("OceanAgreement.prepare") - public async signServiceAgreement( - did: string, - serviceDefinitionId: string, - consumer: Account, - ) { - return await this.agreements.prepare(did, serviceDefinitionId, consumer) - } - - /** - * Signs a service agreement by DID. - * @deprecated Replace by [Ocean.assets.order]{@link #OceanAssets.order} - * @param {string} did Decentralized ID. - * @param {string} serviceDefinitionId Service definition ID. - * @param {Account} consumer Consumer account. - * @return {Promise} - */ - @deprecated("OceanAssets.order") - public async purchaseAssetService( - did: string, - serviceDefinitionId: string, - consumer: Account, - ): Promise { - return await this.assets.order(did, serviceDefinitionId, consumer) - } - - /** - * Creates a new service agreement. - * @deprecated Replace by [Ocean.assets.consume]{@link #OceanAssets.consume} - * @param {string} did Decentralized ID. - * @param {string} serviceDefinitionId Service definition ID. - * @param {string} serviceAgreementId Service agreement ID. - * @param {string} serviceAgreementSignature Service agreement signature. - * @param {Function} cb Callback executen when the access is granted. - * @param {Account} consumer Consumer account. - */ - @deprecated("OceanAssets.consume") - public async initializeServiceAgreement( - did: string, - serviceDefinitionId: string, - serviceAgreementId: string, - serviceAgreementSignature: string, - cb: (files: string[]) => void, - consumer: Account, - ) { - return await this.assets.consume(serviceAgreementId, did, serviceDefinitionId, consumer) - } - - /** - * Executes a service agreement. - * @deprecated Replace by [Ocean.agreements.create]{@link #OceanAgreements.create} - * @param {string} did Decentralized ID. - * @param {string} serviceDefinitionId Service definition ID. - * @param {string} serviceAgreementId Service agreement ID. - * @param {string} serviceAgreementSignature Service agreement signature. - * @param {Account} consumer Consumer account. - * @param {Account} publisher Publisher account. - * @return {Promise} - */ - @deprecated("OceanAgreements.create") - public async executeServiceAgreement( - did: string, - serviceDefinitionId: string, - serviceAgreementId: string, - serviceAgreementSignature: string, - consumer: Account, - publisher: Account, - ): Promise { - return await this.agreements - .create(did, - serviceDefinitionId, - serviceAgreementId, - serviceAgreementSignature, - consumer, - publisher, - ) - } - - /** - * Search over the assets using a query. - * @deprecated Replace by [Ocean.assets.query]{@link #OceanAssets.query} - * @param {SearchQuery} query Query to filter the assets. - * @return {Promise} - */ - @deprecated("OceanAssets.query") - public async searchAssets(query: SearchQuery): Promise { - return await this.assets.query(query) - } - - /** - * Search over the assets using a keyword. - * @deprecated Replace by [Ocean.assets.search]{@link #OceanAssets.search} - * @param {string} text Text to filter the assets. - * @return {Promise} - */ - @deprecated("OceanAssets.search") - public async searchAssetsByText(text: string): Promise { - return await this.assets.search(text) + private constructor() { + super() } } diff --git a/src/ocean/OceanAccounts.ts b/src/ocean/OceanAccounts.ts index bde3345..3e8b301 100644 --- a/src/ocean/OceanAccounts.ts +++ b/src/ocean/OceanAccounts.ts @@ -1,30 +1,23 @@ -import Web3Provider from "../keeper/Web3Provider" import Balance from "../models/Balance" import Account from "./Account" +import { Instantiable, InstantiableConfig } from "../Instantiable.abstract" /** * Account submodule of Ocean Protocol. */ -export class OceanAccounts { +export class OceanAccounts extends Instantiable { /** * Returns the instance of OceanAccounts. * @return {Promise} */ - public static async getInstance(): Promise { - if (!OceanAccounts.instance) { - OceanAccounts.instance = new OceanAccounts() - } + public static async getInstance(config: InstantiableConfig): Promise { + const instance = new OceanAccounts() + instance.setInstanceConfig(config) - return OceanAccounts.instance + return instance } - /** - * OceanAccounts instance. - * @type {OceanAccounts} - */ - private static instance: OceanAccounts = null - /** * Returns the list of accounts. * @return {Promise} @@ -32,9 +25,9 @@ export class OceanAccounts { public async list(): Promise { // retrieve eth accounts - const ethAccounts = await Web3Provider.getWeb3().eth.getAccounts() + const ethAccounts = await this.web3.eth.getAccounts() - return ethAccounts.map((address: string) => new Account(address)) + return ethAccounts.map((address: string) => new Account(address, this.instanceConfig)) } /** diff --git a/src/ocean/OceanAgreements.ts b/src/ocean/OceanAgreements.ts index d5c1ab4..e137742 100644 --- a/src/ocean/OceanAgreements.ts +++ b/src/ocean/OceanAgreements.ts @@ -1,11 +1,9 @@ -import AquariusProvider from "../aquarius/AquariusProvider" -import BrizoProvider from "../brizo/BrizoProvider" import { generateId } from "../utils/GeneratorHelpers" import Account from "./Account" import DID from "./DID" import ServiceAgreement from "./ServiceAgreements/ServiceAgreement" -import { Keeper } from "../keeper/Keeper" import { zeroX, didPrefixed } from "../utils" +import { Instantiable, InstantiableConfig } from "../Instantiable.abstract" import { OceanAgreementsConditions } from "./OceanAgreementsConditions" @@ -17,27 +15,20 @@ export interface AgreementPrepareResult { /** * Agreements submodule of Ocean Protocol. */ -export class OceanAgreements { +export class OceanAgreements extends Instantiable { /** * Returns the instance of OceanAgreements. * @return {Promise} */ - public static async getInstance(): Promise { - if (!OceanAgreements.instance) { - OceanAgreements.instance = new OceanAgreements() - OceanAgreements.instance.conditions = await OceanAgreementsConditions.getInstance() - } + public static async getInstance(config: InstantiableConfig): Promise { + const instance = new OceanAgreements() + instance.setInstanceConfig(config) + instance.conditions = await OceanAgreementsConditions.getInstance(config) - return OceanAgreements.instance + return instance } - /** - * OceanAgreements instance. - * @type {OceanAgreements} - */ - private static instance: OceanAgreements = null - /** * Agreements Conditions submodule. * @type {OceanAgreementsConditions} @@ -58,16 +49,16 @@ export class OceanAgreements { ): Promise { const d: DID = DID.parse(did as string) - const ddo = await AquariusProvider.getAquarius().retrieveDDO(d) + const ddo = await this.ocean.aquarius.retrieveDDO(d) const agreementId: string = generateId() - const keeper = await Keeper.getInstance() const templateName = ddo.findServiceByType("Access").serviceAgreementTemplate.contractName - const agreementConditionsIds = await keeper + const agreementConditionsIds = await this.ocean.keeper .getTemplateByName(templateName) .getAgreementIdsFromDDO(agreementId, ddo, consumer.getId(), consumer.getId()) const signature = await ServiceAgreement.signServiceAgreement( + this.web3, ddo, serviceDefinitionId, agreementId, @@ -93,8 +84,7 @@ export class OceanAgreements { consumer: Account, ): Promise { - const result = await BrizoProvider - .getBrizo() + const result = await this.ocean.brizo .initializeServiceAgreement( didPrefixed(did), zeroX(agreementId), @@ -128,13 +118,11 @@ export class OceanAgreements { consumer: Account, publisher: Account, ) { - const keeper = await Keeper.getInstance() - const d: DID = DID.parse(did) - const ddo = await AquariusProvider.getAquarius().retrieveDDO(d) + const ddo = await this.ocean.aquarius.retrieveDDO(d) const templateName = ddo.findServiceById<"Access">(serviceDefinitionId).serviceAgreementTemplate.contractName - await keeper + await this.ocean.keeper .getTemplateByName(templateName) .createAgreementFromDDO(agreementId, ddo, consumer.getId(), publisher.getId()) diff --git a/src/ocean/OceanAgreementsConditions.ts b/src/ocean/OceanAgreementsConditions.ts index c30589d..2b4542a 100644 --- a/src/ocean/OceanAgreementsConditions.ts +++ b/src/ocean/OceanAgreementsConditions.ts @@ -1,32 +1,22 @@ -import Keeper from "../keeper/Keeper" import Account from "./Account" +import { Instantiable, InstantiableConfig } from "../Instantiable.abstract" /** * Agreements Conditions submodule of Ocean Protocol. */ -export class OceanAgreementsConditions { +export class OceanAgreementsConditions extends Instantiable { /** * Returns the instance of OceanAgreementsConditions. * @return {Promise} */ - public static async getInstance(): Promise { - if (!OceanAgreementsConditions.instance) { - OceanAgreementsConditions.instance = new OceanAgreementsConditions() - OceanAgreementsConditions.instance.keeper = await Keeper.getInstance() - } + public static async getInstance(config: InstantiableConfig): Promise { + const instance = new OceanAgreementsConditions() + instance.setInstanceConfig(config) - return OceanAgreementsConditions.instance + return instance } - /** - * OceanAgreementsConditions instance. - * @type {OceanAgreementsConditions} - */ - private static instance: OceanAgreementsConditions = null - - private keeper: Keeper - /** * Transfers tokens to the EscrowRewardCondition contract as an escrow payment. * This is required before access can be given to the asset data. @@ -34,12 +24,12 @@ export class OceanAgreementsConditions { * @param {number} amount Asset amount. * @param {Account} from Account of sender. */ - public async lockReward(agreementId: string, amount: number, from: Account = new Account()) { - const {lockRewardCondition, escrowReward} = this.keeper.conditions + public async lockReward(agreementId: string, amount: number, from?: Account) { + const {lockRewardCondition, escrowReward} = this.ocean.keeper.conditions - await this.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.getId()) + const receipt = await lockRewardCondition.fulfill(agreementId, escrowReward.getAddress(), amount, from && from.getId()) return !!receipt.events.Fulfilled } @@ -50,10 +40,10 @@ export class OceanAgreementsConditions { * @param {string} grantee Consumer address. * @param {Account} from Account of sender. */ - public async grantAccess(agreementId: string, did: string, grantee: string, from: Account = new Account()) { - const {accessSecretStoreCondition} = this.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.getId()) + const receipt = await accessSecretStoreCondition.fulfill(agreementId, did, grantee, from && from.getId()) return !!receipt.events.Fulfilled } @@ -76,9 +66,9 @@ export class OceanAgreementsConditions { did: string, consumer: string, publisher: string, - from: Account = new Account(), + from?: Account, ) { - const {escrowReward, accessSecretStoreCondition, lockRewardCondition} = this.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) @@ -90,7 +80,7 @@ export class OceanAgreementsConditions { consumer, conditionIdLock, conditionIdAccess, - from.getId(), + from && from.getId(), ) return !!receipt.events.Fulfilled } diff --git a/src/ocean/OceanAssets.ts b/src/ocean/OceanAssets.ts index 5fe288f..e032aec 100644 --- a/src/ocean/OceanAssets.ts +++ b/src/ocean/OceanAssets.ts @@ -1,41 +1,28 @@ -import AquariusProvider from "../aquarius/AquariusProvider" import { SearchQuery } from "../aquarius/query/SearchQuery" -import BrizoProvider from "../brizo/BrizoProvider" -import ConfigProvider from "../ConfigProvider" import { DDO } from "../ddo/DDO" import { MetaData } from "../ddo/MetaData" -import { ServiceAgreementTemplateCondition } from "../ddo/ServiceAgreementTemplate" import { Service, ServiceAuthorization } from "../ddo/Service" -import Keeper from "../keeper/Keeper" -import SecretStoreProvider from "../secretstore/SecretStoreProvider" -import { LoggerInstance, fillConditionsWithDDO } from "../utils" import Account from "./Account" import DID from "./DID" -import { OceanAgreements } from "./OceanAgreements" +import { fillConditionsWithDDO } from "../utils" +import { Instantiable, InstantiableConfig } from "../Instantiable.abstract" /** * Assets submodule of Ocean Protocol. */ -export class OceanAssets { +export class OceanAssets extends Instantiable { /** * Returns the instance of OceanAssets. * @return {Promise} */ - public static async getInstance(): Promise { - if (!OceanAssets.instance) { - OceanAssets.instance = new OceanAssets() - } + public static async getInstance(config: InstantiableConfig): Promise { + const instance = new OceanAssets() + instance.setInstanceConfig(config) - return OceanAssets.instance + return instance } - /** - * OceanAssets instance. - * @type {OceanAssets} - */ - private static instance: OceanAssets = null - /** * Returns a DDO by DID. * @param {string} did Decentralized ID. @@ -43,7 +30,7 @@ export class OceanAssets { */ public async resolve(did: string): Promise { const d: DID = DID.parse(did) - return AquariusProvider.getAquarius().retrieveDDO(d) + return this.ocean.aquarius.retrieveDDO(d) } /** @@ -53,24 +40,19 @@ export class OceanAssets { * @return {Promise} */ public async create(metadata: MetaData, publisher: Account, services: Service[] = []): Promise { - const {secretStoreUri} = ConfigProvider.getConfig() - const {didRegistry, templates} = await Keeper.getInstance() - const aquarius = AquariusProvider.getAquarius() - const brizo = BrizoProvider.getBrizo() + const {secretStoreUri} = this.config + const {didRegistry, templates} = this.ocean.keeper const did: DID = DID.generate() const authorizationService = (services.find(({type}) => type === "Authorization") || {}) as ServiceAuthorization const secretStoreUrl = authorizationService.service === "SecretStore" && authorizationService.serviceEndpoint - const secretStoreConfig = { - secretStoreUri: secretStoreUrl, - } - const encryptedFiles = await SecretStoreProvider.getSecretStore(secretStoreConfig).encryptDocument(did.getId(), metadata.base.files) + const encryptedFiles = await this.ocean.secretStore.encrypt(did.getId(), metadata.base.files, null, secretStoreUrl) const serviceAgreementTemplate = await templates.escrowAccessSecretStoreTemplate.getServiceAgreementTemplate() - const serviceEndpoint = aquarius.getServiceEndpoint(did) + const serviceEndpoint = this.ocean.aquarius.getServiceEndpoint(did) let serviceDefinitionIdCount = 0 // create ddo itself @@ -91,15 +73,15 @@ export class OceanAssets { service: [ { type: "Access", - purchaseEndpoint: brizo.getPurchaseEndpoint(), - serviceEndpoint: brizo.getConsumeEndpoint(), + purchaseEndpoint: this.ocean.brizo.getPurchaseEndpoint(), + serviceEndpoint: this.ocean.brizo.getConsumeEndpoint(), serviceDefinitionId: String(serviceDefinitionIdCount++), templateId: templates.escrowAccessSecretStoreTemplate.getAddress(), serviceAgreementTemplate, }, { type: "Compute", - serviceEndpoint: brizo.getComputeEndpoint(publisher.getId(), String(serviceDefinitionIdCount), "xxx", "xxx"), + serviceEndpoint: this.ocean.brizo.getComputeEndpoint(publisher.getId(), String(serviceDefinitionIdCount), "xxx", "xxx"), serviceDefinitionId: String(serviceDefinitionIdCount++), }, { @@ -148,9 +130,9 @@ export class OceanAssets { serviceAgreementTemplate.conditions = conditions ddo.addChecksum() - await ddo.addProof(publisher.getId(), publisher.getPassword()) + await ddo.addProof(this.web3, publisher.getId(), publisher.getPassword()) - const storedDdo = await aquarius.storeDDO(ddo) + const storedDdo = await this.ocean.aquarius.storeDDO(ddo) await didRegistry.registerAttribute( did.getId(), ddo.getChecksum(), @@ -172,7 +154,6 @@ export class OceanAssets { resultPath?: string, ): Promise { - const brizo = BrizoProvider.getBrizo() const ddo = await this.resolve(did) const {metadata} = ddo.findServiceByType("Metadata") @@ -188,27 +169,23 @@ export class OceanAssets { } const secretStoreUrl = authorizationService.service === "SecretStore" && authorizationService.serviceEndpoint - const secretStoreConfig = { - secretStoreUri: secretStoreUrl, - } - LoggerInstance.log("Decrypting files") - const decryptedFiles = await SecretStoreProvider - .getSecretStore(secretStoreConfig) - .decryptDocument(DID.parse(did).getId(), files) - LoggerInstance.log("Files decrypted") + this.logger.log("Decrypting files") + const decryptedFiles = await this.ocean.secretStore + .decrypt(did, files, consumerAccount, secretStoreUrl) + this.logger.log("Files decrypted") - LoggerInstance.log("Consuming files") + this.logger.log("Consuming files") resultPath = resultPath ? `${resultPath}/datafile.${ddo.shortId()}.${agreementId}/` : undefined - await brizo.consumeService( + await this.ocean.brizo.consumeService( agreementId, serviceEndpoint, consumerAccount, decryptedFiles, resultPath, ) - LoggerInstance.log("Files consumed") + this.logger.log("Files consumed") if (resultPath) { return resultPath @@ -230,53 +207,54 @@ export class OceanAssets { consumer: Account, ): Promise { - const oceanAgreements = await OceanAgreements.getInstance() + const oceanAgreements = this.ocean.agreements - LoggerInstance.log("Asking for agreement signature") + this.logger.log("Asking for agreement signature") const {agreementId, signature} = await oceanAgreements.prepare(did, serviceDefinitionId, consumer) - LoggerInstance.log(`Agreement ${agreementId} signed`) + this.logger.log(`Agreement ${agreementId} signed`) const ddo = await this.resolve(did) - const keeper = await Keeper.getInstance() + const keeper = this.ocean.keeper const templateName = ddo.findServiceByType("Access").serviceAgreementTemplate.contractName const template = keeper.getTemplateByName(templateName) const accessCondition = keeper.conditions.accessSecretStoreCondition - const paymentFlow = new Promise((resolve, reject) => { - template - .getAgreementCreatedEvent(agreementId) - .listenOnce(async (...args) => { - LoggerInstance.log("Agreement initialized") + const paymentFlow = new Promise(async (resolve, reject) => { + await template.getAgreementCreatedEvent(agreementId).once() - const {metadata} = ddo.findServiceByType("Metadata") + this.logger.log("Agreement initialized") - LoggerInstance.log("Locking payment") + const {metadata} = ddo.findServiceByType("Metadata") - const paid = await oceanAgreements.conditions.lockReward(agreementId, metadata.base.price, consumer) + this.logger.log("Locking payment") - if (paid) { - LoggerInstance.log("Payment was OK") - } else { - LoggerInstance.error("Payment was KO") - LoggerInstance.error("Agreement ID: ", agreementId) - LoggerInstance.error("DID: ", ddo.id) - reject("Error on payment") - } - }) + const paid = await oceanAgreements.conditions.lockReward(agreementId, metadata.base.price, consumer) - accessCondition - .getConditionFulfilledEvent(agreementId) - .listenOnce(async (...args) => { - LoggerInstance.log("Access granted") - resolve() - }) + if (paid) { + 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") + } + + await accessCondition.getConditionFulfilledEvent(agreementId).once() + + this.logger.log("Access granted") + resolve() }) - LoggerInstance.log("Sending agreement request") + this.logger.log("Sending agreement request") await oceanAgreements.send(did, agreementId, serviceDefinitionId, signature, consumer) + this.logger.log("Agreement request sent") - await paymentFlow + try { + await paymentFlow + } catch(e) { + throw new Error("Error paying the asset.") + } return agreementId } @@ -287,7 +265,7 @@ export class OceanAssets { * @return {Promise} */ public async query(query: SearchQuery): Promise { - return AquariusProvider.getAquarius().queryMetadataByText(query) + return this.ocean.aquarius.queryMetadataByText(query) } /** @@ -296,7 +274,7 @@ export class OceanAssets { * @return {Promise} */ public async search(text: string): Promise { - return AquariusProvider.getAquarius().queryMetadataByText({ + return this.ocean.aquarius.queryMetadataByText({ text, page: 0, offset: 100, diff --git a/src/ocean/OceanSecretStore.ts b/src/ocean/OceanSecretStore.ts index 202847d..faca9e5 100644 --- a/src/ocean/OceanSecretStore.ts +++ b/src/ocean/OceanSecretStore.ts @@ -1,29 +1,24 @@ import SecretStoreProvider from "../secretstore/SecretStoreProvider" import Account from "./Account" +import { noDidPrefixed } from "../utils" +import { Instantiable, InstantiableConfig } from "../Instantiable.abstract" /** * SecretStore submodule of Ocean Protocol. */ -export class OceanSecretStore { +export class OceanSecretStore extends Instantiable { /** * Returns the instance of OceanSecretStore. * @return {Promise} */ - public static async getInstance(): Promise { - if (!OceanSecretStore.instance) { - OceanSecretStore.instance = new OceanSecretStore() - } + public static async getInstance(config: InstantiableConfig): Promise { + const instance = new OceanSecretStore() + instance.setInstanceConfig(config) - return OceanSecretStore.instance + return instance } - /** - * OceanSecretStore instance. - * @type {OceanSecretStore} - */ - private static instance: OceanSecretStore = null - /** * Encrypt the given text and store the encryption keys using the `did`. * The encrypted text can be decrypted using the same keys identified by the `did`. @@ -32,10 +27,9 @@ export class OceanSecretStore { * @param {string} publisher Publisher account. * @return {Promise} Encrypted text. */ - public async encrypt(did: string, content: any, publisher: Account): Promise { - return await this.getSecretStoreByAccount(publisher) - // TODO did to id - .encryptDocument(did, content) + public async encrypt(did: string, content: any, publisher?: Account, secretStoreUrl?: string): Promise { + return await this.getSecretStoreByAccount(publisher, secretStoreUrl) + .encryptDocument(noDidPrefixed(did), content) } /** @@ -46,17 +40,22 @@ export class OceanSecretStore { * @param {string} consumer cONSUMER account. * @return {Promise} Encrypted text. */ - public async decrypt(did: string, content: string, consumer: Account): Promise { - return await this.getSecretStoreByAccount(consumer) - // TODO did to id - .decryptDocument(did, content) + public async decrypt(did: string, content: string, consumer?: Account, secretStoreUrl?: string): Promise { + return await this.getSecretStoreByAccount(consumer, secretStoreUrl) + .decryptDocument(noDidPrefixed(did), content) } - private getSecretStoreByAccount(account: Account) { - const config: any = {address: account.getId()} - if (account.getPassword()) { + private getSecretStoreByAccount(account: Account, secretStoreUrl?: string) { + const config: any = {...this.config} + if (account) { + config.address = account.getId() + } + if (account && account.getPassword()) { config.password = account.getPassword() } + if (secretStoreUrl) { + config.secretStoreUri = secretStoreUrl + } return SecretStoreProvider.getSecretStore(config) } } diff --git a/src/ocean/OceanTokens.ts b/src/ocean/OceanTokens.ts index 3765792..8df8e72 100644 --- a/src/ocean/OceanTokens.ts +++ b/src/ocean/OceanTokens.ts @@ -1,29 +1,23 @@ import Keeper from "../keeper/Keeper" import Account from "./Account" +import { Instantiable, InstantiableConfig } from "../Instantiable.abstract" /** * Tokens submodule of Ocean Protocol. */ -export class OceanTokens { +export class OceanTokens extends Instantiable { /** * Returns the instance of OceanTokens. * @return {Promise} */ - public static async getInstance(): Promise { - if (!OceanTokens.instance) { - OceanTokens.instance = new OceanTokens() - } + public static async getInstance(config: InstantiableConfig): Promise { + const instance = new OceanTokens() + instance.setInstanceConfig(config) - return OceanTokens.instance + return instance } - /** - * OceanTokens instance. - * @type {OceanTokens} - */ - private static instance: OceanTokens = null - /** * Transfer a number of tokens to the mentioned account. * @param {string} to Address that receives the account. @@ -32,7 +26,7 @@ export class OceanTokens { * @return {Promise} Success, */ public async transfer(to: string, amount: number, from: Account): Promise { - (await Keeper.getInstance()) + this.ocean.keeper .token .transfer(to, amount, from.getId()) return true diff --git a/src/ocean/ServiceAgreements/ServiceAgreement.ts b/src/ocean/ServiceAgreements/ServiceAgreement.ts index f12bcb3..0b301d3 100644 --- a/src/ocean/ServiceAgreements/ServiceAgreement.ts +++ b/src/ocean/ServiceAgreements/ServiceAgreement.ts @@ -1,9 +1,9 @@ +import * as Web3 from "web3" import { ServiceAgreementTemplateCondition } from "../../ddo/ServiceAgreementTemplate" import { DDO } from "../../ddo/DDO" import { ServiceAccess } from "../../ddo/Service" -import Web3Provider from "../../keeper/Web3Provider" -import ValuePair from "../../models/ValuePair" import LoggerInstance from "../../utils/Logger" +import Web3Provider from "../../keeper/Web3Provider" import Account from "../Account" import { signText, zeroX } from "../../utils" @@ -11,6 +11,7 @@ import { signText, zeroX } from "../../utils" export default class ServiceAgreement { public static async signServiceAgreement( + web3: Web3, ddo: DDO, serviceDefinitionId: string, serviceAgreementId: string, @@ -27,6 +28,7 @@ export default class ServiceAgreement { } const serviceAgreementHashSignature = await ServiceAgreement.createHashSignature( + web3, service.templateId, serviceAgreementId, agreementConditionsIds, @@ -41,6 +43,7 @@ export default class ServiceAgreement { } public static async createHashSignature( + web3: Web3, templateId: string, serviceAgreementId: string, valueHashes: string[], @@ -57,7 +60,7 @@ export default class ServiceAgreement { timeoutValues, ) - const serviceAgreementHashSignature = await signText(serviceAgreementHash, consumer.getId(), consumer.getPassword()) + const serviceAgreementHashSignature = await signText(web3, serviceAgreementHash, consumer.getId(), consumer.getPassword()) return serviceAgreementHashSignature } diff --git a/src/secretstore/SecretStoreProvider.ts b/src/secretstore/SecretStoreProvider.ts index d7ef684..656f442 100644 --- a/src/secretstore/SecretStoreProvider.ts +++ b/src/secretstore/SecretStoreProvider.ts @@ -1,42 +1,22 @@ import SecretStore from "@oceanprotocol/secret-store-client" import SecretStoreConfig from "@oceanprotocol/secret-store-client/dist/models/SecretStoreConfig" -import ConfigProvider from "../ConfigProvider" -import Config from "../models/Config" export default class SecretStoreProvider { - public static setSecretStore(secretStore: SecretStore) { - - SecretStoreProvider.secretStore = secretStore - } - - public static getSecretStore(config?: Partial): SecretStore { - config = {...config} + public static getSecretStore(config: SecretStoreConfig): SecretStore { + const {secretStoreUri, parityUri, password, address, threshold} = config + config = {secretStoreUri, parityUri, password, address, threshold} // Cleaning undefined parameters Object.keys(config) - .forEach((key) => config[key] || delete config[key]) + .forEach((key) => config[key] || config[key] === 0 || delete config[key]) - if (!Object.keys(config).length) { - if (!SecretStoreProvider.secretStore) { - SecretStoreProvider.secretStore = new SecretStore(ConfigProvider.getConfig()) - } - - return SecretStoreProvider.secretStore - } else { - const configRef = JSON.stringify(config) - if (!SecretStoreProvider.secretStoreWithConfig.get(configRef)) { - SecretStoreProvider.secretStoreWithConfig.set(configRef, - new SecretStore({ - ...ConfigProvider.getConfig(), - ...config, - }), - ) - } - - return SecretStoreProvider.secretStoreWithConfig.get(configRef) + const configRef = JSON.stringify(config) + if (!SecretStoreProvider.secretStoreWithConfig.get(configRef)) { + SecretStoreProvider.secretStoreWithConfig.set(configRef, new SecretStore({...config})) } + + return SecretStoreProvider.secretStoreWithConfig.get(configRef) } - private static secretStore: SecretStore private static secretStoreWithConfig = new Map() } diff --git a/src/squid.ts b/src/squid.ts index dbc49d5..77a7245 100644 --- a/src/squid.ts +++ b/src/squid.ts @@ -2,7 +2,7 @@ import Config from "./models/Config" import Account from "./ocean/Account" import DID from "./ocean/DID" import { Ocean } from "./ocean/Ocean" -import LoggerInstance from "./utils/Logger" +import { LoggerInstance as Logger} from "./utils/Logger" import WebServiceConnectorProvider from "./utils/WebServiceConnectorProvider" import Keeper from "./keeper/Keeper" import EventListener from "./keeper/EventListener" @@ -24,9 +24,8 @@ export { Account, Config, DID, - EventListener, + Logger, Keeper, - LoggerInstance, WebServiceConnectorProvider, conditions, diff --git a/src/utils/Logger.ts b/src/utils/Logger.ts index 8246ca1..bef1f12 100644 --- a/src/utils/Logger.ts +++ b/src/utils/Logger.ts @@ -11,7 +11,6 @@ export class Logger { constructor(private logLevel: LogLevel = LogLevel.Verbose) { } public setLevel(logLevel: LogLevel) { - this.warn("Logger.setLevel is deprecated") this.logLevel = logLevel } diff --git a/src/utils/SignatureHelpers.ts b/src/utils/SignatureHelpers.ts index 5c84f3b..ea2ff10 100644 --- a/src/utils/SignatureHelpers.ts +++ b/src/utils/SignatureHelpers.ts @@ -1,9 +1,8 @@ -import Web3Provider from "../keeper/Web3Provider" +import * as Web3 from "web3" import LoggerInstance from "./Logger" -export async function signText(text: string, publicKey: string, password?: string): Promise { - const web3 = Web3Provider.getWeb3() +export async function signText(web3: Web3, text: string, publicKey: string, password?: string): Promise { try { return await web3.eth.personal.sign(text, publicKey, password) } catch (e) { @@ -19,8 +18,6 @@ export async function signText(text: string, publicKey: string, password?: strin } } -export async function verifyText(text: string, signature: string): Promise { - const web3 = Web3Provider.getWeb3() - +export async function verifyText(web3: Web3, text: string, signature: string): Promise { return await web3.eth.personal.ecRecover(text, signature) } diff --git a/test/aquarius/Aquarius.test.ts b/test/aquarius/Aquarius.test.ts index 0506081..04f6c7c 100644 --- a/test/aquarius/Aquarius.test.ts +++ b/test/aquarius/Aquarius.test.ts @@ -1,5 +1,5 @@ import * as assert from "assert" -import Aquarius from "../../src/aquarius/Aquarius" +import { Aquarius } from "../../src/aquarius/Aquarius" import { SearchQuery } from "../../src/aquarius/query/SearchQuery" import { DDO } from "../../src/ddo/DDO" import DID from "../../src/ocean/DID" @@ -9,7 +9,7 @@ import WebServiceConnectorMock from "../mocks/WebServiceConnector.mock" describe("Aquarius", () => { - const aquarius: Aquarius = new Aquarius(config) + const aquarius: Aquarius = new Aquarius({config}) describe("#queryMetadata()", () => { diff --git a/test/config.ts b/test/config.ts index 392bcc2..f6d1cc3 100644 --- a/test/config.ts +++ b/test/config.ts @@ -1,4 +1,7 @@ -import { Config, LogLevel} from "../src/models/Config" +import { Config, LogLevel } from "../src/models/Config" +import { LoggerInstance } from "../src/utils" + +LoggerInstance.setLevel(LogLevel.Error) export default { aquariusUri: "http://localhost:5000", diff --git a/test/ddo/DDO.test.ts b/test/ddo/DDO.test.ts index bd1c8ec..a1bbeea 100644 --- a/test/ddo/DDO.test.ts +++ b/test/ddo/DDO.test.ts @@ -1,10 +1,11 @@ import { assert, expect, spy, use } from "chai" import * as spies from "chai-spies" +import * as Web3 from "web3" -import ConfigProvider from "../../src/ConfigProvider" import { DDO } from "../../src/ddo/DDO" import { Service } from "../../src/ddo/Service" import * as signatureHelpers from "../../src/utils/SignatureHelpers" +import { Ocean } from "../../src/ocean/Ocean" import config from "../config" import * as jsonDDO from "../testdata/ddo.json" @@ -162,8 +163,10 @@ describe("DDO", () => { ], }) - before(async () => { - ConfigProvider.setConfig(config) + let web3: Web3 + + beforeEach(async () => { + web3 = (await Ocean.getInstance(config) as any).web3 }) afterEach(() => { @@ -254,7 +257,7 @@ describe("DDO", () => { const signTextSpy = spy.on(signatureHelpers, "signText", () => signature) const ddo = new DDO(testDDO) const checksum = ddo.getChecksum() - const proof = await ddo.generateProof(publicKey) + const proof = await ddo.generateProof(web3, publicKey) assert.include(proof as any, { creator: publicKey, @@ -278,7 +281,7 @@ describe("DDO", () => { } as any const ddo = new DDO(testDDO) const generateProofSpy = spy.on(ddo, "generateProof", () => fakeProof) - await ddo.addProof(publicKey) + await ddo.addProof(web3, publicKey) assert.equal(ddo.proof, fakeProof) expect(generateProofSpy).to.have.been.called.with(publicKey) diff --git a/test/keeper/ContractBase.test.ts b/test/keeper/ContractBase.test.ts index bae3e1c..88d3907 100644 --- a/test/keeper/ContractBase.test.ts +++ b/test/keeper/ContractBase.test.ts @@ -1,5 +1,4 @@ import {assert} from "chai" -import ConfigProvider from "../../src/ConfigProvider" import Account from "../../src/ocean/Account" import { Ocean } from "../../src/ocean/Ocean" import config from "../config" @@ -12,11 +11,10 @@ let accounts: Account[] describe("ContractWrapperBase", () => { before(async () => { - ConfigProvider.setConfig(config) await TestContractHandler.prepareContracts() - await wrappedContract.initMock() const ocean: Ocean = await Ocean.getInstance(config) - accounts = await ocean.getAccounts() + accounts = await ocean.accounts.list() + await wrappedContract.initMock((ocean).instanceConfig) }) describe("#call()", () => { diff --git a/test/keeper/ContractEvent.test.ts b/test/keeper/ContractEvent.test.ts new file mode 100644 index 0000000..f4bdf60 --- /dev/null +++ b/test/keeper/ContractEvent.test.ts @@ -0,0 +1,97 @@ +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 + let executeTransaction: () => Promise + + beforeEach(async () => { + await TestContractHandler.prepareContracts() + ocean = await Ocean.getInstance(config) + eventHandler = new EventHandler((ocean).instanceConfig) + account = (await ocean.accounts.list())[0].getId() + + 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}) + let validResolve = false + let subscription: ContractEventSubscription + + const waitUntilEvent = new Promise(resolve => { + subscription = event.subscribe(events => { + assert.isDefined(events) + assert.lengthOf(events, 2) + if (validResolve) { + resolve() + } + }) + }) + + await Promise.all([ + executeTransaction(), + executeTransaction(), + ]) + + await new Promise(_ => setTimeout(_, 2000)) + validResolve = true + + await Promise.all([ + executeTransaction(), + executeTransaction(), + ]) + + await waitUntilEvent + + subscription.unsubscribe() + }) + }) + + describe("#once()", () => { + it("should listen only once", async () => { + const to = account + const event = eventHandler.getEvent(ocean.keeper.token, "Transfer", {to}) + let canBeRejected = false + + const waitUntilEvent = new Promise((resolve, reject) => { + event.once(events => { + if (canBeRejected) { + reject() + } + setTimeout(resolve, 600) + }) + }) + + await executeTransaction() + + await new Promise(_ => setTimeout(_, 2000)) + canBeRejected = true + + await executeTransaction() + + await waitUntilEvent + }) + + it("should get the event like a promise", async () => { + const to = account + const event = eventHandler.getEvent(ocean.keeper.token, "Transfer", {to}) + + const waitUntilEvent = event.once() + + await new Promise(_ => setTimeout(_, 400)) + + await executeTransaction() + + await waitUntilEvent + }) + }) +}) diff --git a/test/keeper/ContractHandler.test.ts b/test/keeper/ContractHandler.test.ts index 68d81d2..391efeb 100644 --- a/test/keeper/ContractHandler.test.ts +++ b/test/keeper/ContractHandler.test.ts @@ -1,25 +1,28 @@ import {assert} from "chai" -import ConfigProvider from "../../src/ConfigProvider" import ContractHandler from "../../src/keeper/ContractHandler" +import { Ocean } from "../../src/ocean/Ocean" import config from "../config" + describe("ContractHandler", () => { + let contractHandler: ContractHandler before(async () => { - ConfigProvider.setConfig(config) + const instanceConfig = (await Ocean.getInstance(config)).instanceConfig + + contractHandler = new ContractHandler(instanceConfig) }) describe("#get()", () => { it("should load and get OceanToken correctly", async () => { - assert(await ContractHandler.get("OceanToken")) + assert(await contractHandler.get("OceanToken")) }) it("should fail to load an unknown contract", (done) => { - ContractHandler.get("OceanXXX") + contractHandler.get("OceanXXX") .catch(() => { - done() }) }) diff --git a/test/keeper/DIDRegistry.test.ts b/test/keeper/DIDRegistry.test.ts index c157499..112c9ec 100644 --- a/test/keeper/DIDRegistry.test.ts +++ b/test/keeper/DIDRegistry.test.ts @@ -1,10 +1,8 @@ import {assert} from "chai" -import ConfigProvider from "../../src/ConfigProvider" 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 Logger from "../../src/utils/Logger" import config from "../config" import TestContractHandler from "./TestContractHandler" @@ -14,16 +12,15 @@ let didRegistry: DIDRegistry describe("DIDRegistry", () => { before(async () => { - ConfigProvider.setConfig(config) await TestContractHandler.prepareContracts() ocean = await Ocean.getInstance(config) - didRegistry = await DIDRegistry.getInstance() + didRegistry = ocean.keeper.didRegistry }) describe("#registerAttribute()", () => { it("should register an attribute in a new did", async () => { - const ownerAccount: Account = (await ocean.getAccounts())[0] + 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()) @@ -32,7 +29,7 @@ describe("DIDRegistry", () => { }) it("should register another attribute in the same did", async () => { - const ownerAccount: Account = (await ocean.getAccounts())[0] + const ownerAccount: Account = (await ocean.accounts.list())[0] const did = generateId() { // register the first attribute @@ -53,7 +50,7 @@ describe("DIDRegistry", () => { // describe("#getOwner()", () => { // it("should get the owner of a did properly", async () => { - // const ownerAccount: Account = (await ocean.getAccounts())[0] + // 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()) @@ -73,7 +70,7 @@ describe("DIDRegistry", () => { // describe("#getUpdateAt()", () => { // it("should the block number of the last update of the did attribute", async () => { - // const ownerAccount: Account = (await ocean.getAccounts())[0] + // 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()) diff --git a/test/keeper/Event.test.ts b/test/keeper/Event.test.ts deleted file mode 100644 index 9d2c6c3..0000000 --- a/test/keeper/Event.test.ts +++ /dev/null @@ -1,85 +0,0 @@ -import {assert} from "chai" -import ConfigProvider from "../../src/ConfigProvider" -import EventListener from "../../src/keeper/EventListener" -import Keeper from "../../src/keeper/Keeper" -import Account from "../../src/ocean/Account" -import { Ocean } from "../../src/ocean/Ocean" -import config from "../config" -import TestContractHandler from "./TestContractHandler" - -let keeper: Keeper -let ocean: Ocean -let accounts: Account[] - -describe("EventListener", () => { - - before(async () => { - ConfigProvider.setConfig(config) - await TestContractHandler.prepareContracts() - keeper = await Keeper.getInstance() - assert(keeper) - ocean = await Ocean.getInstance(config) - assert(ocean) - accounts = await ocean.getAccounts() - assert(accounts) - }) - - describe("#listen()", () => { - - it("should listen to an event", (done) => { - - const acc = accounts[1] - - const event = EventListener.subscribe("OceanToken", - "Transfer", - { - to: acc.getId(), - }) - - let doneCalled: boolean - event.listen((events) => { - assert(events) - assert(events.length === 2) - EventListener.unsubscribe(event) - if (!doneCalled) { - doneCalled = true - done() - } - }) - - const {dispenser} = keeper - - dispenser.requestTokens(10, acc.getId()) - dispenser.requestTokens(10, acc.getId()) - }) - }) - - describe("#listenOnce()", () => { - - it("should listen once", (done) => { - - const acc = accounts[1] - - const countBefore = EventListener.count() - const event = EventListener.subscribe("OceanToken", - "Transfer", - { - to: acc.getId(), - }) - - event.listenOnce( - (data: any) => { - - assert(data) - assert(data.blockNumber) - assert(EventListener.count() === countBefore) - done() - }) - - const {dispenser} = keeper - - dispenser.requestTokens(10, acc.getId()) - }) - }) - -}) diff --git a/test/keeper/EventHandler.test.ts b/test/keeper/EventHandler.test.ts new file mode 100644 index 0000000..ec3e7c0 --- /dev/null +++ b/test/keeper/EventHandler.test.ts @@ -0,0 +1,89 @@ +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", () => { + + let ocean: Ocean + let eventHandler: EventHandler + + before(async () => { + ocean = await Ocean.getInstance(config) + eventHandler = new EventHandler((ocean).instanceConfig) + }) + + afterEach(() => { + spy.restore() + }) + + describe("#subscribe()", () => { + it("should subscribe to an event", async () => { + const countBefore = eventHandler.count + + const subscription = eventHandler.subscribe(() => {}) + assert.isDefined(subscription) + + const countAfter = eventHandler.count + assert.equal(countBefore + 1, countAfter, "The event seems not added.") + + try { + // Not important in this test + subscription.unsubscribe() + } catch(e) { } + }) + + it("should unsubscribe using the subscription", async () => { + const countBefore = eventHandler.count + + const subscription = eventHandler.subscribe(() => {}) + assert.isDefined(subscription) + + subscription.unsubscribe() + + const countAfter = eventHandler.count + assert.equal(countBefore, countAfter, "The event seems not added.") + }) + }) + + describe("#unsubscribe()", () => { + it("should unsubscribe from an event", async () => { + const countBefore = eventHandler.count + const callback = () => {} + + eventHandler.subscribe(callback) + eventHandler.unsubscribe(callback) + + const countAfter = eventHandler.count + assert.equal(countBefore, countAfter, "The event seems not removed.") + }) + }) + + 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) + + const subscription = eventHandler.subscribe(callbackSpy) + + await new Promise(_ => setTimeout(_, 300)) + + expect(callbackSpy).not.to.has.been.called() + blockNumber++ + + await new Promise(_ => setTimeout(_, 300)) + + expect(callbackSpy).to.has.been.called.with(blockNumber) + + try { + // Not important in this test + subscription.unsubscribe() + } catch(e) { } + }) + }) +}) diff --git a/test/keeper/EventListener.test.ts b/test/keeper/EventListener.test.ts deleted file mode 100644 index 01c0ed0..0000000 --- a/test/keeper/EventListener.test.ts +++ /dev/null @@ -1,69 +0,0 @@ -import {assert} from "chai" -import ConfigProvider from "../../src/ConfigProvider" -import EventListener from "../../src/keeper/EventListener" -import Keeper from "../../src/keeper/Keeper" -import Account from "../../src/ocean/Account" -import { Ocean } from "../../src/ocean/Ocean" -import config from "../config" -import TestContractHandler from "./TestContractHandler" - -let keeper: Keeper -let ocean: Ocean -let accounts: Account[] - -describe("EventListener", () => { - - before(async () => { - ConfigProvider.setConfig(config) - await TestContractHandler.prepareContracts() - keeper = await Keeper.getInstance() - assert(keeper) - ocean = await Ocean.getInstance(config) - assert(ocean) - accounts = await ocean.getAccounts() - assert(accounts) - }) - - describe("#subscribe()", () => { - - it("should subscribe to an event", (done) => { - - const acc = accounts[1] - const countBefore = EventListener.count() - - const event = EventListener.subscribe("OceanToken", - "Transfer", - { - to: acc.getId(), - }) - assert(event) - - const countAfter = EventListener.count() - assert(countBefore + 1 === countAfter, `${countBefore}${countAfter}`) - - EventListener.unsubscribe(event) - done() - }) - }) - - describe("#unsubscribe()", () => { - - it("should unsubscribe from an event", (done) => { - - const countBefore = EventListener.count() - const event = EventListener.subscribe("OceanToken", - "Transfer", - {}) - const count = EventListener.count() - - const unsubscribed = EventListener.unsubscribe(event) - assert(unsubscribed) - - const countAfter = EventListener.count() - assert(count > countBefore, `${count}${countAfter}`) - assert(countBefore === countAfter, `${countBefore}${countAfter}`) - done() - }) - }) - -}) diff --git a/test/keeper/Keeper.test.ts b/test/keeper/Keeper.test.ts index bfd7011..af16b39 100644 --- a/test/keeper/Keeper.test.ts +++ b/test/keeper/Keeper.test.ts @@ -1,17 +1,17 @@ import {assert} from "chai" -import ConfigProvider from "../../src/ConfigProvider" -import Keeper from "../../src/keeper/Keeper" 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", () => { before(async () => { - ConfigProvider.setConfig(config) await TestContractHandler.prepareContracts() - keeper = await Keeper.getInstance() + const ocean = await Ocean.getInstance(config) + keeper = ocean.keeper }) describe("public interface", () => { diff --git a/test/keeper/TestContractHandler.ts b/test/keeper/TestContractHandler.ts index 939f45d..aa6750f 100644 --- a/test/keeper/TestContractHandler.ts +++ b/test/keeper/TestContractHandler.ts @@ -2,13 +2,16 @@ 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() { + private static networkId: number - const web3 = Web3Provider.getWeb3() + public static async prepareContracts() { + const web3 = Web3Provider.getWeb3(config) const deployerAddress = (await web3.eth.getAccounts())[0] + this.networkId = await web3.eth.net.getId() // deploy contracts await TestContractHandler.deployContracts(deployerAddress) @@ -79,13 +82,17 @@ export default class TestContractHandler extends ContractHandler { args: any[] = [], tokens: {[name: string]: string} = {}, ): Promise { + const where = this.networkId // dont redeploy if there is already something loaded - if (ContractHandler.has(name)) { - return {...await ContractHandler.get(name), $initialized: true} + if (TestContractHandler.hasContract(name, where)) { + const contract = await ContractHandler.getContract(name, where) + if (contract.testContract) { + return {...contract, $initialized: true} + } } - const web3 = Web3Provider.getWeb3() + const web3 = Web3Provider.getWeb3(config) let contractInstance: Contract try { @@ -117,7 +124,8 @@ export default class TestContractHandler extends ContractHandler { if (isZos) { await contractInstance.methods.initialize(...args).send(sendConfig) } - TestContractHandler.set(name, contractInstance) + 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) diff --git a/test/keeper/conditions/AccessSecretStoreCondition.test.ts b/test/keeper/conditions/AccessSecretStoreCondition.test.ts index 6e4ce7a..2af214c 100644 --- a/test/keeper/conditions/AccessSecretStoreCondition.test.ts +++ b/test/keeper/conditions/AccessSecretStoreCondition.test.ts @@ -1,7 +1,6 @@ import {assert} from "chai" -import ConfigProvider from "../../../src/ConfigProvider" import { AccessSecretStoreCondition } from "../../../src/keeper/contracts/conditions" -import Keeper from "../../../src/keeper/Keeper" +import { Ocean } from "../../../src/ocean/Ocean" import config from "../../config" import TestContractHandler from "../TestContractHandler" @@ -10,14 +9,12 @@ let condition: AccessSecretStoreCondition describe("AccessSecretStoreCondition", () => { const agreementId = `0x${"a".repeat(64)}` - const did = `0x${"a".repeat(64)}` + const did = `did:op:${"a".repeat(64)}` const address = `0x${"a".repeat(40)}` before(async () => { - ConfigProvider.setConfig(config) await TestContractHandler.prepareContracts() - condition = (await Keeper.getInstance()).conditions.accessSecretStoreCondition - + condition = (await Ocean.getInstance(config)).keeper.conditions.accessSecretStoreCondition }) describe("#hashValues()", () => { diff --git a/test/keeper/conditions/EscrowReward.test.ts b/test/keeper/conditions/EscrowReward.test.ts index 6959dd3..e883131 100644 --- a/test/keeper/conditions/EscrowReward.test.ts +++ b/test/keeper/conditions/EscrowReward.test.ts @@ -1,7 +1,6 @@ import {assert} from "chai" -import ConfigProvider from "../../../src/ConfigProvider" import { EscrowReward } from "../../../src/keeper/contracts/conditions" -import Keeper from "../../../src/keeper/Keeper" +import { Ocean } from "../../../src/ocean/Ocean" import config from "../../config" import TestContractHandler from "../TestContractHandler" @@ -18,9 +17,9 @@ describe("EscrowReward", () => { let releaseCondition before(async () => { - ConfigProvider.setConfig(config) + const keeper = (await Ocean.getInstance(config)).keeper + await TestContractHandler.prepareContracts() - const keeper = await Keeper.getInstance() condition = keeper.conditions.escrowReward lockCondition = await keeper.conditions.lockRewardCondition.generateIdHash(agreementId, publisher, amount) diff --git a/test/keeper/conditions/LockRewardCondition.test.ts b/test/keeper/conditions/LockRewardCondition.test.ts index 1b273d1..32b7639 100644 --- a/test/keeper/conditions/LockRewardCondition.test.ts +++ b/test/keeper/conditions/LockRewardCondition.test.ts @@ -1,7 +1,6 @@ import {assert} from "chai" -import ConfigProvider from "../../../src/ConfigProvider" import { LockRewardCondition } from "../../../src/keeper/contracts/conditions" -import Keeper from "../../../src/keeper/Keeper" +import { Ocean } from "../../../src/ocean/Ocean" import config from "../../config" import TestContractHandler from "../TestContractHandler" @@ -14,10 +13,8 @@ describe("LockRewardCondition", () => { const amount = 15 before(async () => { - ConfigProvider.setConfig(config) await TestContractHandler.prepareContracts() - condition = (await Keeper.getInstance()).conditions.lockRewardCondition - + condition = (await Ocean.getInstance(config)).keeper.conditions.lockRewardCondition }) describe("#hashValues()", () => { diff --git a/test/keeper/templates/EscrowAccessSecretStoreTemplate.test.ts b/test/keeper/templates/EscrowAccessSecretStoreTemplate.test.ts index 9bdac0b..7349a29 100644 --- a/test/keeper/templates/EscrowAccessSecretStoreTemplate.test.ts +++ b/test/keeper/templates/EscrowAccessSecretStoreTemplate.test.ts @@ -1,18 +1,18 @@ import {assert} from "chai" -import ConfigProvider from "../../../src/ConfigProvider" import { EscrowAccessSecretStoreTemplate } from "../../../src/keeper/contracts/templates" -import Keeper from "../../../src/keeper/Keeper" import config from "../../config" import TestContractHandler from "../TestContractHandler" +import { Ocean } from "../../../src/ocean/Ocean" + let condition: EscrowAccessSecretStoreTemplate describe("EscrowAccessSecretStoreTemplate", () => { before(async () => { - ConfigProvider.setConfig(config) + const ocean: Ocean = await Ocean.getInstance(config) await TestContractHandler.prepareContracts() - condition = (await Keeper.getInstance()).templates.escrowAccessSecretStoreTemplate + condition = ocean.keeper.templates.escrowAccessSecretStoreTemplate }) diff --git a/test/mocha.opts b/test/mocha.opts index 2500e57..2e94ff1 100644 --- a/test/mocha.opts +++ b/test/mocha.opts @@ -4,4 +4,4 @@ --bail --exit --timeout 20000 -test/**/*.test.ts +test/config.ts test/**/*.test.ts diff --git a/test/mocks/Aquarius.mock.ts b/test/mocks/Aquarius.mock.ts index 23e9e09..0dc9e2d 100644 --- a/test/mocks/Aquarius.mock.ts +++ b/test/mocks/Aquarius.mock.ts @@ -1,4 +1,4 @@ -import Aquarius from "../../src/aquarius/Aquarius" +import { Aquarius } from "../../src/aquarius/Aquarius" import { DDO } from "../../src/ddo/DDO" import DID from "../../src/ocean/DID" diff --git a/test/mocks/Brizo.mock.ts b/test/mocks/Brizo.mock.ts index 3c2ca97..fd58dbd 100644 --- a/test/mocks/Brizo.mock.ts +++ b/test/mocks/Brizo.mock.ts @@ -1,4 +1,4 @@ -import Brizo from "../../src/brizo/Brizo" +import { Brizo } from "../../src/brizo/Brizo" export default class BrizoMock extends Brizo { diff --git a/test/mocks/ContractBase.Mock.ts b/test/mocks/ContractBase.Mock.ts index 7d756f8..00a7b65 100644 --- a/test/mocks/ContractBase.Mock.ts +++ b/test/mocks/ContractBase.Mock.ts @@ -1,8 +1,8 @@ import ContractBase from "../../src/keeper/contracts/ContractBase" export default class ContractBaseMock extends ContractBase { - public async initMock() { - await this.init() + public async initMock(config: any) { + await this.init(config) } public async callMock(name: string, args: any[], from?: string) { diff --git a/test/ocean/Account.test.ts b/test/ocean/Account.test.ts index ae3d2b9..188699a 100644 --- a/test/ocean/Account.test.ts +++ b/test/ocean/Account.test.ts @@ -1,5 +1,4 @@ import {assert} from "chai" -import ConfigProvider from "../../src/ConfigProvider" import Web3Provider from "../../src/keeper/Web3Provider" import Account from "../../src/ocean/Account" import { Ocean } from "../../src/ocean/Ocean" @@ -12,11 +11,9 @@ let accounts: Account[] describe("Account", () => { before(async () => { - ConfigProvider.setConfig(config) await TestContractHandler.prepareContracts() ocean = await Ocean.getInstance(config) - - accounts = await ocean.getAccounts() + accounts = await ocean.accounts.list() }) describe("#getOceanBalance()", () => { @@ -25,17 +22,17 @@ describe("Account", () => { const balance = await accounts[8].getOceanBalance() - assert(0 === balance, `Expected 0 got ${balance}`) + assert.equal(0, balance, `Expected 0 got ${balance}`) }) it("should get the correct balance", async () => { - const amount: number = 100 const account: Account = accounts[0] + const initialBalance = await account.getOceanBalance() await account.requestTokens(amount) const balance = await account.getOceanBalance() - assert(amount === balance) + assert.equal(balance, initialBalance + amount) }) }) diff --git a/test/ocean/Ocean.test.ts b/test/ocean/Ocean.test.ts index 3040d96..87d13e6 100644 --- a/test/ocean/Ocean.test.ts +++ b/test/ocean/Ocean.test.ts @@ -1,23 +1,13 @@ import { assert, spy, use } from "chai" import * as spies from "chai-spies" -import AquariusProvider from "../../src/aquarius/AquariusProvider" import { SearchQuery } from "../../src/aquarius/query/SearchQuery" -import BrizoProvider from "../../src/brizo/BrizoProvider" -import ConfigProvider from "../../src/ConfigProvider" import { DDO } from "../../src/ddo/DDO" -import { Service } from "../../src/ddo/Service" import Account from "../../src/ocean/Account" import { Ocean } from "../../src/ocean/Ocean" -import SecretStoreProvider from "../../src/secretstore/SecretStoreProvider" import * as signatureHelpers from "../../src/utils/SignatureHelpers" -import WebServiceConnectorProvider from "../../src/utils/WebServiceConnectorProvider" import config from "../config" import TestContractHandler from "../keeper/TestContractHandler" -import AquariusMock from "../mocks/Aquarius.mock" -import BrizoMock from "../mocks/Brizo.mock" -import SecretStoreMock from "../mocks/SecretStore.mock" -import WebServiceConnectorMock from "../mocks/WebServiceConnector.mock" import { metadataMock } from "../testdata/MetaData" use(spies) @@ -30,10 +20,6 @@ describe("Ocean", () => { const metadata = metadataMock - before(async () => { - ConfigProvider.setConfig(config) - }) - beforeEach(async () => { spy.on(signatureHelpers, "signText", () => `0x${"a".repeat(130)}`) }) @@ -42,13 +28,9 @@ describe("Ocean", () => { }) before(async () => { - ConfigProvider.setConfig(config) - AquariusProvider.setAquarius(new AquariusMock(config)) - BrizoProvider.setBrizo(new BrizoMock(config)) - SecretStoreProvider.setSecretStore(new SecretStoreMock(config)) await TestContractHandler.prepareContracts() ocean = await Ocean.getInstance(config) - accounts = await ocean.getAccounts() + accounts = await ocean.accounts.list() testPublisher = accounts[0] }) @@ -65,7 +47,7 @@ describe("Ocean", () => { describe("#getAccounts()", () => { it("should list accounts", async () => { - const accs: Account[] = await ocean.getAccounts() + const accs: Account[] = await ocean.accounts.list() assert(10 === accs.length) assert(0 === (await accs[5].getBalance()).ocn) @@ -73,28 +55,6 @@ describe("Ocean", () => { }) }) - // TODO: ensure if it should fail or not - describe("#resolveDID()", () => { - it("should resolve a did to a ddo", async () => { - const ddo: DDO = await ocean.registerAsset(metadata, testPublisher) - - const resolvedDDO: DDO = await ocean.resolveDID(ddo.id) - - assert(resolvedDDO) - assert(resolvedDDO.id === ddo.id) - }) - }) - - // TODO: ensure if it should fail or not - describe("#registerAsset()", () => { - it("should register an asset", async () => { - const ddo: DDO = await ocean.registerAsset(metadata, testPublisher) - - assert(ddo) - assert(ddo.id.startsWith("did:op:")) - }) - }) - describe("#searchAssets()", () => { it("should search for assets", async () => { const query = { @@ -109,7 +69,7 @@ describe("Ocean", () => { text: "Office", } as SearchQuery - const assets: any[] = await ocean.searchAssets(query) + const assets: any[] = await ocean.assets.query(query) assert(assets) }) @@ -118,33 +78,9 @@ describe("Ocean", () => { describe("#searchAssetsByText()", () => { it("should search for assets", async () => { const text = "office" - const assets: any[] = await ocean.searchAssetsByText(text) + const assets: any[] = await ocean.assets.search(text) assert(assets) }) }) - - describe("#signServiceAgreement()", () => { - it("should sign an service agreement", async () => { - const publisher = accounts[0] - const consumer = accounts[1] - - const ddo: DDO = await ocean.registerAsset(metadata, publisher) - - const service: Service = ddo.findServiceByType("Access") - - // @ts-ignore - WebServiceConnectorProvider.setConnector(new WebServiceConnectorMock(ddo)) - - await consumer.requestTokens(metadata.base.price) - - const signServiceAgreementResult: any = await ocean.signServiceAgreement(ddo.id, service.serviceDefinitionId, consumer) - - assert(signServiceAgreementResult) - assert(signServiceAgreementResult.agreementId, "no agreementId") - assert(signServiceAgreementResult.signature, "no signature") - assert(signServiceAgreementResult.signature.startsWith("0x")) - assert(signServiceAgreementResult.signature.length === 132) - }) - }) }) diff --git a/test/ocean/OceanAccounts.test.ts b/test/ocean/OceanAccounts.test.ts index b3a2c4e..7cad14b 100644 --- a/test/ocean/OceanAccounts.test.ts +++ b/test/ocean/OceanAccounts.test.ts @@ -1,7 +1,9 @@ import { assert, /*expect,*/ spy, use } from "chai" import * as spies from "chai-spies" +import config from "../config" import Account from "../../src/ocean/Account" +import { Ocean } from "../../src/ocean/Ocean" import { OceanAccounts } from "../../src/ocean/OceanAccounts" use(spies) @@ -11,21 +13,13 @@ describe("OceanAccounts", () => { let oceanAccounts: OceanAccounts before(async () => { - oceanAccounts = await OceanAccounts.getInstance() + oceanAccounts = (await Ocean.getInstance(config)).accounts }) afterEach(() => { spy.restore() }) - describe("#getInstance()", () => { - it("should get an instance of OceanAccounts", async () => { - const oceanAccountsInstance: OceanAccounts = await OceanAccounts.getInstance() - - assert.instanceOf(oceanAccountsInstance, OceanAccounts, "No returned OceanAccounts instance") - }) - }) - describe("#list()", () => { it("should return the list of accounts", async () => { const accounts = await oceanAccounts.list() diff --git a/test/ocean/OceanSecretStore.test.ts b/test/ocean/OceanSecretStore.test.ts index c698181..6bcd42a 100644 --- a/test/ocean/OceanSecretStore.test.ts +++ b/test/ocean/OceanSecretStore.test.ts @@ -1,7 +1,6 @@ import { assert, expect, spy, use } from "chai" import * as spies from "chai-spies" -import ConfigProvider from "../../src/ConfigProvider" import Account from "../../src/ocean/Account" import { Ocean } from "../../src/ocean/Ocean" import { OceanSecretStore } from "../../src/ocean/OceanSecretStore" @@ -15,37 +14,27 @@ describe("OceanSecretStore", () => { let oceanSecretStore: OceanSecretStore let accounts: Account[] - const did = `did:op:${"a".repeat(64)}` + const did = "a".repeat(64) before(async () => { - oceanSecretStore = await OceanSecretStore.getInstance() - ConfigProvider.setConfig(config) - const ocean = await Ocean.getInstance(config) - accounts = await ocean.getAccounts() + oceanSecretStore = ocean.secretStore + accounts = await ocean.accounts.list() }) afterEach(() => { spy.restore() }) - describe("#getInstance()", () => { - it("should get an instance of OceanSecretStore", async () => { - const oceanSecretStoreInstance: OceanSecretStore = await OceanSecretStore.getInstance() - - assert.instanceOf(oceanSecretStoreInstance, OceanSecretStore, "No returned OceanSecretStore instance") - }) - }) - describe("#encrypt()", () => { it("should encrypt a content", async () => { - const secretStoreToSpy = SecretStoreProvider.getSecretStore() + const secretStoreToSpy = SecretStoreProvider.getSecretStore({...config, address: accounts[0].getId()}) const secretStoreEncryptSpy = spy.on(secretStoreToSpy, "encryptDocument", () => "encryptedResult") const secretStoreProviderGetInstanceSpy = spy.on(SecretStoreProvider, "getSecretStore", () => secretStoreToSpy) const result = await oceanSecretStore.encrypt(did, "test", accounts[0]) - expect(secretStoreProviderGetInstanceSpy).to.have.been.called.with({address: accounts[0].getId()}) + expect(secretStoreProviderGetInstanceSpy).to.have.been.called.with({...config, address: accounts[0].getId()}) expect(secretStoreEncryptSpy).to.have.been.called.with(did, "test") assert.equal(result, "encryptedResult", "Result doesn't match") @@ -54,13 +43,13 @@ describe("OceanSecretStore", () => { describe("#decrypt()", () => { it("should decrypt a content", async () => { - const secretStoreToSpy = SecretStoreProvider.getSecretStore() + const secretStoreToSpy = SecretStoreProvider.getSecretStore({...config, address: accounts[0].getId()}) const secretStoreEncryptSpy = spy.on(secretStoreToSpy, "decryptDocument", () => "decryptedResult") const secretStoreProviderGetInstanceSpy = spy.on(SecretStoreProvider, "getSecretStore", () => secretStoreToSpy) const result = await oceanSecretStore.decrypt(did, "encryptedContent", accounts[0]) - expect(secretStoreProviderGetInstanceSpy).to.have.been.called.with({address: accounts[0].getId()}) + expect(secretStoreProviderGetInstanceSpy).to.have.been.called.with({...config, address: accounts[0].getId()}) expect(secretStoreEncryptSpy).to.have.been.called.with(did, "encryptedContent") assert.equal(result, "decryptedResult", "Result doesn't match") diff --git a/test/ocean/ServiceAgreement.test.ts b/test/ocean/ServiceAgreement.test.ts index 7306c29..1d06704 100644 --- a/test/ocean/ServiceAgreement.test.ts +++ b/test/ocean/ServiceAgreement.test.ts @@ -1,5 +1,4 @@ import {assert} from "chai" -import ConfigProvider from "../../src/ConfigProvider" import { DDO } from "../../src/ddo/DDO" import Account from "../../src/ocean/Account" import DID from "../../src/ocean/DID" @@ -18,10 +17,9 @@ describe("ServiceAgreement", () => { let consumerAccount: Account before(async () => { - ConfigProvider.setConfig(config) await TestContractHandler.prepareContracts() ocean = await Ocean.getInstance(config) - const accounts = await ocean.getAccounts() + const accounts = await ocean.accounts.list() publisherAccount = accounts[1] consumerAccount = accounts[2] diff --git a/test/utils/SignatureHelpers.test.ts b/test/utils/SignatureHelpers.test.ts index bf865d9..76fc9ed 100644 --- a/test/utils/SignatureHelpers.test.ts +++ b/test/utils/SignatureHelpers.test.ts @@ -1,10 +1,8 @@ import { assert, expect, spy, use } from "chai" import * as spies from "chai-spies" -import ConfigProvider from "../../src/ConfigProvider" import Web3Provider from "../../src/keeper/Web3Provider" import { signText, verifyText } from "../../src/utils/SignatureHelpers" -import config from "../config" use(spies) @@ -13,10 +11,8 @@ describe("SignatureHelpers", () => { const publicKey = `0x${"a".repeat(40)}` const text = "0123456789abcde" const signature = `0x${"a".repeat(130)}` + let web3 - before(async () => { - ConfigProvider.setConfig(config) - }) afterEach(() => { spy.restore() }) @@ -25,19 +21,19 @@ describe("SignatureHelpers", () => { let personalSignSpy beforeEach(() => { - const web3 = Web3Provider.getWeb3() + web3 = Web3Provider.getWeb3() personalSignSpy = spy.on(web3.eth.personal, "sign", () => signature) }) it("should sign a text as expected", async () => { - const signed = await signText(text, publicKey) + const signed = await signText(web3, text, publicKey) assert.equal(signed, signature) expect(personalSignSpy).to.have.been.called.with(text, publicKey) }) it("should sign a text as expected using password", async () => { - const signed = await signText(text, publicKey, "test") + const signed = await signText(web3, text, publicKey, "test") assert.equal(signed, signature) expect(personalSignSpy).to.have.been.called.with(text, publicKey, "test") @@ -49,7 +45,7 @@ describe("SignatureHelpers", () => { const web3 = Web3Provider.getWeb3() const personalRecoverSpy = spy.on(web3.eth.personal, "ecRecover", () => publicKey) - const verifiedPublicKey = await verifyText(text, signature) + const verifiedPublicKey = await verifyText(web3, text, signature) assert.equal(publicKey, verifiedPublicKey) expect(personalRecoverSpy).to.have.been.called.with(text, signature)