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

Merge pull request #20 from oceanprotocol/feature/new-ocean-interface

Squid v0.1.0
This commit is contained in:
Sebastian Gerske 2018-10-18 16:04:41 +02:00 committed by GitHub
commit 56e4a74483
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
52 changed files with 7394 additions and 2948 deletions

7
.gitignore vendored
View File

@ -1,2 +1,7 @@
node_modules/
dist/
dist/
.nyc_output/
coverage/
doc/
test/**/*.js
src/**/*.js

View File

@ -1 +1,10 @@
node_modules/
node_modules/
coverage/
.github
.nyc_output
.travis.yml
test/
src/
tsconfig.json
tslint.json
oceanprotocol-squid-*.tgz

View File

@ -1,6 +1,6 @@
language: node_js
node_js:
- "8"
- "10"
services:
- docker
@ -13,18 +13,21 @@ matrix:
fast_finish: true
before_install:
- npm install -g npm
- npm install -g release-it greenkeeper-lockfile
- npm install -g npm
- npm install -g release-it greenkeeper-lockfile ganache-cli
before_script:
- greenkeeper-lockfile-update
- greenkeeper-lockfile-update
- ganache-cli > ganache-cli.log &
- sleep 2
script:
- npm test
- npm run build
- npm run test:cover
- npm run build
- npm run doc
after_script:
- greenkeeper-lockfile-upload
- greenkeeper-lockfile-upload
notifications:
email: false

1
SQUID_INTERFACE.md Normal file
View File

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

8452
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,17 +1,39 @@
{
"name": "@oceanprotocol/squid",
"version": "0.0.12",
"version": "0.1.0-beta.16",
"description": "JavaScript client library for Ocean Protocol",
"main": "dist/squid.js",
"scripts": {
"test": "tslint -c tslint.json 'src/**/*.ts'",
"start": "tsc -w",
"build": "tsc",
"test": "mocha",
"test:watch": "mocha -w --watch-extensions js,ts",
"test:cover": "nyc mocha",
"lint": "tslint -c tslint.json 'src/**/*.ts'",
"start": "npm link @oceanprotocol/keeper-contracts && npm run build:watch",
"build": "npm run lint && tsc && npm run doc",
"build:watch": "tsc -w",
"doc": "typedoc --mode modules --out ./doc/ src/",
"release": "./node_modules/release-it/bin/release-it.js --src.tagName='v%s' --github.release --npm.publish --non-interactive",
"release-minor": "./node_modules/release-it/bin/release-it.js minor --src.tagName='v%s' --github.release --npm.publish --non-interactive",
"release-major": "./node_modules/release-it/bin/release-it.js major --src.tagName='v%s' --github.release --npm.publish --non-interactive",
"prepublishOnly": "npm run build"
},
"nyc": {
"include": [
"src/**/*.ts"
],
"extension": [
".ts"
],
"require": [
"ts-node/register"
],
"reporter": [
"text-summary",
"html"
],
"sourceMap": true,
"instrument": true
},
"repository": {
"type": "git",
"url": "git+https://github.com/oceanprotocol/squid-js.git"
@ -23,18 +45,31 @@
"url": "https://github.com/oceanprotocol/squid-js/issues"
},
"homepage": "https://github.com/oceanprotocol/squid-js#readme",
"dependencies": {
"@oceanprotocol/keeper-contracts": "^0.2.0",
"bignumber.js": "^7.2.1",
"truffle-contract": "^3.0.6",
"web3": "0.20.6"
},
"engines": {
"node": ">=8 <10"
},
"dependencies": {
"@oceanprotocol/keeper-contracts": "^0.3.3",
"bignumber.js": "^7.2.1",
"eth-crypto": "^1.2.4",
"eth-ecies": "^1.0.3",
"ethereumjs-util": "^6.0.0",
"jsonwebtoken": "^8.3.0",
"node-fetch": "^2.2.0",
"web3": "1.0.0-beta.36",
"web3-utils": "1.0.0-beta.36"
},
"devDependencies": {
"@types/web3": "^1.0.6",
"@types/chai": "^4.1.6",
"@types/mocha": "^5.2.5",
"@types/node": "^8.10.36",
"chai": "^4.2.0",
"mocha": "^5.2.0",
"nyc": "^13.1.0",
"source-map-support": "^0.5.9",
"ts-node": "^7.0.1",
"tslint": "^5.11.0",
"typescript": "^3.0.3"
"typedoc": "^0.13.0",
"typescript": "^3.1.3"
}
}

15
src/ConfigProvider.ts Normal file
View File

@ -0,0 +1,15 @@
import Config from "./models/Config"
export default class ConfigProvider {
public static getConfig() {
return ConfigProvider.config
}
public static configure(config: Config) {
ConfigProvider.config = config
}
private static config: Config
}

47
src/keeper/Auth.ts Normal file
View File

