moved purchase logic to squid, new structure, mockable contracts, first version of unit tests

This commit is contained in:
Sebastian Gerske 2018-10-01 18:10:26 +02:00
parent d4c746ccd0
commit d63fc69dab
25 changed files with 5368 additions and 357 deletions

3
.gitignore vendored
View File

@ -1,2 +1,3 @@
node_modules/
dist/
dist/
test/**/*.js

4936
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -4,7 +4,8 @@
"description": "JavaScript client library for Ocean Protocol",
"main": "dist/squid.js",
"scripts": {
"test": "tslint -c tslint.json 'src/**/*.ts'",
"test": "mocha -r ts-node/register test/**/*.test.ts",
"linkt": "tslint -c tslint.json 'src/**/*.ts'",
"start": "tsc -w",
"build": "tsc",
"release": "./node_modules/release-it/bin/release-it.js --src.tagName='v%s' --github.release --npm.publish --non-interactive",
@ -23,18 +24,25 @@
"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.2.0",
"bignumber.js": "^7.2.1",
"eth-crypto": "^1.2.4",
"eth-ecies": "^1.0.3",
"ethereumjs-util": "^5.2.0",
"jsonwebtoken": "^8.3.0",
"web3": "^1.0.0-beta.36"
},
"devDependencies": {
"@types/web3": "^1.0.6",
"@types/chai": "^4.1.6",
"@types/mocha": "^5.2.5",
"chai": "^4.2.0",
"mocha": "^5.2.0",
"ts-node": "^7.0.1",
"tslint": "^5.11.0",
"typescript": "^3.0.3"
"typescript": "^3.1.1"
}
}

55
src/Ocean.ts Normal file
View File

@ -0,0 +1,55 @@
import Keeper from "./keeper/Keeper";
import Web3Helper from "./keeper/Web3Helper";
import MetaData from "./metadata";
import Config from "./models/config";
import Asset from "./ocean/Asset";
import Order from "./ocean/Order";
export default class Ocean {
public static async getInstance(config) {
const ocean = new Ocean(config);
ocean.keeper = await Keeper.getInstance(config, ocean.helper);
ocean.order = new Order(ocean.keeper);
ocean.asset = new Asset(ocean.keeper);
return ocean;
}
public order: Order;
public asset: Asset;
public helper: Web3Helper;
public metadata: MetaData;
private keeper: Keeper;
private config: Config;
private constructor(config: Config) {
this.config = config;
this.helper = new Web3Helper(config);
this.metadata = new MetaData(config);
}
// Transactions with gas cost
public async requestTokens(amount: number, receiver: string): Promise<boolean> {
return this.keeper.market.requestTokens(amount, receiver);
}
public async getAccounts() {
const {token} = this.keeper;
const {helper} = this;
return Promise.all((await helper.getAccounts()).map(async (account: string) => {
// await ocean.market.requestTokens(account, 1000)
return {
name: account,
balance: {
eth: await token.getEthBalance(account),
ocn: await token.getTokenBalance(account),
},
};
}));
}
}

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

@ -0,0 +1,38 @@
import BigNumber from "bignumber.js";
import Asset from "../models/Asset";
import Config from "../models/Config";
import ContractBaseWrapper from "./ContractWrapperBase";
import Web3Helper from "./Web3Helper";
export default class OceanAuth extends ContractBaseWrapper {
public static async getInstance(config: Config, web3Helper: Web3Helper) {
const auth = new OceanAuth(config, "OceanAuth", web3Helper);
await auth.init();
return auth;
}
public async getOrderStatus(orderId: string): Promise<number> {
return this.contract.statusOfAccessRequest.call(orderId)
.then((status: BigNumber) => status.toNumber());
}
public async cancelAccessRequest(orderId: string, senderAddress: string) {
return this.contract.cancelAccessRequest.send(orderId, {
from: senderAddress,
});
}
public async getEncryptedAccessToken(orderId: string, senderAddress: string) {
return this.contract.getEncryptedAccessToken.send(orderId, {
from: senderAddress,
});
}
public async initiateAccessRequest(asset: Asset, publicKey: string, timeout, buyerAddress: string) {
return this.contract.initiateAccessRequest.send(
asset.assetId, asset.publisherId, publicKey, timeout, {
from: buyerAddress, gas: this.config.defaultGas,
});
}
}

View File

