diff --git a/.env.development b/.env.development new file mode 100644 index 0000000..048e1e3 --- /dev/null +++ b/.env.development @@ -0,0 +1,5 @@ +ENVIRONMENT=dev +PORT=3005 +SECRETS_FILE="path/to/secrets/file.json" +LOGGING_DIR="" +SOLANA_VALIDATORS_URL="http://vip-api.mainnet-beta.solana.com" diff --git a/README.md b/README.md index 04ed7f5..1bd7cc3 100644 --- a/README.md +++ b/README.md @@ -1 +1,62 @@ # serum-rest-server + +# Install + +This server uses `yarn` to manage node.js dependencies. To install dependencies, from the root directory run + +``` +yarn +``` + +to build the workspace run + +``` +yarn build +``` + +to start the server in debug mode + +``` +DEBUG=js:* yarn start +``` + +# Configuration + +Server configurations are managed with [dotenv](https://www.npmjs.com/package/dotenv). A default configuration is +provided in `.env.development`. The server looks for solana private keys in the file specified by the `SECRETS_FILE` +config. Without any further configuration to permission the server, create a file with following format, replacing +`"your_bs58_private_key"` with your base58 encoded solana private key (which you can export from sollet.io). + +```json +{ + "serum_private_key": "your_bs58_private_key" +} +``` + +Then store this file at a location of your choosing and set the `SECRETS_FILE` config to your chosen location. Note +that `dotenv` by default looks for `.env` files, so you will need to rename `.env.development` to `.env` for the +configurtation file to take effect. + +# Shell + +A node.js shell is provided for debugging purposes. Start the shell with + +``` +yarn shell +``` + +An example of fetching an orderbook for the `BTC/USDC` pair is provided below. + +``` +[~/serum-rest-server]$ yarn shell +> sapi = await SerumApi.create() +... +> await sapi.getWsOrderbook('BTC', 'USDC') +{ + bids: [...], + asks: [...], + market: Pair { coin: 'BTC', priceCurrency: 'USDC' }, + validAt: ..., + receivedAt: ... +} +``` diff --git a/src/exchange/api.ts b/src/exchange/api.ts index 3908069..f38cf23 100644 --- a/src/exchange/api.ts +++ b/src/exchange/api.ts @@ -62,6 +62,7 @@ import { } from "./solana"; import { WRAPPED_SOL_MINT } from "@project-serum/serum/lib/token-instructions"; import { parse as urlParse } from "url"; +import bs58 from "bs58"; export class SerumApi { static readonly exchange: Exchange = "serum"; @@ -115,7 +116,7 @@ export class SerumApi { this.exchange = exchange; this._connections = conections; this._privateKey = getKeys([`${this.exchange}_private_key`])[0]; - this._account = new Account(this._privateKey); + this._account = new Account(bs58.decode(this._privateKey)); this._publicKey = this._account.publicKey; this._loadedMarkets = {}; this._wsOrderbooks = {}; @@ -641,7 +642,7 @@ export class SerumApi { logger.info( `Order parameters: ${side}, ${coin}, ${priceCurrency}, ${quantity}, ${price}, ${orderType}` ); - const owner = new Account(this._privateKey); + const owner = this._account; let payer; if (coin === "SOL" && side === Dir.S) { payer = this._publicKey; @@ -808,7 +809,7 @@ export class SerumApi { new BN(orderId) ); txn.add(market.makeMatchOrdersTransaction(5)); - const signers = [new Account(this._privateKey)]; + const signers = [this._account]; return { transaction: txn, signers, @@ -861,7 +862,7 @@ export class SerumApi { order.info.toSerumOrder() ); transaction.add(serumMarket.makeMatchOrdersTransaction(5)); - const signers = [new Account(this._privateKey)]; + const signers = [this._account]; return { transaction, signers, @@ -1366,7 +1367,7 @@ export class SerumApi { market .settleFunds( this._connection, - new Account(this._privateKey), + this._account, openOrders, baseTokenAccount, quoteTokenAccount diff --git a/src/exchange/config.ts b/src/exchange/config.ts index c00e8e2..e0ff1b7 100644 --- a/src/exchange/config.ts +++ b/src/exchange/config.ts @@ -3,7 +3,9 @@ import { HARD_CODED_MINTS } from "../config"; import { Pair } from "./types"; import { PublicKey } from "@solana/web3.js"; -export const MARKET_PARAMS = MARKETS.filter(marketInfo => !marketInfo.deprecated).map((marketInfo) => { +export const MARKET_PARAMS = MARKETS.filter( + (marketInfo) => !marketInfo.deprecated +).map((marketInfo) => { const [coin, priceCurrency] = marketInfo.name.split("/"); return { address: marketInfo.address,