@ -0,0 +1,47 @@
import {Receipt} from "web3-utils"
import AccessStatus from "../models/AccessStatus"
import Asset from "../ocean/Asset"
import Order from "../ocean/Order"
import ContractBase from "./ContractBase"
export default class OceanAuth extends ContractBase {
public static async getInstance(): Promise<OceanAuth> {
const auth: OceanAuth = new OceanAuth("OceanAuth")
await auth.init()
return auth
}
public async getOrderStatus(orderId: string): Promise<AccessStatus> {
return this.call("statusOfAccessRequest", [orderId])
.then((status: string) => {
const statusInt = parseInt(status, 10)
const statusString = AccessStatus[statusInt]
return AccessStatus[statusString]
})
}
public async getEncryptedAccessToken(orderId: string, consumerAddress: string): Promise<Receipt> {
return this.call("getEncryptedAccessToken", [orderId], consumerAddress)
}
public async initiateAccessRequest(asset: Asset, publicKey: string,
timeout: number, buyerAddress: string): Promise<Receipt> {
const args = [asset.getId(), asset.publisher.getId(), publicKey, timeout]
return this.sendTransaction("initiateAccessRequest", buyerAddress, args)
}
public async commitAccessRequest(order: Order, publisherAddress: string) {
const args = [order.getId(), true, 9999999999, "discovery", "read", "slaLink", "slaType"]
return this.sendTransaction("commitAccessRequest", publisherAddress, args)
}
public async getTempPubKey(orderId: string) {
return this.call("getTempPubKey", [orderId])
}
public async deliverAccessToken(orderId: string, accessToken: string, publisherAddress: string) {
return this.sendTransaction("deliverAccessToken", publisherAddress, [orderId, accessToken])
}
}

View File

@ -0,0 +1,82 @@
import Event from "web3"
import Contract from "web3-eth-contract"
import Logger from "../utils/Logger"
import ContractHandler from "./ContractHandler"
export default abstract class ContractBase {
protected static instance = null
private contract: Contract = null
private contractName: string
constructor(contractName) {
this.contractName = contractName
}
/*
public async listenToEventOnce(eventName: string, options: any): Promise<any> {
return new Promise<any>((resolve, reject) => {
if (!this.contract.events[eventName]) {
throw new Error(`Event ${eventName} not found on contract ${this.contractName}`)
}
this.contract.events[eventName](options, (err) => {
reject(err)
})
.on("data", (eventData: any) => {
resolve(eventData)
})
})
}
*/
public async getEventData(eventName: any, options: any): Promise<Event[]> {
if (!this.contract.events[eventName]) {
throw new Error(`Event ${eventName} not found on contract ${this.contractName}`)
}
return this.contract.getPastEvents(eventName, options)
}
public getAddress() {
return this.contract.options.address
}
protected async init() {
this.contract = await ContractHandler.get(this.contractName)
}
protected async sendTransaction(name: string, from: string, args: any[]) {
if (!this.contract.methods[name]) {
throw new Error(`Method ${name} is not part of contract ${this.contractName}`)
}
try {
const tx = this.contract.methods[name](...args)
const gas = await tx.estimateGas(args, {
from,
})
return tx.send({
from,
gas,
})
} catch (err) {
const argString = JSON.stringify(args, null, 2)
Logger.error(`Sending transaction ${name} on contract ${this.contractName} failed.`)
Logger.error(`Args: ${argString} From: ${from}`)
throw err
}
}
protected async call(name: string, args: any[], from?: string) {
if (!this.contract.methods[name]) {
throw new Error(`Method ${name} is not part of contract ${this.contractName}`)
}
try {
const method = this.contract.methods[name](...args)
return method.call(from ? {from} : null)
} catch (err) {
Logger.error(`Calling method ${name} on contract ${this.contractName} failed. Args: ${args}`, err)
throw err
}
}
}

View File

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

53
src/keeper/Keeper.ts Normal file
View File

@ -0,0 +1,53 @@
import OceanAuth from "./Auth"
import OceanMarket from "./Market"
import OceanToken from "./Token"
import Web3Provider from "./Web3Provider"
export default class Keeper {
public static async getInstance() {
if (Keeper.instance === null) {
Keeper.instance = new Keeper()
Keeper.instance.market = await OceanMarket.getInstance()
Keeper.instance.auth = await OceanAuth.getInstance()
Keeper.instance.token = await OceanToken.getInstance()
}
return Keeper.instance
}
private static instance: Keeper = null
public token: OceanToken
public market: OceanMarket
public auth: OceanAuth
public async getNetworkName(): Promise<string> {
return Web3Provider.getWeb3().eth.net.getId()
.then((networkId) => {
let network: string = "unknown"
switch (networkId) {
case 1:
network = "Main"
break
case 2:
network = "Morden"
break
case 3:
network = "Ropsten"
break
case 4:
network = "Rinkeby"
break
case 42:
network = "Kovan"
break
default:
network = "development"
}
return network
})
}
}

47
src/keeper/Market.ts Normal file
View File