@ -0,0 +1,119 @@
import Contract from "web3";
import Logger from "../utils/Logger";
import Web3Helper from "./Web3Helper";
const contracts: Map<string, object> = new Map<string, object>();
export default class ContractHandler {
public static async get(what: string, web3Helper: Web3Helper) {
return contracts.get(what) || await ContractHandler.load(what, web3Helper);
}
public static async deployContracts(web3Helper: Web3Helper) {
Logger.log("Deploying contracts");
const web3 = web3Helper.getWeb3();
const deployerAddress = (await web3.eth.getAccounts())[0];
// deploy libs
const dll = await ContractHandler.deployContract(web3, "DLL", deployerAddress);
const attributeStore = await ContractHandler.deployContract(web3, "AttributeStore", deployerAddress);
// deploy contracts
const token = await ContractHandler.deployContract(web3, "OceanToken", deployerAddress);
const plcrVoting = await ContractHandler.deployContract(web3, "PLCRVoting", deployerAddress, {
args: [token.options.address],
tokens: [
{
name: "DLL", address: dll.options.address,
}, {
name: "AttributeStore", address: attributeStore.options.address,
},
],
});
const registry = await ContractHandler.deployContract(web3, "OceanRegistry", deployerAddress, {
args: [token.options.address, plcrVoting.options.address],
});
const market = await ContractHandler.deployContract(web3, "OceanMarket", deployerAddress, {
args: [token.options.address, registry.options.address],
});
const dispute = await ContractHandler.deployContract(web3, "OceanDispute", deployerAddress, {
args: [market.options.address, registry.options.address, plcrVoting.options.address],
});
const auth = await ContractHandler.deployContract(web3, "OceanAuth", deployerAddress, {
args: [market.options.address, dispute.options.address],
});
// now wire up
await dispute.methods.init().send({
from: deployerAddress,
});
await auth.methods.init().send({
from: deployerAddress,
});
await market.methods.init().send({
from: deployerAddress, gas: 3000000,
gasPrice: 10000000000,
});
}
private static async load(what: string, web3Helper: Web3Helper): Promise<object> {
const where = (await web3Helper.getNetworkName()).toLowerCase();
Logger.log("Loading", what, "from", where);
try {
const artifact = require(`@oceanprotocol/keeper-contracts/artifacts/${what}.${where}`);
// Logger.log('Loaded artifact', artifact)
Logger.log("Getting instance of", what, "from", where, "at", artifact.address);
const web3 = web3Helper.getWeb3();
const contract = new web3.eth.Contract(artifact.abi, artifact.address);
Logger.log("Loaded", what, "from", where);
contracts.set(what, contract);
return contracts.get(what);
} catch (err) {
Logger.error("Failed to load", what, "from", where, err);
}
}
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(web3, name, from, params?): Promise<Contract> {
let contractInstance;
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;
}
}

View File

@ -0,0 +1,33 @@
import Config from "../models/config";
import ContractHandler from "./ContractHandler";
import Web3Helper from "./Web3Helper";
export default class ContractWrapperBase {
protected contract: any = null;
protected config: Config;
protected web3Helper: Web3Helper;
private contractName: string;
constructor(config: Config, contractName: string, web3Helper: Web3Helper) {
this.config = config;
this.contractName = contractName;
this.web3Helper = web3Helper;
}
public async init() {
this.contract = await ContractHandler.get(this.contractName, this.web3Helper);
}
public getAddress() {
return this.contract.address;
}
public getEvent(name: string) {
if (!this.contract.events[name]) {
throw new Error(`Event ${name} not found on contract ${this.contractName}`);
}
return this.contract.events[name];
}
}

View File

@ -0,0 +1,30 @@
import Logger from "../utils/Logger";
export default class EventListener {
public static async listenOnce(event: any, eventName: string): Promise<any> {
return new Promise<any>((resolve, reject) => {
event.watch((error: any, result: any) => {
event.stopWatching();
if (error) {
Logger.log(`Error in keeper ${eventName} event: `, error);
return reject(error);
}
resolve(result);
});
});
}
public static getEvents(event: any): Promise<any[]> {
return new Promise<any>((resolve, reject) => {
event.get((error: any, logs: any[]) => {
if (error) {
reject(error);
throw new Error(error);
} else {
resolve(logs);
}
});
});
}
}

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

