Javascript Client for the Hydro API
A client written in Typescript for interacting with the Hydro API
New in version 2.x
- Updated functions to match new Hydro API specs
- Added support for market orders
- Added convenience functions for wrapping eth and approving tokens
What is the Hydro Protocol?
Hydro Protocol is an open-source framework for building decentralized exchanges on Ethereum. Hydro is designed for developers looking to build decentralized exchanges without having to deal with the complexity and expense of designing, deploying, and securing their own smart contracts.
For more information, please visit https://www.hydroprotocol.io/
What is this Client for?
The Client is built to provide easy access to the Hydro API. The API is intended to give you full access to the state of the market, and to help you easily create new orders based on that information. Using this API, you can write helpers to visualize the market data however you like, clients to help you create orders more easily, or full on bots that will analyze the incoming data and place orders automatically.
By default, this Client connects to the DDEX exchange, but is compatible with any exchange running the Hydro API.
For full API specs, please see the documentation: https://docs.ddex.io/
Getting Started
To get started, simply install the package through npm:
npm i @hydro-protocol/hydro-client-js
Once you've done that there are two main interfaces into the API.
HydroClient
HydroClient is used to query the API for data. Initialize it with your private key to start making API calls.
import { HydroClient } from "@hydro-protocol/hydro-client-js";
let client = HydroClient.withPrivateKey("0x..."); // Your private key here
// Get a list of all markets and their details
let markets = await client.listMarkets();
// Create, sign, and submit a market order for HOT
let order = await client.createOrder("HOT-WETH", "buy", "market", "0.01", "100");
Instantiating a client
Method | Notes |
---|---|
HydroClient.withoutAuth(
options?: HydroClientOptions,
) |
Returns an unauthenticated instance of the HydroClient. This instance can query any public API method but will throw if you try to query any private methods. |
HydroClient.withPrivateKey(
privatekey: string,
options?: HydroClientOptions,
) |
Returns an authenticated instance of the HydroClient using the provided Private Key to sign messages and transactions. |
HydroClient.withCustomAuth(
address: string,
sign: (message: string) => Promise<string>,
signTransaction: (tx: Transaction) => Promise<string>,
options?: HydroClientOptions,
) |
If you are uncomfortable passing your private key directly to the client code, you can implement your own custom authentication using whatever tools you like. You will need to provide: The address of the wallet A sign method which returns a Promise resolving to a string representing the signature of the message in hex. A signTransaction method which returns a Promise resolving to a string representing the signature of the transaction in hex. |
Each instantiation method takes an options object with the following parameters:
HydroClientOptions
Parameter | Type | Notes |
---|---|---|
apiUrl | string | The url to the Hydro API you wish to query. This defaults to the DDEX exchange running on mainnet: https://api.ddex.io/v3/ |
web3Url | string | The url to use to query the blockchain. This is required if you wish to use the blockchain helper methods. Recommended to register an account on Infura and use the mainnet url provided to your account. |
Using the HydroClient to query the API
HydroClient was built to largely mirror the actual Hydro API, so if you see a method in the API docs you should be able to find a way to call it from HydroClient. Here is a brief rundown of available API calls.
Public
These methods do not need a valid signature in order to return data, and can be called without an authenticated HydroClient instance. Public Rest API.
Method | API Docs Link |
---|---|
listMarkets() |
List Markets |
getMarket(marketId: string) |
Get a Market |
listTickers() |
List Tickers |
getTicker(marketId: string) |
Get a Ticker |
getOrderbook(marketId: string, level?: number) |
Get Orderbook |
listTrades(
marketId: string,
page?: number,
perPage?: number,
) |
List Trades |
listCandles(
marketId: string,
from: number,
to: number,
granularity: number,
) |
List Candles |
calculateFees(
marketId: string,
price: string,
amount: string,
) |
Calculate Fees |
Private
These methods return data tied to a specific account, and therefore require an authenticated HydroClient instance. Private Rest API.
Method | API Docs Link |
---|---|
buildOrder(
marketId: string,
side: string,
orderType: string,
price: string,
amount: string,
expires?: number,
) |
Build Unsigned Order |
placeOrder(orderId: string, signature: string) |
Place Order |
createOrder(
marketId: string,
side: string,
orderType: string,
price: string,
amount: string,
expires?: number,
) |
Convenience method. Will build, sign, and place the order in one step. See Build Unsigned Order for parameter details. |
cancelOrder(orderId: string) |
Cancel Order |
listOrders(
marketId?: string,
status?: string,
page?: number,
perPage?: number,
) |
List Orders |
getOrder(orderId: string) |
Get Order |
listAccountTrades(
marketId: string,
page?: number,
perPage?: number,
) |
List Account Trades |
listLockedBalances() |
List Locked Balances |
getLockedBalance(symbol: string) |
Get Locked Balance |
Blockchain
These methods do not query the Hydro API directly, but instead perform actions directly against the blockchain. As these actions will be tied to your account, you must use an authenticated HydroClient instance.
Method | API Docs Link |
---|---|
getBalance(symbol?: string) |
Returns the balance in your account for the token specified by the given symbol. If no symbol is passed it will return your account's ETH balance. |
wrapEth(amount: string, wait?: boolean) |
Wraps the specified amount of ETH into WETH for trading on the Hydro API. If wait is true, the Promise will only resolve once the transaction has been confirmed on the blockchain. See Wrapping Ether for details. |
unwrapEth(amount: string, wait?: boolean) |
Unwraps the specified amount of WETH back into ETH. If wait is true, the Promise will only resolve once the transaction has been confirmed on the blockchain. See Wrapping Ether for details. |
isTokenEnabled(symbol: string) |
Returns whether this token has been enabled for sale on the Hydro API. |
enableToken(symbol: string, wait?: boolean) |
Enables this token for sale on the Hydro API. If wait is true, the Promise will only resolve once the transaction has been confirmed on the blockchain. See Enabling Token Trading for details. |
disableToken(symbol: string, wait?: boolean) |
Disables this token for sale on the Hydro API. If wait is true, the Promise will only resolve once the transaction has been confirmed on the blockchain. See Enabling Token Trading for details. |
HydroWatcher
Our other API interface is HydroWatcher, which is used to get live updates about the state of the market. It will connect to our websocket endpoint and notify you about any changes to the exchange that you are subscribed to. All of this data is public, so no authentication is required. Websocket API.
import { HydroWatcher } from "@hydro-protocol/hydro-client-js"
let watcher = new HydroWatcher({
// Listen for changes to the HOT-WETH ticker and post them to the console.
tickerUpdate: (ticker) => console.log(ticker),
})
watcher.subscribe("ticker", ["HOT-WETH"])
Instantiating a watcher
Method | Notes |
---|---|
new HydroWatcher(
listener: HydroListener,
options?: HydroWatcherOptions,
) |
Returns a HydroWatcher object with which you can use to subscribe to whichever channels you are interested in. |
Listeners for events must be provided in the HydroWatcher constructor via the listener parameter. This is a HydroListener object, which lets you provide callback functions for various events. The object has the following parameters:
HydroListener
Parameter | Callback parameters | Notes |
---|---|---|
subscriptionsUpdate |
(
channels: Channel[],
) |
Received whenever you subscribe or unsubscribe. Passes the current list of channels and market ids you are watching. |
tickerUpdate |
(
ticker: Ticker,
) |
Received when subscribed to a ticker channel and ticker data is updated. |
orderbookSnapshot |
(
orderbook: Orderbook,
) |
Received when subscribed to the orderbook channel right after you subscribe. Passes a full snapshot of the current orderbook. |
orderbookUpdate |
(
side: Side,
priceLevel: PriceLevel,
) |
Received when subscribed to the orderbook channel and there are changes to the orderbook. Passes which side the change occurred on, and the new pricing information. |
fullSnapshot |
(
orderbook: Orderbook,
sequence: number,
) |
Received when subscribed to the full channel right after you subscribe. Passes a full snapshot of the current orderbook, and the current sequence number. |
orderReceived |
(
order: Order,
sequence: number,
time: Date,
) |
Received when subscribed to the full channel and a new order has been created. Passes the order, the current sequence number, and the time the order was created. |
orderOpened |
(
order: Order,
sequence: number,
time: Date,
) |
Received when subscribed to the full channel and a new order has been created, but not immediately fulfilled. Passes the order, the current sequence number, and the time the order was created. |
orderDone |
(
order: Order,
sequence: number,
time: Date,
) |
Received when subscribed to the full channel and an order is being taken off the orderbook, either due to being completely fulfilled or because it was cancelled. Passes the order, the current sequence number, and the time the order was removed. |
orderChanged |
(
order: Order,
sequence: number,
time: Date,
) |
Received when subscribed to the full channel and an order is being updated with new data, usually because it was partially fulfilled. Passes the order, the current sequence number, and the time the order was changed. |
tradeBegin |
(
trade: Trade,
sequence: number,
time: Date,
) |
Received when subscribed to the full channel and two orders have been matched, creating a trade. Passes the trade, the current sequence number, and the time the trade was created. |
tradeSuccess |
(
trade: Trade,
sequence: number,
time: Date,
) |
Received when subscribed to the full channel and a trade has been successfully validated on the blockchain. Passes the trade, the current sequence number, and the time the trade was validated. |
The HydroWatcher constructor takes an options object with the following parameters:
HydroClientOptions
Parameter | Type | Notes |
---|---|---|
websocketUrl | string | The websocket url to the Hydro API you wish to query. This defaults to the DDEX exchange running on mainnet: wss://ws.ddex.io/v3 |
Subscribing
Once you have a HydroWatcher instance defined with callbacks for the events you wish to handle, you must Subscribe to a channel in order to receive any data. You subscribe by specifying a channel, which defines the type of data you want to receive, and a list of market ids, which filters the events to only include data from those markets. Subscription is handled by the following call:
Method | Notes |
---|---|
subscribe(
channel: string,
marketIds: string[],
) |
Notify the watcher that you wish to recieve data for a channel with the passed set of market ids. |
Unsubscribing
If you no longer wish to receive data from a channel, you must Unsubscribe. Unsubscription is handled by the following call:
Method | Notes |
---|---|
unsubscribe(
channel: string,
marketIds: string[],
) |
Notify the watcher that you no longer wish to recieve data for a channel with the passed set of market ids. |
Channel types
There are a few different channels you can subscribe to, as defined in the API.
Channel | API Docs Link |
---|---|
ticker | Ticker - Price updates on a market. |
orderbook | Orderbook - Aggregated orderbook data for a market. |
full | Full - Details on all orders and trades for a market. |