@ -0,0 +1,47 @@
import BigNumber from "bignumber.js"
import {Receipt} from "web3-utils"
import Order from "../ocean/Order"
import ContractBase from "./ContractBase"
export default class OceanMarket extends ContractBase {
public static async getInstance(): Promise<OceanMarket> {
const market: OceanMarket = new OceanMarket("OceanMarket")
await market.init()
return market
}
// call functions (costs no gas)
public async isAssetActive(assetId: string): Promise<boolean> {
return this.call("checkAsset", [assetId])
}
public async verifyOrderPayment(orderId: string): Promise<boolean> {
return this.call("verifyPaymentReceived", [orderId])
}
public async getAssetPrice(assetId: string): Promise<number> {
return this.call("getAssetPrice", [assetId])
.then((price: string) => new BigNumber(price).toNumber())
}
public async requestTokens(amount: number, receiverAddress: string): Promise<Receipt> {
return this.sendTransaction("requestTokens", receiverAddress, [amount])
}
public async generateId(input: string): Promise<string> {
return this.call("generateId", [input])
}
public async register(assetId: string, price: number, publisherAddress: string): Promise<Receipt> {
return this.sendTransaction("register", publisherAddress, [assetId, price])
}
public async payOrder(order: Order, publisherAddress: string,
price: number, consumerAddress: string,
timeout: number): Promise<Receipt> {
return this.sendTransaction("sendPayment", consumerAddress, [
order.getId(), publisherAddress, price, timeout,
])
}
}

21
src/keeper/Token.ts Normal file
View File

@ -0,0 +1,21 @@
import BigNumber from "bignumber.js"
import {Receipt} from "web3-utils"
import ContractBase from "./ContractBase"
export default class OceanToken extends ContractBase {
public static async getInstance(): Promise<OceanToken> {
const token: OceanToken = new OceanToken("OceanToken")
await token.init()
return token
}
public async approve(marketAddress: string, price: number, buyerAddress: string): Promise<Receipt> {
return this.sendTransaction("approve", buyerAddress, [marketAddress, price])
}
public async balanceOf(address: string): Promise<number> {
return this.call("balanceOf", [address])
.then((balance: string) => new BigNumber(balance).toNumber())
}
}

View File

@ -0,0 +1,19 @@
import * as Web3 from "web3"
import ConfigProvider from "../ConfigProvider"
import Logger from "../utils/Logger"
Logger.log("using web3", Web3.version)
export default class Web3Provider {
public static getWeb3() {
if (Web3Provider.web3 === null) {
const config = ConfigProvider.getConfig()
const web3Provider = config.web3Provider || new Web3.providers.HttpProvider(config.nodeUri)
Web3Provider.web3 = new Web3(Web3.givenProvider || web3Provider)
}
return Web3Provider.web3
}
private static web3: Web3 = null
}

View File

@ -1,30 +0,0 @@
import Config from "../utils/config";
import Web3Helper from "../utils/Web3Helper";
import ContractLoader from "./contractLoader";
import KeeperBase from "./keeper-base";
export default class OceanAuth extends KeeperBase {
public static async getInstance(config: Config, web3Helper) {
const auth = new OceanAuth(config, web3Helper);
auth.contract = await ContractLoader.load("OceanAuth", auth.web3Helper);
return auth;
}
private constructor(config: Config, web3Helper: Web3Helper) {
super(config, web3Helper);
}
public cancelAccessRequest(orderId: string, senderAddress: string) {
return this.contract.cancelAccessRequest(orderId, {from: senderAddress});
}
public getOrderStatus(orderId: string) {
return this.contract.statusOfAccessRequest(orderId);
}
public getEncryptedAccessToken(orderId: string, senderAddress: string) {
return this.contract.getEncryptedAccessToken(orderId, {from: senderAddress});
}
}

View File

@ -1,29 +0,0 @@
import * as TruffleContract from "truffle-contract";
import Logger from "../utils/logger";
import Web3Helper from "../utils/Web3Helper";
const contracts: Map<string, object> = new Map<string, object>();
export default class ContractLoader {
public static async load(what: string, web3Helper: Web3Helper) {
return contracts.get(what) || await ContractLoader._doLoad(what, web3Helper);
}
private static async _doLoad(what: string, web3Helper: Web3Helper): Promise<object> {
const where = (await web3Helper.getNetworkName()).toLowerCase();
Logger.log("Loading", what, "from", where);
try {
/* eslint-disable-next-line security/detect-non-literal-require */
const artifact = require(`@oceanprotocol/keeper-contracts/artifacts/${what}.${where}`);
// Logger.log('Loaded artifact', artifact)
const contract = TruffleContract(artifact);
Logger.log("Getting instance of", what, "from", where, "at", artifact.address);
contract.setProvider(web3Helper.web3.currentProvider);
contracts.set(what, await contract.at(artifact.address));
return contracts.get(what);
} catch (err) {
Logger.error("Failed to load", what, "from", where);
}
}
}

View File

@ -1,15 +0,0 @@
import Config from "../utils/config";
import Web3Helper from "../utils/Web3Helper";
export default class KeeperBase {
public contract: any = null;
protected config: Config;
protected web3Helper: Web3Helper;
constructor(config: Config, web3Helper: Web3Helper) {
this.config = config;
this.web3Helper = web3Helper;
}
}

View File

