NAV Navbar
javascript
  • Introduction
  • Public Rest API
  • Private Rest API
  • Websocket
  • Examples
  • Introduction

    Welcome to the Hydro API.

    Our API is similar to major exchanges such as gdax and binance, but as our exchange is decentralized there are a few key differences:

    Endpoints

    Rest API Endpoint

    https://api.ddex.io/v3

    Websocket Endpoint

    wss://ws.ddex.io/v3

    SDK

    We've provided a javascript SDK to get you started. You can view the Github project, or simply install it via npm:

    npm i @hydro-protocol/sdk

    ChangeLog

    General Changes

    1. Bump api version to v3. We will stop supporting calls to v2 in early January 2019.
    2. The v2 API was using base and quote terminology incorrectly. The quoteToken should be the reference token, in most cases WETH or DAI. The baseToken should be the token that is quoted in relation to the quoteToken, meaning the general ERC20 token you wish to trade against WETH or DAI, such as HOT. We have updated the API to correct for this.
    3. For consistency, we now use WETH instead of ETH in marketId.
    4. Added support for market orders.

    Market API Changes

    1. Fee rates for makers and takers are now returned as asMakerFeeRate and asTakerFeeRate.
    2. Gas fees for the current market in baseToken are now returned as gasFeeAmount
    3. There is no longer an upper bound for order size, so the field maxOrderSize has been removed.

    Build Unsigned Order API Changes

    1. Hydro-DDEX now supports both limit and market orders. Use orderType to specify the type of order.
    2. The response has changed significantly for Hydro-DDEX. Check out Build Unsigned Order for more details.

    Sign/Place Order API Changes

    1. Hydro-DDEX now supports EIP712 signing. Use method to specify how the order was signed.

    Note: For API users, we recommend continuing to sign with EthSign. EIP712 signing is mainly an improvement for UI users (e.g. MetaMask). For more detail please read EIP-712.

    Public Rest API

    Introduction

    These are API calls that do not require any user authentication to perform. They will generally give you information about the public state of the market.

    List Markets

    Response

    {
      "status": 0,
      "desc": "success",
      "data": {
        "markets": [
          {
            "id": "ABT-WETH",
            "baseToken": "ABT",
            "baseTokenProjectUrl": "https://www.arcblock.io/",
            "baseTokenName": "ArcBlock",
            "baseTokenDecimals": 18,
            "baseTokenAddress": "0xb98d4c97425d9908e66e53a6fdf673acca0be986",
            "quoteToken": "WETH",
            "quoteTokenDecimals": 18,
            "quoteTokenAddress": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2",
            "minOrderSize": "100.000000000000000000",
            "pricePrecision": 5,
            "priceDecimals": 8,
            "amountDecimals": 8,
            "asMakerFeeRate": "0.00100",
            "asTakerFeeRate": "0.00200",
            "gasFeeAmount": "0.0015",
            "supportedOrderTypes": ["limit", "market"]
          },
          ...
        ]
      }
    }
    

    Returns all active markets.

    HTTP Request

    GET https://api.ddex.io/v3/markets

    Details

    The value returned for minOrderSize represents the lower bound for the amount of baseToken you can specify in a single order.

    Both baseToken and quoteToken give you the contract address of the token, as well as the number of decimals used by the token.

    Price is limited to a precision value in pricePrecision which is the maximum amount of digits in a number. For example, if the precision is 4, a price of "0.000124" is valid, but a price of "1.9029" is not.

    Both price and amount have a minimum unit, as defined in priceDecimals and amountDecimals. Any value specified must not have an increment smaller than the minimum defined unit. For example if priceDecimals is 2, a price of "0.01" is valid, but a price of "1.001" is not.

    Each market defines the fee rate for makers and takers with asMakerFeeRate and asTakerFeeRate

    The estimated amount of gas in quoteToken needed to fill an order is defined in gasFeeAmount. Note that this value is just an estimate and may change as Etherum prices fluctuate.

    The order types supported by a market are found in supportedOrderTypes. Possible values are limit and market.

    Get a Market

    Response

    {
      "status": 0,
      "desc": "success",
      "data": {
        "market": {
          "id": "ZRX-WETH",
          "baseToken": "ZRX",
          "baseTokenProjectUrl": "",
          "baseTokenName": "",
          "baseTokenDecimals": 18,
          "baseTokenAddress": "0xe41d2489571d322189246dafa5ebde1f4699f498",
          "quoteToken": "WETH",
          "quoteTokenDecimals": 18,
          "quoteTokenAddress": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2",
          "minOrderSize": "0.000100000000000000",
          "pricePrecision": 5,
          "priceDecimals": 8,
          "amountDecimals": 8,
          "asMakerFeeRate": "0.00100",
          "asTakerFeeRate": "0.00200",
          "gasFeeAmount": "0.0010",
          "supportedOrderTypes": ["limit"]
        }
      }
    }
    

    Returns a single market identified by marketId.

    HTTP Request

    GET https://api.ddex.io/v3/markets/:marketId

    URL Parameters

    Parameter Description
    marketId Query for information on a specific market. Specified in the form of a trading pair of tokens, e.g. ZRX-WETH.

    Details

    Please see List Markets for a description of the returned metadata.

    List Tickers

    Response

    {
      "status": 0,
      "desc": "success",
      "data": {
        "tickers": [
          {
            "marketId": "ELEC-WETH",
            "price": "0.000144",
            "volume": "27849.39934497",
            "bid": "0.000144",
            "ask": "0.000145",
            "low": "0.000144",
            "high": "0.0001621",
            "updatedAt": 1363828259897
          },
          ...
        ]
      }
    }
    

    Returns ticker data for all active markets.

    HTTP Request

    GET https://api.ddex.io/v3/markets/tickers

    Details

    Each set of ticker data contains the market it represents in marketId, as well as the price of the last trade made. We also give you status of the market at the time of the last trade, with ask being the highest offer for tokens, and bid being the lowest purchase price available at the time. Data about the last 24 hours of trading is available in low, high, and volume.

    Get a Ticker

    Response

    {
      "status": 0,
      "desc": "success",
      "data": {
        "ticker": {
          "marketId": "ELEC-WETH",
          "price": "0.000144",
          "volume": "27849.39934497",
          "bid": "0.000144",
          "ask": "0.000143",
          "low": "0.000144",
          "high": "0.0001621",
          "updatedAt": 1363828259897
        }
      }
    }
    

    Return ticker data for a single market identified by marketId

    HTTP Request

    GET https://api.ddex.io/v3/markets/:marketId/ticker

    URL Parameters

    Parameter Description
    marketId Query for ticker data on a specific market. Specified in the form of a trading pair of tokens, e.g. ELEC-WETH.

    Details

    Please see List Tickers for a description of the returned metadata.

    Get Orderbook

    Aggregated Response

    {
      "status": 0,
      "desc": "success",
      "data": {
        "orderBook": {
          "marketId": "BKX-WTH",
          "bids": [
            {
              "price": "0.0010229",
              "amount": "210"
            },
            ...
          ],
          "asks": [
            {
              "price": "0.0011393",
              "amount": "200"
            },
            ...
          ]
        }
      }
    }
    

    Non-aggregated Response

    {
      "status": 0,
      "desc": "success",
      "data": {
        "orderBook": {
          "marketId": "BKX-WETH",
          "bids": [
            {
              "price": "0.0010229",
              "amount": "210",
              "orderId": "0x7e1e4ea61dc081da6a979848c6c1b12fa167ac7f006750e804a540a3cccbbf8d"
            },
            ...
          ],
          "asks": [
            {
              "price": "0.0011393",
              "amount": "200",
              "orderId": "0x762d6ce2a8b30151c7dc7d29f0068e2dda2d1dd852f637d9e302e4fa408a0611"
            },
            ...
          ]
        }
      }
    }
    

    Return order data for a single market specified by marketId

    HTTP Request

    GET https://api.ddex.io/v3/markets/:marketId/orderbook

    URL Parameters

    Parameter Description
    marketId Query for orderbook data on a specific market. Specified in the form of a trading pair of tokens, e.g. BKX-WETH.

    Query Parameters

    Parameter Description
    level (Optional) Controls the level of detail in the returned orderbook data. Defaults to level 1.

    Levels

    Level Description
    1 The best bid and ask prices
    2 The top 50 bids and asks, with orders at the same price aggregated together
    3 Returns the full orderbook with no aggregation

    Details

    This returns an array of bids and asks for the orderbook in the specified market. Each bid/ask contains the price and the amount of token available/requested at that price. If you set the level to 3, you will get the full orderbook with no aggregation, and as such we also include the orderId with each bid/ask.

    List Trades

    Response

    {
      "status": 0,
      "desc": "success",
      "data": {
        "totalPages": 10,
        "currentPage": 1,
        "trades": [
          {
            "id": "c77a2506-4e70-4041-a1c4-c5851a406cd8",
            "marketId": "ZRX-WETH",
            "status": "successful",
            "amount": "2099.39882679",
            "price": "0.00138045",
            "executedAt": 1520914296000,
            "createdAt": 1520914269749
          },
          ...
        ]
      }
    }
    

    Return paginated data for all trades in a single market identified by marketId. The trades are sorted by creation time in descending order.

    HTTP Request

    GET https://api.ddex.io/v3/markets/:marketId/trades

    URL Parameters

    Parameter Description
    marketId Query for trade data on a specific market. Specified in the form of a trading pair of tokens, e.g. ZRX-WETH.

    Query Parameters

    Parameter Description
    page (Optional) Used for pagination. Defaults to 1.
    perPage (Optional) Used for pagination. Value must be between 1-100. Defaults to 100.

    Details

    Returns all trade data for the specified market. Results will be paginated with a default page size of 20 results.

    Each set of trade data includes the price and amount of the order, as well as the status. We also include the time at which the trade was created due to matching orders in the book (createdAt) and the time the trade was completed on the blockchain (executedAt).

    List Candles

    Response

    {
      "status": 0,
      "desc": "success",
      "data": {
        "candles": [
          {
            "time": 1518454800000,
            "volume": "25140",
            "open": "0.0012258",
            "close": "0.00118",
            "high": "0.0012258",
            "low": "0.0011755"
          },
          {
            "time": 1518458400000,
            "volume": "17322",
            "open": "0.00118",
            "close": "0.0011782",
            "high": "0.00119",
            "low": "0.0011769"
          },
          ...
        ]
      }
    }
    

    Returns "candles" for a specific market specified by marketId. These candles are useful for creating a chart of the trading history of a market.

    HTTP Request

    GET https://api.ddex.io/v3/markets/:marketId/candles

    URL Parameters

    Parameter Description
    marketId Query for candles on a specific market. Specified in the form of a trading pair of tokens, e.g. ZRX-WETH.

    Query Parameters

    Parameter Description
    from The beginning of the time range in seconds for which you want candles. Specified as a Unix Timestamp, e.g. 1518451200
    to The end of the time range in seconds for which you want candles. Specified as a Unix Timestamp, e.g. 1520870400
    granularity The width of each candle in seconds, e.g. 3600 for width of 1 hour.

    Details

    Returns a list of candles, each representing a span of time on the graph defined by the granularity passed in. The candle data includes the open and close price, the high and low price, and the amount of volume traded in the span of time represented by the candle.

    Calculate Fees

    Request

    {
      "amount": "5500000",
      "price": "0.001"
    }
    

    Response

    {
      "status": 0,
      "desc": "success",
      "data": {
        "asMakerTotalFeeAmount": "0.09821247429725166592",
        "asMakerTradeFeeAmount": "0.01",
        "asMakerFeeRate": "0.00100",
        "asTakerTotalFeeAmount": "0.10821247429725166592",
        "asTakerTradeFeeAmount": "0.02",
        "asTakerFeeRate": "0.00200",
        "gasFeeAmount": "0.08821247429725166592"
      }
    }
    

    Calculates the approximate fee that will be charged for an order.

    HTTP Request

    GET https://api.ddex.io/v3/fees

    Query Parameters

    Parameter Description
    price The price of the order. e.g. 0.001
    amount The amount of token in the order. e.g. 5500000
    marketId Query for fee data on a specific market. Specified in the form of a trading pair of tokens, e.g. HOT-WETH

    Details

    The server will calculate a fee based on current conditions and return the totalFeeAmount as well as the feeRate that was used to calculate that amount.

    Private Rest API

    Introduction

    API calls that return data about a specific account, or let you post data to the system. These calls will require you to authenticate in order to access them. Please see the Authentication) section below for more details.

    Authentication

    Example (web3)

    const address = web3.eth.coinbase;
    const message = "[email protected]" + Date.now();
    web3.personal.sign(web3.toHex(message), address, (err, sign) => {
      console.log(address + "#" + message + "#" + sign);
    });
    

    Example (ethereumjs-util)

    import {
      hashPersonalMessage,
      ecsign,
      toRpcSig,
      toBuffer,
      privateToAddress
    } from "ethereumjs-util";
    
    const message = "[email protected]" + Date.now();
    const privateKey =
      "0xe4abcbf75d38cf61c4fde0ade1148f90376616f5233b7c1fef2a78c5992a9a50";
    const address = "0x" + privateToAddress(privateKey).toString("hex");
    
    const sha = hashPersonalMessage(toBuffer(message));
    const ecdsaSignature = ecsign(sha, toBuffer(privateKey));
    const signature = toRpcSig(
      ecdsaSignature.v,
      ecdsaSignature.r,
      ecdsaSignature.s
    );
    console.log(address + "#" + message + "#" + signature);
    

    Hydro uses an Authentication Header to control access to the API.

    Header Format

    Hydro-Authentication: {Address}#{Message}#{Signature}

    Header Components

    Component Description
    Address The ethereum address used for trading, e.g. 0xed6d484f5c289ec8c6b6f934ef6419230169f534
    Message A static message plus the current UTC timestamp in milliseconds, e.g. [email protected]
    Signature The result of signing the Message component with the private key of the Address

    Details

    In order to authenticate a request, you must construct a token validating your ownership of the trading address. The token is time sensitive to prevent a leaked token from giving irrevocable access to the Hydro API for a particular trading address. As part of the Message component, you will include a current timestamp in UTC. The token will be valid for up to 5 minutes. In general we suggest creating a new token for each request.

    A full example header using the example Address and Message values above:

    Hydro-Authentication: 0xed6d484f5c289ec8c6b6f934ef6419230169f534#[email protected]#0x2b3eacf8844008fe3822a9d3ba97a9d6df1a7aeb95636c10024e34334a0e008e7129b86a87c1dfcad9a25743fb6598e555c086cfede2e245e0d8043ac7e17f8e00

    Wrapping Ether

    Example Wrap (web3)

    const wethAddress = "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2";
    const wethAmount = new web3.BigNumber(1); // 1 ETH to WETH
    web3.eth
      .contract([
        {
          constant: false,
          inputs: [],
          name: "deposit",
          outputs: [],
          payable: true,
          stateMutability: "payable",
          type: "function"
        }
      ])
      .at(wethAddress)
      .deposit(
        {
          value: wethAmount.mul(new web3.BigNumber(10).pow(18)) // Convert to WEI
        },
        (err, res) => console.log(res) // Transaction id
      );
    

    Example Unwrap (web3)

    const wethAddress = "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2";
    const wethAmount = new web3.BigNumber(1); // 1 ETH to WETH
    web3.eth
      .contract([
        {
          constant: false,
          inputs: [
            {
              name: "wad",
              type: "uint256"
            }
          ],
          name: "withdraw",
          outputs: [],
          payable: false,
          stateMutability: "nonpayable",
          type: "function"
        }
      ])
      .at(wethAddress)
      .withdraw(
        wethAmount.mul(new web3.BigNumber(10).pow(18)), // Convert to WEI
        (err, res) => console.log(res) // Transaction id
      );
    

    Exchanges built using the Hydro Protocol allow users to trade ERC20 tokens directly from their digital wallets. Unfortunately, Ether itself does not conform to the ERC20 standards (yet!). Because of this, ETH must first be converted to what is known as "wrapped ether" (WETH), which does conform to the ERC20 Standard. ETH and WETH are always exchanged at a 1:1 ratio. You can wrap/unwrap ETH yourself with web3 as shown in the example, or visit our Support Article for information on how to wrap through our DDEX exchange.

    Enabling Token Trading

    Example Enable WETH (web3)

    const wethAddress = "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2";
    const proxyAddress = "0x74622073a4821dbfd046e9aa2ccf691341a076e1";
    
    web3.eth
      .contract([
        {
          constant: false,
          inputs: [
            {
              name: "guy",
              type: "address"
            },
            {
              name: "wad",
              type: "uint256"
            }
          ],
          name: "approve",
          outputs: [
            {
              name: "",
              type: "bool"
            }
          ],
          payable: false,
          stateMutability: "nonpayable",
          type: "function"
        }
      ])
      .at(wethAddress)
      .approve(
        proxyAddress,
        new web3.BigNumber(2).pow(256).minus(1), // MAX_INT, unlimited allowance
        (err, res) => console.log(res) // Transaction id
      );
    

    Example Disable WETH (web3)

    const wethAddress = "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2";
    const proxyAddress = "0x74622073a4821dbfd046e9aa2ccf691341a076e1";
    
    web3.eth
      .contract([
        {
          constant: false,
          inputs: [
            {
              name: "guy",
              type: "address"
            },
            {
              name: "wad",
              type: "uint256"
            }
          ],
          name: "approve",
          outputs: [
            {
              name: "",
              type: "bool"
            }
          ],
          payable: false,
          stateMutability: "nonpayable",
          type: "function"
        }
      ])
      .at(wethAddress)
      .approve(
        proxyAddress,
        new web3.BigNumber(0), // Zero allowance
        (err, res) => console.log(res) // Transaction id
      );
    

    To allow a relayer to match trades from your digital wallet for a given token type, users must first perform a 1-time transaction to "enable" (or unlock) each type of token they wish to trade. This enabling process only has to be done once, and can be done through our DDEX exchange. Please visit our Support Article for more information on how to make sure your tokens are enabled for trading.

    Build Unsigned Order

    Request (Limit Order)

    {
      "amount": "10",
      "price": "0.1",
      "side": "sell",
      "orderType": "limit",
      "marketId": "HOT-WETH"
    }
    

    Request (Market Order)

    {
      "amount": "1",
      "price": 0,
      "side": "sell",
      "orderType": "market",
      "marketId": "DVD-DAI"
    }
    

    Response

    {
      "status": 0,
      "desc": "success",
      "data": {
        "order": {
          "id": "0x972a06a57332cc6445e4c16961302332e33273210f44c2c5e70c69840cd84026",
          "marketId": "HOT-DAI",
          "side": "sell",
          "type": "limit",
          "price": "1",
          "amount": "10",
          "json": {
            "trader": "0x3870b6f2c0b723f4855d8ad53ab7599b02d4df84",
            "relayer": "0xd4a1963e645244c7fb4fe8efab12e4bc02c5fad3",
            "baseToken": "0x6829f329f8f0768ad62a65477514deed90825564",
            "quoteToken": "0x9712e6cadf82d1902088ef858502ca17261bb893",
            "baseTokenAmount": "10000000000000000000",
            "quoteTokenAmount": "10000000000000000000",
            "gasTokenAmount": "166441169306985574",
            "data": "0x01010002540be3ff006400c80064000000000002605700000000000000000000"
          },
          "makerFeeRate": "0.00100",
          "takerFeeRate": "0.01000",
          "makerRebateRate": "0.001",
          "gasFeeAmount": "0.16644116930698557453"
        }
      }
    }
    

    Returns data about an unsigned order based on the requested order parameters passed in. To place an order you will sign this data and post it back to the API to authenticate the use of your account in the trade.

    HTTP Request

    POST https://api.ddex.io/v3/orders/build

    Query Parameters

    Parameter Description
    marketId The market you wish to post the order to. Specified in the form of a trading pair of tokens, e.g. ZEN-WETH.
    side buy or sell.
    orderType The type of the order, limit or market.
    price If orderType is limit, this is the price of the order, e.g. 0.0007. If orderType is market, this is used as the maximum price you are willing to pay for buy and the minimum price you are willing to sell for. No price limit will be used if set to 0.
    amount The amount of token in the order. e.g. 100.
    expires (Optional) Time in seconds after which this order will expire. Minimum valid value is 3600 (1 hour), any smaller positive value will be read as a 1 hour expiration time. An expiration time of 0 means the order will never expire. Defaults to 0.

    Details

    Returns information about the order you wish to create, mostly mirroring the values passed in. The id field inside order is what you will sign and post to allow the exchange to fulfill the order on your behalf. Additionally we return data about the the rates that will be charged to makers and takers, and an estimated amount of gas that will be charged to fill the order.

    Sign Order

    Example (EthSign, web3)

    const address = web3.eth.coinbase;
    const orderId =
      "0x36975d8312c7f09003e0d280f3e8f48d406961a74afdf023873c12b99d35e86f";
    web3.personal.sign(web3.toHex(orderId), address, (err, signature) => {
      console.log(signature);
    });
    

    Example (EthSign, ethereumjs-util)

    import {
      hashPersonalMessage,
      ecsign,
      toRpcSig,
      toBuffer,
      privateToAddress
    } from "ethereumjs-util";
    
    const orderId =
      "0x36975d8312c7f09003e0d280f3e8f48d406961a74afdf023873c12b99d35e86f";
    const privateKey =
      "0xe4abcbf75d38cf61c4fde0ade1148f90376616f5233b7c1fef2a78c5992a9a50";
    const address = privateToAddress(privateKey).toString("hex");
    
    const sha = hashPersonalMessage(toBuffer(orderId));
    const ecdsaSignature = ecsign(sha, toBuffer(privateKey));
    const signature = toRpcSig(
      ecdsaSignature.v,
      ecdsaSignature.r,
      ecdsaSignature.s
    );
    console.log(signature);
    

    Once you have an orderId for an unsigned order built on the server, you will have to sign it in order to post it to the orderbook.

    Place Order

    Request

    {
      "orderId": "0x81e6031c4f6dd2d4ef4d3fd688dc3a8ebf4fbdad41265a3ab503afd659c0fb01",
      "signature": "0x7ec1f88bceb223a11f612de483b5cc25fa21b271674e4836914bffce36d05cfb2710b8d65b4c86e5bf14c46e279da7f70c63fc4108ca82e7a36455027d8a160e1c",
      "method": 1
    }
    

    Response

    {
      "status": 0,
      "desc": "success",
      "data": {
        "order": {
          "id": "0x81e6031c4f6dd2d4ef4d3fd688dc3a8ebf4fbdad41265a3ab503afd659c0fb01",
          "type": "limit",
          "version": "hydro-v1",
          "status": "pending",
          "amount": "1",
          "availableAmount": "1",
          "pendingAmount": "0",
          "canceledAmount": "0",
          "confirmedAmount": "0",
          "price": "1",
          "side": "buy",
          "makerFeeRate": "0.00100",
          "takerFeeRate": "0.01000",
          "makerRebateRate": "0.001",
          "gasFeeAmount": "0.08826210908345922093",
          "account": "0x85cf54dd216997bcf324c72aa1c845be2f059299",
          "createdAt": null,
          "marketId": "HOT-DAI",
          "json": {
            "trader": "0x85cf54dd216997bcf324c72aa1c845be2f059299",
            "relayer": "0xd4a1963e645244c7fb4fe8efab12e4bc02c5fad3",
            "baseToken": "0xa0530fa979fdbc3c6e8a91573277827826b80950",
            "quoteToken": "0x9712e6cadf82d1902088ef858502ca17261bb893",
            "baseTokenAmount": "1000000000000000000",
            "quoteTokenAmount": "1000000000000000000",
            "gasTokenAmount": "88262109083459220",
            "data": "0x010000005c135353006403e8006400000000000ee40800000000000000000000",
            "signature": {
              "v": 28,
              "r": "0x7ec1f88bceb223a11f612de483b5cc25fa21b271674e4836914bffce36d05cfb",
              "s": "0x2710b8d65b4c86e5bf14c46e279da7f70c63fc4108ca82e7a36455027d8a160e",
              "config": "0x1c01"
            }
          }
        }
      }
    }
    

    After signing the orderId you can post it to this endpoint with the signature you created in order to send it to the orderbook. If you simply signed the order id hash, use the EthSign method and pass 0, otherwise if you have chosen to sign the full order data with EIP712, pass 1.

    HTTP Request

    POST https://api.ddex.io/v3/orders

    Query Parameters

    Parameter Description
    orderId The id returned from the Build Unsigned Order endpoint.
    signature The signature created during the Sign Order step.
    method (Optional) The signing method, 0 (EthSign) or 1 (EIP712). Defaults to 0.

    Details

    Returns information about the order that was posted to the orderbook. The json field in the order contains values that the exchange will need to complete the transaction. Also included in the data is the original marketId, side, price and amount requested for the order, the account used to make the order, and information on the various rates and fees that will be applied to fill the order.

    The averagePrice shows the average cost per token so far for this order. If no token has been exchanged yet, this will always be 0. Once the order has begun being filled, this could differ from the requested order price in a few ways. If a matching order with a better price was found, the better price will be used. In the case of a market order, the price is only used as an upper/lower bound, so this will display the actual price used. Finally, the average price also takes into account any trading fees, gas fees, and rebates involved in the process.

    The order also includes a number of amounts related to the status of the order. availableAmount is how much token is still available to be filled for this order, pendingAmount is how much token has been claimed to be filled, but has not yet been confirmed on the blockchain. confirmedAmount is the amount that has been filled and confirmed on the blockchain, and canceledAmount is how much of the token was left when an order was canceled, and is no longer available to be filled.

    status shows the fill state of the order, can be pending, canceled, partial filled or full filled.

    Cancel Order

    Response

    {
      "status": 0,
      "desc": "success"
    }
    

    Used to cancel an order given an orderId

    HTTP Request

    DELETE https://api.ddex.io/v3/orders/:orderId

    URL Parameters

    Parameter Description
    orderId The id of the order you wish to cancel.

    Details

    Simply returns success if we were able to cancel the order, or an error if the order doesn't exist or is not in a cancellable state (e.g. being fulfilled).

    List Orders

    Response

    {
      "status": 0,
      "desc": "success",
      "data": {
        "totalCount": 100,
        "totalPages": 10,
        "currentPage": 1,
        "orders": [
          {
            "id": "0xb8beb447e62a8f22c0e3fad435b43e28e365c297366c0016563b9ddb0a7bedf1",
            "type": "limit",
            "version": "hydro-v1",
            "status": "pending",
            "amount": "1",
            "availableAmount": "1",
            "pendingAmount": "0",
            "canceledAmount": "0",
            "confirmedAmount": "0",
            "price": "2",
            "averagePrice": "0",
            "side": "buy",
            "makerFeeRate": "0.00100",
            "takerFeeRate": "0.01000",
            "makerRebateRate": "0.00100",
            "gasFeeAmount": "0.127706049036078318",
            "account": "0x85cf54dd216997bcf324c72aa1c845be2f059299",
            "createdAt": 1544091412000,
            "marketId": "HOT-DAI",
            "json": {
              "data": "0x010000005c122e28006403e80064000000000009aa3f00000000000000000000",
              "trader": "0x85cf54dd216997bcf324c72aa1c845be2f059299",
              "relayer": "0xd4a1963e645244c7fb4fe8efab12e4bc02c5fad3",
              "baseToken": "0xa0530fa979fdbc3c6e8a91573277827826b80950",
              "signature": {
                "r": "0xcae9f845e40a2d8de9fd4703c85e85ba71d5c1f58b5ba9e8b5f50110fcdebea1",
                "s": "0x75e4d7b22e34322076423f3c43275ac165ff10f412793cd6f545cfe602509d39",
                "config": "0x1c01"
              },
              "quoteToken": "0x9712e6cadf82d1902088ef858502ca17261bb893",
              "gasTokenAmount": "127706049036078317",
              "baseTokenAmount": "1000000000000000000",
              "quoteTokenAmount": "2000000000000000000"
            }
          },
          "..."
        ]
      }
    }
    

    Return paginated data for all orders created by the currently authenticated trading account. The orders are sorted by creation time in descending order.

    HTTP Request

    GET https://api.ddex.io/v3/orders

    Query Parameters

    Parameter Description
    marketId (Optional) The market you wish to list orders from. Specified in the form of a trading pair of tokens, e.g. DTA-WETH.
    status (Optional) pending or all. Defaults to pending.
    page (Optional) Used for pagination. Defaults to 1.
    perPage (Optional) Used for pagination. Value must be between 1-100. Defaults to 100.

    Details

    Please see Place Order for a description of the data returned for each order in the list.

    Get Order

    Response

    {
      "status": 0,
      "desc": "success",
      "data": {
        "order": {
          "id": "0xde27b4cd08177f11a129490c872729976856291e8169e40e8cc75454b271c948",
          "type": "limit",
          "version": "hydro-v1",
          "status": "full filled",
          "amount": "1",
          "availableAmount": "0",
          "pendingAmount": "0",
          "canceledAmount": "0",
          "confirmedAmount": "1",
          "price": "1",
          "averagePrice": "0.7778615582982067",
          "side": "sell",
          "makerFeeRate": "0.00100",
          "takerFeeRate": "0.00200",
          "makerRebateRate": "0.00100",
          "gasFeeAmount": "0.222138441701793308",
          "account": "0x85cf54dd216997bcf324c72aa1c845be2f059299",
          "createdAt": 1545203072441,
          "marketId": "HOT-DAI",
          "json": {
              "data": "0x01010007b3cb197d006400c8006400000000000491d700000000000000000000",
              "trader": "0x85cf54dd216997bcf324c72aa1c845be2f059299",
              "relayer": "0xd10bc568235c6838b0620e2081643deecbddf504",
              "baseToken": "0x6829f329f8f0768ad62a65477514deed90825564",
              "signature": {
                  "r": "0x933c050e69ad2b797c3b0b39bbe5971a93e422151264e474ae7d211e46ffdd01",
                  "s": "0x5f896a53b6eb1109b4d840f8b512b5a342efa1b8aa873d714d11849e96fdff40",
                  "config": "0x1c01"
              },
              "quoteToken": "0x9712e6cadf82d1902088ef858502ca17261bb893",
              "gasTokenAmount": "222138441701793307",
              "baseTokenAmount": "1000000000000000000",
              "quoteTokenAmount": "1000000000000000000"
          }
        }
      }
    }
    

    Return a single order identified by orderId

    HTTP Request

    GET https://api.ddex.io/v3/orders/:orderId

    URL Parameters

    Parameter Description
    orderId The id of the order you wish to query.

    Details

    Please see Place Order for a description of the data returned for the order.

    List Account Trades

    Response

    {
      "status": 0,
      "desc": "success",
      "data": {
        "totalPages": 10,
        "currentPage": 1,
        "trades": [
          {
            "id": "d9d0672d-fd4f-4454-98e6-406c30e2b6c2",
            "maker": "0xd01af191c9143e26e7103d6fe41412b894b25e97",
            "taker": "0xe269e891a2ec8585a378882ffa531141205e92e9",
            "amount": "2099.39882679",
            "price": "0.00138045",
            "takerPrice": "0.0013804",
            "feeAmount": "0.002898010140500916",
            "buyer": "0xe269e891a2ec8585a378882ffa531141205e92e9",
            "seller": "0xd01af191c9143e26e7103d6fe41412b894b25e97",
            "marketId": "ZRX-WETH",
            "transactionId": "0x762d6ce2a8b30151c7dc7d29f0068e2dda2d1dd852f637d9e302e4fa408a0611",
            "transactionHash": "0x99f8108d17056bf90c8c174cf521722b01192325f560c768c4b41fa145f78a7f",
            "makerOrderId": "0x9c97edd05124ffa5ff4cf88e24acd9014034e26ba5151caec0564681a470dfe1",
            "takerOrderId": "0x20f79c4ce66d143f4894696b3b4340de6aa68d22ea2a7e67231359b6d26dec5d",
            "executedAt": 1520914296000,
            "status": "successful",
            "createdAt": 1520914269749
          },
          ...
        ]
      }
    }
    

    Return paginated data for all trades made by the currently authenticated user account in a single market identified by marketId. The trades are sorted by creation time in descending order.

    HTTP Request

    GET https://api.ddex.io/v3/markets/:marketId/trades/mine

    URL Parameters

    Parameter Description
    marketId Query for trade data on a specific market. Specified in the form of a trading pair of tokens, e.g. ZRX-WETH.

    Query Parameters

    Parameter Description
    page (Optional) Used for pagination. Defaults to 1.
    perPage (Optional) Used for pagination. Value must be between 1-100. Defaults to 100.

    Details

    Returns all of the authenticated user's trade data for the specified market. Results will be paginated with a default page size of 20 results.

    Each set of trade data contains all the information about the maker (creator of the order) and taker, including account addresses, order ids, and the final transaction id. It also includes all the order details including the price and amount of the order. We also return the feeAmount paid to the exchange, as well as the takerPrice. Finally you can view the status of the order, the time at which the trade was created due to matching orders in the book (createdAt) and the time the trade was completed on the blockchain (executedAt).

    List Locked Balances

    Response

    {
      "status": 0,
      "desc": "success",
      "data": {
        "lockedBalances": [
          {
            "amount": "6000000000000000000006",
            "symbol": "ZEN",
            "updatedAt": 1363828259897
          },
          ...
        ]
      }
    }
    

    List locked balances of each active symbol on the market for the currently authenticated user.

    HTTP Request

    GET https://api.ddex.io/v3/account/lockedBalances

    Details

    The locked balance for a symbol is the amount of that token that is currently listed in orders owned by the currently authenticated user. For example, if the account has created 3 sell orders for the ZEN symbol at 100, 1000, and 500 tokens respectively, and the orders are still pending, the locked balance for ZEN will be 1600.

    Get Locked Balance

    Response

    {
      "status": 0,
      "desc": "success",
      "data": {
        "lockedBalance": {
          "amount": "6000000000000000000006",
          "symbol": "ZEN",
          "updatedAt": 1363828259897
        }
      }
    }
    

    Get the locked balance of a specific symbol for the currently authenticated user.

    HTTP Request

    GET https://api.ddex.io/v3/account/lockedBalance

    Query Parameters

    Parameter Description
    symbol The symbol you wish to query for locked balance, e.g. ZEN.

    Details

    Please see List Locked Balances for details.

    Websocket

    Overview

    The Websocket API is intended to provide real-time updates to the state of the market. In order to receive updates, you must open a socket to the websocket endpoint, and send a subscription message. This message will define what real-time data you are interested in, so you only get the updates you need.

    Endpoint: wss://ws.ddex.io/v3

    Subscribe

    Request

    {
      "type": "subscribe",
      "channels": [
        {
          "name": "full",
          "marketIds": [ "HOT-WETH" ]
        },
        {
          "name": "ticker",
          "marketIds": [ "HOT-WETH" ]
        }
      ]
    }
    

    Response

    {
      "type": "subscriptions",
      "channels": [
        {
          "name": "full",
          "marketIds": [ "HOT-WETH" ]
        },
        {
          "name": "ticker",
          "marketIds": [ "HOT-WETH" ]
        }
      ]
    }
    

    To begin receiving websocket messages, you must first send a subscribe message to the server indicating which channels you are interested in, and for which markets you wish to receive updates.

    JSON Fields

    Parameter Description
    type subscribe
    channels An array of Channel Data describing which channels and markets you wish to subscribe to.

    Channel Data

    Parameter Description
    name ticker, orderbook, or full
    marketIds An array of market ids, specified in the form of a trading pair of tokens, e.g. ZRX-WETH

    Details

    Once a subscribe message is received, the server will respond with a subscriptions message that lists all channels you are currently subscribed to.

    Unsubscribe

    Request

    {
      "type": "unsubscribe",
      "channels": [
        {
          "name": "full",
          "marketIds": [ "HOT-WETH" ]
        }
      ]
    }
    

    Response

    {
      "type": "subscriptions",
      "channels": [
        {
          "name": "ticker",
          "marketIds": [ "HOT-WETH" ]
        }
      ]
    }
    

    If you are no longer interested in a channel, you may send an unsubscribe message to the server indicating which channels you no longer wish to receive updates for.

    JSON Fields

    Parameter Description
    type unsubscribe
    channels An array of Channel Data describing which channels and markets you wish to unsubscribe to.

    Channel Data

    Parameter Description
    name ticker, orderbook, or full
    marketIds An array of market ids, specified in the form of a trading pair of tokens, e.g. ZRX-WETH

    Details

    Once an unsubscribe message is received, the server will respond with a subscriptions message that lists all channels you are currently subscribed to.

    Ticker Channel

    Subscription Request

    {
      "type": "subscribe",
      "channels": [
        {
          "name": "ticker",
          "marketIds": [ "ZRX-WETH" ]
        }
      ]
    }
    

    Sample Message

    {
      "type": "ticker",
      "time": 1520847743338,
      "marketId": "ZRX-WETH",
      "bid": null,
      "price": "0.08",
      "volume": "1",
      "high": "0.08",
      "low": "0",
      "tradeId":"f8548cd5-b9be-4e43-a6e8-12b468c7dd6c"
    }
    

    Subscribing to the ticker channel will provide real time price updates every time a trade is completed. In case of cascading trades, the updates will be batched to avoid excess bandwidth usage.

    Details

    The ticker data returned in the message includes the marketId, as well as the current price, volume, high and low values for that market.

    Orderbook Channel

    Subscription Request

    {
      "type": "subscribe",
      "channels": [
        {
          "name": "orderbook",
          "marketIds": [ "HOT-WETH" ]
        }
      ]
    }
    

    Snapshot Message

    {
      "type": "level2OrderbookSnapshot",
      "marketId": "HOT-WETH",
      "bids": [
        {"price": "0.007", "amount" : "400"},
        {"price": "0.00911", "amount" : "270"},
        {"price": "0.00913", "amount" : "190"},
        {"price": "0.014412", "amount" : "120"},
        {"price": "0.014413", "amount" : "220"},
        {"price": "0.014434", "amount" : "130"},
        {"price": "0.014438", "amount" : "170"},
        {"price": "0.014456", "amount" : "100"},
        {"price": "0.01448", "amount" : "200"},
        {"price": "0.0145", "amount" : "400"}
      ],
      "asks": [
        {"price" : "0.01498", "amount": "100"},
        {"price" : "0.014977", "amount": "130"},
        {"price" : "0.014971", "amount": "130"},
        {"price" : "0.014949", "amount": "130"},
        {"price" : "0.0149", "amount": "0"},
        {"price" : "0.01489", "amount": "0"},
        {"price" : "0.014883", "amount": "0"},
        {"price" : "0.014855", "amount": "146"},
        {"price" : "0.014848", "amount": "110"},
        {"price" : "0.014843", "amount": "100"},
        {"price" : "0.014818", "amount": "100"},
        {"price" : "0.01481", "amount": "82"},
        {"price" : "0.0148", "amount": "400"},
        {"price" : "0.014774", "amount": "100"}
      ]
    }
    

    Update Message

    {
      "type": "level2OrderbookUpdate",
      "marketId": "HOT-WETH",
      "changes": [
        {"side": "sell", "price": "0.014789", "amount": "0"}
      ]
    }
    

    The orderbook channel provides an easy way to maintain a live view of the aggregated orderbook.

    Snapshot

    After subscribing to the channel, it will send a message of type level2OrderbookSnapshot for each subscribed market. The message is a complete, although aggregated, snapshot of the current orderbook, where bids and asks are lists of json data containing price and amount of token available at that price (aggregated over all orders in the book).

    Update

    Once you get the initial snapshot, messages will be sent corresponding to any change in the orderbook. The message will have the type level2OrderbookUpdate and list which market the change occurred in. It also contains a list of changes which contain which side the change occurred on, the price the change occurred at, and the new amount at that price level.

    Note that if the new amount in an update is 0, the price level can be removed from your orderbook.

    Full Channel

    Subscription Request

    {
      "type": "subscribe",
      "channels": [
        {
          "name": "full",
          "marketIds": [ "HOT-WETH" ]
        }
      ]
    }
    

    Snapshot Message

    {
      "type": "level3OrderbookSnapshot",
      "marketId": "HOT-WETH",
      "sequence": 345,
      "bids": [
        {
          "price": "0.00054",       // price,
          "amount": "1200",          // amount
          "orderId": "0xabde02351..." // orderId
        },
        ....
      ],
      "asks": [
        {
          "price": "0.00064",       // price,
          "amount": "40000",         // amount
          "orderId": "0x4055f060c..." // orderId
        },
        ....
      ]
    }
    

    Receive Message

    {
      "type": "receive",
      "time": 1520577582556,
      "marketId": "ZRX-WETH",
      "sequence": 1,
      "price": "0.1",
      "orderId": "0xa60d846292e50bed9a37eac69d91bb9180ed754f43fa44c5dff5bf9aeddb5128",
      "orderType": "limit",
      "side": "sell",
      "canceledAmount": "0",
      "confirmedAmount": "0",
      "availableAmount": "1",
      "pendingAmount": "0"
    }
    

    Open Message

    {
      "type": "open",
      "time": 1520837845343,
      "marketId": "ZRX-WETH",
      "sequence": 2,
      "price": "0.8",
      "orderId": "0x531b9e9e7aba5f4f84940e4a9923ce44cf8a43b6e3f5aac98d56e439e467efdb",
      "orderType": "limit",
      "side": "sell",
      "canceledAmount": "0",
      "confirmedAmount": "0",
      "availableAmount": "1",
      "pendingAmount": "0"
    }
    

    Done Message

    {
      "type": "done",
      "time": 1520837846102,
      "marketId": "ZRX-WETH",
      "sequence": 14,
      "price": "0.8",
      "orderId": "0x531b9e9e7aba5f4f84940e4a9923ce44cf8a43b6e3f5aac98d56e439e467efdb",
      "orderType": "limit",
      "side": "sell",
      "canceledAmount": "0",
      "confirmedAmount": "0",
      "availableAmount": "0",
      "pendingAmount": "1"
    }
    

    Change Message

    {
      "type": "change",
      "time": 1520837846102,
      "marketId": "ZRX-WETH",
      "sequence": 14,
      "price": "0.8",
      "orderId": "0x531b9e9e7aba5f4f84940e4a9923ce44cf8a43b6e3f5aac98d56e439e467efdb",
      "orderType": "limit",
      "side": "sell",
      "oldAvailableAmount": "2",
      "newAvailableAmount": "1"
    }
    

    Trade Message

    {
      "type": "trade",
      "time": 1520844812020,
      "marketId": "ZRX-WETH",
      "sequence": 15,
      "price": "0.8",
      "transactionId": "0xb1a42cbe03b749edb07d220286f4c99c5ac6ebcac6f8ef92b26769cb5f0f0fc2",
      "makerOrderId": "0x1f6d2e6c9deba47c842eda4a1529f53d4d74c071ab6dffcf8d4b71a5bc913c2b",
      "takerOrderId": "0x50ca7438f009d752bd4bd093d93f1db49076dea0c566690891cd6b9fee4c2343",
      "taker": "0x5409ed021d9299bf6814279a6a1411a7e866a631",
      "maker": "0x1edad6dad44367a6e0e342e76e9df595049b8224",
      "amount": "1",
      "makerSide": "sell"
    }
    

    Trade Success Message

    {
      "type": "trade_success",
      "time": 1520844820685,
      "marketId": "ZRX-WETH",
      "price": "0.09",
      "transactionId": "0x9ed3c60f199aaadf13e9766ceebb156f10817a2186a78f3f3f374757471bbfc5",
      "makerOrderId": "0x722794395d38d70c848be14484f016c8bb696c15c655bea3a951d47ae413f731",
      "takerOrderId": "0x8a3eddfd60a64714afcbfdf1079a45bcb6707931142e9cdc03181f6d5dd03640",
      "amount": "0.5",
      "makerSide": "sell"
    }
    

    The full channel provides real-time updates on all orders and trades for the specified markets. These updates can be applied on to a level 3 orderbook snapshot to maintain an accurate, non-aggregated copy of the exchange orderbook.

    Sequence Numbers

    Updates you receive will contain a sequence number. Sequence numbers are increasing integer values that will always increase by 1 for each new message in the sequence. If the sequence number you receive is more than 1 higher than the previous value, then a message has been dropped. If you see a sequence number lower than the previous value, then a message has arrived out of order and can likely be ignored. In both cases you may need to perform some logic to get your system to consistent state. For example, if you miss a change message, you should resubscribe to the channel in order to receive a full snapshot message and reset your state.

    Snapshot

    After subscribing to the channel, it will send a message of type level3OrderbookSnapshot for each subscribed market. The message is a complete, non-aggregated snapshot of the current orderbook, where bids and asks are lists of json data containing price, amount, and the orderId for the order it represents. These data blobs are not aggregated, so you will receive one for every order on the market.

    Receive

    A valid order has been received and is now active. This message is emitted for every valid order as soon as the matching engine receives it, whether it fills immediately or not.

    Open

    A new order is now open on the orderbook. This message will only be sent for orders which are not fulfilled immediately. availableAmount will indicate how much of the order is unfulfilled and available on the orderbook.

    Done

    An order is no longer available on the orderbook. This message can result from an order being canceled or completely filled. There will be no more messages for this orderId once this message has been received. canceledAmount indicates how much of the order went unfulfilled, and confirmedAmount indicates how much of the order was fulfilled.

    Change

    If an order is changed due to self-trade prevention, you will receive a change message for that orderId. It will contain the oldAvailableAmount, as well as the newAvailableAmount which is the amount of token left over in the order that can still be fulfilled.

    Trade

    Two orders have been matched, and a trade has occurred. The orders will be marked as pending until the trade is successfully validated on the blockchain.

    Trade Success

    A trade has been validated on the blockchain.

    Examples

    GitHub

    Maker Demo

    A simple "maker" bot that will post orders based on price changes. If the price goes up, it will place a bid order at the new price, and if the price goes down it will place an ask order at that price.

    Maker Demo

    Orderbook Demo

    Maintains a live orderbook, receiving websocket updates and keeping a full level 2 orderbook. Displayed graphically in the command line.

    Orderbook Demo