@ -0,0 +1,31 @@
import Config from "../models/Config";
import OceanAuth from "./Auth";
import OceanMarket from "./Market";
import OceanToken from "./Token";
import Web3Helper from "./Web3Helper";
export default class Keeper {
public static async getInstance(config: Config, helper: Web3Helper) {
const contracts = new Keeper(config, helper);
contracts.market = await OceanMarket.getInstance(config, helper);
contracts.auth = await OceanAuth.getInstance(config, helper);
contracts.token = await OceanToken.getInstance(config, helper);
return contracts;
}
public web3Helper: Web3Helper;
public token: OceanToken;
public market: OceanMarket;
public auth: OceanAuth;
private config: Config;
private constructor(config: Config, helper: Web3Helper) {
this.config = config;
this.web3Helper = helper;
}
}

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

@ -0,0 +1,56 @@
import Asset from "../models/Asset";
import Config from "../models/Config";
import Order from "../models/Order";
import Logger from "../utils/Logger";
import ContractWrapperBase from "./ContractWrapperBase";
import Web3Helper from "./Web3Helper";
export default class OceanMarket extends ContractWrapperBase {
public static async getInstance(config: Config, web3Helper: Web3Helper) {
const market = new OceanMarket(config, "OceanMarket", web3Helper);
await market.init();
return market;
}
// call functions (costs no gas)
public async isAssetActive(assetId: string): Promise<boolean> {
return this.contract.methods.checkAsset(assetId).call;
}
public async verifyOrderPayment(orderId: string): Promise<boolean> {
return this.contract.methods.verifyPaymentReceived(orderId).call;
}
public async getAssetPrice(assetId: string): Promise<number> {
return this.contract.methods.getAssetPrice(assetId).call().then((result) => result.toNumber());
}
public async requestTokens(amount: number, receiverAddress: string): Promise<boolean> {
return this.contract.methods.requestTokens(amount).send({
from: receiverAddress,
});
}
public async registerAsset(name: string, description: string,
price: number, publisherAddress: string): Promise<string> {
const assetId = await this.contract.methods.generateId(name + description).call();
Logger.log("Registering: ", assetId);
const result = await this.contract.methods.register(assetId, price).send({
from: publisherAddress,
gas: this.config.defaultGas,
},
);
Logger.log("Registered: ", result);
return assetId;
}
public async payAsset(asset: Asset, order: Order, buyerAddress: string): Promise<boolean> {
Logger.log("Sending payment");
return this.contract.methods.sendPayment(order.id, asset.publisherId, asset.price, order.timeout).send({
from: buyerAddress,
gas: this.config.defaultGas,
});
}
}

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

@ -0,0 +1,37 @@
import Config from "../models/config";
import Logger from "../utils/Logger";
import ContractBaseWrapper from "./ContractWrapperBase";
import Web3Helper from "./Web3Helper";
export default class OceanToken extends ContractBaseWrapper {
public static async getInstance(config: Config, web3Helper: Web3Helper) {
const token = new OceanToken(config, "OceanToken", web3Helper);
await token.init();
return token;
}
public async getTokenBalance(accountAddress: string) {
return this.contract.methods.balanceOf(accountAddress).call();
}
public async getEthBalance(account: string): Promise<number> {
return new Promise<number>((resolve, reject) => {
// Logger.log("getting balance for", account);
this.web3Helper.getWeb3().eth.getBalance(account, "latest", (err: any, balance: number) => {
if (err) {
return reject(err);
}
// Logger.log("balance", balance);
resolve(balance);
});
});
}
public async approve(marketAddress: string, price: number, buyerAddress: string) {
return this.contract.methods.approve(marketAddress, price).send({
from: buyerAddress,
gas: this.config.defaultGas,
});
}
}

View File