@ -1,61 +0,0 @@
import BigNumber from "bignumber.js";
import Config from "../utils/config";
import Logger from "../utils/logger";
import Web3Helper from "../utils/Web3Helper";
import ContractLoader from "./contractLoader";
import KeeperBase from "./keeper-base";
export default class OceanMarket extends KeeperBase {
public static async getInstance(config: Config, web3Helper: Web3Helper) {
const market = new OceanMarket(config, web3Helper);
market.contract = await ContractLoader.load("OceanMarket", market.web3Helper);
return market;
}
private constructor(config: Config, web3Helper: Web3Helper) {
super(config, web3Helper);
}
// call functions (costs no gas)
public checkAsset(assetId: string) {
return this.contract.checkAsset(assetId);
}
public verifyOrderPayment(orderId: string): boolean {
return this.contract.verifyPaymentReceived(orderId);
}
public getAssetPrice(assetId: string) {
return this.contract.getAssetPrice(assetId)
.then((price: BigNumber) => price.toNumber());
}
// Transactions with gas cost
public requestTokens(amount: number, address: string) {
return this.contract.requestTokens(amount, {from: address});
}
public async registerAsset(name: string, description: string, price: number, publisherAddress: string) {
const assetId = await this.contract.generateId(name + description);
const result = await this.contract.register(
assetId,
price, {
from: publisherAddress,
gas: this.config.defaultGas,
},
);
Logger.log("registered: ", result);
return assetId;
}
public async payAsset(assetId: string, order: any, publisherAddress: string, senderAddress: string) {
const assetPrice = await this.contract.getAssetPrice(assetId)
.then((price: BigNumber) => price.toNumber());
this.contract.sendPayment(order.id, publisherAddress, assetPrice, order.timeout, {
from: senderAddress,
gas: 2000000,
});
}
}

View File

@ -1,36 +0,0 @@
import Config from "../utils/config";
import Logger from "../utils/logger";
import Web3Helper from "../utils/Web3Helper";
import ContractLoader from "./contractLoader";
import KeeperBase from "./keeper-base";
export default class OceanToken extends KeeperBase {
public static async getInstance(config: Config, web3Helper: Web3Helper) {
const token = new OceanToken(config, web3Helper);
token.contract = await ContractLoader.load("OceanToken", token.web3Helper);
return token;
}
private constructor(config: Config, web3Helper: Web3Helper) {
super(config, web3Helper);
}
public getTokenBalance(accountAddress: string) {
return this.contract.balanceOf.call(accountAddress);
}
public async getEthBalance(account: string): Promise<number> {
return new Promise<number>((resolve, reject) => {
// Logger.log("getting balance for", account);
this.web3Helper.web3.eth.getBalance(account, "latest", (err: any, balance: number) => {
if (err) {
return reject(err);
}
// Logger.log("balance", balance);
resolve(balance);
});
});
}
}

View File

@ -1,45 +0,0 @@
import Config from "./utils/config";
import Logger from "./utils/logger";
declare var fetch;
export default class MetaData {
private assetsUrl: string;
constructor(config: Config) {
const providerUri = config.providerUri || null;
this.assetsUrl = providerUri + "/assets";
}
public getAssetsMetadata() {
return fetch(this.assetsUrl + "/metadata", {method: "GET"})
.then((res) => res.json())
.then((data) => JSON.parse(data));
}
public publishDataAsset(asset: object) {
return fetch(this.assetsUrl + "/metadata",
{
method: "POST",
body: JSON.stringify(asset),
headers: {"Content-type": "application/json"},
})
.then((response: any) => {
Logger.log("Success:", response);
if (response.ok) {
Logger.log("Success:", response);
return true;
}
Logger.log("Failed: ", response.status, response.statusText);
return false;
// throw new Error(response.statusText ? response.statusText :
// `publish asset failed with status ${response.status}`)
})
.catch((error: Error) => {
Logger.log(`Publish asset to ocean database could not be completed: ${error.message}`);
return false;
});
}
}

View File

@ -0,0 +1,9 @@
enum AccessStatus {
Requested,
Committed,
Delivered,
Verified,
Revoked,
}
export default AccessStatus

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

@ -0,0 +1,4 @@
export default class Balance {
public eth: number
public ocn: number
}

5
src/models/Config.ts Normal file
View File

@ -0,0 +1,5 @@
export default class Config {
public providerUri: string
public nodeUri: string
public web3Provider: any
}

View File

