From 9b7e39c8feb0552ddf95dfbe04671f94fa215e1c Mon Sep 17 00:00:00 2001 From: Gary Wang Date: Thu, 13 Aug 2020 12:45:16 -0700 Subject: [PATCH] Add method for retrieving fills --- README.md | 12 +++++++++++- package.json | 2 +- src/market.ts | 29 +++++++++++++++++++++++++++ src/queue.ts | 54 ++++++++++++++++++++++++++++++++++++++------------- 4 files changed, 82 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index 63c64f4..a8e13a2 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ WIP `yarn add @project-serum/serum` ```js -import { Connection, PublicKey } from '@solana/web3.js'; +import { Account, Connection, PublicKey } from '@solana/web3.js'; import { Market } from '@project-serum/serum'; let connection = new Connection('https://testnet.solana.com'); @@ -45,4 +45,14 @@ for (let order of await market.loadBids(connection)) { await market.cancelOrder(connection, owner, order); } } + +for (let fill of await market.loadFills(connection)) { + console.log( + fill.orderId, + fill.owner.toBase58(), + fill.price, + fill.size, + fill.side, + ); +} ``` diff --git a/package.json b/package.json index a02af49..777169f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@project-serum/serum", - "version": "0.3.2", + "version": "0.3.3", "description": "Library for interacting with the serum dex", "license": "MIT", "repository": "project-serum/serum-js", diff --git a/src/market.ts b/src/market.ts index c8cb4f8..93f35bd 100644 --- a/src/market.ts +++ b/src/market.ts @@ -272,6 +272,35 @@ export class Market { return decodeEventQueue(data); } + async loadFills(connection: Connection, limit = 100) { + // TODO: once there's a separate source of fills use that instead + const { data } = throwIfNull( + await connection.getAccountInfo(this._decoded.eventQueue), + ); + const events = decodeEventQueue(data, limit); + return events + .filter((event) => event.eventFlags.fill && event.quantityPaid.gtn(0)) + .map((event) => + event.eventFlags.bid + ? { + ...event, + size: this.baseSizeLotsToNumber(event.quantityReleased), + price: this.priceLotsToNumber( + event.quantityPaid.divRound(event.quantityReleased), + ), + side: 'buy', + } + : { + ...event, + size: this.baseSizeLotsToNumber(event.quantityPaid), + price: this.priceLotsToNumber( + event.quantityReleased.divRound(event.quantityPaid), + ), + side: 'sell', + }, + ); + } + private get _baseSplTokenMultiplier() { return new BN(10).pow(new BN(this._baseSplTokenDecimals)); } diff --git a/src/queue.ts b/src/queue.ts index c5b7a10..761c704 100644 --- a/src/queue.ts +++ b/src/queue.ts @@ -69,34 +69,62 @@ export interface Event { owner: PublicKey; } -function decodeQueue(headerLayout, nodeLayout, buffer) { +function decodeQueue( + headerLayout, + nodeLayout, + buffer: Buffer, + history?: number, +) { const header = headerLayout.decode(buffer); const allocLen = Math.floor( (buffer.length - headerLayout.span) / nodeLayout.span, ); const nodes: any[] = []; - for (let i = 0; i < header.count; ++i) { - const nodeIndex = (header.head + i) % allocLen; - nodes.push( - nodeLayout.decode( - buffer, - headerLayout.span + nodeIndex * nodeLayout.span, - ), - ); + if (history) { + for (let i = 0; i < Math.min(history, allocLen); ++i) { + const nodeIndex = + (header.head + header.count + allocLen - 1 - i) % allocLen; + nodes.push( + nodeLayout.decode( + buffer, + headerLayout.span + nodeIndex * nodeLayout.span, + ), + ); + } + } else { + for (let i = 0; i < header.count; ++i) { + const nodeIndex = (header.head + i) % allocLen; + nodes.push( + nodeLayout.decode( + buffer, + headerLayout.span + nodeIndex * nodeLayout.span, + ), + ); + } } return { header, nodes }; } -export function decodeRequestQueue(buffer: Buffer) { - const { header, nodes } = decodeQueue(REQUEST_QUEUE_HEADER, REQUEST, buffer); +export function decodeRequestQueue(buffer: Buffer, history?: number) { + const { header, nodes } = decodeQueue( + REQUEST_QUEUE_HEADER, + REQUEST, + buffer, + history, + ); if (!header.accountFlags.initialized || !header.accountFlags.requestQueue) { throw new Error('Invalid requests queue'); } return nodes; } -export function decodeEventQueue(buffer: Buffer): Event[] { - const { header, nodes } = decodeQueue(EVENT_QUEUE_HEADER, EVENT, buffer); +export function decodeEventQueue(buffer: Buffer, history?: number): Event[] { + const { header, nodes } = decodeQueue( + EVENT_QUEUE_HEADER, + EVENT, + buffer, + history, + ); if (!header.accountFlags.initialized || !header.accountFlags.eventQueue) { throw new Error('Invalid events queue'); }