Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

kosu.js: implement a go-kosu JSONRPC client (the NodeClient) #229

Merged
merged 18 commits into from Aug 23, 2019
Merged
Changes from 1 commit
Commits
File filter...
Filter file types
Jump to…
Jump to file or symbol
Failed to load files and symbols.

Always

Just for now

Next

initial node RPC client implementation

  • Loading branch information
hrharder committed Aug 22, 2019
commit ba893b7cdfa56c26108ecd3a22f0acfb6a67472d
@@ -27,6 +27,7 @@
},
"dependencies": {
"@0x/utils": "^4.3.1",
"@0x/web3-providers-fork": "^0.0.7",
"@0x/web3-wrapper": "^6.0.5",
"@babel/core": "^7.4.4",
"@kosu/system-contracts": "^0.1.6",
@@ -37,13 +38,15 @@
"ethereumjs-util": "^5.2.0",
"isomorphic-ws": "^4.0.1",
"node-fetch": "^2.2.0",
"uuid": "^3.3.3",
"web3": "1.2.0",
"web3-provider-engine": "15.0.0",
"web3-utils": "1.2.0",
"ws": "^6.1.4"
"ws": "^7.1.2"
},
"devDependencies": {
"@istanbuljs/nyc-config-typescript": "^0.1.3",
"@types/ws": "^6.0.2",
"nyc": "^14.1.1",
"simple-mock": "^0.8.0",
"source-map-support": "^0.5.12",
@@ -0,0 +1,114 @@
import { WebsocketProvider, WebsocketProviderOptions } from "@0x/web3-providers-fork";
import uuid from "uuid/v4";

export class NodeClient {
public static DEFAULT_OPTIONS: WebsocketProviderOptions = { timeout: 3000 };

private readonly _provider: WebsocketProvider;
private readonly _heartbeatInterval: number;
private readonly _subscriptionIdMap: { [uuid: string]: string };

private static _convertValidatorData(rawValidators: any[]): Validator[] {
const validators = [];
for (const validator of rawValidators) {
const balance = parseInt(validator.balance.split(": "));
validators.push({ ...validator, balance });
}
return validators;
}

constructor(url: string, options?: WebsocketProviderOptions) {
this._provider = new WebsocketProvider(url, options || NodeClient.DEFAULT_OPTIONS);
this._subscriptionIdMap = {};
}

public async addOrders(...orders: any[]): Promise<OrderValidationResult[]> {
return this._call("kosu_addOrders", ...orders);
}

public async latestHeight(): Promise<number> {
return this._call("kosu_latestHeight");
}

public async numberPosters(): Promise<number> {
return this._call("kosu_numberPosters");
}

public async queryPoster(address: string): Promise<Poster> {
if (/^0x[a-fA-F0-9]{40}$/.test(address)) {
throw new Error("invalid Ethereum address string");
}
return this._call("kosu_queryPoster", address.toLowerCase());
}

public async queryValidator(nodeId: string): Promise<Validator> {
if (/^[a-fA-F0-9]{40}$/.test(nodeId)) {
throw new Error("invalid validator node ID string");
}

// hack: dealing with protobuf decoding issues
const raw = await this._call("kosu_queryValidator", nodeId);
const balance = parseInt(raw.balance.split(": "));
return { ...raw, balance };
}

public async remainingLimit(): Promise<number> {
return this._call("kosu_remainingLimit");
}

public async roundInfo(): Promise<RoundInfo> {
const {
number: num,
limit,
starts_at: startsAt,
ends_at: endsAt,
} = await this._call("kosu_roundInfo");
return { number: num, limit, startsAt, endsAt };
}

public async totalOrders(): Promise<number> {
return this._call("kosu_totalOrders");
}

public async validators(): Promise<Validator[]> {
const rawValidators = this._call("kosu_validators");
return NodeClient._convertValidatorData(rawValidators as unknown as any[]);
}

public async subscribeToOrders(cb: (orders: any[]) => void): Promise<string> {
const id = await this._subscribe("newOrders");
const subId = this._subscriptionIdMap[id];
this._provider.on(subId, cb as any);
return id;
}

public async subscribeToBlocks(cb: (orders: any[]) => void): Promise<string> {
const id = await this._subscribe("newBlocks");
const subId = this._subscriptionIdMap[id];
this._provider.on(subId, cb as any);
return id;
}

public async subscribeToRebalances(cb: (orders: any[]) => void): Promise<string> {
const id = await this._subscribe("newRebalances");
const subId = this._subscriptionIdMap[id];
this._provider.on(subId, cb as any);
return id;
}

public async unsubscribe(subscriptionId: string): Promise<void> {
const kosuSubscriptionId = this._subscriptionIdMap[subscriptionId];
await this._call("kosu_unsubscribe", kosuSubscriptionId);
}

private async _call(method: string, ...params: any[]): Promise<any> {
return this._provider.send(method, params || []);
}

private async _subscribe(topic: string): Promise<string> {
const kosuSubscriptionId = await this._provider.subscribe("kosu_subscribe", topic, []);
const mappingId = uuid();
this._subscriptionIdMap[mappingId] = kosuSubscriptionId;
return mappingId;
}
}
@@ -11,3 +11,4 @@ export { NULL_ADDRESS, toBytes32 } from "./utils";
export { ValidatorRegistry } from "./ValidatorRegistry";
export { Voting } from "./Voting";
export { OrderSerializer } from "./OrderSerializer";
export { NodeClient } from "./NodeClient";
@@ -49,10 +49,44 @@ interface Signature {
sign(web3: Web3, messageHex: string, signer: string): Promise<string>;
}

interface DecodedKosuLogArgs {}
interface DecodedKosuLogArgs { }

interface LogWithDecodedKosuArgs<A, B> extends LogWithDecodedArgs {
event: string;
args: A;
decodedArgs: B;
}

interface OrderValidationResult {
accepted: string[];
rejected: OrderRejectionInfo[];
}

interface OrderRejectionInfo {
order: string;
reason: string;
}

interface Poster {
balance: number;
limit: number;
}

interface Validator {
balance: number;
power: number;
publicKey: string;
firstVote: number;
lastVoted: number;
lastProposed: number;
totalVotes: number;
active: number;
applied: number;
}

interface RoundInfo {
number: number;
startsAt: number;
endsAt: number;
limit: number;
}
@@ -6,7 +6,13 @@
"resolveJsonModule": true,
"sourceMap": true,
"moduleResolution": "node",
"typeRoots": ["node_modules/@types"]
"typeRoots": [
"node_modules/@types",
"node_modules/@0x/typescript-typings/types"
]
},
"include": ["./src/**/*", "../kosu-system-contracts/src/types.d.ts"]
}
"include": [
"./src/**/*",
"../kosu-system-contracts/src/types.d.ts"
]
}
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.