@ -1,153 +0,0 @@
import BigNumber from "bignumber.js";
import OceanAuth from "./keeper/auth";
import OceanMarket from "./keeper/market";
import OceanToken from "./keeper/token";
import MetaData from "./metadata";
import Config from "./utils/config";
import Logger from "./utils/logger";
import Web3Helper from "./utils/Web3Helper";
export default class Ocean {
public static async getInstance(config) {
const ocean = new Ocean(config);
ocean.market = await OceanMarket.getInstance(config, ocean.helper);
ocean.auth = await OceanAuth.getInstance(config, ocean.helper);
ocean.token = await OceanToken.getInstance(config, ocean.helper);
return ocean;
}
public token: OceanToken;
public market: OceanMarket;
public auth: OceanAuth;
public helper: Web3Helper;
public metadata: MetaData;
private config: Config;
private constructor(config: Config) {
this.config = config;
this.helper = new Web3Helper(config);
this.metadata = new MetaData(config);
}
public async getAccounts() {
return Promise.all((await this.helper.getAccounts()).map(async (account: string) => {
// await ocean.market.requestTokens(account, 1000)
const {token} = this;
return {
name: account,
balance: {
eth: await token.getEthBalance(account),
ocn: await token.getTokenBalance(account),
},
};
}));
}
public async getOrdersByConsumer(consumerAddress: string) {
const {auth} = this;
const accessConsentEvent = auth.contract.AccessConsentRequested({_consumer: consumerAddress}, {
fromBlock: 0,
toBlock: "latest",
});
let outerResolve = null;
let outerReject = null;
const promise = new Promise<any[]>((resolve, reject) => {
outerResolve = resolve;
outerReject = reject;
});
const getEvents = (): Promise<any[]> => {
accessConsentEvent.get((error: any, logs: any[]) => {
if (error) {
outerReject(error);
throw new Error(error);
} else {
outerResolve(logs);
}
});
return promise;
};
const events = await getEvents().then((result) => result);
// let orders = await this.buildOrdersFromEvents(events, consumerAddress).then((result) => result)
const orders = events
.filter((obj: any) => (obj.args._consumer === consumerAddress))
.map(async (event: any) => ({
...event.args,
timeout: event.args._timeout.toNumber(),
status: await this.auth.getOrderStatus(event.args._id)
.then((status: BigNumber) => status.toNumber()),
paid: this.market.verifyOrderPayment(event.args._id),
key: null,
}));
Logger.debug("got orders: ", orders);
return orders;
}
public async purchaseAsset(
assetId: string, publisherId: string, price: number, privateKey: string, publicKey: string, timeout: number,
senderAddress: string, initialRequestEventHandler, accessCommittedEventHandler, tokenPublishedEventHandler) {
const {token, market, auth, config} = this;
try {
// Allow market contract to transfer funds on the consumer"s behalf
await token.contract.approve(market.contract.address, price, {from: senderAddress, gas: config.defaultGas});
} catch (err) {
Logger.log("token approve", err);
}
try {
// Submit the access request
await auth.contract.initiateAccessRequest(
assetId, publisherId, publicKey,
timeout, {from: senderAddress, gas: 1000000},
);
} catch (err) {
Logger.log("initiateAccessRequest", err);
}
const resourceFilter = {_resourceId: assetId, _consumer: senderAddress};
const initRequestEvent = auth.contract.AccessConsentRequested(resourceFilter);
let order: any = {};
this._listenOnce(
initRequestEvent,
"AccessConsentRequested",
(result: any, error: any) => {
order = initialRequestEventHandler(result, error);
const requestIdFilter = {_id: order.id};
const accessCommittedEvent = auth.contract.AccessRequestCommitted(requestIdFilter);
const tokenPublishedEvent = auth.contract.EncryptedTokenPublished(requestIdFilter);
this._listenOnce(
accessCommittedEvent,
"AccessRequestCommitted",
(accessRequestCommittedResult: any, accessRequestCommittedError: any) => {
accessCommittedEventHandler(accessRequestCommittedResult, order, accessRequestCommittedError);
},
);
this._listenOnce(
tokenPublishedEvent,
"EncryptedTokenPublished",
(encryptedTokenPublishedResult: any, encryptedTokenPublishedError: any) => {
tokenPublishedEventHandler(encryptedTokenPublishedResult, order, encryptedTokenPublishedError);
},
);
});
return order;
}
// Helper functions (private)
public _listenOnce(event: any, eventName: string, callback) {
// eslint-disable-next-line security/detect-non-literal-fs-filename
event.watch((error: any, result: any) => {
event.stopWatching();
if (error) {
Logger.log(`Error in keeper ${eventName} event: `, error);
}
callback(result, error);
});
}
}

41
src/ocean/Account.ts Normal file
View File

@ -0,0 +1,41 @@
import BigNumber from "bignumber.js"
import Keeper from "../keeper/Keeper"
import Web3Provider from "../keeper/Web3Provider"
import Balance from "../models/Balance"
import OceanBase from "./OceanBase"
export default class Account extends OceanBase {
private balance: Balance
public async getOceanBalance(): Promise<number> {
return (await Keeper.getInstance()).token.balanceOf(this.id)
}
public async getEtherBalance(): Promise<number> {
// Logger.log("getting balance for", account);
return Web3Provider.getWeb3().eth
.getBalance(this.id, "latest")
.then((balance: string): number => {
// Logger.log("balance", balance);
return new BigNumber(balance).toNumber()
})
}
public async getBalance(): Promise<Balance> {
if (!this.balance) {
this.balance = {
eth: await this.getEtherBalance(),
ocn: await this.getOceanBalance(),
} as Balance
}
return this.balance
}
// Transactions with gas cost
public async requestTokens(amount: number): Promise<number> {
await (await Keeper.getInstance()).market.requestTokens(amount, this.id)
return amount
}
}

56
src/ocean/Asset.ts Normal file
View File

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

93
src/ocean/Ocean.ts Normal file
View File

