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:
commit
56e4a74483
5
.gitignore
vendored
5
.gitignore
vendored
@ -1,2 +1,7 @@
|
||||
node_modules/
|
||||
dist/
|
||||
.nyc_output/
|
||||
coverage/
|
||||
doc/
|
||||
test/**/*.js
|
||||
src/**/*.js
|
||||
|
@ -1 +1,10 @@
|
||||
node_modules/
|
||||
coverage/
|
||||
.github
|
||||
.nyc_output
|
||||
.travis.yml
|
||||
test/
|
||||
src/
|
||||
tsconfig.json
|
||||
tslint.json
|
||||
oceanprotocol-squid-*.tgz
|
||||
|
17
.travis.yml
17
.travis.yml
@ -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
1
SQUID_INTERFACE.md
Normal file
@ -0,0 +1 @@
|
||||
this document has been moved to [here](https://github.com/oceanprotocol/dev-ocean/blob/master/doc/development/squid.md).
|
8424
package-lock.json
generated
8424
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
59
package.json
59
package.json
@ -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
15
src/ConfigProvider.ts
Normal 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
47
src/keeper/Auth.ts
Normal 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])
|
||||
}
|
||||
|
||||
}
|
82
src/keeper/ContractBase.ts
Normal file
82
src/keeper/ContractBase.ts
Normal 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
|
||||
}
|
||||
}
|
||||
|
||||
}
|
128
src/keeper/ContractHandler.ts
Normal file
128
src/keeper/ContractHandler.ts
Normal 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
53
src/keeper/Keeper.ts
Normal 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
47
src/keeper/Market.ts
Normal 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
21
src/keeper/Token.ts
Normal 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())
|
||||
}
|
||||
}
|
19
src/keeper/Web3Provider.ts
Normal file
19
src/keeper/Web3Provider.ts
Normal 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
|
||||
}
|
@ -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});
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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,
|
||||
});
|
||||
}
|
||||
}
|
@ -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);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
@ -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;
|
||||
});
|
||||
}
|
||||
}
|
9
src/models/AccessStatus.ts
Normal file
9
src/models/AccessStatus.ts
Normal file
@ -0,0 +1,9 @@
|
||||
enum AccessStatus {
|
||||
Requested,
|
||||
Committed,
|
||||
Delivered,
|
||||
Verified,
|
||||
Revoked,
|
||||
}
|
||||
|
||||
export default AccessStatus
|
4
src/models/Balance.ts
Normal file
4
src/models/Balance.ts
Normal file
@ -0,0 +1,4 @@
|
||||
export default class Balance {
|
||||
public eth: number
|
||||
public ocn: number
|
||||
}
|
5
src/models/Config.ts
Normal file
5
src/models/Config.ts
Normal file
@ -0,0 +1,5 @@
|
||||
export default class Config {
|
||||
public providerUri: string
|
||||
public nodeUri: string
|
||||
public web3Provider: any
|
||||
}
|
153
src/ocean.ts
153
src/ocean.ts
@ -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
41
src/ocean/Account.ts
Normal 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
56
src/ocean/Asset.ts
Normal 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
93
src/ocean/Ocean.ts
Normal 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
18
src/ocean/OceanBase.ts
Normal 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
97
src/ocean/Order.ts
Normal 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
30
src/provider/Provider.ts
Normal 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
|
||||
}
|
||||
}
|
14
src/provider/ProviderProvider.ts
Normal file
14
src/provider/ProviderProvider.ts
Normal 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
|
||||
}
|
10
src/squid.ts
10
src/squid.ts
@ -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,
|
||||
};
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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
25
test/Squid.test.ts
Normal 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
5
test/config.ts
Normal file
@ -0,0 +1,5 @@
|
||||
import Config from "../src/models/Config"
|
||||
|
||||
export default {
|
||||
nodeUri: "http://localhost:8545",
|
||||
} as Config
|
68
test/keeper/ContractBase.test.ts
Normal file
68
test/keeper/ContractBase.test.ts
Normal 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()
|
||||
})
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
})
|
28
test/keeper/ContractHandler.test.ts
Normal file
28
test/keeper/ContractHandler.test.ts
Normal 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()
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
40
test/keeper/Keeper.test.ts
Normal file
40
test/keeper/Keeper.test.ts
Normal 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
5
test/mocha.opts
Normal file
@ -0,0 +1,5 @@
|
||||
--require ts-node/register
|
||||
--require source-map-support/register
|
||||
--full-trace
|
||||
--bail
|
||||
test/**/*.test.ts
|
15
test/mocks/ContractBase.Mock.ts
Normal file
15
test/mocks/ContractBase.Mock.ts
Normal 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)
|
||||
}
|
||||
}
|
4
test/mocks/OceanBase.Mock.ts
Normal file
4
test/mocks/OceanBase.Mock.ts
Normal file
@ -0,0 +1,4 @@
|
||||
import OceanBase from "../../src/ocean/OceanBase"
|
||||
|
||||
export default class OceanBaseMock extends OceanBase {
|
||||
}
|
8
test/mocks/Provider.Mock.ts
Normal file
8
test/mocks/Provider.Mock.ts
Normal 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"
|
||||
}
|
||||
}
|
78
test/ocean/Account.test.ts
Normal file
78
test/ocean/Account.test.ts
Normal 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
47
test/ocean/Asset.test.ts
Normal 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
87
test/ocean/Ocean.test.ts
Normal 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())
|
||||
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
})
|
30
test/ocean/OceanBase.test.ts
Normal file
30
test/ocean/OceanBase.test.ts
Normal 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
101
test/ocean/Order.test.ts
Normal 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
9
test/tsconfig.json
Normal file
@ -0,0 +1,9 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"lib": [
|
||||
"es6",
|
||||
"es7"
|
||||
],
|
||||
"noUnusedLocals": true
|
||||
}
|
||||
}
|
@ -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"
|
||||
]
|
||||
}
|
||||
|
@ -5,7 +5,11 @@
|
||||
],
|
||||
"jsRules": {},
|
||||
"rules": {
|
||||
"object-literal-sort-keys": false
|
||||
"object-literal-sort-keys": false,
|
||||
"semicolon": [
|
||||
true,
|
||||
"never"
|
||||
]
|
||||
},
|
||||
"rulesDirectory": []
|
||||
}
|
Loading…
Reference in New Issue
Block a user