Skip to content
This repository has been archived by the owner on Oct 11, 2024. It is now read-only.

Implement getOrdersAsync getOrdersForPageAsync for browsers #655

Merged
merged 4 commits into from
Jan 21, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ This changelog is a work in progress and may contain notes for versions which ha
- Implemented custom order filters, which allow users to filter out all but the orders they care about. When a custom order filter is specified, Mesh will only send and receive orders that pass the filter. ([#630](https://github.com/0xProject/0x-mesh/pull/630)).
- Developers can now override the contract addresses for any testnet using the `CUSTOM_CONTRACT_ADDRESSES` env config ([#640](https://github.com/0xProject/0x-mesh/pull/640)).
- Added `getOrdersForPageAsync` method to `@0x/mesh-rpc-client` WS client interface so that clients can paginate through the retrieved orders themselves ([#642](https://github.com/0xProject/0x-mesh/pull/642)).
- Added `getStatsAsync` to the `@0x/mesh-browser` package. This exposes the `getStats` method to browser users. ([#654](https://github.com/0xProject/0x-mesh/pull/654)).
- Added `getStatsAsync` to the `@0x/mesh-browser` package. ([#654](https://github.com/0xProject/0x-mesh/pull/654)).
- Added `getOrdersAsync` and `getOrdersForPageAsync` to the `@0x/mesh-browser` package. ([#655](https://github.com/0xProject/0x-mesh/pull/655)).


## v8.1.1
Expand Down
23 changes: 23 additions & 0 deletions browser/go/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,17 @@ func (cw *MeshWrapper) GetStats() (js.Value, error) {
return js.ValueOf(stats), nil
}

// GetOrders converts raw JavaScript parameters into the appropriate type, calls
// core.App.GetOrders, converts the result into basic JavaScript types (string,
// int, etc.) and returns it.
func (cw *MeshWrapper) GetOrders(page int, perPage int, snapshotID string) (js.Value, error) {
ordersResponse, err := cw.app.GetOrders(page, perPage, snapshotID)
if err != nil {
return js.Undefined(), err
}
return js.ValueOf(ordersResponse), nil
}

// JSValue satisfies the js.Wrapper interface. The return value is a JavaScript
// object consisting of named functions. They act like methods by capturing the
// MeshWrapper through a closure.
Expand Down Expand Up @@ -269,6 +280,18 @@ func (cw *MeshWrapper) JSValue() js.Value {
return cw.GetStats()
})
}),
// getOrdersForPageAsync(page: number, perPage: number, snapshotID?: string): Promise<GetOrdersResponse>
"getOrdersForPageAsync": js.FuncOf(func(this js.Value, args []js.Value) interface{} {
return wrapInPromise(func() (interface{}, error) {
// snapshotID is optional in the JavaScript function. Check if it is
// null or undefined.
snapshotID := ""
if !isNullOrUndefined(args[2]) {
snapshotID = args[2].String()
}
return cw.GetOrders(args[0].Int(), args[1].Int(), snapshotID)
})
}),
// addOrdersAsync(orders: Array<SignedOrder>): Promise<ValidationResults>
"addOrdersAsync": js.FuncOf(func(this js.Value, args []js.Value) interface{} {
return wrapInPromise(func() (interface{}, error) {
Expand Down
102 changes: 102 additions & 0 deletions browser/ts/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,30 @@ export interface Stats {
ethRPCRateLimitExpiredRequests: number;
}

interface WrapperOrderInfo {
orderHash: string;
signedOrder: WrapperSignedOrder;
fillableTakerAssetAmount: string;
}

export interface OrderInfo {
orderHash: string;
signedOrder: SignedOrder;
fillableTakerAssetAmount: BigNumber;
}

interface WrapperGetOrdersResponse {
snapshotID: string;
snapshotTimestamp: number;
ordersInfos: WrapperOrderInfo[];
}

export interface GetOrdersResponse {
snapshotID: string;
snapshotTimestamp: number;
ordersInfos: OrderInfo[];
}

export enum Verbosity {
Panic = 0,
Fatal = 1,
Expand All @@ -275,6 +299,7 @@ interface MeshWrapper {
onError(handler: (err: Error) => void): void;
onOrderEvents(handler: (events: WrapperOrderEvent[]) => void): void;
getStatsAsync(): Promise<WrapperStats>;
getOrdersForPageAsync(page: number, perPage: number, snapshotID?: string): Promise<WrapperGetOrdersResponse>;
addOrdersAsync(orders: WrapperSignedOrder[], pinned: boolean): Promise<WrapperValidationResults>;
}

Expand Down Expand Up @@ -761,6 +786,66 @@ export class Mesh {
return wrapperStatsToStats(wrapperStats);
}

/**
* Get all 0x signed orders currently stored in the Mesh node
* @param perPage number of signedOrders to fetch per paginated request
* @returns the snapshotID, snapshotTimestamp and all orders, their hashes and fillableTakerAssetAmounts
*/
public async getOrdersAsync(perPage: number = 200): Promise<GetOrdersResponse> {
await waitForLoadAsync();
if (this._wrapper === undefined) {
// If this is called after startAsync, this._wrapper is always
// defined. This check is here just in case and satisfies the
// compiler.
return Promise.reject(new Error('Mesh is still loading. Try again soon.'));
}

let snapshotID = ''; // New snapshot

// TODO(albrow): De-dupe this code with the method by the same name
// in the TypeScript RPC client.
let page = 0;
let getOrdersResponse = await this.getOrdersForPageAsync(page, perPage, snapshotID);
snapshotID = getOrdersResponse.snapshotID;
let ordersInfos = getOrdersResponse.ordersInfos;

let allOrderInfos: OrderInfo[] = [];

do {
allOrderInfos = [...allOrderInfos, ...ordersInfos];
page++;
getOrdersResponse = await this.getOrdersForPageAsync(page, perPage, snapshotID);
ordersInfos = getOrdersResponse.ordersInfos;
} while (ordersInfos.length > 0);
fabioberger marked this conversation as resolved.
Show resolved Hide resolved

getOrdersResponse = {
snapshotID,
snapshotTimestamp: getOrdersResponse.snapshotTimestamp,
ordersInfos: allOrderInfos,
};
return getOrdersResponse;
}

/**
* Get page of 0x signed orders stored on the Mesh node at the specified snapshot
* @param page Page index at which to retrieve orders
* @param perPage Number of signedOrders to fetch per paginated request
* @param snapshotID The DB snapshot at which to fetch orders. If omitted, a new snapshot is created
* @returns the snapshotID, snapshotTimestamp and all orders, their hashes and fillableTakerAssetAmounts
*/
public async getOrdersForPageAsync(page: number, perPage: number, snapshotID?: string): Promise<GetOrdersResponse> {
await waitForLoadAsync();
if (this._wrapper === undefined) {
// If this is called after startAsync, this._wrapper is always
// defined. This check is here just in case and satisfies the
// compiler.
return Promise.reject(new Error('Mesh is still loading. Try again soon.'));
}

const wrapperOrderResponse = await this._wrapper.getOrdersForPageAsync(page, perPage, snapshotID);
return wrapperGetOrdersResponseToGetOrdersResponse(wrapperOrderResponse);
}

/**
* Validates and adds the given orders to Mesh. If an order is successfully
* added, Mesh will share it with any peers in the network and start
Expand Down Expand Up @@ -1003,6 +1088,23 @@ function wrapperStatsToStats(wrapperStats: WrapperStats): Stats {
};
}

function wrapperGetOrdersResponseToGetOrdersResponse(
wrapperGetOrdersResponse: WrapperGetOrdersResponse,
): GetOrdersResponse {
return {
...wrapperGetOrdersResponse,
ordersInfos: wrapperGetOrdersResponse.ordersInfos.map(wrapperOrderInfoToOrderInfo),
};
}

function wrapperOrderInfoToOrderInfo(wrapperOrderInfo: WrapperOrderInfo): OrderInfo {
return {
...wrapperOrderInfo,
fillableTakerAssetAmount: new BigNumber(wrapperOrderInfo.fillableTakerAssetAmount),
signedOrder: wrapperSignedOrderToSignedOrder(wrapperOrderInfo.signedOrder),
};
}

function wrapperValidationResultsToValidationResults(
wrapperValidationResults: WrapperValidationResults,
): ValidationResults {
Expand Down
11 changes: 11 additions & 0 deletions common/types/types_js.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,14 @@ func (s *Stats) JSValue() js.Value {
statsJS := js.Global().Get("JSON").Call("parse", string(encodedStats))
return statsJS
}

func (r *GetOrdersResponse) JSValue() js.Value {
// TODO(albrow): Optimize this. Remove other uses of the JSON
// encoding/decoding hack.
encodedResponse, err := json.Marshal(r)
if err != nil {
panic(err)
}
responseJS := js.Global().Get("JSON").Call("parse", string(encodedResponse))
return responseJS
}
21 changes: 18 additions & 3 deletions integration-tests/browser/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,9 +63,24 @@ provider.start();
// canceled, or filled. We will check for certain events to be logged in the
// integration tests.
mesh.onOrderEvents((events: Array<OrderEvent>) => {
for (let event of events) {
console.log(JSON.stringify(event));
}
(async () => {
for (let event of events) {
// Check the happy path for getOrdersForPageAsync. There should
// be two orders. (just make sure it doesn't throw/reject).
const firstOrdersResponse = await mesh.getOrdersForPageAsync(0, 1, '');
console.log(JSON.stringify(firstOrdersResponse));
const secondOrdersResponse = await mesh.getOrdersForPageAsync(1, 1, firstOrdersResponse.snapshotID);
console.log(JSON.stringify(secondOrdersResponse));

// Check the happy path for getOrders (just make sure it
// doesn't throw/reject).
await mesh.getOrdersAsync();

// Log the event. The Go code will be watching the logs for
// this.
console.log(JSON.stringify(event));
}
})().catch(err => console.error(err));
});

// Start Mesh *after* we set up the handlers.
Expand Down