@ -0,0 +1,93 @@
import ConfigProvider from "../ConfigProvider"
import Keeper from "../keeper/Keeper"
import Web3Provider from "../keeper/Web3Provider"
import Provider from "../provider/Provider"
import ProviderProvider from "../provider/ProviderProvider"
import Logger from "../utils/Logger"
import Account from "./Account"
import Asset from "./Asset"
import Order from "./Order"
export default class Ocean {
public static async getInstance(config) {
if (!Ocean.instance) {
ConfigProvider.configure(config)
ProviderProvider.setProvider(Provider)
Ocean.instance = new Ocean(await Keeper.getInstance())
}
return Ocean.instance
}
private static instance = null
private keeper: Keeper
private constructor(keeper: Keeper) {
this.keeper = keeper
}
public async getAccounts(): Promise<Account[]> {
// retrieve eth accounts
const ethAccounts = await Web3Provider.getWeb3().eth.getAccounts()
return ethAccounts.map((address: string) => new Account(address))
}
public async register(asset: Asset): Promise<string> {
const {market} = this.keeper
// generate an id
const assetId = await market.generateId(asset.name + asset.description)
Logger.log(`Registering: ${assetId} with price ${asset.price} for ${asset.publisher.getId()}`)
asset.setId(assetId)
const isAssetActive = await market.isAssetActive(assetId)
// register asset in the market
if (!isAssetActive) {
const result = await market.register(asset.getId(), asset.price, asset.publisher.getId())
Logger.log("Registered:", assetId, "in block", result.blockNumber)
} else {
throw new Error("Asset already registered")
}
return assetId
}
public async getOrdersByAccount(consumer: Account): Promise<Order[]> {
const {auth} = this.keeper
Logger.log("Getting orders")
const accessConsentRequestedData = await auth.getEventData(
"AccessConsentRequested", {
filter: {
_consumer: consumer.getId(),
},
fromBlock: 0,
toBlock: "latest",
})
const orders = await Promise.all(
accessConsentRequestedData
.map(async (event: any) => {
const {returnValues} = event
const order: Order = new Order(
null,
parseInt(returnValues._timeout, 10),
null, null)
order.setId(returnValues._id)
return order
}),
)
// Logger.log("Got orders:", JSON.stringify(orders, null, 2))
Logger.log(`Got ${Object.keys(orders).length} orders`)
return orders
}
}

18
src/ocean/OceanBase.ts Normal file
View File

@ -0,0 +1,18 @@
export default abstract class OceanBase {
protected id = "0x00"
constructor(id?) {
if (id) {
this.id = id
}
}
public getId() {
return this.id
}
public setId(id) {
this.id = id
}
}

97
src/ocean/Order.ts Normal file
View File

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

30
src/provider/Provider.ts Normal file
View File

@ -0,0 +1,30 @@
import fetch from "node-fetch"
import Logger from "../utils/Logger"
export default class Provider {
public static async getAccessUrl(accessToken: any, payload: any): Promise<string> {
const accessUrl = await fetch(`${accessToken.service_endpoint}/${accessToken.resource_id}`, {
method: "POST",
body: payload,
headers: {
"Content-type": "application/json",
},
})
.then((response: any) => {
if (response.ok) {
return response.text()
}
Logger.log("Failed: ", response.status, response.statusText)
})
.then((consumptionUrl: string) => {
Logger.log("Success accessing consume endpoint: ", consumptionUrl)
return consumptionUrl
})
.catch((error) => {
Logger.error("Error fetching the data asset consumption url: ", error)
})
return accessUrl
}
}

View File

@ -0,0 +1,14 @@
export default class ProviderProvider {
public static setProvider(provider) {
ProviderProvider.provider = provider
}
public static getProvider() {
return ProviderProvider.provider
}
private static provider
}

View File

@ -1,7 +1,11 @@
import Ocean from "./ocean";
import Logger from "./utils/logger";
import Asset from "./ocean/Asset"
import Ocean from "./ocean/Ocean"
import Order from "./ocean/Order"
import Logger from "./utils/Logger"
export {
Ocean,
Order,
Asset,
Logger,
};
}

View File

@ -1,22 +1,21 @@
export default class Logger {
public static log(...args: any[]) {
Logger.dispatch("log", ...args);
Logger.dispatch("log", ...args)
}
public static debug(...args: any[]) {
Logger.dispatch("debug", ...args);
Logger.dispatch("debug", ...args)
}
public static warn(...args: any[]) {
Logger.dispatch("warn", ...args);
Logger.dispatch("warn", ...args)
}
public static error(...args: any[]) {
Logger.dispatch("error", ...args);
Logger.dispatch("error", ...args)
}
private static dispatch(verb: string, ...args: any[]) {
/* eslint-disable-next-line no-console */
console[verb](...args);
console[verb](...args)
}
}

View File