@ -1,18 +1,29 @@
import Web3 = require("web3");
import Config from "./config";
import Config from "../models/Config";
import Logger from "../utils/Logger";
export default class Web3Helper {
public web3: Web3;
private web3: Web3;
public constructor(config: Config) {
const web3Provider = config.web3Provider || new Web3.providers.HttpProvider(config.nodeUri);
this.web3 = new Web3(web3Provider);
}
public getWeb3() {
return this.web3;
}
public getCurrentProvider() {
return this.web3.currentProvider;
}
public async getAccounts(): Promise<any[]> {
return new Promise<any[]>((resolve, reject) => {
this.web3.eth.getAccounts((err: any, accounts: string[]) => {
if (err) {
reject(err);
throw err;
}
resolve(accounts);
@ -23,25 +34,26 @@ export default class Web3Helper {
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) => {
this.web3.eth.net.getId((err, networkId) => {
if (err) {
reject(err);
throw err;
}
switch (networkId) {
case "1":
case 1:
network = "Main";
break;
case "2":
case 2:
network = "Morden";
break;
case "3":
case 3:
network = "Ropsten";
break;
case "4":
case 4:
network = "Rinkeby";
break;
case "42":
case 42:
network = "Kovan";
break;
default:
@ -56,4 +68,5 @@ export default class Web3Helper {
public sign(accountAddress: string, message: string) {
return this.web3.eth.sign(accountAddress, message);
}
}

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,5 +1,5 @@
import Config from "./utils/config";
import Logger from "./utils/logger";
import Config from "./models/Config";
import Logger from "./utils/Logger";
declare var fetch;

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

@ -0,0 +1,5 @@
export default class Asset {
public assetId: string;
public publisherId: string;
public price: number;
}

10
src/models/Order.ts Normal file
View File

@ -0,0 +1,10 @@
import Asset from "./Asset";
export default class Order {
public id: string;
public asset: Asset;
public assetId: string;
public timeout: any;
public pubkey: string;
public key: any;
}

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

@ -0,0 +1,16 @@
import Keeper from "../keeper/Keeper";
export default class Asset {
private keeper: Keeper;
constructor(keeper: Keeper) {
this.keeper = keeper;
}
public isAssetActive(assetId: string): Promise<boolean> {
const {market} = this.keeper;
return market.isAssetActive(assetId);
}
}

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

@ -0,0 +1,188 @@
import * as EthCrypto from "eth-crypto";
import EthEcies from "eth-ecies";
import * as EthjsUtil from "ethereumjs-util";
import JWT from "jsonwebtoken";
import EventListener from "../keeper/EventListener";
import Keeper from "../keeper/Keeper";
import Asset from "../models/Asset";
import OrderModel from "../models/Order";
import Logger from "../utils/Logger";
declare var fetch;
export default class Order {
private static create(asset: Asset, args, key): OrderModel {
Logger.log("keeper AccessConsentRequested event received on asset: ", asset.assetId, "\nevent:", args);
const accessId = args._id;
Logger.log("got new access request id: ", accessId);
return {
id: accessId,
assetId: asset.assetId,
asset,
timeout: args._timeout,
pubkey: args._pubKey,
key,
} as OrderModel;
}
private keeper: Keeper;
constructor(keeper: Keeper) {
this.keeper = keeper;
}
public async getOrdersByConsumer(consumerAddress: string) {
const {auth, market} = this.keeper;
const accessConsentEvent = auth.getEvent("AccessConsentRequested")({
_consumer: consumerAddress,
}, {
fromBlock: 0,
toBlock: "latest",
});
const events = await EventListener.getEvents(accessConsentEvent);
const orders = await Promise.all(events
.filter((event: any) => (event.args._consumer === consumerAddress))
.map(async (event: any) => ({
...event.args,
timeout: event.args._timeout.toNumber(),
status: await auth.getOrderStatus(event.args._id),
paid: await market.verifyOrderPayment(event.args._id),
key: null,
} as Order)));
Logger.log("Got orders: ", orders);
return orders;
}
public async purchaseAsset(asset: Asset, timeout: number, buyerAddress: string): Promise<OrderModel> {
const {token, market, auth} = this.keeper;
const key = EthCrypto.createIdentity();
const publicKey = EthjsUtil.privateToPublic(key.privateKey).toString("hex");
const price = await market.getAssetPrice(asset.assetId);
const isValid = await market.isAssetActive(asset.assetId);
Logger.log("The asset:", asset.assetId, "is it valid?", isValid, "it's price is:", price);
if (!isValid) {
throw new Error("asset not valid");
}
try {
// Allow market contract to transfer funds on the consumer"s behalf
await token.approve(market.getAddress(), price, buyerAddress);
} catch (err) {
Logger.log("token approve", err);
}
try {
// Submit the access request
await auth.initiateAccessRequest(asset, publicKey, timeout, buyerAddress);
} catch (err) {
Logger.log("initiateAccessRequest", err);
}
const resourceFilter = {
_resourceId: asset.assetId,
_consumer: buyerAddress,
};
// todo: Event - implement proper eventing
const accessConsentRequestedEvent = auth.getEvent("AccessConsentRequested")(resourceFilter);
let order: OrderModel;
const finalOrder: OrderModel = await EventListener.listenOnce(
accessConsentRequestedEvent,
"AccessConsentRequested")
.then((accessConsentRequestedResult) => {
order = Order.create(asset, accessConsentRequestedResult.args, key);
const requestIdFilter = {
_id: order.id,
};
// todo: Event - implement proper eventing
const accessCommittedEvent = auth.getEvent("AccessRequestCommitted")(requestIdFilter);
return EventListener.listenOnce(accessCommittedEvent, "AccessRequestCommitted");
})
.then((accessRequestCommittedResult) => {
return this.payAsset(asset, accessRequestCommittedResult.args, order, buyerAddress);
})
.then(() => {
const requestIdFilter = {
_id: order.id,
};
// todo: Event - implement proper eventing
const tokenPublishedEvent = auth.getEvent("EncryptedTokenPublished")(requestIdFilter);
return EventListener.listenOnce(tokenPublishedEvent, "EncryptedTokenPublished");
})
.then((result) => {
return this.finalizePurchaseAsset(
result, order, key, buyerAddress,
);
});
return finalOrder;
}
private async payAsset(asset: Asset, args, order, buyerAddress) {
const {market} = this.keeper;
// send payment
Logger.log("Sending payment: ", order.id, args._id, asset.publisherId, asset.price, order.timeout);
return market.payAsset(asset, order, buyerAddress);
}
private async finalizePurchaseAsset(args, order, key, buyerAddress): Promise<OrderModel> {
const {auth, web3Helper} = this.keeper;
// Logger.log('keeper EncryptedTokenPublished event received: ', order.id, eventResult.args)
const encryptedAccessToken = await auth.getEncryptedAccessToken(args._id, buyerAddress);
// grab the access token from acl contract
const tokenNo0x = encryptedAccessToken.slice(2);
const encryptedTokenBuffer = Buffer.from(tokenNo0x, "hex");
const privateKey = key.privateKey.slice(2);
const accessTokenEncoded = EthEcies.Decrypt(Buffer.from(privateKey, "hex"), encryptedTokenBuffer);
const accessToken = JWT.decode(accessTokenEncoded); // Returns a json object
// sign it
const hexEncrToken = `0x${encryptedTokenBuffer.toString("hex")}`;
const signature = web3Helper.sign(buyerAddress, hexEncrToken);
const fixedMsgSha = web3Helper.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: buyerAddress,
fixed_msg: fixedMsgSha,
sigEncJWT: signature,
jwt: accessTokenEncoded,
});
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);
});
Logger.log("consume url: ", accessUrl);
order.accessUrl = accessUrl;
return order;
}
}

View File

@ -1,5 +1,5 @@
import Ocean from "./ocean";
import Logger from "./utils/logger";
import Ocean from "./Ocean";
import Logger from "./utils/Logger";
export {
Ocean,

22
src/utils/Logger.ts Normal file
View File

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

24
test/Keeper.test.ts Normal file
View File

@ -0,0 +1,24 @@
import ContractHandler from "../src/keeper/ContractHandler";
import Keeper from "../src/keeper/Keeper";
import Web3Helper from "../src/keeper/Web3Helper";
import Config from "../src/models/Config";
import Logger from "../src/utils/Logger";
let keeper: Keeper;
before(async () => {
const config: Config = {nodeUri: "http://localhost:8545"} as Config;
const web3Helper = new Web3Helper(config);
await ContractHandler.deployContracts(web3Helper);
keeper = await Keeper.getInstance(config, web3Helper);
});
describe("Keeper", () => {
it("should keep", async () => {
const balance = await keeper.token.getTokenBalance("0xB0EdD05A5874c5c1Fcd6bCB4E52143fB7134b7EE");
Logger.log(balance);
});
});

8
test/tsconfig.json Normal file
View File

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

View File

@ -14,10 +14,11 @@
"sourceMap": true
},
"include": [
"src/**/*"
"src/**/*",
"test/**/*"
],
"exclude": [
"node_modules",
"**/*.spec.ts"
"**/*.test.ts"
]
}