@ -1,59 +0,0 @@
import Web3 = require("web3");
import Config from "./config";
export default class Web3Helper {
public web3: Web3;
public constructor(config: Config) {
const web3Provider = config.web3Provider || new Web3.providers.HttpProvider(config.nodeUri);
this.web3 = new Web3(web3Provider);
}
public async getAccounts(): Promise<any[]> {
return new Promise<any[]>((resolve, reject) => {
this.web3.eth.getAccounts((err: any, accounts: string[]) => {
if (err) {
throw err;
}
resolve(accounts);
});
});
}
public async getNetworkName(): Promise<string> {
return new Promise<string>((resolve, reject) => {
let network: string = "unknown";
// @ts-ignore old version of web3, lets get to 1.0
this.web3.version.getNetwork((err, networkId) => {
if (err) {
throw err;
}
switch (networkId) {
case "1":
network = "Main";
break;
case "2":
network = "Morden";
break;
case "3":
network = "Ropsten";
break;
case "4":
network = "Rinkeby";
break;
case "42":
network = "Kovan";
break;
default:
network = "development";
}
resolve(network);
});
});
}
// web3 wrappers
public sign(accountAddress: string, message: string) {
return this.web3.eth.sign(accountAddress, message);
}
}

View File

@ -1,7 +0,0 @@
export default class Config {
public defaultGas: number = 300000;
public providerUri: string;
public nodeUri: string;
public web3Provider: any;
}

25
test/Squid.test.ts Normal file
View File

@ -0,0 +1,25 @@
import * as assert from "assert"
import * as squid from "../src/squid"
describe("Squid", () => {
describe("interface", () => {
it("should expose Ocean", async () => {
assert(squid.Ocean)
})
it("should expose Logger", async () => {
assert(squid.Logger)
})
it("should expose Asset", async () => {
assert(squid.Asset)
})
it("should expose Order", async () => {
assert(squid.Order)
})
})
})

5
test/config.ts Normal file
View File

@ -0,0 +1,5 @@
import Config from "../src/models/Config"
export default {
nodeUri: "http://localhost:8545",
} as Config

View File

@ -0,0 +1,68 @@
import ConfigProvider from "../../src/ConfigProvider"
import ContractHandler from "../../src/keeper/ContractHandler"
import config from "../config"
import ContractBaseMock from "../mocks/ContractBase.Mock"
const wrappedContract = new ContractBaseMock("OceanToken")
before(async () => {
ConfigProvider.configure(config)
await ContractHandler.deployContracts()
wrappedContract.initMock()
})
describe("ContractWrapperBase", () => {
describe("#call()", () => {
it("should fail to call on an unknown contract function", (done) => {
wrappedContract.callMock("balanceOfxxx", [])
.catch(() => {
done()
})
})
it("should fail to call on an contract function with wrong set of parameters", (done) => {
wrappedContract.callMock("balanceOf", [])
.catch(() => {
done()
})
})
it("should fail to call on an unknown contract function", (done) => {
wrappedContract.sendMock("balanceOfxxx", "0x00", ["0x00"])
.catch(() => {
done()
})
})
it("should fail to call on an contract function with wrong set of parameters", (done) => {
wrappedContract.sendMock("approve", "0x000", [])
.catch(() => {
done()
})
})
})
describe("#getEventData()", () => {
it("should fail on unknown event", (done) => {
wrappedContract.getEventData("crazyevent", {})
.catch(() => {
done()
})
})
})
})

View File

@ -0,0 +1,28 @@
import {assert} from "chai"
import ConfigProvider from "../../src/ConfigProvider"
import ContractHandler from "../../src/keeper/ContractHandler"
import config from "../config"
before(async () => {
ConfigProvider.configure(config)
await ContractHandler.deployContracts()
})
describe("ContractHandler", () => {
describe("#get()", () => {
it("should load and get OceanToken correctly", async () => {
assert(await ContractHandler.get("OceanToken"))
})
it("should fail to load an unknown contract", (done) => {
ContractHandler.get("OceanXXX")
.catch(() => {
done()
})
})
})
})

View File

@ -0,0 +1,40 @@
import {assert} from "chai"
import ConfigProvider from "../../src/ConfigProvider"
import ContractHandler from "../../src/keeper/ContractHandler"
import Keeper from "../../src/keeper/Keeper"
import config from "../config"
let keeper: Keeper
before(async () => {
ConfigProvider.configure(config)
await ContractHandler.deployContracts()
keeper = await Keeper.getInstance()
})
describe("Keeper", () => {
describe("public interface", () => {
it("should have market", () => {
assert(keeper.market !== null)
})
it("should have auth", () => {
assert(keeper.auth !== null)
})
it("should have token", () => {
assert(keeper.token !== null)
})
})
describe("#getNetworkName()", () => {
it("should get development as default", async () => {
const networkName: string = await keeper.getNetworkName()
assert(networkName === "development")
})
})
})

5
test/mocha.opts Normal file
View File

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

View File

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

View File

@ -0,0 +1,4 @@
import OceanBase from "../../src/ocean/OceanBase"
export default class OceanBaseMock extends OceanBase {
}

View File

@ -0,0 +1,8 @@
import Provider from "../../src/provider/Provider"
export default class ProviderMock extends Provider {
public static async getAccessUrl(accessToken: any, payload: any): Promise<string> {
return "http://test/test"
}
}

View File

@ -0,0 +1,78 @@
import {assert} from "chai"
import ConfigProvider from "../../src/ConfigProvider"
import ContractHandler from "../../src/keeper/ContractHandler"
import Web3Provider from "../../src/keeper/Web3Provider"
import Account from "../../src/ocean/Account"
import Ocean from "../../src/ocean/Ocean"
import config from "../config"
let ocean: Ocean
let accounts: Account[]
before(async () => {
ConfigProvider.configure(config)
await ContractHandler.deployContracts()
ocean = await Ocean.getInstance(config)
accounts = await ocean.getAccounts()
})
describe("Account", () => {
describe("#getOceanBalance()", () => {
it("should get initial ocean balance", async () => {
const balance = await accounts[8].getOceanBalance()
assert(0 === balance, `Expected 0 got ${balance}`)
})
it("should get the correct balance", async () => {
const amount: number = 100
const account: Account = accounts[0]
await account.requestTokens(amount)
const balance = await account.getOceanBalance()
assert(amount === balance)
})
})
describe("#getEthBalance()", () => {
it("should get initial ether balance", async () => {
const account: Account = accounts[9]
const balance = await account.getEtherBalance()
const web3 = Web3Provider.getWeb3()
assert(Number(web3.utils.toWei("100", "ether")) === balance)
})
})
describe("#getBalance()", () => {
it("should get initial balance", async () => {
const account: Account = accounts[9]
const balance = await account.getBalance()
const web3 = Web3Provider.getWeb3()
assert(Number(web3.utils.toWei("100", "ether")) === balance.eth)
assert(0 === balance.ocn)
})
})
describe("#requestTokens()", () => {
it("should return the amount of tokens granted", async () => {
const tokens = 500
const account: Account = accounts[0]
const tokensGranted: number = await account.requestTokens(tokens)
assert(tokensGranted === tokens)
})
})
})

47
test/ocean/Asset.test.ts Normal file
View File

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

87
test/ocean/Ocean.test.ts Normal file
View File

@ -0,0 +1,87 @@
import {assert} from "chai"
import ConfigProvider from "../../src/ConfigProvider"
import ContractHandler from "../../src/keeper/ContractHandler"
import Account from "../../src/ocean/Account"
import Asset from "../../src/ocean/Asset"
import Ocean from "../../src/ocean/Ocean"
import Order from "../../src/ocean/Order"
import config from "../config"
let ocean: Ocean
let accounts: Account[]
let testAsset: Asset
let testPublisher: Account
const name = "Test Asset 3"
const description = "This asset is pure owange"
const price = 100
const timeout = 100000000
before(async () => {
ConfigProvider.configure(config)
await ContractHandler.deployContracts()
ocean = await Ocean.getInstance(config)
accounts = await ocean.getAccounts()
testPublisher = accounts[0]
testAsset = new Asset(name, description, price, testPublisher)
})
describe("Ocean", () => {
describe("#getInstance()", () => {
it("should list accounts", async () => {
const ocn = Ocean.getInstance(config)
assert(ocn)
})
})
describe("#getAccounts()", () => {
it("should list accounts", async () => {
const accs: Account[] = await ocean.getAccounts()
assert(10 === accs.length)
assert(0 === (await accs[5].getBalance()).ocn)
assert("string" === typeof accs[0].getId())
})
})
describe("#register()", () => {
it("should register an asset", async () => {
const assetId: string = await ocean.register(testAsset)
assert(assetId.length === 66)
assert(assetId.startsWith("0x"))
})
})
describe("#getOrdersByConsumer()", () => {
it("should list orders", async () => {
const testConsumer = accounts[1]
const asset: Asset = new Asset("getOrdersByConsumer test", description, price, testPublisher)
await ocean.register(asset)
const order: Order = await asset.purchase(testConsumer, timeout)
const orders = await ocean.getOrdersByAccount(testConsumer)
assert(orders.length === 1)
assert(orders[0].getId() === order.getId())
})
})
})

View File

@ -0,0 +1,30 @@
import {assert} from "chai"
import OceanBaseMock from "../mocks/OceanBase.Mock"
describe("OceanBase", () => {
describe("#getId()", () => {
it("should get the id", async () => {
const id = "test"
const oceanBase = new OceanBaseMock(id)
assert(oceanBase.getId() === id)
})
})
describe("#setId()", () => {
it("should get the id", async () => {
const id = "test"
const oceanBase = new OceanBaseMock()
oceanBase.setId(id)
assert(oceanBase.getId() === id)
})
})
})

101
test/ocean/Order.test.ts Normal file
View File

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

9
test/tsconfig.json Normal file
View File

@ -0,0 +1,9 @@
{
"compilerOptions": {
"lib": [
"es6",
"es7"
],
"noUnusedLocals": true
}
}

View File

@ -1,10 +1,12 @@
{
"compilerOptions": {
"resolveJsonModule": true,
"lib": [
"es6",
"es7"
],
"declaration": true,
"noUnusedLocals": true,
"module": "commonjs",
"noImplicitAny": false,
"removeComments": true,
@ -18,6 +20,6 @@
],
"exclude": [
"node_modules",
"**/*.spec.ts"
"**/*.test.ts"
]
}

View File

@ -5,7 +5,11 @@
],
"jsRules": {},
"rules": {
"object-literal-sort-keys": false
"object-literal-sort-keys": false,
"semicolon": [
true,
"never"
]
},
"rulesDirectory": []
}