NAV navbar
python javascript ruby solidity

Public REST API

Scroll down for code samples, example requests and responses. Select a language for code samples from the tabs above or the mobile navigation menu.

This is a readonly REST API which can be used to fetch data about the DerivaDEX exchange. Realtime equivalents for most of these endpoints can be found in the Realtime API section.

Trader

These APIs provide data for a particular trader.

Get Trader

Code samples

require 'rest-client'
require 'json'

headers = {
  'Accept' => 'application/json'
}

result = RestClient.get '/stats/api/v1/account/{trader}',
  params: {
  }, headers: headers

p JSON.parse(result)
import requests
headers = {
  'Accept': 'application/json'
}

r = requests.get('/stats/api/v1/account/{trader}', headers = headers)

print(r.json())

const headers = {
  'Accept':'application/json'
};

fetch('/stats/api/v1/account/{trader}',
{
  method: 'GET',

  headers: headers
})
.then(function(res) {
    return res.json();
}).then(function(body) {
    console.log(body);
});

GET /stats/api/v1/account/{trader}

Get current trader DDX balance and profile

Parameters

Name In Type Required Description
trader path string true The trader address.

Responses

Status Meaning Description Schema
200 OK Trader data Inline
400 Bad Request Bad request Inline
500 Internal Server Error Unexpected error Inline

Response Schema

Example responses

200 Response

{
  "value": {
    "trader": "0x00b993e587c15a9e0a0fe4f111de98fd6b5ce7067d",
    "availDdx": "1000",
    "lockedDdx": "200",
    "payFeesInDdx": true
  },
  "success": true,
  "timestamp": 1673031089
}

Status Code 200

Successful response for the Trader API

Name Type Required Restrictions Description
» value any true none The value of the response.

anyOf

Name Type Required Restrictions Description
»» anonymous object false none Entity which represents the current trader state.
»»» trader string true none The trader address prefixed with the blockchain discriminant.
»»» availDdx string true none The amount of DDX that the trader holds.
»»» lockedDdx string true none The amount of DDX that the trader has initiated for withdrawal.
»»» payFeesInDdx boolean true none A flag which indicates whether the trader wants to attempt to pay trading fees using their DDX balance.

or

Name Type Required Restrictions Description
»» anonymous null false none The value will be null if there is no value for the parameters used.

continued

Name Type Required Restrictions Description
» success boolean true none Whether the request was successful
» timestamp number true none The timestamp of the response

Status Code 400

Name Type Required Restrictions Description
» success boolean true none none
» errorMsg any false none none

anyOf

Name Type Required Restrictions Description
»» anonymous string false none none

or

Name Type Required Restrictions Description
»» anonymous [object] false none none

Status Code 500

Name Type Required Restrictions Description
» success boolean true none none
» errorMsg any false none none

anyOf

Name Type Required Restrictions Description
»» anonymous string false none none

or

Name Type Required Restrictions Description
»» anonymous [object] false none none

Get Strategy Fees History

Code samples

require 'rest-client'
require 'json'

headers = {
  'Accept' => 'application/json'
}

result = RestClient.get '/stats/api/v1/account/{trader}/strategy/{strategyId}/fees',
  params: {
  }, headers: headers

p JSON.parse(result)
import requests
headers = {
  'Accept': 'application/json'
}

r = requests.get('/stats/api/v1/account/{trader}/strategy/{strategyId}/fees', headers = headers)

print(r.json())

const headers = {
  'Accept':'application/json'
};

fetch('/stats/api/v1/account/{trader}/strategy/{strategyId}/fees',
{
  method: 'GET',

  headers: headers
})
.then(function(res) {
    return res.json();
}).then(function(body) {
    console.log(body);
});

GET /stats/api/v1/account/{trader}/strategy/{strategyId}/fees

Get maker/taker fee aggregates for a strategy

Parameters

Name In Type Required Description
trader path string true The trader address.
strategyId path string true The strategy ID.
limit query integer false The number of rows to return
epoch query integer false The epoch boundary used when fetching the next timeseries page.
txOrdinal query integer false The txOrdinal boundary used when fetching the next timeseries page. Must be passed along with epoch.
ordinal query integer false The ordinal boundary used when fetching the next timeseries page. Must be passed along with epoch and txOrdinal.
symbol query string false The symbol
order query string false The ordering of the results.
Enumerated Values
Parameter Value
order asc
order desc

Responses

Status Meaning Description Schema
200 OK Fees timeseries data Inline
400 Bad Request Bad request Inline
500 Internal Server Error Unexpected error Inline

Response Schema

Example responses

200 Response

{
  "value": [
    {
      "epochId": 100,
      "txOrdinal": 3432,
      "ordinal": 0,
      "amount": "1.0",
      "feeSymbol": "USDC",
      "symbol": "ETHP",
      "createdAt": "2023-01-06T16:37:27.929Z"
    }
  ],
  "success": true,
  "timestamp": 1673031089
}

Status Code 200

Successful response for the Fee API

Name Type Required Restrictions Description
» value [object] true none The value of the response
»» epochId string true none The epoch in which this transaction occured.
»» txOrdinal string true none The transaction ordinal, within the epoch.
»» ordinal string true none The ordinal within this particular transaction.
»» amount string true none The amount of fee paid
»» feeSymbol string true none The symbol of the fee paid (USDC or DDX)
»» symbol string true none The symbol of the asset for which the fee was paid.
»» createdAt string(date-time) true none The time when this row was added to the database.
» success boolean true none Whether the request was successful
» timestamp number true none The timestamp of the response

Status Code 400

Name Type Required Restrictions Description
» success boolean true none none
» errorMsg any false none none

anyOf

Name Type Required Restrictions Description
»» anonymous string false none none

or

Name Type Required Restrictions Description
»» anonymous [object] false none none

Status Code 500

Name Type Required Restrictions Description
» success boolean true none none
» errorMsg any false none none

anyOf

Name Type Required Restrictions Description
»» anonymous string false none none

or

Name Type Required Restrictions Description
»» anonymous [object] false none none

Get Strategy

Code samples

require 'rest-client'
require 'json'

headers = {
  'Accept' => 'application/json'
}

result = RestClient.get '/stats/api/v1/account/{trader}/strategy/{strategyId}',
  params: {
  }, headers: headers

p JSON.parse(result)
import requests
headers = {
  'Accept': 'application/json'
}

r = requests.get('/stats/api/v1/account/{trader}/strategy/{strategyId}', headers = headers)

print(r.json())

const headers = {
  'Accept':'application/json'
};

fetch('/stats/api/v1/account/{trader}/strategy/{strategyId}',
{
  method: 'GET',

  headers: headers
})
.then(function(res) {
    return res.json();
}).then(function(body) {
    console.log(body);
});

GET /stats/api/v1/account/{trader}/strategy/{strategyId}

Get current state of trader’s strategy

Parameters

Name In Type Required Description
trader path string true The trader address.
strategyId path string true The strategy ID.

Responses

Status Meaning Description Schema
200 OK Strategy data Inline
400 Bad Request Bad request Inline
500 Internal Server Error Unexpected error Inline

Response Schema

Example responses

200 Response

{
  "value": {
    "trader": "0x00b993e587c15a9e0a0fe4f111de98fd6b5ce7067d",
    "strategyIdHash": "0x2576ebd1",
    "strategyId": "main",
    "maxLeverage": 3,
    "availCollateral": "10000",
    "lockedCollateral": "1000",
    "frozen": false
  },
  "success": true,
  "timestamp": 1673031089
}

Status Code 200

Successful response for the Strategy API

Name Type Required Restrictions Description
» value any true none The value of the response.

anyOf

Name Type Required Restrictions Description
»» anonymous object false none Current state of a trader's strategy.
»»» trader string true none The trader address prefixed with the blockchain discriminant of the trader who owns this strategy.
»»» strategyIdHash string true none The hashed version of this strategy ID.
»»» strategyId string true none An identifier for this strategy.
»»» maxLeverage number true none The maximum leverage this strategy is allowed to take on.
»»» availCollateral string true none The amount of collateral that this strategy holds.
»»» lockedCollateral string true none The amount of collateral which has been initiated for withdrawal.
»»» frozen boolean true none Whether this strategy is frozen. Not currently in use.

or

Name Type Required Restrictions Description
»» anonymous null false none The value will be null if there is no value for the parameters used.

continued

Name Type Required Restrictions Description
» success boolean true none Whether the request was successful
» timestamp number true none The timestamp of the response

Status Code 400

Name Type Required Restrictions Description
» success boolean true none none
» errorMsg any false none none

anyOf

Name Type Required Restrictions Description
»» anonymous string false none none

or

Name Type Required Restrictions Description
»» anonymous [object] false none none

Status Code 500

Name Type Required Restrictions Description
» success boolean true none none
» errorMsg any false none none

anyOf

Name Type Required Restrictions Description
»» anonymous string false none none

or

Name Type Required Restrictions Description
»» anonymous [object] false none none

Get Strategy Metrics

Code samples

require 'rest-client'
require 'json'

headers = {
  'Accept' => 'application/json'
}

result = RestClient.get '/stats/api/v1/account/{trader}/strategy/{strategyId}/metrics',
  params: {
  }, headers: headers

p JSON.parse(result)
import requests
headers = {
  'Accept': 'application/json'
}

r = requests.get('/stats/api/v1/account/{trader}/strategy/{strategyId}/metrics', headers = headers)

print(r.json())

const headers = {
  'Accept':'application/json'
};

fetch('/stats/api/v1/account/{trader}/strategy/{strategyId}/metrics',
{
  method: 'GET',

  headers: headers
})
.then(function(res) {
    return res.json();
}).then(function(body) {
    console.log(body);
});

GET /stats/api/v1/account/{trader}/strategy/{strategyId}/metrics

Get KPIs and risk metrics for a strategy, like margin fraction, maintenance margin ratio, leverage, strategy available collateral and strategy value.

Parameters

Name In Type Required Description
trader path string true The trader address.
strategyId path string true The strategy ID.

Responses

Status Meaning Description Schema
200 OK Strategy metrics data Inline
400 Bad Request Bad request Inline
500 Internal Server Error Unexpected error Inline

Response Schema

Example responses

200 Response

{
  "value": {
    "marginFraction": "999999999999",
    "mmr": "0.05",
    "leverage": "3",
    "strategyMargin": "6147.5",
    "strategyValue": "9233.3"
  },
  "success": true,
  "timestamp": 1673031089
}

Status Code 200

Successful response for the Strategy Metrics API

Name Type Required Restrictions Description
» value any true none The value of the response.

anyOf

Name Type Required Restrictions Description
»» anonymous object false none Strategy metrics
»»» marginFraction string true none The current margin fraction of the strategy.
»»» mmr string true none The maintenance margin ratio. The margin fraction of the strategy should be greater than this number, or it may be subject to liquidation.
»»» leverage string true none The current leverage of the strategy.
»»» strategyMargin string true none The amount of unsettled margin and unutilized collateral available for new trades, or as a buffer against losses.
»»» strategyValue string true none The total value of all positions owned by this strategy.

or

Name Type Required Restrictions Description
»» anonymous null false none The value will be null if there is no value for the parameters used.

continued

Name Type Required Restrictions Description
» success boolean true none Whether the request was successful
» timestamp number true none The timestamp of the response

Status Code 400

Name Type Required Restrictions Description
» success boolean true none none
» errorMsg any false none none

anyOf

Name Type Required Restrictions Description
»» anonymous string false none none

or

Name Type Required Restrictions Description
»» anonymous [object] false none none

Status Code 500

Name Type Required Restrictions Description
» success boolean true none none
» errorMsg any false none none

anyOf

Name Type Required Restrictions Description
»» anonymous string false none none

or

Name Type Required Restrictions Description
»» anonymous [object] false none none

Get Strategy Positions

Code samples

require 'rest-client'
require 'json'

headers = {
  'Accept' => 'application/json'
}

result = RestClient.get '/stats/api/v1/account/{trader}/strategy/{strategyId}/positions',
  params: {
  }, headers: headers

p JSON.parse(result)
import requests
headers = {
  'Accept': 'application/json'
}

r = requests.get('/stats/api/v1/account/{trader}/strategy/{strategyId}/positions', headers = headers)

print(r.json())

const headers = {
  'Accept':'application/json'
};

fetch('/stats/api/v1/account/{trader}/strategy/{strategyId}/positions',
{
  method: 'GET',

  headers: headers
})
.then(function(res) {
    return res.json();
}).then(function(body) {
    console.log(body);
});

GET /stats/api/v1/account/{trader}/strategy/{strategyId}/positions

Get current positions for a strategy

Parameters

Name In Type Required Description
trader path string true The trader address.
strategyId path string true The strategy ID.
symbol query string false The symbol

Responses

Status Meaning Description Schema
200 OK Positions data Inline
400 Bad Request Bad request Inline
500 Internal Server Error Unexpected error Inline

Response Schema

Example responses

200 Response

{
  "value": [
    {
      "trader": "0x00b993e587c15a9e0a0fe4f111de98fd6b5ce7067d",
      "symbol": "ETHP",
      "strategyIdHash": "0x2576ebd1",
      "side": 0,
      "balance": "1.0",
      "avgEntryPrice": "1500",
      "lastModifiedInEpoch": 35
    }
  ],
  "success": true,
  "timestamp": 1673031089
}

Status Code 200

Successful response for positions API

Name Type Required Restrictions Description
» value [object] true none The value of the response
»» trader string true none The trader address prefixed with the blockchain discriminant of the trader who owns this position.
»» symbol string true none The symbol of the asset for this position.
»» strategyIdHash string true none The hash of the strategy which owns this position.
»» side number true none The side of the position. Values include: 0: None, 1: Long, 2: Short
»» balance string true none The current balance of this position.
»» avgEntryPrice string true none The average entry price of this position.
»» lastModifiedInEpoch number,null true none The epoch in which this position's balance was last modified.
» success boolean true none Whether the request was successful
» timestamp number true none The timestamp of the response

Status Code 400

Name Type Required Restrictions Description
» success boolean true none none
» errorMsg any false none none

anyOf

Name Type Required Restrictions Description
»» anonymous string false none none

or

Name Type Required Restrictions Description
»» anonymous [object] false none none

Status Code 500

Name Type Required Restrictions Description
» success boolean true none none
» errorMsg any false none none

anyOf

Name Type Required Restrictions Description
»» anonymous string false none none

or

Name Type Required Restrictions Description
»» anonymous [object] false none none

System

These APIs return system info.

Get Epochs

Code samples

require 'rest-client'
require 'json'

headers = {
  'Accept' => 'application/json'
}

result = RestClient.get '/stats/api/v1/epochs',
  params: {
  }, headers: headers

p JSON.parse(result)
import requests
headers = {
  'Accept': 'application/json'
}

r = requests.get('/stats/api/v1/epochs', headers = headers)

print(r.json())

const headers = {
  'Accept':'application/json'
};

fetch('/stats/api/v1/epochs',
{
  method: 'GET',

  headers: headers
})
.then(function(res) {
    return res.json();
}).then(function(body) {
    console.log(body);
});

GET /stats/api/v1/epochs

Get epoch timetable and paging cursors

Parameters

Name In Type Required Description
epoch query integer false The epoch boundary used when fetching the next timeseries page.
limit query integer false The number of rows to return
offset query integer false The offset of returned rows

Responses

Status Meaning Description Schema
200 OK Epoch start and end time data Inline
400 Bad Request Bad request Inline
500 Internal Server Error Unexpected error Inline

Response Schema

Example responses

200 Response

{
  "value": [
    {
      "epochId": 100,
      "startTime": "2023-01-06T16:37:27.929Z",
      "endTime": "2023-01-06T16:37:27.929Z"
    }
  ],
  "success": true,
  "timestamp": 1673031089
}

Status Code 200

Successful response for Epochs API

Name Type Required Restrictions Description
» value [object] true none The value of the response
»» epochId string true none The epoch number.
»» startTime string(date-time) true none The timestamp at which this epoch started.
»» endTime string true none The timestamp at which this epoch ended. This will be null if the epoch is still ongoing.

anyOf

Name Type Required Restrictions Description
»»» anonymous object(date-time) false none none

or

Name Type Required Restrictions Description
»»» anonymous null false none none

continued

Name Type Required Restrictions Description
» success boolean true none Whether the request was successful
» timestamp number true none The timestamp of the response

Status Code 400

Name Type Required Restrictions Description
» success boolean true none none
» errorMsg any false none none

anyOf

Name Type Required Restrictions Description
»» anonymous string false none none

or

Name Type Required Restrictions Description
»» anonymous [object] false none none

Status Code 500

Name Type Required Restrictions Description
» success boolean true none none
» errorMsg any false none none

anyOf

Name Type Required Restrictions Description
»» anonymous string false none none

or

Name Type Required Restrictions Description
»» anonymous [object] false none none

Get Insurance Fund History

Code samples

require 'rest-client'
require 'json'

headers = {
  'Accept' => 'application/json'
}

result = RestClient.get '/stats/api/v1/insurance_fund',
  params: {
  }, headers: headers

p JSON.parse(result)
import requests
headers = {
  'Accept': 'application/json'
}

r = requests.get('/stats/api/v1/insurance_fund', headers = headers)

print(r.json())

const headers = {
  'Accept':'application/json'
};

fetch('/stats/api/v1/insurance_fund',
{
  method: 'GET',

  headers: headers
})
.then(function(res) {
    return res.json();
}).then(function(body) {
    console.log(body);
});

GET /stats/api/v1/insurance_fund

Get insurance fund balance

Parameters

Name In Type Required Description
limit query integer false The number of rows to return
epoch query integer false The epoch boundary used when fetching the next timeseries page.
txOrdinal query integer false The txOrdinal boundary used when fetching the next timeseries page. Must be passed along with epoch.
order query string false The ordering of the results.
symbol query string false The symbol
Enumerated Values
Parameter Value
order asc
order desc

Responses

Status Meaning Description Schema
200 OK Insurance fund capitalization timeseries data Inline
400 Bad Request Bad request Inline
500 Internal Server Error Unexpected error Inline

Response Schema

Example responses

200 Response

{
  "nextEpoch": 100,
  "nextTxOrdinal": 3432,
  "nextOrdinal": 100,
  "value": [
    {
      "epochId": 100,
      "txOrdinal": 3432,
      "symbol": "USDC",
      "totalCapitalization": "1000000",
      "kind": 0,
      "createdAt": "2023-01-06T16:37:27.929Z"
    }
  ],
  "success": true,
  "timestamp": 1673031089
}

Status Code 200

Successful response for Insurance Fund API

Name Type Required Restrictions Description
» nextEpoch number,null true none Pointer for the epoch boundary of the next page. Will return null when there is no more data left to fetch.
» nextTxOrdinal number,null true none Pointer for the txOrdinal boundary of the next page. Will return null when there is no more data left to fetch.
» nextOrdinal number,null true none Pointer for the ordinal boundary of the next page. Will return null when there is no more data left to fetch.
» value [object] true none The value of the response
»» epochId string true none The epoch in which this transaction occured.
»» txOrdinal string true none The transaction ordinal, within the epoch.
»» symbol string true none The symbol of the insurance fund asset.
»» totalCapitalization string,null true none The total capitalization of the insurance fund after this transaction occured.
»» kind number true none The type of insurance fund capitalization change. Values include: 0: fill, 1: liquidation, 2: deposit, 3: withdrawal
»» createdAt string(date-time) true none The time when this row was added to the database.
» success boolean true none Whether the request was successful
» timestamp number true none The timestamp of the response

Status Code 400

Name Type Required Restrictions Description
» success boolean true none none
» errorMsg any false none none

anyOf

Name Type Required Restrictions Description
»» anonymous string false none none

or

Name Type Required Restrictions Description
»» anonymous [object] false none none

Status Code 500

Name Type Required Restrictions Description
» success boolean true none none
» errorMsg any false none none

anyOf

Name Type Required Restrictions Description
»» anonymous string false none none

or

Name Type Required Restrictions Description
»» anonymous [object] false none none

Get Specs

Code samples

require 'rest-client'
require 'json'

headers = {
  'Accept' => 'application/json'
}

result = RestClient.get '/stats/api/v1/specs',
  params: {
  }, headers: headers

p JSON.parse(result)
import requests
headers = {
  'Accept': 'application/json'
}

r = requests.get('/stats/api/v1/specs', headers = headers)

print(r.json())

const headers = {
  'Accept':'application/json'
};

fetch('/stats/api/v1/specs',
{
  method: 'GET',

  headers: headers
})
.then(function(res) {
    return res.json();
}).then(function(body) {
    console.log(body);
});

GET /stats/api/v1/specs

Get current operator configuration settings

Parameters

Name In Type Required Description
kind query integer false The type of spec update. Values include:
limit query integer false The number of rows to return
offset query integer false The offset of returned rows
Detailed descriptions

kind: The type of spec update. Values include: 0: Market 1: MarketGateway

Enumerated Values
Parameter Value
kind 0
kind 1

Responses

Status Meaning Description Schema
200 OK Specs data Inline
400 Bad Request Bad request Inline
500 Internal Server Error Unexpected error Inline

Response Schema

Example responses

200 Response

{
  "value": [
    {
      "kind": 0,
      "name": "ETHP",
      "expr": "(Market :name \"ETHP\":tick-size 0.1:max-order-notional 1000000:max-taker-price-deviation 0.02:min-order-size 0.0001)",
      "value": {
        "tickSize": "0.1",
        "minOrderSize": "0.0001",
        "maxOrderNotional": "1000000",
        "maxTakerPriceDeviation": "0.02"
      }
    }
  ],
  "success": true,
  "timestamp": 1673031089
}

Status Code 200

Successful response for the Specs API

Name Type Required Restrictions Description
» value [object] true none The value of the response
»» kind number true none The type of setting. Values include: 0: Market, 1: MarketGateway - a group of settings for a particular price feed source,
»» name string true none The name of the setting.
»» expr string true none A colon seperated set of key value pairs describing the setting
»» value any true none The value of the setting .
» success boolean true none Whether the request was successful
» timestamp number true none The timestamp of the response

Status Code 400

Name Type Required Restrictions Description
» success boolean true none none
» errorMsg any false none none

anyOf

Name Type Required Restrictions Description
»» anonymous string false none none

or

Name Type Required Restrictions Description
»» anonymous [object] false none none

Status Code 500

Name Type Required Restrictions Description
» success boolean true none none
» errorMsg any false none none

anyOf

Name Type Required Restrictions Description
»» anonymous string false none none

or

Name Type Required Restrictions Description
»» anonymous [object] false none none

Get Exchange Status

Code samples

require 'rest-client'
require 'json'

headers = {
  'Accept' => 'application/json'
}

result = RestClient.get '/stats/api/v1/status/exchange',
  params: {
  }, headers: headers

p JSON.parse(result)
import requests
headers = {
  'Accept': 'application/json'
}

r = requests.get('/stats/api/v1/status/exchange', headers = headers)

print(r.json())

const headers = {
  'Accept':'application/json'
};

fetch('/stats/api/v1/status/exchange',
{
  method: 'GET',

  headers: headers
})
.then(function(res) {
    return res.json();
}).then(function(body) {
    console.log(body);
});

GET /stats/api/v1/status/exchange

Get high-level exchange status information

Responses

Status Meaning Description Schema
200 OK Exchange status data Inline
400 Bad Request Bad request Inline
500 Internal Server Error Unexpected error Inline

Response Schema

Example responses

200 Response

{
  "value": {
    "currentEpoch": "9958",
    "latestOnChainCheckpoint": {
      "latestOnChainCheckpoint": 9920,
      "latestCheckpointTransactionLink": "https://goerli.etherscan.io/tx/0x05f4e74a64b2626af2edc555249484781732508f2096aed0aa52be2d09a51a73"
    },
    "activeAddresses": "20"
  },
  "success": true,
  "timestamp": 1673031089
}

Status Code 200

Successful response for the Exchange Status API

Name Type Required Restrictions Description
» value object true none The value of the response.
»» latestOnChainCheckpoint any true none Information about the latest on-chain checkpoint. Returns null if there haven't been any on-chain checkpoints.

anyOf

Name Type Required Restrictions Description
»»» anonymous object false none Data about the latest on-chain checkpoint.
»»»» latestOnChainCheckpoint number true none The latest on-chain checkpoint number.
»»»» latestCheckpointTransactionLink string,null true none An etherscan link to the latest on-chain checkpoint transaction.

or

Name Type Required Restrictions Description
»»» anonymous null false none none

continued

Name Type Required Restrictions Description
»» activeAddresses number true none The number of active addresses on the exchange. Active addresses are defined as addresses that have deposited, withdrawn, or traded within the last 24 hours or have currently open positions.
»» currentEpoch string true none The latest epoch on the Operator network.
» success boolean true none Whether the request was successful
» timestamp number true none The timestamp of the response

Status Code 400

Name Type Required Restrictions Description
» success boolean true none none
» errorMsg any false none none

anyOf

Name Type Required Restrictions Description
»» anonymous string false none none

or

Name Type Required Restrictions Description
»» anonymous [object] false none none

Status Code 500

Name Type Required Restrictions Description
» success boolean true none none
» errorMsg any false none none

anyOf

Name Type Required Restrictions Description
»» anonymous string false none none

or

Name Type Required Restrictions Description
»» anonymous [object] false none none

Get DDX Supply

Code samples

require 'rest-client'
require 'json'

headers = {
  'Accept' => 'application/json'
}

result = RestClient.get '/stats/api/v1/supply',
  params: {
  }, headers: headers

p JSON.parse(result)
import requests
headers = {
  'Accept': 'application/json'
}

r = requests.get('/stats/api/v1/supply', headers = headers)

print(r.json())

const headers = {
  'Accept':'application/json'
};

fetch('/stats/api/v1/supply',
{
  method: 'GET',

  headers: headers
})
.then(function(res) {
    return res.json();
}).then(function(body) {
    console.log(body);
});

GET /stats/api/v1/supply

Get total DDX circulation information

Responses

Status Meaning Description Schema
200 OK DDX Circulating Supply Inline
400 Bad Request Bad request Inline
500 Internal Server Error Unexpected error Inline

Response Schema

Example responses

200 Response

{
  "value": {
    "circulatingSupply": "26094663"
  },
  "success": true,
  "timestamp": 1673031089
}

Status Code 200

Successful response for the Exchange Supply API

Name Type Required Restrictions Description
» value object true none The value of the response.
»» circulatingSupply string true none The current circulating supply of DDX tokens.
» success boolean true none Whether the request was successful
» timestamp number true none The timestamp of the response

Status Code 400

Name Type Required Restrictions Description
» success boolean true none none
» errorMsg any false none none

anyOf

Name Type Required Restrictions Description
»» anonymous string false none none

or

Name Type Required Restrictions Description
»» anonymous [object] false none none

Status Code 500

Name Type Required Restrictions Description
» success boolean true none none
» errorMsg any false none none

anyOf

Name Type Required Restrictions Description
»» anonymous string false none none

or

Name Type Required Restrictions Description
»» anonymous [object] false none none

Get Tradable Products

Code samples

require 'rest-client'
require 'json'

headers = {
  'Accept' => 'application/json'
}

result = RestClient.get '/stats/api/v1/tradable_products',
  params: {
  }, headers: headers

p JSON.parse(result)
import requests
headers = {
  'Accept': 'application/json'
}

r = requests.get('/stats/api/v1/tradable_products', headers = headers)

print(r.json())

const headers = {
  'Accept':'application/json'
};

fetch('/stats/api/v1/tradable_products',
{
  method: 'GET',

  headers: headers
})
.then(function(res) {
    return res.json();
}).then(function(body) {
    console.log(body);
});

GET /stats/api/v1/tradable_products

Get list of available trading products

Parameters

Name In Type Required Description
kind query integer false The type of spec update. Values include:
isActive query boolean false Checks for the active state of the tradable product. Values include:
limit query integer false The number of rows to return
offset query integer false The offset of returned rows
Detailed descriptions

kind: The type of spec update. Values include: 0: Market 1: MarketGateway

isActive: Checks for the active state of the tradable product. Values include: true false

Enumerated Values
Parameter Value
kind 0
kind 1

Responses

Status Meaning Description Schema
200 OK Tradable products data Inline
400 Bad Request Bad request Inline
500 Internal Server Error Unexpected error Inline

Response Schema

Example responses

200 Response

{
  "value": [
    {
      "kind": 0,
      "symbol": "ETHP",
      "name": "ETHP",
      "isActive": true,
      "createdAt": "2023-01-06T16:37:27.929Z"
    }
  ],
  "success": true,
  "timestamp": 1673031089
}

Status Code 200

Successful response for the Tradable Product API

Name Type Required Restrictions Description
» value [object] true none The value of the response
»» kind number true none The type of setting. Values include: 0: Perpetual Market, 2: Index Market, 4: Futures Market
»» symbol string true none The symbol of the asset for this product.
»» name string true none The corresponding name in the specs setting.
»» isActive boolean true none The state of the tradable product. If true, then this product is available to trade on the exchange, otherwise false.
»» createdAt string(date-time) true none The time when this row was added to the database.
» success boolean true none Whether the request was successful
» timestamp number true none The timestamp of the response

Status Code 400

Name Type Required Restrictions Description
» success boolean true none none
» errorMsg any false none none

anyOf

Name Type Required Restrictions Description
»» anonymous string false none none

or

Name Type Required Restrictions Description
»» anonymous [object] false none none

Status Code 500

Name Type Required Restrictions Description
» success boolean true none none
» errorMsg any false none none

anyOf

Name Type Required Restrictions Description
»» anonymous string false none none

or

Name Type Required Restrictions Description
»» anonymous [object] false none none

Market

These APIs return key high level metrics for markets.

Get Funding Rate History

Code samples

require 'rest-client'
require 'json'

headers = {
  'Accept' => 'application/json'
}

result = RestClient.get '/stats/api/v1/funding_rate_history',
  params: {
  }, headers: headers

p JSON.parse(result)
import requests
headers = {
  'Accept': 'application/json'
}

r = requests.get('/stats/api/v1/funding_rate_history', headers = headers)

print(r.json())

const headers = {
  'Accept':'application/json'
};

fetch('/stats/api/v1/funding_rate_history',
{
  method: 'GET',

  headers: headers
})
.then(function(res) {
    return res.json();
}).then(function(body) {
    console.log(body);
});

GET /stats/api/v1/funding_rate_history

Get funding rates over time

Parameters

Name In Type Required Description
limit query integer false The number of rows to return
epoch query integer false The epoch boundary used when fetching the next timeseries page.
txOrdinal query integer false The txOrdinal boundary used when fetching the next timeseries page. Must be passed along with epoch.
order query string false The ordering of the results.
symbol query string false The symbol
since query integer false The earliest time in seconds to fetch rows for. This param cannot be used together with param order = 'desc'
Enumerated Values
Parameter Value
order asc
order desc

Responses

Status Meaning Description Schema
200 OK Funding Rate History Data Inline
400 Bad Request Bad request Inline
500 Internal Server Error Unexpected error Inline

Response Schema

Example responses

200 Response

{
  "value": [
    {
      "epochId": 100,
      "txOrdinal": 3432,
      "symbol": "BTCP",
      "fundingRate": "0.005",
      "createdAt": "2023-01-06T16:37:27.929Z"
    }
  ],
  "success": true,
  "timestamp": 1673031089
}

Status Code 200

Successful response for the Funding Rate History API

Name Type Required Restrictions Description
» value [object] true none The value of the response
»» epochId string true none The epoch in which this funding rate update occured.
»» txOrdinal string true none The transaction ordinal, within the epoch.
»» symbol string true none The symbol of the market.
»» fundingRate string true none The funding rate for the given market.
»» createdAt string(date-time) true none The time when this row was added to the database.
» success boolean true none Whether the request was successful
» timestamp number true none The timestamp of the response

Status Code 400

Name Type Required Restrictions Description
» success boolean true none none
» errorMsg any false none none

anyOf

Name Type Required Restrictions Description
»» anonymous string false none none

or

Name Type Required Restrictions Description
»» anonymous [object] false none none

Status Code 500

Name Type Required Restrictions Description
» success boolean true none none
» errorMsg any false none none

anyOf

Name Type Required Restrictions Description
»» anonymous string false none none

or

Name Type Required Restrictions Description
»» anonymous [object] false none none

Get Order Book (L2)

Code samples

require 'rest-client'
require 'json'

headers = {
  'Accept' => 'application/json'
}

result = RestClient.get '/stats/api/v1/markets/order_book/L2',
  params: {
  }, headers: headers

p JSON.parse(result)
import requests
headers = {
  'Accept': 'application/json'
}

r = requests.get('/stats/api/v1/markets/order_book/L2', headers = headers)

print(r.json())

const headers = {
  'Accept':'application/json'
};

fetch('/stats/api/v1/markets/order_book/L2',
{
  method: 'GET',

  headers: headers
})
.then(function(res) {
    return res.json();
}).then(function(body) {
    console.log(body);
});

GET /stats/api/v1/markets/order_book/L2

Get current L2 aggregated order book

Parameters

Name In Type Required Description
symbol query string false The symbol
depth query integer false The best N bids and asks to return, where N = depth
side query integer false The side of the order. Values include:
priceAggregation query number false The price aggregation to use for the L2 orderbook. Valid values for each symbol include:
Detailed descriptions

side: The side of the order. Values include: 0: Bid, 1: Ask

priceAggregation: The price aggregation to use for the L2 orderbook. Valid values for each symbol include: ETHP: 0.1, 1, 10 BTCP: 1, 10, 100

Enumerated Values
Parameter Value
side 0
side 1
priceAggregation 0.1
priceAggregation 1
priceAggregation 10
priceAggregation 100

Responses

Status Meaning Description Schema
200 OK Order Book L2 data Inline
400 Bad Request Bad request Inline
500 Internal Server Error Unexpected error Inline

Response Schema

Example responses

200 Response

{
  "value": [
    {
      "symbol": "ETHP",
      "amount": "0.1",
      "price": 1000,
      "side": 0
    }
  ],
  "success": true,
  "timestamp": 1673031089
}

Status Code 200

Successful response for the Order Book L2 API

Name Type Required Restrictions Description
» value [object] true none The value of the response
»» symbol string true none The symbol of the asset for this order aggregation.
»» side number true none The side of the order aggregation. Values include: 0: Bid, 1: Ask
»» amount string true none The order amount currently left on this aggregation level.
»» price string true none The price level of the aggregation.
» success boolean true none Whether the request was successful
» timestamp number true none The timestamp of the response

Status Code 400

Name Type Required Restrictions Description
» success boolean true none none
» errorMsg any false none none

anyOf

Name Type Required Restrictions Description
»» anonymous string false none none

or

Name Type Required Restrictions Description
»» anonymous [object] false none none

Status Code 500

Name Type Required Restrictions Description
» success boolean true none none
» errorMsg any false none none

anyOf

Name Type Required Restrictions Description
»» anonymous string false none none

or

Name Type Required Restrictions Description
»» anonymous [object] false none none

Get Open Interest History

Code samples

require 'rest-client'
require 'json'

headers = {
  'Accept' => 'application/json'
}

result = RestClient.get '/stats/api/v1/open_interest_history',
  params: {
  }, headers: headers

p JSON.parse(result)
import requests
headers = {
  'Accept': 'application/json'
}

r = requests.get('/stats/api/v1/open_interest_history', headers = headers)

print(r.json())

const headers = {
  'Accept':'application/json'
};

fetch('/stats/api/v1/open_interest_history',
{
  method: 'GET',

  headers: headers
})
.then(function(res) {
    return res.json();
}).then(function(body) {
    console.log(body);
});

GET /stats/api/v1/open_interest_history

Get open interest over time

Parameters

Name In Type Required Description
limit query integer false The number of rows to return
order query string false The ordering of the results.
symbol query string false The symbol
interval query string false The interval for open interest history.
since query integer false The earliest time in seconds to fetch rows for. This param cannot be used together with param order = 'desc'
Enumerated Values
Parameter Value
order asc
order desc
interval 5m
interval 1h
interval 1d

Responses

Status Meaning Description Schema
200 OK Open Interest History Data Inline
400 Bad Request Bad request Inline
500 Internal Server Error Unexpected error Inline

Response Schema

Example responses

200 Response

{
  "value": [
    {
      "symbol": "BTCP",
      "amount": "1000",
      "createdAt": "2023-01-06T16:37:27.929Z"
    }
  ],
  "success": true,
  "timestamp": 1673031089
}

Status Code 200

Successful response for the Open Interest History API

Name Type Required Restrictions Description
» value [object] true none The value of the response
»» symbol string true none The symbol of the market.
»» amount string true none The amount of open interest for the given market.
»» createdAt string(date-time) true none The time when this row was added to the database.
» success boolean true none Whether the request was successful
» timestamp number true none The timestamp of the response

Status Code 400

Name Type Required Restrictions Description
» success boolean true none none
» errorMsg any false none none

anyOf

Name Type Required Restrictions Description
»» anonymous string false none none

or

Name Type Required Restrictions Description
»» anonymous [object] false none none

Status Code 500

Name Type Required Restrictions Description
» success boolean true none none
» errorMsg any false none none

anyOf

Name Type Required Restrictions Description
»» anonymous string false none none

or

Name Type Required Restrictions Description
»» anonymous [object] false none none

Get Price Checkpoint History

Code samples

require 'rest-client'
require 'json'

headers = {
  'Accept' => 'application/json'
}

result = RestClient.get '/stats/api/v1/price_checkpoints',
  params: {
  }, headers: headers

p JSON.parse(result)
import requests
headers = {
  'Accept': 'application/json'
}

r = requests.get('/stats/api/v1/price_checkpoints', headers = headers)

print(r.json())

const headers = {
  'Accept':'application/json'
};

fetch('/stats/api/v1/price_checkpoints',
{
  method: 'GET',

  headers: headers
})
.then(function(res) {
    return res.json();
}).then(function(body) {
    console.log(body);
});

GET /stats/api/v1/price_checkpoints

Get price checkpoints over time

Parameters

Name In Type Required Description
limit query integer false The number of rows to return
epoch query integer false The epoch boundary used when fetching the next timeseries page.
txOrdinal query integer false The txOrdinal boundary used when fetching the next timeseries page. Must be passed along with epoch.
order query string false The ordering of the results.
symbol query string false The symbol
priceHash query string false the index price hash of the mark price. Multiple price hash values can be provided.
Enumerated Values
Parameter Value
order asc
order desc

Responses

Status Meaning Description Schema
200 OK Price checkpoint data Inline
400 Bad Request Bad request Inline
500 Internal Server Error Unexpected error Inline

Response Schema

Example responses

200 Response

{
  "nextEpoch": 100,
  "nextTxOrdinal": 3432,
  "nextOrdinal": 100,
  "value": [
    {
      "epochId": 100,
      "txOrdinal": 3432,
      "indexPriceHash": "0x607b9303d1da6aa842c4f7af2ae18d8616e5af63b692a05151",
      "symbol": "ETHP",
      "indexPrice": "5311.571505",
      "markPrice": "5311.203",
      "time": "100",
      "ema": "-2.67",
      "priceOrdinal": "100",
      "createdAt": "2023-01-06T16:37:27.929Z"
    }
  ],
  "success": true,
  "timestamp": 1673031089
}

Status Code 200

Successful response for the Price Checkpoints API

Name Type Required Restrictions Description
» nextEpoch number,null true none Pointer for the epoch boundary of the next page. Will return null when there is no more data left to fetch.
» nextTxOrdinal number,null true none Pointer for the txOrdinal boundary of the next page. Will return null when there is no more data left to fetch.
» nextOrdinal number,null true none Pointer for the ordinal boundary of the next page. Will return null when there is no more data left to fetch.
» value [object] true none The value of the response
»» epochId string true none The epoch in which this transaction occured.
»» txOrdinal string true none The transaction ordinal, within the epoch.
»» indexPriceHash string true none The hash of the index price.
»» symbol string true none The symbol of the asset.
»» indexPrice string true none The exponential weighted average of prices from the price feed by source.
»» markPrice string true none The index price + ema clamped to 50bps above/below the index price at all times.
»» time string true none The monotonic clock tick associated with this price checkpoint.
»» ema string,null true none Exponential moving average which tracks the spread between the DerivaDEX Petual swap price and the underlying index price it is tracking.
»» priceOrdinal string true none The ordinal of this price update.
»» createdAt string(date-time) true none The time when this row was added to the database.
» success boolean true none Whether the request was successful
» timestamp number true none The timestamp of the response

Status Code 400

Name Type Required Restrictions Description
» success boolean true none none
» errorMsg any false none none

anyOf

Name Type Required Restrictions Description
»» anonymous string false none none

or

Name Type Required Restrictions Description
»» anonymous [object] false none none

Status Code 500

Name Type Required Restrictions Description
» success boolean true none none
» errorMsg any false none none

anyOf

Name Type Required Restrictions Description
»» anonymous string false none none

or

Name Type Required Restrictions Description
»» anonymous [object] false none none

Aggregations

Balance aggregation

Code samples

require 'rest-client'
require 'json'

headers = {
  'Accept' => 'application/json'
}

result = RestClient.get '/stats/api/v1/aggregations/account/{trader}/strategy/{strategyId}/balance',
  params: {
  }, headers: headers

p JSON.parse(result)
import requests
headers = {
  'Accept': 'application/json'
}

r = requests.get('/stats/api/v1/aggregations/account/{trader}/strategy/{strategyId}/balance', headers = headers)

print(r.json())

const headers = {
  'Accept':'application/json'
};

fetch('/stats/api/v1/aggregations/account/{trader}/strategy/{strategyId}/balance',
{
  method: 'GET',

  headers: headers
})
.then(function(res) {
    return res.json();
}).then(function(body) {
    console.log(body);
});

GET /stats/api/v1/aggregations/account/{trader}/strategy/{strategyId}/balance

Returns the change of trader's balance for a specific strategy over a specific time period, looking back from the present

Parameters

Name In Type Required Description
limit query integer false The number of rows to return
trader path string true The trader address.
strategyId path string true The strategy ID.
aggregationPeriod query string false The period for the aggregation.
lookbackCount query integer false The number of periods to look back from present.
Enumerated Values
Parameter Value
aggregationPeriod week
aggregationPeriod day
aggregationPeriod hour
aggregationPeriod minute

Responses

Status Meaning Description Schema
200 OK Balance aggregation data Inline
400 Bad Request Bad request Inline
500 Internal Server Error Unexpected error Inline

Response Schema

Example responses

200 Response

{
  "value": [
    {
      "trader": "0x00b993e587c15a9e0a0fe4f111de98fd6b5ce7067d",
      "strategyIdHash": "0x2576ebd1",
      "amount": "0.9",
      "timestamp": 1673308800
    }
  ],
  "success": true,
  "timestamp": 1673031089
}

Status Code 200

Successful response for the Balance API

Name Type Required Restrictions Description
» value [object] true none The value of the response
»» trader string true none The trader address prefixed with the blockchain discriminant.
»» strategyIdHash string true none The strategy id hash of the trader.
»» amount string true none The amount.
»» timestamp number true none The unix timestamp at the start of the aggregation period.
» success boolean true none Whether the request was successful
» timestamp number true none The timestamp of the response

Status Code 400

Name Type Required Restrictions Description
» success boolean true none none
» errorMsg any false none none

anyOf

Name Type Required Restrictions Description
»» anonymous string false none none

or

Name Type Required Restrictions Description
»» anonymous [object] false none none

Status Code 500

Name Type Required Restrictions Description
» success boolean true none none
» errorMsg any false none none

anyOf

Name Type Required Restrictions Description
»» anonymous string false none none

or

Name Type Required Restrictions Description
»» anonymous [object] false none none

Funding rate payments aggregation

Code samples

require 'rest-client'
require 'json'

headers = {
  'Accept' => 'application/json'
}

result = RestClient.get '/stats/api/v1/aggregations/account/{trader}/strategy/{strategyId}/funding_rate_payments',
  params: {
  }, headers: headers

p JSON.parse(result)
import requests
headers = {
  'Accept': 'application/json'
}

r = requests.get('/stats/api/v1/aggregations/account/{trader}/strategy/{strategyId}/funding_rate_payments', headers = headers)

print(r.json())

const headers = {
  'Accept':'application/json'
};

fetch('/stats/api/v1/aggregations/account/{trader}/strategy/{strategyId}/funding_rate_payments',
{
  method: 'GET',

  headers: headers
})
.then(function(res) {
    return res.json();
}).then(function(body) {
    console.log(body);
});

GET /stats/api/v1/aggregations/account/{trader}/strategy/{strategyId}/funding_rate_payments

Returns the change of trader's funding rate payments for a specific strategy over a specific time period, looking back from the present

Parameters

Name In Type Required Description
trader path string true The trader address.
strategyId path string true The strategy ID.
aggregationPeriod query string false The period for the aggregation.
lookbackCount query integer false The number of periods to look back from present.
Enumerated Values
Parameter Value
aggregationPeriod week
aggregationPeriod day
aggregationPeriod hour
aggregationPeriod minute

Responses

Status Meaning Description Schema
200 OK Funding rate payments aggregation data Inline
400 Bad Request Bad request Inline
500 Internal Server Error Unexpected error Inline

Response Schema

Example responses

200 Response

{
  "value": [
    {
      "trader": "0x00b993e587c15a9e0a0fe4f111de98fd6b5ce7067d",
      "strategyIdHash": "0x2576ebd1",
      "amount": "0.9",
      "timestamp": 1673308800
    }
  ],
  "success": true,
  "timestamp": 1673031089
}

Status Code 200

Successful response for the Funding Rate Payments API

Name Type Required Restrictions Description
» value [object] true none The value of the response
»» trader string true none The trader address prefixed with the blockchain discriminant.
»» strategyIdHash string true none The strategy id hash of the trader.
»» amount string true none The amount.
»» timestamp number true none The unix timestamp at the start of the aggregation period.
» success boolean true none Whether the request was successful
» timestamp number true none The timestamp of the response

Status Code 400

Name Type Required Restrictions Description
» success boolean true none none
» errorMsg any false none none

anyOf

Name Type Required Restrictions Description
»» anonymous string false none none

or

Name Type Required Restrictions Description
»» anonymous [object] false none none

Status Code 500

Name Type Required Restrictions Description
» success boolean true none none
» errorMsg any false none none

anyOf

Name Type Required Restrictions Description
»» anonymous string false none none

or

Name Type Required Restrictions Description
»» anonymous [object] false none none

Realized pnl aggregation

Code samples

require 'rest-client'
require 'json'

headers = {
  'Accept' => 'application/json'
}

result = RestClient.get '/stats/api/v1/aggregations/account/{trader}/strategy/{strategyId}/realized_pnl',
  params: {
  }, headers: headers

p JSON.parse(result)
import requests
headers = {
  'Accept': 'application/json'
}

r = requests.get('/stats/api/v1/aggregations/account/{trader}/strategy/{strategyId}/realized_pnl', headers = headers)

print(r.json())

const headers = {
  'Accept':'application/json'
};

fetch('/stats/api/v1/aggregations/account/{trader}/strategy/{strategyId}/realized_pnl',
{
  method: 'GET',

  headers: headers
})
.then(function(res) {
    return res.json();
}).then(function(body) {
    console.log(body);
});

GET /stats/api/v1/aggregations/account/{trader}/strategy/{strategyId}/realized_pnl

Returns the change of trader's realized pnl, per time period looking back from the present

Parameters

Name In Type Required Description
trader path string true The trader address.
strategyId path string true The strategy ID.
aggregationPeriod query string false The period for the aggregation.
lookbackCount query integer false The number of periods to look back from present.
Enumerated Values
Parameter Value
aggregationPeriod week
aggregationPeriod day
aggregationPeriod hour
aggregationPeriod minute

Responses

Status Meaning Description Schema
200 OK Realized Pnl aggregation data Inline
400 Bad Request Bad request Inline
500 Internal Server Error Unexpected error Inline

Response Schema

Example responses

200 Response

{
  "value": [
    {
      "trader": "0x00b993e587c15a9e0a0fe4f111de98fd6b5ce7067d",
      "strategyIdHash": "0x2576ebd1",
      "amount": "0.9",
      "timestamp": 1673308800
    }
  ],
  "success": true,
  "timestamp": 1673031089
}

Status Code 200

Successful response for the Realized Pnl API

Name Type Required Restrictions Description
» value [object] true none The value of the response
»» trader string true none The trader address prefixed with the blockchain discriminant.
»» strategyIdHash string true none The strategy id hash of the trader.
»» amount string true none The amount.
»» timestamp number true none The unix timestamp at the start of the aggregation period.
» success boolean true none Whether the request was successful
» timestamp number true none The timestamp of the response

Status Code 400

Name Type Required Restrictions Description
» success boolean true none none
» errorMsg any false none none

anyOf

Name Type Required Restrictions Description
»» anonymous string false none none

or

Name Type Required Restrictions Description
»» anonymous [object] false none none

Status Code 500

Name Type Required Restrictions Description
» success boolean true none none
» errorMsg any false none none

anyOf

Name Type Required Restrictions Description
»» anonymous string false none none

or

Name Type Required Restrictions Description
»» anonymous [object] false none none

Volume aggregation

Code samples

require 'rest-client'
require 'json'

headers = {
  'Accept' => 'application/json'
}

result = RestClient.get '/stats/api/v1/aggregations/volume',
  params: {
  }, headers: headers

p JSON.parse(result)
import requests
headers = {
  'Accept': 'application/json'
}

r = requests.get('/stats/api/v1/aggregations/volume', headers = headers)

print(r.json())

const headers = {
  'Accept':'application/json'
};

fetch('/stats/api/v1/aggregations/volume',
{
  method: 'GET',

  headers: headers
})
.then(function(res) {
    return res.json();
}).then(function(body) {
    console.log(body);
});

GET /stats/api/v1/aggregations/volume

Returns volume per time period looking back from the present

Parameters

Name In Type Required Description
group query string false The grouping for the aggregation.
symbol query string false The symbol
aggregationPeriod query string false The period for the aggregation.
lookbackCount query integer false The number of periods to look back from present.
lookbackTimestamp query number false The timestamp of the when to begin the lookback from. Each lookback query will return nextLookbackTimestamp in the response, which can be passed as a query parameter here to get the next page of results.
Detailed descriptions

lookbackTimestamp: The timestamp of the when to begin the lookback from. Each lookback query will return nextLookbackTimestamp in the response, which can be passed as a query parameter here to get the next page of results.

Enumerated Values
Parameter Value
group symbol
aggregationPeriod week
aggregationPeriod day
aggregationPeriod hour
aggregationPeriod minute

Responses

Status Meaning Description Schema
200 OK Volume aggregation data Inline
400 Bad Request Bad request Inline
500 Internal Server Error Unexpected error Inline

Response Schema

Example responses

200 Response

{
  "nextLookbackTimestamp": 1673384400,
  "value": [
    {
      "timestamp": 1673308800,
      "volume_notional_overall": "164113411.21248"
    }
  ],
  "success": true,
  "timestamp": 1673031089
}

Status Code 200

Successful response for the Volume aggregation API

Name Type Required Restrictions Description
» nextLookbackTimestamp number,null true none Time pointer for where the next lookback should begin. Pass this value as lookbackTimestamp to get the next page of data. Will also skip over gaps in the data to return the next non-null. aggregation period. When this value is null, it indicates there is no more data to fetch.
» value [object] true none The value of the response
»» additionalProperties string false none none
»» timestamp number true none The unix timestamp at the start of the aggregation period.
» success boolean true none Whether the request was successful
» timestamp number true none The timestamp of the response

Status Code 400

Name Type Required Restrictions Description
» success boolean true none none
» errorMsg any false none none

anyOf

Name Type Required Restrictions Description
»» anonymous string false none none

or

Name Type Required Restrictions Description
»» anonymous [object] false none none

Status Code 500

Name Type Required Restrictions Description
» success boolean true none none
» errorMsg any false none none

anyOf

Name Type Required Restrictions Description
»» anonymous string false none none

or

Name Type Required Restrictions Description
»» anonymous [object] false none none

Trade Mining Rewards for the trader

Code samples

require 'rest-client'
require 'json'

headers = {
  'Accept' => 'application/json'
}

result = RestClient.get '/stats/api/v1/aggregations/account/{trader}/trade_mining_rewards',
  params: {
  }, headers: headers

p JSON.parse(result)
import requests
headers = {
  'Accept': 'application/json'
}

r = requests.get('/stats/api/v1/aggregations/account/{trader}/trade_mining_rewards', headers = headers)

print(r.json())

const headers = {
  'Accept':'application/json'
};

fetch('/stats/api/v1/aggregations/account/{trader}/trade_mining_rewards',
{
  method: 'GET',

  headers: headers
})
.then(function(res) {
    return res.json();
}).then(function(body) {
    console.log(body);
});

GET /stats/api/v1/aggregations/account/{trader}/trade_mining_rewards

Returns the aggregation of a trader's trade mining rewards

Parameters

Name In Type Required Description
trader path string true The trader address.
aggregationPeriod query string false The period for the aggregation.
lookbackCount query integer false The number of periods to look back from present.
Enumerated Values
Parameter Value
aggregationPeriod week
aggregationPeriod day
aggregationPeriod hour
aggregationPeriod minute

Responses

Status Meaning Description Schema
200 OK Trade mining rewards aggregation data Inline
400 Bad Request Bad request Inline
500 Internal Server Error Unexpected error Inline

Response Schema

Example responses

200 Response

{
  "value": [
    {
      "trader": "0x00b993e587c15a9e0a0fe4f111de98fd6b5ce7067d",
      "amount": "0.9",
      "timestamp": 1673308800
    }
  ],
  "success": true,
  "timestamp": 1673031089
}

Status Code 200

Successful response for the Trade Mining Rewards API

Name Type Required Restrictions Description
» value [object] true none The value of the response
»» trader string true none The trader address prefixed with the blockchain discriminant.
»» amount string true none The amount.
»» timestamp number true none The unix timestamp at the start of the aggregation period.
» success boolean true none Whether the request was successful
» timestamp number true none The timestamp of the response

Status Code 400

Name Type Required Restrictions Description
» success boolean true none none
» errorMsg any false none none

anyOf

Name Type Required Restrictions Description
»» anonymous string false none none

or

Name Type Required Restrictions Description
»» anonymous [object] false none none

Status Code 500

Name Type Required Restrictions Description
» success boolean true none none
» errorMsg any false none none

anyOf

Name Type Required Restrictions Description
»» anonymous string false none none

or

Name Type Required Restrictions Description
»» anonymous [object] false none none

Top Traders

Code samples

require 'rest-client'
require 'json'

headers = {
  'Accept' => 'application/json'
}

result = RestClient.get '/stats/api/v1/aggregations/traders',
  params: {
  }, headers: headers

p JSON.parse(result)
import requests
headers = {
  'Accept': 'application/json'
}

r = requests.get('/stats/api/v1/aggregations/traders', headers = headers)

print(r.json())

const headers = {
  'Accept':'application/json'
};

fetch('/stats/api/v1/aggregations/traders',
{
  method: 'GET',

  headers: headers
})
.then(function(res) {
    return res.json();
}).then(function(body) {
    console.log(body);
});

GET /stats/api/v1/aggregations/traders

Returns the top N traders by volume

Parameters

Name In Type Required Description
limit query integer false The number of rows to return
cursor query integer false The cursor for the beginning of the next page of top traders to fetch.
topTradersOrdering query string false The order by which to fetch top traders.
order query string false The ordering of the results.
Enumerated Values
Parameter Value
topTradersOrdering volume
topTradersOrdering pnl
topTradersOrdering accountValue
order asc
order desc

Responses

Status Meaning Description Schema
200 OK Top Traders data Inline
400 Bad Request Bad request Inline
500 Internal Server Error Unexpected error Inline

Response Schema

Example responses

200 Response

{
  "value": [
    {
      "trader": "0x00b993e587c15a9e0a0fe4f111de98fd6b5ce7067d",
      "volume": "18026.42",
      "realizedPnl": "173.10",
      "accountValue": "5600"
    }
  ],
  "nextCursor": 100,
  "success": true,
  "timestamp": 1673031089
}

Status Code 200

Successful response for the TopTraders API

Name Type Required Restrictions Description
» value [object] true none The value of the response
»» trader string true none The trader address prefixed with the blockchain discriminant.
»» volume string,null true none The notional sum of the asset traded.
»» realizedPnl string,null true none The total realized pnl for the trader, excluding funding payments.
»» accountValue string,null true none The total amount of usdc collateral held by this trader.
» nextCursor number,null true none The cursor for the beginning of the next page of top traders to fetch.
» success boolean true none Whether the request was successful
» timestamp number true none The timestamp of the response

Status Code 400

Name Type Required Restrictions Description
» success boolean true none none
» errorMsg any false none none

anyOf

Name Type Required Restrictions Description
»» anonymous string false none none

or

Name Type Required Restrictions Description
»» anonymous [object] false none none

Status Code 500

Name Type Required Restrictions Description
» success boolean true none none
» errorMsg any false none none

anyOf

Name Type Required Restrictions Description
»» anonymous string false none none

or

Name Type Required Restrictions Description
»» anonymous [object] false none none

Collateral aggregation

Code samples

require 'rest-client'
require 'json'

headers = {
  'Accept' => 'application/json'
}

result = RestClient.get '/stats/api/v1/aggregations/collateral',
  params: {
  }, headers: headers

p JSON.parse(result)
import requests
headers = {
  'Accept': 'application/json'
}

r = requests.get('/stats/api/v1/aggregations/collateral', headers = headers)

print(r.json())

const headers = {
  'Accept':'application/json'
};

fetch('/stats/api/v1/aggregations/collateral',
{
  method: 'GET',

  headers: headers
})
.then(function(res) {
    return res.json();
}).then(function(body) {
    console.log(body);
});

GET /stats/api/v1/aggregations/collateral

Returns a rolling sum of collateral per time period grouped by the inflow and outflow types.

Parameters

Name In Type Required Description
aggregationPeriod query string false The period for the aggregation.
startingValue query number false The partial total of this aggregation, used for rolling aggregation paging.
fromEpoch query integer false The from epoch
toEpoch query integer false The to epoch
Enumerated Values
Parameter Value
aggregationPeriod week
aggregationPeriod day
aggregationPeriod hour
aggregationPeriod minute

Responses

Status Meaning Description Schema
200 OK Collateral aggregation data Inline
400 Bad Request Bad request Inline
500 Internal Server Error Unexpected error Inline

Response Schema

Example responses

200 Response

{
  "nextStartingValue": "34000",
  "value": [
    {
      "timestamp": 1673222400,
      "collateral_deposits": "765000000",
      "collateral_withdrawals": "-4125604.939779",
      "collateral_fees": "-122277.669972",
      "collateral_liquidations": "-339878.8954",
      "collateral_overall": "760412238.494849"
    }
  ],
  "success": true,
  "timestamp": 1673031089
}

Status Code 200

Successful response for the Collateral aggregation API

Name Type Required Restrictions Description
» nextStartingValue string,null true none The partial total for this aggregation, which can be passed as startingValue to get the next page for rolling aggregation type APIs.
» value [object] true none The value of the response
»» additionalProperties string false none none
»» timestamp number true none The unix timestamp at the start of the aggregation period.
» success boolean true none Whether the request was successful
» timestamp number true none The timestamp of the response

Status Code 400

Name Type Required Restrictions Description
» success boolean true none none
» errorMsg any false none none

anyOf

Name Type Required Restrictions Description
»» anonymous string false none none

or

Name Type Required Restrictions Description
»» anonymous [object] false none none

Status Code 500

Name Type Required Restrictions Description
» success boolean true none none
» errorMsg any false none none

anyOf

Name Type Required Restrictions Description
»» anonymous string false none none

or

Name Type Required Restrictions Description
»» anonymous [object] false none none

DDX aggregation

Code samples

require 'rest-client'
require 'json'

headers = {
  'Accept' => 'application/json'
}

result = RestClient.get '/stats/api/v1/aggregations/ddx',
  params: {
  }, headers: headers

p JSON.parse(result)
import requests
headers = {
  'Accept': 'application/json'
}

r = requests.get('/stats/api/v1/aggregations/ddx', headers = headers)

print(r.json())

const headers = {
  'Accept':'application/json'
};

fetch('/stats/api/v1/aggregations/ddx',
{
  method: 'GET',

  headers: headers
})
.then(function(res) {
    return res.json();
}).then(function(body) {
    console.log(body);
});

GET /stats/api/v1/aggregations/ddx

Returns a rolling sum of DDX per time period grouped by the inflow and outflow types.

Parameters

Name In Type Required Description
aggregationPeriod query string false The period for the aggregation.
startingValue query number false The partial total of this aggregation, used for rolling aggregation paging.
fromEpoch query integer false The from epoch
toEpoch query integer false The to epoch
Enumerated Values
Parameter Value
aggregationPeriod week
aggregationPeriod day
aggregationPeriod hour
aggregationPeriod minute

Responses

Status Meaning Description Schema
200 OK DDX aggregation data Inline
400 Bad Request Bad request Inline
500 Internal Server Error Unexpected error Inline

Response Schema

Example responses

200 Response

{
  "nextStartingValue": "34000",
  "value": [
    {
      "timestamp": 1669680000,
      "ddx_deposits": "2000000",
      "ddx_withdrawals": "0",
      "ddx_trade-mining-rewards": "0",
      "ddx_fees": "0",
      "ddx_overall": "2000000"
    }
  ],
  "success": true,
  "timestamp": 1673031089
}

Status Code 200

Successful response for the DDX aggregaton API

Name Type Required Restrictions Description
» nextStartingValue string,null true none The partial total for this aggregation, which can be passed as startingValue to get the next page for rolling aggregation type APIs.
» value [object] true none The value of the response
»» additionalProperties string false none none
»» timestamp number true none The unix timestamp at the start of the aggregation period.
» success boolean true none Whether the request was successful
» timestamp number true none The timestamp of the response

Status Code 400

Name Type Required Restrictions Description
» success boolean true none none
» errorMsg any false none none

anyOf

Name Type Required Restrictions Description
»» anonymous string false none none

or

Name Type Required Restrictions Description
»» anonymous [object] false none none

Status Code 500

Name Type Required Restrictions Description
» success boolean true none none
» errorMsg any false none none

anyOf

Name Type Required Restrictions Description
»» anonymous string false none none

or

Name Type Required Restrictions Description
»» anonymous [object] false none none

Fees aggregation

Code samples

require 'rest-client'
require 'json'

headers = {
  'Accept' => 'application/json'
}

result = RestClient.get '/stats/api/v1/aggregations/fees',
  params: {
  }, headers: headers

p JSON.parse(result)
import requests
headers = {
  'Accept': 'application/json'
}

r = requests.get('/stats/api/v1/aggregations/fees', headers = headers)

print(r.json())

const headers = {
  'Accept':'application/json'
};

fetch('/stats/api/v1/aggregations/fees',
{
  method: 'GET',

  headers: headers
})
.then(function(res) {
    return res.json();
}).then(function(body) {
    console.log(body);
});

GET /stats/api/v1/aggregations/fees

Returns fees per time period looking back from the present

Parameters

Name In Type Required Description
group query string false The grouping for the aggregation.
symbol query string false The symbol
feeSymbol query string false The fee symbol
aggregationPeriod query string false The period for the aggregation.
lookbackCount query integer false The number of periods to look back from present.
lookbackTimestamp query number false The timestamp of the when to begin the lookback from. Each lookback query will return nextLookbackTimestamp in the response, which can be passed as a query parameter here to get the next page of results.
Detailed descriptions

lookbackTimestamp: The timestamp of the when to begin the lookback from. Each lookback query will return nextLookbackTimestamp in the response, which can be passed as a query parameter here to get the next page of results.

Enumerated Values
Parameter Value
group symbol
group feeSymbol
feeSymbol USDC
feeSymbol DDX
aggregationPeriod week
aggregationPeriod day
aggregationPeriod hour
aggregationPeriod minute

Responses

Status Meaning Description Schema
200 OK Fees aggregation data Inline
400 Bad Request Bad request Inline
500 Internal Server Error Unexpected error Inline

Response Schema

Example responses

200 Response

{
  "nextLookbackTimestamp": 1673384400,
  "value": [
    {
      "timestamp": 1671062400,
      "fees_DDX": "5.823239",
      "fees_USDC": "7.8"
    }
  ],
  "success": true,
  "timestamp": 1673031089
}

Status Code 200

Successful response for the Fees aggregation API

Name Type Required Restrictions Description
» nextLookbackTimestamp number,null true none Time pointer for where the next lookback should begin. Pass this value as lookbackTimestamp to get the next page of data. Will also skip over gaps in the data to return the next non-null. aggregation period. When this value is null, it indicates there is no more data to fetch.
» value [object] true none The value of the response
»» additionalProperties string false none none
»» timestamp number true none The unix timestamp at the start of the aggregation period.
» success boolean true none Whether the request was successful
» timestamp number true none The timestamp of the response

Status Code 400

Name Type Required Restrictions Description
» success boolean true none none
» errorMsg any false none none

anyOf

Name Type Required Restrictions Description
»» anonymous string false none none

or

Name Type Required Restrictions Description
»» anonymous [object] false none none

Status Code 500

Name Type Required Restrictions Description
» success boolean true none none
» errorMsg any false none none

anyOf

Name Type Required Restrictions Description
»» anonymous string false none none

or

Name Type Required Restrictions Description
»» anonymous [object] false none none

Funding Rate Comparison

Code samples

require 'rest-client'
require 'json'

headers = {
  'Accept' => 'application/json'
}

result = RestClient.get '/stats/api/v1/aggregations/funding_rate_comparison',
  params: {
  }, headers: headers

p JSON.parse(result)
import requests
headers = {
  'Accept': 'application/json'
}

r = requests.get('/stats/api/v1/aggregations/funding_rate_comparison', headers = headers)

print(r.json())

const headers = {
  'Accept':'application/json'
};

fetch('/stats/api/v1/aggregations/funding_rate_comparison',
{
  method: 'GET',

  headers: headers
})
.then(function(res) {
    return res.json();
}).then(function(body) {
    console.log(body);
});

GET /stats/api/v1/aggregations/funding_rate_comparison

Returns funding rate comparison data between DerivaDEX and major exchanges

Parameters

Name In Type Required Description
symbol query string false The symbol

Responses

Status Meaning Description Schema
200 OK Funding Rate Comparison Data Inline
400 Bad Request Bad request Inline
500 Internal Server Error Unexpected error Inline

Response Schema

Example responses

200 Response

{
  "value": [
    {
      "symbol": "BTCP",
      "derivadexFundingRate": "0.005",
      "binanceFundingRate": "0.005",
      "derivadexBinanceArbitrage": "0.005",
      "bybitFundingRate": "0.005",
      "derivadexBybitArbitrage": "0.005"
    }
  ],
  "success": true,
  "timestamp": 1673031089
}

Status Code 200

Successful response for the Funding Rate Comparison API

Name Type Required Restrictions Description
» value [object] true none The value of the response
»» symbol string true none The symbol of the market.
»» derivadexFundingRate number true none The funding rate for the given market.
»» binanceFundingRate number true none The funding rate for the given market.
»» derivadexBinanceArbitrage number true none The funding rate difference between DerivaDEX and the given market.
»» bybitFundingRate number true none The funding rate for the given market.
»» derivadexBybitArbitrage number true none The funding rate difference between DerivaDEX and the given market.
» success boolean true none Whether the request was successful
» timestamp number true none The timestamp of the response

Status Code 400

Name Type Required Restrictions Description
» success boolean true none none
» errorMsg any false none none

anyOf

Name Type Required Restrictions Description
»» anonymous string false none none

or

Name Type Required Restrictions Description
»» anonymous [object] false none none

Status Code 500

Name Type Required Restrictions Description
» success boolean true none none
» errorMsg any false none none

anyOf

Name Type Required Restrictions Description
»» anonymous string false none none

or

Name Type Required Restrictions Description
»» anonymous [object] false none none

Insurance Fund aggregation

Code samples

require 'rest-client'
require 'json'

headers = {
  'Accept' => 'application/json'
}

result = RestClient.get '/stats/api/v1/aggregations/insurance_fund',
  params: {
  }, headers: headers

p JSON.parse(result)
import requests
headers = {
  'Accept': 'application/json'
}

r = requests.get('/stats/api/v1/aggregations/insurance_fund', headers = headers)

print(r.json())

const headers = {
  'Accept':'application/json'
};

fetch('/stats/api/v1/aggregations/insurance_fund',
{
  method: 'GET',

  headers: headers
})
.then(function(res) {
    return res.json();
}).then(function(body) {
    console.log(body);
});

GET /stats/api/v1/aggregations/insurance_fund

Returns a rolling sum of insurance fund value per time period grouped by the inflow and outflow types.

Parameters

Name In Type Required Description
aggregationPeriod query string false The period for the aggregation.
startingValue query number false The partial total of this aggregation, used for rolling aggregation paging.
fromEpoch query integer false The from epoch
toEpoch query integer false The to epoch
Enumerated Values
Parameter Value
aggregationPeriod week
aggregationPeriod day
aggregationPeriod hour
aggregationPeriod minute

Responses

Status Meaning Description Schema
200 OK Insurance Fund aggregation data Inline
400 Bad Request Bad request Inline
500 Internal Server Error Unexpected error Inline

Response Schema

Example responses

200 Response

{
  "nextStartingValue": "34000",
  "value": [
    {
      "timestamp": 1669766400,
      "insurance-fund_fees": "99.99534",
      "insurance-fund_positive-liquidations": "0",
      "insurance-fund_negative-liquidations": "0",
      "insurance-fund_deposits": "0",
      "insurance-fund_withdrawals": "0",
      "insurance-fund_overall": "99.99534"
    }
  ],
  "success": true,
  "timestamp": 1673031089
}

Status Code 200

Successful response for the Insurance Fund aggregation API

Name Type Required Restrictions Description
» nextStartingValue string,null true none The partial total for this aggregation, which can be passed as startingValue to get the next page for rolling aggregation type APIs.
» value [object] true none The value of the response
»» additionalProperties string false none none
»» timestamp number true none The unix timestamp at the start of the aggregation period.
» success boolean true none Whether the request was successful
» timestamp number true none The timestamp of the response

Status Code 400

Name Type Required Restrictions Description
» success boolean true none none
» errorMsg any false none none

anyOf

Name Type Required Restrictions Description
»» anonymous string false none none

or

Name Type Required Restrictions Description
»» anonymous [object] false none none

Status Code 500

Name Type Required Restrictions Description
» success boolean true none none
» errorMsg any false none none

anyOf

Name Type Required Restrictions Description
»» anonymous string false none none

or

Name Type Required Restrictions Description
»» anonymous [object] false none none

Public Exchange REST API

Scroll down for code samples, example requests and responses. Select a language for code samples from the tabs above or the mobile navigation menu.

This is a readonly Exchange REST API which can be used to fetch data about the DerivaDEX exchange. Realtime equivalents for most of these endpoints can be found in the Realtime API section.

Trader

These APIs provide data for a particular trader.

Get Trader Update History

Code samples

require 'rest-client'
require 'json'

headers = {
  'Accept' => 'application/json'
}

result = RestClient.get '/exchange/api/v1/trader_updates',
  params: {
  }, headers: headers

p JSON.parse(result)
import requests
headers = {
  'Accept': 'application/json'
}

r = requests.get('/exchange/api/v1/trader_updates', headers = headers)

print(r.json())
const headers = {
    Accept: 'application/json',
};

fetch('/exchange/api/v1/trader_updates', {
    method: 'GET',

    headers: headers,
})
    .then(function (res) {
        return res.json();
    })
    .then(function (body) {
        console.log(body);
    });

GET /exchange/api/v1/trader_updates

Get trader DDX balance and profile updates over time

Parameters

Name In Type Required Description
trader path string false The trader address, with the discriminant prefix.
reason query integer false The type of trader update. Multiple trader update values can be provided. Values include:
limit query integer false The number of rows to return
epoch query integer false The epoch boundary used when fetching the next timeseries page.
txOrdinal query integer false The txOrdinal boundary used when fetching the next timeseries page. Must be passed along with epoch.
ordinal query integer false The ordinal boundary used when fetching the next timeseries page. Must be passed along with epoch and txOrdinal.
order query string false The ordering of the results.
Detailed descriptions

reason: The type of trader update. Multiple trader update values can be provided. Values include: 0: Deposit - DDX was deposited on-chain, 1: WithdrawDDX - DDX withdrawal was claimed on-chain, 2: WithdrawDDXIntent - DDX was locked for withdrawal, 3: TradeMiningReward - DDX was rewarded for participation in trade mining, 4: ProfileUpdate - DDX fee preferences were changed, 5: FeeDistribution - DDX was rewarded for participation as a custodian during checkpointing,

Enumerated Values
Parameter Value
reason 0
reason 1
reason 2
reason 3
reason 4
reason 5
order asc
order desc

Responses

Status Meaning Description Schema
200 OK trader update data Inline
400 Bad Request Bad request Inline
500 Internal Server Error Unexpected error Inline

Response Schema

Example responses

200 Response

{
    "nextEpoch": 100,
    "nextTxOrdinal": 3432,
    "nextOrdinal": 100,
    "value": [
        {
            "epochId": 100,
            "txOrdinal": 3432,
            "ordinal": 0,
            "withdrawDdxRejection": 0,
            "reason": 0,
            "traderAddress": "0x00b993e587c15a9e0a0fe4f111de98fd6b5ce7067d",
            "amount": "1000",
            "newAvailDdxBalance": "1200",
            "newLockedDdxBalance": "100",
            "payFeesInDdx": true,
            "blockNumber": "344100",
            "createdAt": "2023-01-06T16:37:27.929Z"
        }
    ],
    "success": true,
    "timestamp": 1673031089
}

Status Code 200

Successful response for the Trader Update API

Name Type Required Restrictions Description
» nextEpoch number,null true none Pointer for the epoch boundary of the next page. Will return null when there is no more data left to fetch.
» nextTxOrdinal number,null true none Pointer for the txOrdinal boundary of the next page. Will return null when there is no more data left to fetch.
» nextOrdinal number,null true none Pointer for the ordinal boundary of the next page. Will return null when there is no more data left to fetch.
» value [object] true none The value of the response
»» epochId number true none The epoch in which this transaction occured.
»» txOrdinal number true none The transaction ordinal, within the epoch.
»» ordinal number true none The ordinal within this particular transaction.
»» withdrawDdxRejection number false none The withdraw rejection type when applicable. Optional field only present on rejections.
»» reason number true none The reason of trader update. Values include: 0: Deposit 1: WithdrawDDX 2: ClaimDDXWithdraw 3: TradeMiningReward 4: ProfileUpdate 5: FeeDistribution
»» traderAddress string true none The trader address prefixed with the blockchain discriminant of the trader.
»» amount string false none The amount of DDX was modified in this trader.
»» newAvailDdxBalance string false none The new DDX balance after updating this trader.
»» newLockedDdxBalance string false none The new locked DDX balance after updating this trader.
»» payFeesInDdx boolean false none A flag which when set will attempt to pay trading fees using the DDX held in this trader.
»» blockNumber number false none The block number in which this strategy update was processed.
»» createdAt string(date-time) true none The time when this row was added to the database.
» success boolean true none Whether the request was successful
» timestamp number true none The timestamp of the response
Enumerated Values
Property Value
withdrawDdxRejection 0
withdrawDdxRejection 1
reason 0
reason 1
reason 2
reason 3
reason 4
reason 5

Status Code 400

Name Type Required Restrictions Description
» success boolean true none none
» errorMsg any false none none

anyOf

Name Type Required Restrictions Description
»» anonymous string false none none

or

Name Type Required Restrictions Description
»» anonymous [object] false none none

Status Code 500

Name Type Required Restrictions Description
» success boolean true none none
» errorMsg any false none none

anyOf

Name Type Required Restrictions Description
»» anonymous string false none none

or

Name Type Required Restrictions Description
»» anonymous [object] false none none

Market

These APIs return key high level metrics for markets.

Get Mark Price History

Code samples

require 'rest-client'
require 'json'

headers = {
  'Accept' => 'application/json'
}

result = RestClient.get '/exchange/api/v1/mark_prices',
  params: {
  }, headers: headers

p JSON.parse(result)
import requests
headers = {
  'Accept': 'application/json'
}

r = requests.get('/exchange/api/v1/mark_prices', headers = headers)

print(r.json())
const headers = {
    Accept: 'application/json',
};

fetch('/exchange/api/v1/mark_prices', {
    method: 'GET',

    headers: headers,
})
    .then(function (res) {
        return res.json();
    })
    .then(function (body) {
        console.log(body);
    });

GET /exchange/api/v1/mark_prices

Get mark prices over time

Parameters

Name In Type Required Description
limit query integer false The number of rows to return
epoch query integer false The epoch boundary used when fetching the next timeseries page.
symbol query string false The symbol
order query string false The ordering of the results.
offset query integer false The offset of returned rows
Enumerated Values
Parameter Value
order asc
order desc

Responses

Status Meaning Description Schema
200 OK Mark price data Inline
400 Bad Request Bad request Inline
500 Internal Server Error Unexpected error Inline

Response Schema

Example responses

200 Response

{
    "value": [
        {
            "fundingRate": 0.005,
            "epochId": 100,
            "requestIndex": 981,
            "symbol": "ETHP",
            "price": 3428.44,
            "createdAt": "2023-01-06T16:37:27.929Z"
        }
    ],
    "success": true,
    "timestamp": 1673031089
}

Status Code 200

Successful response for the Mark Price API

Name Type Required Restrictions Description
» value [object] true none The value of the response
»» fundingRate string true none The funding rate value.
»» epochId string true none The epoch in which the mark price belongs.
»» requestIndex string true none The request index associated with the mark price.
»» symbol string true none The symbol of the asset.
»» price string true none The mark price value.
»» createdAt string(date-time) true none The time when this row was added to the database.
» success boolean true none Whether the request was successful
» timestamp number true none The timestamp of the response

Status Code 400

Name Type Required Restrictions Description
» success boolean true none none
» errorMsg any false none none

anyOf

Name Type Required Restrictions Description
»» anonymous string false none none

or

Name Type Required Restrictions Description
»» anonymous [object] false none none

Status Code 500

Name Type Required Restrictions Description
» success boolean true none none
» errorMsg any false none none

anyOf

Name Type Required Restrictions Description
»» anonymous string false none none

or

Name Type Required Restrictions Description
»» anonymous [object] false none none

Get Order Book (L3)

Code samples

require 'rest-client'
require 'json'

headers = {
  'Accept' => 'application/json'
}

result = RestClient.get '/exchange/api/v1/order_book',
  params: {
  }, headers: headers

p JSON.parse(result)
import requests
headers = {
  'Accept': 'application/json'
}

r = requests.get('/exchange/api/v1/order_book', headers = headers)

print(r.json())
const headers = {
    Accept: 'application/json',
};

fetch('/exchange/api/v1/order_book', {
    method: 'GET',

    headers: headers,
})
    .then(function (res) {
        return res.json();
    })
    .then(function (body) {
        console.log(body);
    });

GET /exchange/api/v1/order_book

Get current L3 order book

Parameters

Name In Type Required Description
trader path string false The trader address, with the discriminant prefix.
strategyIdHash path string false The strategy id hash.
depth query integer false The best N bids and asks to return, where N = depth
symbol query string false The symbol
side query integer false The side of the order. Values include:
Detailed descriptions

side: The side of the order. Values include: 0: Bid, 1: Ask

Enumerated Values
Parameter Value
side 0
side 1

Responses

Status Meaning Description Schema
200 OK Order book l3 data Inline
400 Bad Request Bad request Inline
500 Internal Server Error Unexpected error Inline

Response Schema

Example responses

200 Response

{
    "value": [
        {
            "bookOrdinal": 0,
            "orderHash": "0xc8ab0f901fc3968dfae99b6efb34b0bdd81d69aefb21effcf5",
            "symbol": "ETHP",
            "side": 0,
            "originalAmount": "1.0",
            "amount": "0.9",
            "price": "595.8",
            "traderAddress": "0x00b993e587c15a9e0a0fe4f111de98fd6b5ce7067d",
            "strategyIdHash": "0x2576ebd1"
        }
    ],
    "success": true,
    "timestamp": 1673031089
}

Status Code 200

Successful response for the OrderBook L3 API

Name Type Required Restrictions Description
» value [object] true none The value of the response
»» bookOrdinal number true none none
»» orderHash string true none A hash of the order details.
»» symbol string true none The symbol of the asset for this order.
»» side number true none The side of the order. Values include: 0: Bid, 1: Ask
»» originalAmount string true none The original order amount (before any fills).
»» amount string true none The order amount currently left on this order.
»» price string true none The order price.
»» traderAddress string true none The trader address prefixed with the blockchain discriminant of the trader who owns this order.
»» strategyIdHash string true none The strategy id hash of the trader.
» success boolean true none Whether the request was successful
» timestamp number true none The timestamp of the response

Status Code 400

Name Type Required Restrictions Description
» success boolean true none none
» errorMsg any false none none

anyOf

Name Type Required Restrictions Description
»» anonymous string false none none

or

Name Type Required Restrictions Description
»» anonymous [object] false none none

Status Code 500

Name Type Required Restrictions Description
» success boolean true none none
» errorMsg any false none none

anyOf

Name Type Required Restrictions Description
»» anonymous string false none none

or

Name Type Required Restrictions Description
»» anonymous [object] false none none

Get Order Update History

Code samples

require 'rest-client'
require 'json'

headers = {
  'Accept' => 'application/json'
}

result = RestClient.get '/exchange/api/v1/order_updates',
  params: {
  }, headers: headers

p JSON.parse(result)
import requests
headers = {
  'Accept': 'application/json'
}

r = requests.get('/exchange/api/v1/order_updates', headers = headers)

print(r.json())
const headers = {
    Accept: 'application/json',
};

fetch('/exchange/api/v1/order_updates', {
    method: 'GET',

    headers: headers,
})
    .then(function (res) {
        return res.json();
    })
    .then(function (body) {
        console.log(body);
    });

GET /exchange/api/v1/order_updates

Get order updates (trades, liquidations, cancels)

Parameters

Name In Type Required Description
trader path string false The trader address, with the discriminant prefix.
strategyIdHash path string false The strategy id hash.
limit query integer false The number of rows to return
epoch query integer false The epoch boundary used when fetching the next timeseries page.
txOrdinal query integer false The txOrdinal boundary used when fetching the next timeseries page. Must be passed along with epoch.
ordinal query integer false The ordinal boundary used when fetching the next timeseries page. Must be passed along with epoch and txOrdinal.
order query string false The ordering of the results.
symbol query string false The symbol
orderHash query string false the order hash of the order intent. Multiple order hash values can be provided.
reason query integer false The reason for the creation of this row. 0-Trade; 1-Liquidation; 2-Cancel. Multiple reason values can be provided.
since query integer false The earliest time in seconds to fetch rows for. This param cannot be used together with param order = 'desc'
Enumerated Values
Parameter Value
order asc
order desc

Responses

Status Meaning Description Schema
200 OK Order update data Inline
400 Bad Request Bad request Inline
500 Internal Server Error Unexpected error Inline

Response Schema

Example responses

200 Response

{
    "nextEpoch": 100,
    "nextTxOrdinal": 3432,
    "nextOrdinal": 100,
    "value": [
        {
            "epochId": 100,
            "txOrdinal": 3432,
            "ordinal": 0,
            "orderRejection": 0,
            "cancelRejection": 0,
            "reason": 0,
            "amount": "1.5",
            "quoteAssetAmount": "750",
            "symbol": "ETHP",
            "price": "500",
            "makerFeeCollateral": "0",
            "makerFeeDDX": "0",
            "makerRealizedPnl": "0",
            "takerOrderIntent": {
                "epochId": 100,
                "orderHash": "0xa3c4c1c18c6e72c4aea8cfa0a1868ac4bc0f9b6463e8c9687f",
                "symbol": "ETHP",
                "side": 0,
                "amount": "1.0",
                "price": "1500.0",
                "traderAddress": "0x00b993e587c15a9e0a0fe4f111de98fd6b5ce7067d",
                "strategyIdHash": "main",
                "orderType": 0,
                "stopPrice": "0",
                "nonce": "0x3136373332393531393331383537373332363800000000000000000000000000",
                "signature": "0xf9b19b088e3d0ad2c6330231899e03e50b45a8c7a1f52082aa0e9a61391fd5a35d3aece9dd2d42132a25b0aef5ac1bda7aee87c0c0c25ab9525d5eeeff9787d81b",
                "createdAt": "2023-01-06T16:37:27.929Z"
            },
            "takerFeeCollateral": "1.7874",
            "takerFeeDDX": "1.7874",
            "takerRealizedPnl": "0",
            "liquidatedTraderAddress": null,
            "liquidatedStrategyIdHash": null,
            "makerOrderIntent": {
                "epochId": 100,
                "orderHash": "0xa3c4c1c18c6e72c4aea8cfa0a1868ac4bc0f9b6463e8c9687f",
                "symbol": "ETHP",
                "side": 0,
                "amount": "1.0",
                "price": "1500.0",
                "traderAddress": "0x00b993e587c15a9e0a0fe4f111de98fd6b5ce7067d",
                "strategyIdHash": "main",
                "orderType": 0,
                "stopPrice": "0",
                "nonce": "0x3136373332393531393331383537373332363800000000000000000000000000",
                "signature": "0xf9b19b088e3d0ad2c6330231899e03e50b45a8c7a1f52082aa0e9a61391fd5a35d3aece9dd2d42132a25b0aef5ac1bda7aee87c0c0c25ab9525d5eeeff9787d81b",
                "createdAt": "2023-01-06T16:37:27.929Z"
            },
            "createdAt": "2023-01-06T16:37:27.929Z"
        }
    ],
    "success": true,
    "timestamp": 1673031089
}

Status Code 200

Successful response for the Order Update API

Name Type Required Restrictions Description
» nextEpoch number,null true none Pointer for the epoch boundary of the next page. Will return null when there is no more data left to fetch.
» nextTxOrdinal number,null true none Pointer for the txOrdinal boundary of the next page. Will return null when there is no more data left to fetch.
» nextOrdinal number,null true none Pointer for the ordinal boundary of the next page. Will return null when there is no more data left to fetch.
» value [object] true none The value of the response
»» epochId number true none The epoch in which this transaction occured.
»» txOrdinal number true none The transaction ordinal, within the epoch.
»» ordinal number true none The ordinal within this particular transaction.
»» orderRejection number false none The order rejection type. Only applicable when its rejection.
»» cancelRejection number false none The cancel rejection type. Only applicable when its rejection.
»» reason number true none The type of fill. Values include: 0: trade, 1: liquidation, 2: cancel
»» amount string false none The amount that was filled.
»» quoteAssetAmount string false none The quote asset amount.
»» symbol string true none The symbol of the asset that was filled.
»» price string false none The fill price.
»» makerFeeCollateral string false none The USDC fee that was incurred to the maker side of the fill if the maker receives fees in USDC.
»» makerFeeDDX string false none The fee that was incurred to the maker side of the fill if the maker elected to receive fees in DDX. Null otherwise.
»» makerRealizedPnl string false none The realized profit and loss (not inclusive of fees) incurred to the maker due to this fill. Null otherwise.
»» takerOrderIntent object false none The order intent from the taker associated with this fill. Only present when reason is trade.
»»» epochId number true none The epoch in which this transaction occured.
»»» orderHash string true none A hash of this order contents.
»»» symbol string true none The symbol of the asset for this order.
»»» side number true none The side of the order. Values include: 0: Bid, 1: Ask
»»» amount string true none The amount of the order.
»»» price string true none The price of the order.
»»» traderAddress string true none The trader address prefixed with the blockchain discriminant of the trader who issues this order.
»»» strategyIdHash string true none The strategy of the trader which owns this order.
»»» orderType number true none The type of order. Values include: 0: Limit, 1: Market 2: Stop 3: LimitPostOnly
»»» stopPrice string true none The stop price for this order. Not currently an active field.
»»» nonce string true none The nonce sent by the trader when placing this order.
»»» signature string true none A signature which was used to verify the authenticity of the order, when it was sent by the trader. Encrypted using the public key exposed by the leader Operator.
»»» createdAt string(date-time) true none The time when this row was added to the database.
»» takerFeeCollateral string false none The fee that was incurred to the taker side of the fill if taker receives fees in USDC. Null otherwise
»» takerFeeDDX string false none The fee that was incurred to the taker side of the fill if taker receives fees in DDX. Null otherwise
»» takerRealizedPnl string false none The realized profit and loss (not inclusive of fees) incurred to the taker due to this fill.
»» liquidatedTraderAddress string false none In the case that this was a liquidation fill, the trader address prefixed with the blockchain discriminant of the trader that was liquidated.
»» liquidatedStrategyIdHash string false none The liquidated strategy id hash
»» makerOrderIntent object true none The order intent from the maker associated with this fill.
»»» epochId number true none The epoch in which this transaction occured.
»»» orderHash string true none A hash of this order contents.
»»» symbol string true none The symbol of the asset for this order.
»»» side number true none The side of the order. Values include: 0: Bid, 1: Ask
»»» amount string true none The amount of the order.
»»» price string true none The price of the order.
»»» traderAddress string true none The trader address prefixed with the blockchain discriminant of the trader who issues this order.
»»» strategyIdHash string true none The strategy of the trader which owns this order.
»»» orderType number true none The type of order. Values include: 0: Limit, 1: Market 2: Stop 3: LimitPostOnly
»»» stopPrice string true none The stop price for this order. Not currently an active field.
»»» nonce string true none The nonce sent by the trader when placing this order.
»»» signature string true none A signature which was used to verify the authenticity of the order, when it was sent by the trader. Encrypted using the public key exposed by the leader Operator.
»»» createdAt string(date-time) true none The time when this row was added to the database.
»» createdAt string(date-time) true none The time when this row was added to the database.
» success boolean true none Whether the request was successful
» timestamp number true none The timestamp of the response
Enumerated Values
Property Value
orderRejection 0
orderRejection 1
orderRejection 2
orderRejection 3
orderRejection 4
orderRejection 5
reason 0
reason 1
reason 2
side 0
side 1
orderType 0
orderType 1
orderType 2
orderType 3
side 0
side 1
orderType 0
orderType 1
orderType 2
orderType 3

Status Code 400

Name Type Required Restrictions Description
» success boolean true none none
» errorMsg any false none none

anyOf

Name Type Required Restrictions Description
»» anonymous string false none none

or

Name Type Required Restrictions Description
»» anonymous [object] false none none

Status Code 500

Name Type Required Restrictions Description
» success boolean true none none
» errorMsg any false none none

anyOf

Name Type Required Restrictions Description
»» anonymous string false none none

or

Name Type Required Restrictions Description
»» anonymous [object] false none none

Get Strategy Update History

Code samples

require 'rest-client'
require 'json'

headers = {
  'Accept' => 'application/json'
}

result = RestClient.get '/exchange/api/v1/strategy_updates',
  params: {
  }, headers: headers

p JSON.parse(result)
import requests
headers = {
  'Accept': 'application/json'
}

r = requests.get('/exchange/api/v1/strategy_updates', headers = headers)

print(r.json())
const headers = {
    Accept: 'application/json',
};

fetch('/exchange/api/v1/strategy_updates', {
    method: 'GET',

    headers: headers,
})
    .then(function (res) {
        return res.json();
    })
    .then(function (body) {
        console.log(body);
    });

GET /exchange/api/v1/strategy_updates

Get strategy updates over time

Parameters

Name In Type Required Description
trader path string false The trader address, with the discriminant prefix.
strategyIdHash path string false The strategy id hash.
reason query integer false The type of strategy update. Multiple strategy update values can be provided. Values include:
limit query integer false The number of rows to return
epoch query integer false The epoch boundary used when fetching the next timeseries page.
txOrdinal query integer false The txOrdinal boundary used when fetching the next timeseries page. Must be passed along with epoch.
ordinal query integer false The ordinal boundary used when fetching the next timeseries page. Must be passed along with epoch and txOrdinal.
order query string false The ordering of the results.
Detailed descriptions

reason: The type of strategy update. Multiple strategy update values can be provided. Values include: 0: Deposit - Collateral was deposited on-chain, 1: Withdraw - Collateral withdrawal was claimed on-chain, 2: WithdrawIntent - Collateral was locked for withdrawal, 3: FundingPayment - Funding payments were distributed, 4: RealizedPnl - PnL was realized, 5: ADL - ADL occurred on one or more positions,

Enumerated Values
Parameter Value
reason 0
reason 1
reason 2
reason 3
reason 4
reason 5
order asc
order desc

Responses

Status Meaning Description Schema
200 OK Strategy update data Inline
400 Bad Request Bad request Inline
500 Internal Server Error Unexpected error Inline

Response Schema

Example responses

200 Response

{
    "nextEpoch": 100,
    "nextTxOrdinal": 3432,
    "nextOrdinal": 100,
    "value": [
        {
            "epochId": 0,
            "txOrdinal": 3432,
            "ordinal": 0,
            "withdrawRejection": 0,
            "reason": 0,
            "traderAddress": "0x00b993e587c15a9e0a0fe4f111de98fd6b5ce7067d",
            "strategyIdHash": "0x2576ebd1",
            "collateralAddress": "0x8ea76477cfaca8f7ea06477fd3c09a740ac6012a",
            "collateralSymbol": "USDC",
            "amount": "1000",
            "newAvailCollateral": "10000",
            "newLockedCollateral": "10000",
            "blockNumber": "344100",
            "positions": [
                {
                    "symbol": "ETHP",
                    "side": 0,
                    "avgEntryPrice": "1500",
                    "realizedPnl": "1500"
                }
            ],
            "createdAt": "2023-01-06T16:37:27.929Z"
        }
    ],
    "success": true,
    "timestamp": 1673031089
}

Status Code 200

Successful response for the Strategy Update API

Name Type Required Restrictions Description
» nextEpoch number,null true none Pointer for the epoch boundary of the next page. Will return null when there is no more data left to fetch.
» nextTxOrdinal number,null true none Pointer for the txOrdinal boundary of the next page. Will return null when there is no more data left to fetch.
» nextOrdinal number,null true none Pointer for the ordinal boundary of the next page. Will return null when there is no more data left to fetch.
» value [object] true none The value of the response
»» epochId number true none The epoch in which this transaction occured.
»» txOrdinal number true none The transaction ordinal, within the epoch.
»» ordinal number true none The ordinal within this particular transaction.
»» withdrawRejection number false none The withdraw rejection type when applicable. Optional field only present on rejections.
»» reason number true none The reason of strategy update. Values include: 0: Deposit, 1: Withdraw, 2: WithdrawIntent, 3: FundingPayment, 4: RealizedPnl 5: Adl
»» traderAddress string true none The trader address prefixed with the blockchain discriminant.
»» strategyIdHash string true none The strategy id hash of the trader.
»» collateralAddress string true none The collateral address on which this strategy update took place.
»» collateralSymbol string true none The collateral symbol on which this strategy update took place.
»» amount string true none The amount that was modified in the strategy.
»» newAvailCollateral string false none If affected, the updated available collateral amount after this strategy update. Not present on Adl reason.
»» newLockedCollateral string false none If affected, the updated locked collateral amount after this strategy update. Not present on Adl reason.
»» blockNumber number false none The block number in which this strategy update was processed. Not present on Adl reason.
»» positions [object] false none The position fields and values affected by this strategy update.
»»» symbol string true none The symbol affected.
»»» side number false none The side. Only present on Adl strategy update. Values include: 0: Bid, 1: Ask
»»» avgEntryPrice string false none After a RealizedPnl strategy update, what the new average entry prices is for this strategies open positions.
»»» realizedPnl string true none After a RealizedPnl or Adl strategy update, what the realized pnl is for this strategies open positions.
»» createdAt string(date-time) true none The time when this row was added to the database.
» success boolean true none Whether the request was successful
» timestamp number true none The timestamp of the response
Enumerated Values
Property Value
withdrawRejection 0
withdrawRejection 1
withdrawRejection 2
withdrawRejection 3
withdrawRejection 4
reason 0
reason 1
reason 2
reason 3
reason 4
reason 5
side 0
side 1

Status Code 400

Name Type Required Restrictions Description
» success boolean true none none
» errorMsg any false none none

anyOf

Name Type Required Restrictions Description
»» anonymous string false none none

or

Name Type Required Restrictions Description
»» anonymous [object] false none none

Status Code 500

Name Type Required Restrictions Description
» success boolean true none none
» errorMsg any false none none

anyOf

Name Type Required Restrictions Description
»» anonymous string false none none

or

Name Type Required Restrictions Description
»» anonymous [object] false none none

Get Tickers

Code samples

require 'rest-client'
require 'json'

headers = {
  'Accept' => 'application/json'
}

result = RestClient.get '/exchange/api/v1/tickers',
  params: {
  }, headers: headers

p JSON.parse(result)
import requests
headers = {
  'Accept': 'application/json'
}

r = requests.get('/exchange/api/v1/tickers', headers = headers)

print(r.json())
const headers = {
    Accept: 'application/json',
};

fetch('/exchange/api/v1/tickers', {
    method: 'GET',

    headers: headers,
})
    .then(function (res) {
        return res.json();
    })
    .then(function (body) {
        console.log(body);
    });

GET /exchange/api/v1/tickers

Get convenient market tickers data, like funding rate and open interest data, price related data, trading volume in the last 24 hours.

Parameters

Name In Type Required Description
symbol query string false The symbol
marketKind query integer false The type of markets to return data for. 0: SingleNamePerpetual, 2: IndexFundPerpetual, 4: FixedExpiryFuture. Multiple types can be provided.
Detailed descriptions

marketKind: The type of markets to return data for. 0: SingleNamePerpetual, 2: IndexFundPerpetual, 4: FixedExpiryFuture. Multiple types can be provided.

Enumerated Values
Parameter Value
marketKind 0
marketKind 2
marketKind 4

Responses

Status Meaning Description Schema
200 OK Tickers data Inline
400 Bad Request Bad request Inline
500 Internal Server Error Unexpected error Inline

Response Schema

Example responses

200 Response

{
    "value": [
        {
            "symbol": "ETHP",
            "highPrice24h": "2650",
            "lowPrice24h": "2300",
            "prevPrice24h": "2300",
            "lastPrice": "2650",
            "markPrice": "2500",
            "indexPrice": "2450",
            "nextFundingTime": "2023-01-06T16:37:27.929Z",
            "volume24h": "100000",
            "amount24h": "1000",
            "fundingRate": "0.0005",
            "openInterest": "220",
            "openInterestValue": "1500000"
        }
    ],
    "success": true,
    "timestamp": 1673031089
}

Status Code 200

Successful response for the Ticker API

Name Type Required Restrictions Description
» value [object] true none The value of the response
»» symbol string true none The symbol of the market.
»» highPrice24h string true none The highest price in the last 24 hours.
»» lowPrice24h string true none The lowest price in the last 24 hours.
»» prevPrice24h string true none The open price 24 hours ago.
»» lastPrice string true none The last traded price.
»» markPrice string true none The mark price.
»» indexPrice string true none The index price.
»» nextFundingTime string(date-time) true none The time estimated for the next funding rate to occur.
»» volume24h string true none The volume in the last 24 hours.
»» amount24h string,null true none The amount in the last 24 hours.
»» fundingRate string true none The funding rate value..
»» openInterest string true none The current open interest for the market.
»» openInterestValue string true none The current open interest value, amount of positions multiplied by the average price, for the market.
» success boolean true none Whether the request was successful
» timestamp number true none The timestamp of the response

Status Code 400

Name Type Required Restrictions Description
» success boolean true none none
» errorMsg any false none none

anyOf

Name Type Required Restrictions Description
»» anonymous string false none none

or

Name Type Required Restrictions Description
»» anonymous [object] false none none

Status Code 500

Name Type Required Restrictions Description
» success boolean true none none
» errorMsg any false none none

anyOf

Name Type Required Restrictions Description
»» anonymous string false none none

or

Name Type Required Restrictions Description
»» anonymous [object] false none none

System

These APIs return system info.

Get Exchange Info

Code samples

require 'rest-client'
require 'json'

headers = {
  'Accept' => 'application/json'
}

result = RestClient.get '/exchange/api/v1/exchange_info',
  params: {
  }, headers: headers

p JSON.parse(result)
import requests
headers = {
  'Accept': 'application/json'
}

r = requests.get('/exchange/api/v1/exchange_info', headers = headers)

print(r.json())
const headers = {
    Accept: 'application/json',
};

fetch('/exchange/api/v1/exchange_info', {
    method: 'GET',

    headers: headers,
})
    .then(function (res) {
        return res.json();
    })
    .then(function (body) {
        console.log(body);
    });

GET /exchange/api/v1/exchange_info

Get global exchange configuration

Responses

Status Meaning Description Schema
200 OK Exchange info data Inline
400 Bad Request Bad request Inline
500 Internal Server Error Unexpected error Inline

Response Schema

Example responses

200 Response

{
    "value": {
        "settlementsInfo": [
            {
                "type": "epoch",
                "durationValue": "5",
                "durationUnit": "minute"
            }
        ],
        "assets": ["USDC"],
        "symbols": [
            {
                "symbol": "ETHP",
                "tickSize": "0.1",
                "maxOrderNotional": "1000000",
                "maxTakerPriceDeviation": "0.02",
                "minOrderSize": "0.0001",
                "kind": "SingleNamePerpetual"
            }
        ]
    },
    "success": true,
    "timestamp": 1673031089
}

Status Code 200

Successful response for the Exchange Info API

Name Type Required Restrictions Description

anyOf

Name Type Required Restrictions Description
» anonymous object false none none
»» value object true none The value of the response.
»»» settlementsInfo [object] true none A settlement info, contains the specific settlement and the interval value.
»»»» type string true none The type of the settlement.
»»»» durationValue string true none The duration value of this type of settlement.
»»»» durationUnit string true none The duration unit of this type of settlement.
»»» assets [string] true none The assets supported in the exchange.
»»» symbols [object] true none A symbol info, with details of the symbol present in the exchange.
»»»» symbol string true none The symbol name.
»»»» tickSize string true none The tick size of the symbol.
»»»» maxOrderNotional string true none The max order notional of the symbol.
»»»» maxTakerPriceDeviation string true none The max taker price deviation of the symbol.
»»»» minOrderSize string true none The min order size of the symbol.
»»»» kind string true none The type of the symbol.
»» success boolean true none Whether the request was successful
»» timestamp number true none The timestamp of the response

or

Name Type Required Restrictions Description
» anonymous object false none none
»» success boolean true none none
»» errorMsg any false none none

anyOf

Name Type Required Restrictions Description
»»» anonymous string false none none

or

Name Type Required Restrictions Description
»»» anonymous [object] false none none
Enumerated Values
Property Value
kind SingleNamePerpetual
kind IndexFundPerpetual
kind FixedExpiryFuture

Status Code 400

Name Type Required Restrictions Description
» success boolean true none none
» errorMsg any false none none

anyOf

Name Type Required Restrictions Description
»» anonymous string false none none

or

Name Type Required Restrictions Description
»» anonymous [object] false none none

Status Code 500

Name Type Required Restrictions Description
» success boolean true none none
» errorMsg any false none none

anyOf

Name Type Required Restrictions Description
»» anonymous string false none none

or

Name Type Required Restrictions Description
»» anonymous [object] false none none

Test Connectivity

Code samples

require 'rest-client'
require 'json'

headers = {
  'Accept' => 'application/json'
}

result = RestClient.get '/exchange/api/v1/ping',
  params: {
  }, headers: headers

p JSON.parse(result)
import requests
headers = {
  'Accept': 'application/json'
}

r = requests.get('/exchange/api/v1/ping', headers = headers)

print(r.json())
const headers = {
    Accept: 'application/json',
};

fetch('/exchange/api/v1/ping', {
    method: 'GET',

    headers: headers,
})
    .then(function (res) {
        return res.json();
    })
    .then(function (body) {
        console.log(body);
    });

GET /exchange/api/v1/ping

Simple connectivity test

Responses

Status Meaning Description Schema
200 OK empty object Inline
400 Bad Request Bad request Inline
500 Internal Server Error Unexpected error Inline

Response Schema

Example responses

200 Response

{}

Status Code 400

Name Type Required Restrictions Description
» success boolean true none none
» errorMsg any false none none

anyOf

Name Type Required Restrictions Description
»» anonymous string false none none

or

Name Type Required Restrictions Description
»» anonymous [object] false none none

Status Code 500

Name Type Required Restrictions Description
» success boolean true none none
» errorMsg any false none none

anyOf

Name Type Required Restrictions Description
»» anonymous string false none none

or

Name Type Required Restrictions Description
»» anonymous [object] false none none

Get Symbols

Code samples

require 'rest-client'
require 'json'

headers = {
  'Accept' => 'application/json'
}

result = RestClient.get '/exchange/api/v1/symbols',
  params: {
  }, headers: headers

p JSON.parse(result)
import requests
headers = {
  'Accept': 'application/json'
}

r = requests.get('/exchange/api/v1/symbols', headers = headers)

print(r.json())
const headers = {
    Accept: 'application/json',
};

fetch('/exchange/api/v1/symbols', {
    method: 'GET',

    headers: headers,
})
    .then(function (res) {
        return res.json();
    })
    .then(function (body) {
        console.log(body);
    });

GET /exchange/api/v1/symbols

SEO-friendly alias for tradable products

Parameters

Name In Type Required Description
kind query integer false The type of spec update. Values include:
isActive query boolean false Checks for the active state of the tradable product. Values include:
limit query integer false The number of rows to return
offset query integer false The offset of returned rows
Detailed descriptions

kind: The type of spec update. Values include: 0: Market 1: MarketGateway

isActive: Checks for the active state of the tradable product. Values include: true false

Enumerated Values
Parameter Value
kind 0
kind 1

Responses

Status Meaning Description Schema
200 OK Tradable products data Inline
400 Bad Request Bad request Inline
500 Internal Server Error Unexpected error Inline

Response Schema

Example responses

200 Response

{
    "value": [
        {
            "kind": 0,
            "symbol": "ETHP",
            "name": "ETHP",
            "isActive": true,
            "createdAt": "2023-01-06T16:37:27.929Z"
        }
    ],
    "success": true,
    "timestamp": 1673031089
}

Status Code 200

Successful response for the Tradable Product API

Name Type Required Restrictions Description
» value [object] true none The value of the response
»» kind number true none The type of setting. Values include: 0: Perpetual Market, 2: Index Market, 4: Futures Market
»» symbol string true none The symbol of the asset for this product.
»» name string true none The corresponding name in the specs setting.
»» isActive boolean true none The state of the tradable product. If true, then this product is available to trade on the exchange, otherwise false.
»» createdAt string(date-time) true none The time when this row was added to the database.
» success boolean true none Whether the request was successful
» timestamp number true none The timestamp of the response

Status Code 400

Name Type Required Restrictions Description
» success boolean true none none
» errorMsg any false none none

anyOf

Name Type Required Restrictions Description
»» anonymous string false none none

or

Name Type Required Restrictions Description
»» anonymous [object] false none none

Status Code 500

Name Type Required Restrictions Description
» success boolean true none none
» errorMsg any false none none

anyOf

Name Type Required Restrictions Description
»» anonymous string false none none

or

Name Type Required Restrictions Description
»» anonymous [object] false none none

Get Server Time

Code samples

require 'rest-client'
require 'json'

headers = {
  'Accept' => 'application/json'
}

result = RestClient.get '/exchange/api/v1/time',
  params: {
  }, headers: headers

p JSON.parse(result)
import requests
headers = {
  'Accept': 'application/json'
}

r = requests.get('/exchange/api/v1/time', headers = headers)

print(r.json())
const headers = {
    Accept: 'application/json',
};

fetch('/exchange/api/v1/time', {
    method: 'GET',

    headers: headers,
})
    .then(function (res) {
        return res.json();
    })
    .then(function (body) {
        console.log(body);
    });

GET /exchange/api/v1/time

Get server time for clock synchronization

Responses

Status Meaning Description Schema
200 OK Server time data Inline
400 Bad Request Bad request Inline
500 Internal Server Error Unexpected error Inline

Response Schema

Example responses

200 Response

{
    "serverTime": 1747304089528
}

Status Code 200

Name Type Required Restrictions Description
» serverTime number true none none

Status Code 400

Name Type Required Restrictions Description
» success boolean true none none
» errorMsg any false none none

anyOf

Name Type Required Restrictions Description
»» anonymous string false none none

or

Name Type Required Restrictions Description
»» anonymous [object] false none none

Status Code 500

Name Type Required Restrictions Description
» success boolean true none none
» errorMsg any false none none

anyOf

Name Type Required Restrictions Description
»» anonymous string false none none

or

Name Type Required Restrictions Description
»» anonymous [object] false none none

Authenticated REST API

Users may send requests, including placing orders, canceling orders, and withdrawing funds.

Since requests modify system state, these requests must include an EIP-712 signature.

Please keep in mind, all sample requests displayed below are NOT encrypted. The reason for this is to more clearly display the formats of the various requests you may send. You MUST encrypt these messages prior to sending them to the exchange.

Place order

Request

Request format (JSON)

{
    "t": "Order",
    "c": {
        "symbol": "ETHP",
        "strategy": "main",
        "side": "Bid",
        "orderType": "Limit",
        "nonce": "0x3136313839303336353634383833373230303000000000000000000000000000",
        "amount": 10,
        "price": 487.5,
        "stopPrice": 0,
        "signature": "0xd5a1ca6d40a030368710ab86d391e5d16164ea16d2c809894eefddd1658bb08c6898177aa492d4d45272ee41cb40f252327a23e8d1fc2af6904e8860d3f72b3b1b"
    }
}

Request (Python)

from web3 import Web3
from eth_account.signers.local import (
    LocalAccount,
)
import requests
import simplejson as json
from ddx_python.decimal import Decimal
from decimal import Decimal as PyDecimal

class OutputEncoder(json.JSONEncoder):
    """
    Custom JSON-encoder for serializing objects
    """

    def __init__(self, **kwargs):
        super(OutputEncoder, self).__init__(**kwargs)

    def default(self, o):
        if type(o) == Decimal:
            return PyDecimal(str(o))
        return json.JSONEncoder.default(self, o)

def place_order(
    web3_account: LocalAccount,
    symbol: str,
    strategy: str,
    side: str,
    order_type: str,
    nonce: str,
    amount: Decimal,
    price: Decimal,
    stop_price: Decimal,
    verifying_contract_address: str,
    chain_id: int,
):
    # Refer to #derivadex-requests-signatures-and-hashing for
    # these helper implementations.
    eip712_domain_struct_hash = compute_eip712_domain_struct_hash(
        chain_id, verifying_contract_address
    )
    eip712_message_struct_hash = compute_eip712_message_struct_hash(
        symbol, strategy, side, order_type, nonce, amount, price, stop_price
    )
    eip712_hash = compute_eip712_hash(
        eip191_header, eip712_domain_struct_hash, eip712_message_struct_hash
    )

    contents = {
        "t": "Order",
        "c": {
            "symbol": symbol,
            "strategy": strategy,
            "side": side,
            "orderType": order_type,
            "nonce": nonce,
            "amount": amount,
            "price": price,
            "stopPrice": stop_price,
            "signature": web3_account.signHash(
                bytes.fromhex(eip712_hash)
            ).signature.hex(),
        },
    }

    # Encrypt request contents, please refer to
    # #derivadex-requests-encryption.
    encryption_key = requests.get(
        f"https://testnet.derivadex.io/v2/encryption-key"
    ).json()
    encrypted_contents = encrypt_with_nonce(
        encryption_key, OutputEncoder().encode(contents)
    )

    # Submit request.
    requests.post(f"https://testnet.derivadex.io/v2/request", data=encrypted_contents)

rpc_url = '<your_rpc_url>'
private_key = '<your_private_key>'
verifying_contract_address = '0xd9239543d15fb9479f2cc9951b45432ba4221bfa'
chain_id = 11155111
w3 = Web3(Web3.HTTPProvider(rpc_url, request_kwargs={"timeout": 60}))
web3_account = w3.eth.account.from_key(private_key)

place_order(
    web3_account,
    'ETHP',
    'main',
    'Bid',
    'Limit',
    '0x3136343630373732323434323935363430303000000000000000000000000000',
    Decimal('12.3'),
    Decimal('2031.4'),
    Decimal('0'),
    verifying_contract_address,
    chain_id
)

You can place new orders by specifying specific attributes in the Order request payload. These requests are subject to a set of validations.

type field description
string t Request type, which in this case will be Order
dict c Request contents containing the order being placed
string c.symbol Name of the market to trade. Currently, this is limited to ETHP or BTCP, but new symbols are coming soon!
string c.strategy Name of the cross-margined strategy this trade belongs to. Currently, this is limited to the default main strategy, but support for multiple strategies is coming soon!
string c.side Side of trade, either Bid (buy/long) or an Ask (sell/short)
string c.orderType Order type, either Limit or Market. Other order types coming soon!
bytes32_s c.nonce An incrementing numeric identifier for this request that is unique per user for all time
decimal c.amount The order amount/size requested
decimal c.price The order price (If orderType is Market, this must be set to 0)
decimal c.stopPrice Currently, always set to 0 as stops are not implemented.
bytes_s c.signature EIP-712 signature of the order placement intent

To be more explicit, all of these fields must be passed in, even if not all of the fields apply due to certain functionalities not currently implemented (i.e. stops) or the fact that prices aren't applicable in the case of market orders. Please follow the guidelines specified in the table above around these conditions.

Response

Receipt (success) format (JSON)

{
    "t": "Sequenced",
    "c": {
        "nonce": "0x3136323631383732373739373732303230303000000000000000000000000000",
        "requestHash": "0xdfcdd015a63119477e456e48ab16a6324cb4820b99c47d8a0520f1d43834d7ef",
        "requestIndex": 54913,
        "sender": "0xe36ea790bc9d7ab70c55260c66d52b1eca985f84",
        "enclaveSignature": "0x69865fca4901d21c84e1fd9b12b0e6ba4d7f7a885594fa8a1aa4dfdaf0dc7b6f433069b38c7822d215e55b3d46118ed012c874bf524fe73cb6aafe9adb42d3e81c"
    }
}

A place order request returns a response receipt, which confirms that an Operator has received the request and has sequenced it for processing. The receipt type will be either Sequenced or Error.

A successful request returns a Sequenced receipt from the Operator. DerivaDEX Operators execute code within a trusted execution environment. The enclaveSignature affirms that this environment has the security guarantees associated with Intel SGX TEEs.

type field description
string t Message type, which in this case will be Sequenced
dict c Message contents
bytes32_s c.nonce The same nonce that was passed in the initial request, which can be used to correlate your initial requests with receipts
bytes32_s c.requestHash Hash of the request
int c.requestIndex A ticket number which guarantees fair sequencing. All tickets are processed and handled by the exchange in order of this requestIndex.
address_s c.sender The request sender's Ethereum address
bytes_s c.enclaveSignature An Operator's signature which proves secure handling of the request

Receipt (error) format (JSON)

{
    "t": "Error",
    "c": {
        "message": "Error: timeout of 2000ms exceeded"
    }
}

An erroneous request returns an Error receipt from the Operator.

type field description
string msg Error message

Cancel order

Request

Request format (JSON)

{
    "t": "CancelOrder",
    "c": {
        "symbol": "ETHP",
        "orderHash": "0xedee9c27b4fc64a481bd45c145eaf35806d6ad49ca0c68890a00000000000000",
        "nonce": "0x3136323635353034303835323735383330303000000000000000000000000000",
        "signature": "0xee6c271fc010e25fb28556b39f8999d832485b03335c9c4a5ceca84455ce6bb205483995f5240e62adeb50bda12ed8db67a990c0930e5512709b3bcff4a98ca01b"
    }
}

Request (Python)

from web3 import Web3
from eth_account.signers.local import (
    LocalAccount,
)
from eth_abi.utils.padding import zpad32_right
import requests
import simplejson as json
from ddx_python.decimal import Decimal
from decimal import Decimal as PyDecimal

class OutputEncoder(json.JSONEncoder):
    """
    Custom JSON-encoder for serializing objects
    """

    def __init__(self, **kwargs):
        super(OutputEncoder, self).__init__(**kwargs)

    def default(self, o):
        if type(o) == Decimal:
            return PyDecimal(str(o))
        return json.JSONEncoder.default(self, o)

def cancel_order(
    web3_account: LocalAccount,
    symbol: str,
    order_hash: str,
    nonce: str,
    verifying_contract_address: str,
    chain_id: int,
):
    # Refer to #derivadex-requests-signatures-and-hashing for
    # these helper implementations.
    eip712_domain_struct_hash = compute_eip712_domain_struct_hash(
        chain_id, verifying_contract_address
    )
    eip712_message_struct_hash = compute_eip712_message_struct_hash(
        symbol,
        order_hash,
        nonce,
    )
    eip712_hash = compute_eip712_hash(
        eip191_header, eip712_domain_struct_hash, eip712_message_struct_hash
    )

    contents = {
        "t": "CancelOrder",
        "c": {
            "symbol": symbol,
            "orderHash": f"0x{zpad32_right(bytes.fromhex(order_hash[2:])).hex()}",
            "nonce": nonce,
            "signature": web3_account.signHash(
                bytes.fromhex(eip712_hash)
            ).signature.hex(),
        },
    }

    # Encrypt request contents, please refer to
    # #derivadex-requests-encryption.
    encryption_key = requests.get(
        f"https://testnet.derivadex.io/v2/encryption-key"
    ).json()
    encrypted_contents = encrypt_with_nonce(
        encryption_key, OutputEncoder().encode(contents)
    )

    # Submit request.
    requests.post(f"https://testnet.derivadex.io/v2/request", data=encrypted_contents)

rpc_url = '<your_rpc_url>'
private_key = '<your_private_key>'
verifying_contract_address = '0xd9239543d15fb9479f2cc9951b45432ba4221bfa'
chain_id = 11155111
w3 = Web3(Web3.HTTPProvider(rpc_url, request_kwargs={"timeout": 60}))
web3_account = w3.eth.account.from_key(private_key)

cancel_order(
    web3_account,
    'ETHP',
    '0xdc15c175ed2cf4613362f81d9c2fd50c3444af2b33af2c5bd6',
    '0x3136393832323333303030393036383930303000000000000000000000000000',
    verifying_contract_address,
    chain_id
)

You can cancel existing orders by specifying specific attributes in the CancelOrder request's payload.

type field description
string t Request type, which in this case will be CancelOrder
dict c Request contents containing the order being canceled
string c.symbol Currently always ETHP or BTCP. New symbols coming soon!
bytes32_s c.orderHash The first 25 bytes of the order's unique hash that is being canceled.
bytes32_s c.nonce An incrementing numeric identifier for this request that is unique per user for all time
bytes_s c.signature EIP-712 signature of the order cancellation request

As described in the Signatures & hashing section, the orderHash is something that you construct client-side prior to submitting the order to the exchange. In this regard, you have the orderHash for each order you submit irrespective of acknowledgement from the exchange. However, you likely will fire order cancellations after you have already had acknowledgement of placement receipt from the exchange. You can obtain the order hashes of your open orders using appropriately defined REST requests or WebSocket subscriptions.

Response

Receipt (success) format (JSON)

{
    "t": "Sequenced",
    "c": {
        "nonce": "0x3136323635353034303835323735383330303000000000000000000000000000",
        "requestHash": "0xdab45fe8ddac0cf1231f79bf4fcbfa847606f45341b446d143b0b0688aa7eed0",
        "requestIndex": 108095,
        "sender": "0xe36ea790bc9d7ab70c55260c66d52b1eca985f84",
        "enclaveSignature": "0x040d24750b994b3603cabb4097093bc310fbfcbe88246501fac4f1d9a441798b20a09eedfdbe52a576cba17ed3986984ba0bfe4a8a3141a525759e7c39f49a441b"
    }
}

A cancel order request returns a response receipt, which confirms that an Operator has received the request and has sequenced it for processing. The receipt type will be either Sequenced or Error.

A successful request returns a Received receipt from the Operator. DerivaDEX Operators execute code within a trusted execution environment. The enclaveSignature affirms that this environment has the security guarantees associated with Intel SGX TEEs.

type field description
string t Message type, which in this case will be Sequenced
dict c Message contents
bytes32_s c.nonce The same nonce that was passed in the initial request, which can be used to correlate your initial requests with receipts
bytes32_s c.requestHash Hash of the request
int c.requestIndex A ticket number which guarantees fair sequencing. All tickets are processed and handled by the exchange in order of this requestIndex.
address_s c.sender The request sender's Ethereum address
bytes_s c.enclaveSignature An Operator's signature which proves secure handling of the request

Receipt (error) format (JSON)

{
    "t": "Error",
    "c": {
        "message": "Error: timeout of 2000ms exceeded"
    }
}

An erroneous request returns an Error receipt from the Operator.

type field description
string msg Error message

Cancel all

Request

Request format (JSON)

{
    "t": "CancelAll",
    "c": {
        "symbol": "ETHP",
        "strategyId": "main",
        "nonce": "0x3136323635353034303835323735383330303000000000000000000000000000",
        "signature": "0xee6c271fc010e25fb28556b39f8999d832485b03335c9c4a5ceca84455ce6bb205483995f5240e62adeb50bda12ed8db67a990c0930e5512709b3bcff4a98ca01b"
    }
}

Request (Python)

from web3 import Web3
from eth_account.signers.local import (
    LocalAccount,
)
from eth_abi.utils.padding import zpad32_right
import requests
import simplejson as json
from ddx_python.decimal import Decimal
from decimal import Decimal as PyDecimal

class OutputEncoder(json.JSONEncoder):
    """
    Custom JSON-encoder for serializing objects
    """

    def __init__(self, **kwargs):
        super(OutputEncoder, self).__init__(**kwargs)

    def default(self, o):
        if type(o) == Decimal:
            return PyDecimal(str(o))
        return json.JSONEncoder.default(self, o)

def cancel_all(
        web3_account: LocalAccount,
        strategy: str,
        symbol: str,
        nonce: str,
        verifying_contract_address: str,
        chain_id: int,
    ):
        # Refer to #derivadex-requests-signatures-and-hashing for
        # these helper implementations.
        eip712_domain_struct_hash = compute_eip712_domain_struct_hash(
            chain_id,
            verifying_contract_address
        )
        eip712_message_struct_hash = compute_eip712_message_struct_hash(
            strategy,
            nonce,
        )
        eip712_hash = compute_eip712_hash(
            eip191_header,
            eip712_domain_struct_hash,
            eip712_message_struct_hash
        )

        contents = {
            "t": "CancelAll",
            "c": {
                "symbol": symbol,
                "strategyId": strategy,
                "nonce": nonce,
                "signature": web3_account.signHash(
                    bytes.fromhex(eip712_hash)
                ).signature.hex(),
            },
        }

        # Encrypt request contents, please refer to
        # #derivadex-requests-encryption.
        encryption_key = requests.get(
            f"https://testnet.derivadex.io/v2/encryption-key"
        ).json()
        encrypted_contents = encrypt_with_nonce(
            encryption_key, OutputEncoder().encode(contents)
        )

        # Submit request.
        requests.post(
            f"https://testnet.derivadex.io/v2/request",
            data=encrypted_contents
        )

rpc_url = '<your_rpc_url>'
private_key = '<your_private_key>'
verifying_contract_address = '0xd9239543d15fb9479f2cc9951b45432ba4221bfa'
chain_id = 11155111
w3 = Web3(Web3.HTTPProvider(rpc_url, request_kwargs={"timeout": 60}))
web3_account = w3.eth.account.from_key(private_key)

cancel_all(
    web3_account,
    'main',
    'ETHP'
    '0x3136393832323431363235313430323730303000000000000000000000000000',
    verifying_contract_address,
    chain_id
)

You can cancel all existing orders by specifying specific attributes in the CancelAll request's payload.

type field description
string t Request type, which in this case will be CancelOrder
dict c Request contents containing the order being canceled
string c.symbol Name of the market to trade. Currently, this is limited to ETHP or BTCP, but new symbols are coming soon!
string c.strategyId Name of the cross-margined strategy this trade belongs to. Currently, this is limited to the default main strategy, but support for multiple strategies is coming soon!
bytes32_s c.nonce An incrementing numeric identifier for this request that is unique per user for all time
bytes_s c.signature EIP-712 signature of the order cancellation request

Response

Receipt (success) format (JSON)

{
    "t": "Sequenced",
    "c": {
        "nonce": "0x3136323635353034303835323735383330303000000000000000000000000000",
        "requestHash": "0xdab45fe8ddac0cf1231f79bf4fcbfa847606f45341b446d143b0b0688aa7eed0",
        "requestIndex": 108095,
        "sender": "0xe36ea790bc9d7ab70c55260c66d52b1eca985f84",
        "enclaveSignature": "0x040d24750b994b3603cabb4097093bc310fbfcbe88246501fac4f1d9a441798b20a09eedfdbe52a576cba17ed3986984ba0bfe4a8a3141a525759e7c39f49a441b"
    }
}

A cancel all request returns a response receipt, which confirms that an Operator has received the request and has sequenced it for processing. The receipt type will be either Sequenced or Error.

A successful request returns a Received receipt from the Operator. DerivaDEX Operators execute code within a trusted execution environment. The enclaveSignature affirms that this environment has the security guarantees associated with Intel SGX TEEs.

type field description
string t Message type, which in this case will be Sequenced
dict c Message contents
bytes32_s c.nonce The same nonce that was passed in the initial request, which can be used to correlate your initial requests with receipts
bytes32_s c.requestHash Hash of the request
int c.requestIndex A ticket number which guarantees fair sequencing. All tickets are processed and handled by the exchange in order of this requestIndex.
address_s c.sender The request sender's Ethereum address
bytes_s c.enclaveSignature An Operator's signature which proves secure handling of the request

Receipt (error) format (JSON)

{
    "t": "Error",
    "c": {
        "message": "Error: timeout of 2000ms exceeded"
    }
}

An erroneous request returns an Error receipt from the Operator.

type field description
string msg Error message

Withdraw

Request

Request format (JSON)

{
    "t": "Withdraw",
    "c": {
        "strategyId": "main",
        "currency": "0x41082c820342539de44c1b404fead3b4b39e15d6",
        "amount": 440.32,
        "nonce": "0x3136313839303336353634383833373230303000000000000000000000000000",
        "signature": "0xd5a1ca6d40a030368710ab86d391e5d16164ea16d2c809894eefddd1658bb08c6898177aa492d4d45272ee41cb40f252327a23e8d1fc2af6904e8860d3f72b3b1b"
    }
}

Request (Python)

from web3 import Web3
from eth_account.signers.local import (
    LocalAccount,
)
from eth_abi.utils.padding import zpad32_right
import requests
import simplejson as json
from ddx_python.decimal import Decimal
from decimal import Decimal as PyDecimal

class OutputEncoder(json.JSONEncoder):
    """
    Custom JSON-encoder for serializing objects
    """

    def __init__(self, **kwargs):
        super(OutputEncoder, self).__init__(**kwargs)

    def default(self, o):
        if type(o) == Decimal:
            return PyDecimal(str(o))
        return json.JSONEncoder.default(self, o)

def withdraw(
        web3_account: LocalAccount,
        strategy: str,
        currency: str,
        amount: Decimal,
        nonce: str,
        verifying_contract_address: str,
        chain_id: int,
    ):
        # Refer to #derivadex-requests-signatures-and-hashing for
        # these helper implementations.
        eip712_domain_struct_hash = compute_eip712_domain_struct_hash(
            chain_id,
            verifying_contract_address
        )
        eip712_message_struct_hash = compute_eip712_message_struct_hash(
            strategy,
            nonce,
        )
        eip712_hash = compute_eip712_hash(
            eip191_header,
            eip712_domain_struct_hash,
            eip712_message_struct_hash
        )

        contents = {
            "t": "Withdraw",
            "c": {
                "strategyId": strategy,
                "currency": currency,
                "amount": amount,
                "nonce": nonce,
                "signature": web3_account.signHash(
                    bytes.fromhex(eip712_hash)
                ).signature.hex(),
            },
        }

        # Encrypt request contents, please refer to
        # #derivadex-requests-encryption.
        encryption_key = requests.get(
            f"https://testnet.derivadex.io/v2/encryption-key"
        ).json()
        encrypted_contents = encrypt_with_nonce(
            encryption_key, OutputEncoder().encode(contents)
        )

        # Submit request.
        requests.post(
            f"https://testnet.derivadex.io/v2/request",
            data=encrypted_contents
        )

rpc_url = '<your_rpc_url>'
private_key = '<your_private_key>'
verifying_contract_address = '0xd9239543d15fb9479f2cc9951b45432ba4221bfa'
chain_id = 5
w3 = Web3(Web3.HTTPProvider(rpc_url, request_kwargs={"timeout": 60}))
web3_account = w3.eth.account.from_key(private_key)

withdraw(
    web3_account,
    '0xe36ea790bc9d7ab70c55260c66d52b1eca985f84',
    'main',
    '0x0998ba4bd2ffbfaa894d8b616ae412813a79bcf9',
    Decimal('4.2'),
    '0x3136323737363235343138383430383030303000000000000000000000000000',
    verifying_contract_address,
    chain_id
)

You can signal withdrawal intents to the Operators by specifying specific attributes in the Withdraw request's payload. Withdrawal is a 2-step process: submitting a withdrawal intent, and performing a smart contract withdrawal. Once a withdrawal intent is initiated, you won"t be able to trade with the collateral you are attempting to withdraw. You will only be able to formally initiate a smart contract withdrawal/token transfer once the epoch in which you signal your withdrawal desire has concluded.

type field description
string t Request type, which in this case will be Withdraw
dict c Request contents containing the withdrawal data
string c.strategyId Name of the cross-margined strategy this withdrawal belongs to. Currently, this is limited to the default main strategy, but support for multiple strategies is coming soon!
address_s c.currency ERC-20 token address being withdrawn
decimal c.amount Amount withdrawn (be sure to use the grains format specific to the collateral token being used (e.g. if you wanted to withdraw 1 USDC, you would enter 1000000 since the USDC token contract has 6 decimal places)
bytes32_s c.nonce An incrementing numeric identifier for this request that is unique per user for all time
bytes_s c.signature EIP-712 signature for the withdrawal request

Response

Receipt (success) format (JSON)

{
    "t": "Sequenced",
    "c": {
        "nonce": "0x3136323631383732373739373732303230303000000000000000000000000000",
        "requestHash": "0xdfcdd015a63119477e456e48ab16a6324cb4820b99c47d8a0520f1d43834d7ef",
        "requestIndex": 54913,
        "sender": "0xe36ea790bc9d7ab70c55260c66d52b1eca985f84",
        "enclaveSignature": "0x69865fca4901d21c84e1fd9b12b0e6ba4d7f7a885594fa8a1aa4dfdaf0dc7b6f433069b38c7822d215e55b3d46118ed012c874bf524fe73cb6aafe9adb42d3e81c"
    }
}

A withdraw request returns a response receipt, which confirms that an Operator has received the request and has sequenced it for processing. The receipt type will be either Received or Error.

A successful request returns a Received receipt from the Operator. DerivaDEX Operators execute code within a trusted execution environment. The enclaveSignature affirms that this environment has the security guarantees associated with Intel SGX TEEs.

type field description
string t Message type, which in this case will be Sequenced
dict c Message contents
bytes32_s c.nonce The same nonce that was passed in the initial request, which can be used to correlate your initial requests with receipts
bytes32_s c.requestHash Hash of the request
int c.requestIndex A ticket number which guarantees fair sequencing. All tickets are processed and handled by the exchange in order of this requestIndex.
address_s c.sender The request sender's Ethereum address
bytes_s c.enclaveSignature An Operator's signature which proves secure handling of the request

Receipt (error) format (JSON)

{
    "t": "Error",
    "c": {
        "message": "Error: timeout of 2000ms exceeded"
    }
}

An erroneous request returns an Error receipt from the Operator.

type field description
string msg Error message

Signatures and hashing

All [requests] on the API must be signed. The payload you will sign using an Ethereum wallet client of your choice (e.g. ethers, web3.js, web3.py, etc.) will need to be hashed as per the EIP-712 standard. We highly recommend referring to the original proposal for full context, but in short, this standard introduced a framework by which users can securely sign typed structured data. This greatly improves the crypto UX as users can now sign data they see and understand as opposed to unreadable byte-strings. While these benefits may not be readily apparent for programmatic traders, you will need to conform to this standard regardless.

EIP-712 hashing consists of three critical components - a header, domain struct hash, and message struct hash.

Header

Sample EIP-191 header definition

bytes2 eip191_header = 0x1901;
eip191_header = b"\x19\x01"

The header is simply the byte-string \x19\x01. You are welcome to do this however you like, but it must adhere to the standard eventually, otherwise the signature will not ultimately successfully recover. Example Solidity and Python reference implementations are displayed on the right, but feel free to utilize whichever language, tooling, and abstractions you see fit.

Domain

Domain separator for sepolia. DO NOT modify these parameters.

{
    "name": "DerivaDEX",
    "version": "1",
    "chainId": 11155111,
    "verifyingContract": "0xd9239543d15fb9479f2cc9951b45432ba4221bfa"
}

Sample computation of domain struct hash

function compute_eip712_domain_struct_hash(
    string memory _name,
    string memory _version,
    uint256 _chainId,
    address _verifyingContract
) public view returns (bytes32) {
    // keccak-256 hash of the encoded schema for the domain separator
    bytes32 domainSchemaHash =
        keccak256(
            abi.encodePacked(
                'EIP712Domain(',
                'string name,',
                'string version,',
                'uint256 chainId,',
                'address verifyingContract',
                ')'
            )
        );

    bytes32 domainStructHash =
        keccak256(
            abi.encodePacked(
                domainSchemaHash,
                keccak256(bytes(_name)),
                keccak256(bytes(_version)),
                _chainId,
                uint256(_verifyingContract)
            )
        );

    return domainStructHash;
}
from eth_abi import encode
from eth_utils.crypto import keccak

def compute_eip712_domain_struct_hash(chain_id: int, verifying_contract: str) -> bytes:
    return keccak(
        keccak(
            b"EIP712Domain("
            + b"string name,"
            + b"string version,"
            + b"uint256 chainId,"
            + b"address verifyingContract"
            + b")"
        )
        + keccak(b"DerivaDEX")
        + keccak(b"1")
        + encode(["uint256"], [chain_id])
        + encode(["address"], [verifying_contract])
    )

The domain is a mandatory field that allows for signature/hashing schemes on one dApp to be unique to itself from other dApps. All requests use the same domain specification. The parameters that comprise the domain are as follows:

type field description
string name Name of the dApp or protocol
string version Current version of the signing domain
uint256 chainId EIP-155 chain ID
address verifyingContract DerivaDEX smart contract's Ethereum address

To generate the domain struct hash, you must perform a series of encodings and hashings of the schema and contents of the domain specfication. You are welcome to do this however you like, but it must adhere to the standard eventually, otherwise the signature will not ultimately successfully recover. Example Solidity and Python reference implementations are displayed on the right, but feel free to utilize whichever language, tooling, and abstractions you see fit.

Message

The message field varies depending on the typed data you are signing, and is illustrated on a case-by-case basis below.

Place order

Sample computation of place order message struct hash

function compute_eip712_message_struct_hash(
    bytes32 _symbol,
    bytes32 _strategy,
    uint256 _side,
    uint256 _orderType,
    bytes32 _nonce,
    uint256 _amount,
    uint256 _price,
    uint256 _stopPrice
) public view returns (bytes32) {
    // keccak-256 hash of the encoded schema for the order params struct
    bytes32 eip712SchemaHash =
        keccak256(
            abi.encodePacked(
                'OrderParams(',
                'bytes32 symbol,',
                'bytes32 strategy,',
                'uint256 side,',
                'uint256 orderType,',
                'bytes32 nonce,',
                'uint256 amount,',
                'uint256 price,',
                'uint256 stopPrice',
                ')'
            )
        );

    bytes32 messageStructHash =
        keccak256(
            abi.encodePacked(
                eip712SchemaHash,
                _symbol,
                _strategy,
                _side,
                _orderType,
                _nonce,
                _amount,
                _price,
                _stopPrice
            )
        );

    return messageStructHash;
}
from eth_utils.crypto import keccak
from eth_abi import encode
from eth_abi.utils.padding import zpad32_right
from ddx_python.decimal import Decimal

def compute_eip712_message_struct_hash(
    symbol: str,
    strategy: str,
    side: str,
    order_type: str,
    nonce: str,
    amount: Decimal,
    price: Decimal,
    stop_price: Decimal,
) -> bytes:
    # keccak-256 hash of the encoded schema for the place order request
    eip712_schema_hash = keccak(
        b"OrderParams("
        + b"bytes32 symbol,"
        + b"bytes32 strategy,"
        + b"uint256 side,"
        + b"uint256 orderType,"
        + b"bytes32 nonce,"
        + b"uint256 amount,"
        + b"uint256 price,"
        + b"uint256 stopPrice"
        + b")"
    )

    # Ensure decimal value has no more than 6 decimals of precision
    def round_to_unit(val: Decimal) -> Decimal:
        return val.quantize(6)

    # Scale up to DDX grains format (i.e. multiply by 1e18)
    def to_base_unit_amount(val: Decimal, decimals: int) -> int:
        return int(round_to_unit(val) * 10**decimals)

    # Convert order side string to int representation
    def order_side_to_int(order_side: str) -> int:
        if order_side == "Bid":
            return 0
        elif order_side == "Ask":
            return 1
        return 2

    # Convert order type string to int representation
    def order_type_to_int(order_type: str) -> int:
        if order_type == "Limit":
            return 0
        elif order_type == "Market":
            return 1
        return 2

    return keccak(
        eip712_schema_hash
        + zpad32_right(
            len(symbol).to_bytes(1, byteorder="little") + symbol.encode("utf8")
        )
        + zpad32_right(
            len(strategy).to_bytes(1, byteorder="little") + strategy.encode("utf8")
        )
        + encode(["uint256"], [order_side_to_int(side)])
        + encode(["uint256"], [order_type_to_int(order_type)])
        + encode(["bytes32"], [bytes.fromhex(nonce[2:])])
        + encode(["uint256"], [to_base_unit_amount(amount, 6)])
        + encode(["uint256"], [to_base_unit_amount(price, 6)])
        + encode(["uint256"], [to_base_unit_amount(stop_price, 6)])
    )

The parameters that comprise the message for the request to place an order are as follows:

type field description
bytes32 symbol 32-byte encoding of the symbol length and symbol this order is for. The symbol of the order you send to the API is a string, however for signing purposes, you must bytes-encode and pad accordingly.
bytes32 strategy 32-byte encoding of the strategy length and strategy this order belongs to. The strategy of the order you send to the API is a string, however for signing purposes, you must bytes-encode and pad accordingly. The strategy refers to the cross-margined bucket this trade belongs to. Currently, there is only the default main strategy, but support for multiple strategies is coming soon!
uint256 side An integer value either 0 (Bid) or 1 (Ask)
uint256 orderType An integer value either 0 (Limit) or 1 (Market)
bytes32 nonce 32-byte value (an incrementing numeric identifier that is unique per user for all time) resulting in uniqueness of order
uint256 amount Order amount (scaled up by 6 decimals; e.g. 2.5 => 2500000). The amount of the order you send to the API is a decimal, however for signing purposes, you must scale up by 6 decimals and convert to an integer.
uint256 price Order price (scaled up by 6 decimals; e.g. 2001.37 => 2001370000). The price of the order you send to the API is a decimal, however for signing purposes, you must scale up by 6 decimals and convert to an integer.
uint256 stopPrice Stop price (scaled up by 6 decimals). The stopPrice of the order you send to the API is a decimal, however for signing purposes, you must scale up by 6 decimals and convert to an integer.

Take special note of the transformations done on several fields as described in the table above. In other words, the order intent you submit to the API will have different representations for some fields than the order intent you hash. You are welcome to do this however you like, but it must adhere to the standard eventually, otherwise the signature will not ultimately successfully recover. Example Solidity and Python reference implementations are displayed on the right, but feel free to utilize whichever language, tooling, and abstractions you see fit.

Cancel order

Sample computation of cancel order message struct hash

function compute_eip712_message_struct_hash(bytes32 _symbol, bytes32 _orderHash, bytes32 _nonce) public view returns (bytes32) {
    // keccak-256 hash of the encoded schema for the cancel order params struct
    bytes32 eip712SchemaHash = keccak256(abi.encodePacked(
        "CancelOrderParams(",
        "bytes32 symbol,",
        "bytes32 orderHash,",
        "bytes32 nonce",
        ")"
    ));

    bytes32 messageStructHash = keccak256(abi.encodePacked(
        eip712SchemaHash,
        _symbol,
        _orderHash,
        _nonce,
    ));

    return messageStructHash;
}
from eth_abi import encode
from eth_abi.utils.padding import zpad32_right
from eth_utils.crypto import keccak

def compute_eip712_message_struct_hash(
    symbol: str, order_hash: str, nonce: str
) -> bytes:
    # keccak-256 hash of the encoded schema for the cancel order request
    eip712_schema_hash = keccak(
        b"CancelOrderParams("
        + b"bytes32 symbol,"
        + b"bytes32 orderHash,"
        + b"bytes32 nonce"
        + b")"
    )

    return keccak(
        eip712_schema_hash
        + zpad32_right(
            len(symbol).to_bytes(1, byteorder="little") + symbol.encode("utf8")
        )
        + encode(["bytes32"], [bytes.fromhex(order_hash[2:])])
        + encode(["bytes32"], [bytes.fromhex(nonce[2:])])
    )

The parameters that comprise the message for the request to cancel an order are as follows:

type field description
bytes32 symbol 32-byte encoding of the symbol length and symbol this order is for. The symbol of the order you send to the API is a string, however for signing purposes, you must bytes-encode and pad accordingly.
bytes32 orderHash 32-byte EIP-712 hash of the order at the time of placement
bytes32 nonce 32-byte value (an incrementing numeric identifier that is unique per user for all time) resulting in uniqueness of order cancellation

Cancel all

Sample computation of cancel all message struct hash

function compute_eip712_message_struct_hash(bytes32 _strategy, bytes32 _nonce) public view returns (bytes32) {
    // keccak-256 hash of the encoded schema for the cancel all params struct
    bytes32 eip712SchemaHash = keccak256(abi.encodePacked(
        "CancelAllParams(",
        "bytes32 symbol,",
        "bytes32 strategy,",
        "bytes32 nonce",
        ")"
    ));

    bytes32 messageStructHash = keccak256(abi.encodePacked(
        eip712SchemaHash,
        _strategy,
        _nonce,
    ));

    return messageStructHash;
}
from eth_abi import encode
from eth_abi.utils.padding import zpad32_right
from eth_utils.crypto import keccak

def compute_eip712_message_struct_hash(strategy: str, nonce: str) -> bytes:
    # keccak-256 hash of the encoded schema for the cancel all request
    eip712_schema_hash = keccak(
        b"CancelAllParams(" + b"bytes32 symbol" + b"bytes32 strategy," + b"bytes32 nonce" + b")"
    )

    return keccak(
        eip712_schema_hash
        + zpad32_right(
            len(strategy).to_bytes(1, byteorder="little") + strategy.encode("utf8")
        )
        + encode(["bytes32"], [bytes.fromhex(nonce[2:])])
    )

The parameters that comprise the message for the request to cancel an order are as follows:

type field description
bytes32 strategy 32-byte encoding of the strategy length and strategy this order belongs to. The strategy of the order you send to the API is a string, however for signing purposes, you must bytes-encode and pad accordingly. The strategy refers to the cross-margined bucket this trade belongs to. Currently, there is only the default main strategy, but support for multiple strategies is coming soon!
bytes32 nonce 32-byte value (an incrementing numeric identifier that is unique per user for all time) resulting in uniqueness of order cancellation

Tying it all together

Computing the final EIP-712 hash

function compute_eip712_hash(
    bytes2 _eip191_header,
    bytes32 _domainStructHash,
    bytes32 _messageStructHash
) public view returns (bytes32) {
    return keccak256(abi.encodePacked(_eip191_header, _domainStructHash, _messageStructHash));
}
from eth_utils.crypto import keccak

def compute_eip712_hash(eip191_header: bytes, eip712_domain_struct_hash: bytes, eip712_message_struct_hash: bytes) -> str:
    # Converting bytes result to a hexadecimal string
    return keccak(
        eip191_header
        + eip712_domain_struct_hash
        + eip712_message_struct_hash
    ).hex()

To derive the final EIP-712 hash of the typed data you will sign, you will need to keccak256 hash the header, eip712_domain_struct_hash, and eip712_message_struct_hash (will vary depending on which request specifically you are sending). You are welcome to do this however you like, but it must adhere to the standard eventually, otherwise the signature will not ultimately successfully recover. Example Solidity and Python reference implementations are displayed on the right, but feel free to utilize whichever language, tooling, and abstractions you see fit.

Samples

Please feel free to use these ground truth samples to validate your EIP-712 hashing implementation for correctness. For the following samples, assume a chainId = 11155111 and verifyingContract = 0xd9239543d15fb9479f2cc9951b45432ba4221bfa.

Place order

The following sample order placement data results in an EIP-712 hash of: 0x1755cce1ec303da618937c7a1654e43b80bd6106fd88563457dc20f2bd979dd1.

field value
symbol "ETHP"
strategy "main"
side "Bid"
orderType "Limit"
nonce "0x3136393832323235373738313438313430303000000000000000000000000000"
amount 51.5
price 1762.4
stopPrice 0

Cancel order

The following sample cancellation data results in an EIP-712 hash of: 0xaeaccd96f66406d1dcfbdf4e94cb77ead89fb0e369eca88cc9e14c3007e4a1f7.

field value
symbol "ETHP"
orderHash "0xdc15c175ed2cf4613362f81d9c2fd50c3444af2b33af2c5bd6"
nonce "0x3136393832323333303030393036383930303000000000000000000000000000"

Cancel all

The following sample cancellation data results in an EIP-712 hash of: 0x9c6adbbbb7c15e33e1e1d69eae3ca5031432068fb35cdffcd6a771ac95818970.

field value
strategy "main"
nonce "0x3136393832323431363235313430323730303000000000000000000000000000"

Encryption

Sample encryption (JSON)

// Sample unencrypted order placement request
{
    "t": "Order",
    "c": {
        "symbol": "ETHP",
        "strategy": "main",
        "side": "Ask",
        "orderType": "Limit",
        "nonce": "0x3136323737363235343138383430383030303000000000000000000000000000",
        "amount": 10.6,
        "price": 2472.1,
        "stopPrice": 0,
        "signature": "0x1b1f419961c742861a41396f14892ea4a665b7b89086637d37d53ec20364a7ef3aaf1e1472867f5a18fa3f27a2748ed16c603eccd13472cfd61d43df1c3ed22a1b"
    }
}

// Sample encrypted order placement request
"0x3bb4fec9257fb81c846c075fb3944151838c32ce41dadb585049fa7788ae591bb970ea295993d42b238e95595fde09d80d675aa960112533cf61ed4b91b9d77dd3f97d6ecf1cf809800854a11b43d27c5da51d69f550463bddeb471be94fb6a17de3e54cf99665be081ec7f8c24b7eebaef691baa27de167e448ed3a0facf6af0c4fec0e856f56515590c40479cf95f6e25918a42a60b4c15b4362614f91bfbd67eba6a6aad6de9edd45ba5fa7fc33e4473fb9e94a14f492c65bfecc08ff97d7c3126d6ce697aa955234e98ebb027fb042500122c299826267deb278b44a7dfc7f06fad6174f448f4fb41ce13e1003c2013b6de2e9a0bf3d9871658c84644fc41d7e5482bd4efad8370172e64b7220d2a2e596c9a5b3ce38997bae79200b3b62839e47bc6aa876128cb6d4430e18b1f51588d7741161e1a9734d0e203d725c9f4d7dae174a0e75fcdb3882c23590437fbc3330046b150bc90818e7b1c3a42571b62363343f2e46bc7cf6fcd0dfd2550ec83d453641d7a236a3a6677e806125b0c50246d5f26c2db3f61ebc78b955d5095d8b0cd7f4929f5bc2adf53c455b2170f546a09d2e11b463db6cc582a771c6aaad96c3c56123d5010643e584849e6f7cf998495e28b018b4c00bcb64a3aa2b7b7e0cb3faea33c7034887c86a15d5c0a01db2c8bc27a4b6ec2acc2e06ccabde4a64962ab3aec63f36"

Sample encryption implementation (Python)

from coincurve import PublicKey, PrivateKey
from Crypto.Cipher import AES
from Crypto.Random import get_random_bytes
from Crypto.Hash import keccak

def encrypt_with_nonce(encryption_key: str, msg: str) -> bytes:
    """
    Encrypt the JSON-stringified request contents

    Parameters
    ----------
    encryption_key: str
        Encryption key
    msg : str
        JSON-stringified request contents
    """

    network_public_key = PublicKey(bytes.fromhex(encryption_key[2:]))
    my_secret_key = PrivateKey(get_random_bytes(32))
    my_public_key = my_secret_key.public_key
    shared_pub = network_public_key.multiply(my_secret_key.secret)
    keccak_256 = keccak.new(digest_bits=256)
    keccak_256.update(shared_pub.format())
    derived_key = keccak_256.digest()[:16]
    nonce = get_random_bytes(12)

    cipher = AES.new(derived_key, AES.MODE_GCM, nonce=nonce)
    encoded_message = msg.encode("utf8")
    ciphertext, tag = cipher.encrypt_and_digest(
        len(encoded_message).to_bytes(4, byteorder="big") + encoded_message
    )

    return ciphertext + tag + nonce + my_public_key.format()

DerivaDEX is a front-running resistant decentralized exchange, achieved with sending encrypted data that can only be decrypted from inside the Operator's trusted hardware. All requests must be encrypted using an AES-GCM128 scheme. The encryption steps are as follows:

  1. Generate n 16-byte (128-bit) ECDH shared key using the operator's public key (0x03bc06b4271530d20b4ddb03e0069b00b2c0d03baf45d0ab60582448b6d70c2737, which can be obtained from this endpoint) and a 32-byte private key of your choosing (you can randomly generate this each time you are sending a request). Make sure you are using a keccak256 ECDH key generation scheme, but since you need a 16-byte shared key, make sure you take only the first 16 bytes of the 32-byte key generated.

  2. Generate a 12-byte random nonce

  3. Setup the payload you want to encrypt, which is the bytes-encoded request's contents prefixed with a 4-byte value indicating the length of this bytes-encoded request's contents

  4. Generate the ciphertext and MAC tag using AES-GCM128

  5. Return the encrypted bytes in the format of [ciphertext][tag][nonce][client_public_key_compressed_format]

To validate your encryption implementation for correctness (assuming you are not using the DerivaDEX Python client library), please reference what follows and the display on the right:

Realtime API

The DerivaDEX Realtime API is a WebSockets API that offers real-time market and user data updates.

These updates provided present information about the order book, mark price, as well as user-specific data such as outstanding orders, strategy collateral balances, and trader DDX balances.

General notes:

Code samples

def strategy_id_hash(strategy_id):
    # 1. UTF-8 encode and ensure ≤31 bytes
    id_bytes = strategy_id.encode('utf-8')
    assert len(id_bytes) <= 31, "ID must be at most 31 bytes"

    # 2. Build 32-byte buffer:
    #    • byte 0 = length
    #    • bytes 1... = data
    #    • remaining = zero padding
    buf = bytes([len(id_bytes)]) + id_bytes + b'\x00' * (31 - len(id_bytes))

    # 3. Compute Keccak-256 hash of the 32-byte buffer
    digest = keccak256(buf)

    # 4. Return first 4 bytes as the abbreviated ID, prefixed with 0x
    return '0x' + digest[:4].hex()

short_id = strategy_id_hash("main")
assert short_id == "0x2576ebd1"

Table of Contents

Servers

mainnet Server

Server providing real-time market and user data updates for mainnet.

Operations

REPLY / Operation: Subscribe

Code samples

require 'faye/websocket'
require 'eventmachine'
require 'json'

EM.run do
  ws = Faye::WebSocket::Client.new('wss://exchange.derivadex.com/realtime-api')
  ws.on :open do |event|
    payload = {
      action: "SUBSCRIBE",
      nonce: "foo",
      feeds: [
        { feed: "ORDER_BOOK_L2", params: { aggregation: 1, symbol: "ETHP" } }
      ]
    }
    ws.send(payload.to_json)
  end

  ws.on :message do |event|
    p JSON.parse(event.data)
    ws.close
  end
end
import websocket
import json

ws = websocket.create_connection("wss://exchange.derivadex.com/realtime-api")
payload = {
    "action": "SUBSCRIBE",
    "nonce": "foo",
    "feeds": [
        {"feed": "ORDER_BOOK_L2", "params": {"aggregation": 1, "symbol": "ETHP"}}
    ]
}
ws.send(json.dumps(payload))
result = ws.recv()
print(json.loads(result))
ws.close()
const ws = new WebSocket('wss://exchange.derivadex.com/realtime-api');
ws.addEventListener('open', () => {
    const payload = {
        action: 'SUBSCRIBE',
        nonce: 'foo',
        feeds: [{ feed: 'ORDER_BOOK_L2', params: { aggregation: 1, symbol: 'ETHP' } }],
    };
    ws.send(JSON.stringify(payload));
});
ws.addEventListener('message', (event) => {
    console.log(JSON.parse(event.data));
    ws.close();
});

Receive a feed subscription, reply with an acknowledgement.

Operation tags
Name Description
websockets Dealing with or part of the WebSockets protocol.

Message Subscribe subscribe

Subscribe to a data feed.

Subscribe to multiple feeds at once, each with their own (mandatory) respective parameters. Expect a reply/acknowledgement with a nonce matching the given nonce.

Payload
Name Type Description Value Constraints
(root) object Information for subscribing to feeds. - -
action ⚠️ string WebSockets action. allowed ("SUBSCRIBE", "UNSUBSCRIBE") -
nonce ⚠️ string Unique nonce/ID for identification. - -
feeds ⚠️ array<object> The feeds to subscribe to. - non-empty
feeds.feed ⚠️ string Feed name. allowed ("ORDER_BOOK_L2", "ORDER_BOOK_L3", "MARK_PRICE", "ORDER_UPDATE", "STRATEGY_UPDATE", "TRADER_UPDATE") -
feeds.params ⚠️ oneOf - - -
feeds.params.0 (oneOf item) object The parameters for the order book level 2 feed. - -
feeds.params.0.symbol ⚠️ string A product symbol, e.g. ETHP. - -
feeds.params.0.aggregation ⚠️ number Aggregation level for prices. Our aggregations vary by symbol and currently are as follows:
Symbol Aggregations
ETHP 0.1, 1, 10
BTCP 1, 10, 100
- > 0
feeds.params.1 (oneOf item) object The parameters for the order book level 3 feed. - -
feeds.params.1.symbol ⚠️ string A product symbol, e.g. ETHP. - -
feeds.params.2 (oneOf item) object The parameters for the mark price feed. - -
feeds.params.2.symbols ⚠️ array<string> Multiple product symbols for filtering. - non-empty
feeds.params.2.symbols (single item) string A product symbol, e.g. ETHP. - -
feeds.params.3 (oneOf item) object The parameters for the order update feed. - -
feeds.params.3.orderIdentifiers ⚠️ array<object> Multiple order identifiers for filtering. - non-empty
feeds.params.3.orderIdentifiers.traderAddress ⚠️ string The trader address prefixed with the blockchain discriminant. - pattern (^0x[0-9a-f]+$)
feeds.params.3.orderIdentifiers.strategyIdHash string The strategy ID hash. - pattern (^0x[0-9a-f]+$)
feeds.params.3.orderIdentifiers.symbol string A product symbol, e.g. ETHP. - -
feeds.params.4 (oneOf item) object The parameters for the strategy update feed. - -
feeds.params.4.strategyIdentifiers ⚠️ array<object> Multiple strategy identifiers for filtering. - non-empty
feeds.params.4.strategyIdentifiers.traderAddress ⚠️ string The trader address prefixed with the blockchain discriminant. - pattern (^0x[0-9a-f]+$)
feeds.params.4.strategyIdentifiers.strategyIdHash string The strategy ID hash. - pattern (^0x[0-9a-f]+$)
feeds.params.5 (oneOf item) object The parameters for the trader update feed. - -
feeds.params.5.traderAddresses ⚠️ array<string> Multiple trader addresses for filtering. - non-empty
feeds.params.5.traderAddresses (single item) string The trader address prefixed with the blockchain discriminant. - pattern (^0x[0-9a-f]+$)

Examples of payload

Order book L2 feed subscription with parameters

{
    "action": "SUBSCRIBE",
    "nonce": "foo",
    "feeds": [
        {
            "feed": "ORDER_BOOK_L2",
            "params": {
                "aggregation": 1,
                "symbol": "ETHP"
            }
        }
    ]
}
Message tags
Name Description
websockets Dealing with or part of the WebSockets protocol.

Response information

Message Acknowledge acknowledge

Acknowledge the receipt of a message.

Acknowledge a message and respond with success or failure.

Payload
Name Type Description Value Constraints
(root) object Acknowledgement of a (un)subscription. - -
action string WebSockets action. allowed ("SUBSCRIBE", "UNSUBSCRIBE") -
nonce string Unique nonce/ID for identification. - -
result ⚠️ object The result. Empty means success. - -
result.error string The error. - -

Examples of payload

Success

{
    "action": "SUBSCRIBE",
    "nonce": "foo",
    "result": {}
}

Failure

{
    "action": "UNSUBSCRIBE",
    "nonce": "bar",
    "result": {
        "error": "Unexpected error."
    }
}

Unknown failure

{
    "result": {
        "error": "Unknown error."
    }
}
Message tags
Name Description
websockets Dealing with or part of the WebSockets protocol.

REPLY / Operation: Unsubscribe

Code samples

require 'faye/websocket'
require 'eventmachine'
require 'json'

EM.run do
  ws = Faye::WebSocket::Client.new('wss://exchange.derivadex.com/realtime-api')
  ws.on :open do |event|
    payload = {
      action: "UNSUBSCRIBE",
      nonce: "foo",
      feeds: ["ORDER_UPDATE", "ORDER_BOOK_L2"]
    }
    ws.send(payload.to_json)
  end

  ws.on :message do |event|
    p JSON.parse(event.data)
    ws.close
  end
end
import websocket
import json

ws = websocket.create_connection("wss://exchange.derivadex.com/realtime-api")
payload = {
    "action": "UNSUBSCRIBE",
    "nonce": "foo",
    "feeds": ["ORDER_UPDATE", "ORDER_BOOK_L2"]
}
ws.send(json.dumps(payload))
result = ws.recv()
print(json.loads(result))
ws.close()
const ws = new WebSocket('wss://exchange.derivadex.com/realtime-api');
ws.addEventListener('open', () => {
    const payload = {
        action: 'UNSUBSCRIBE',
        nonce: 'foo',
        feeds: ['ORDER_UPDATE', 'ORDER_BOOK_L2'],
    };
    ws.send(JSON.stringify(payload));
});
ws.addEventListener('message', (event) => {
    console.log(JSON.parse(event.data));
    ws.close();
});

Receive a feed unsubscription, reply with an acknowledgement.

Operation tags
Name Description
websockets Dealing with or part of the WebSockets protocol.

Message Unsubscribe unsubscribe

Unsubscribe from a data feed.

Unsubscribe from multiple feeds at once. Expect a reply/acknowledgement with a nonce matching the given nonce.

Payload
Name Type Description Value Constraints
(root) object Information for unsubscribing to feeds. - -
action ⚠️ string WebSockets action. allowed ("SUBSCRIBE", "UNSUBSCRIBE") -
nonce ⚠️ string Unique nonce/ID for identification. - -
feeds ⚠️ array<string> The feeds to unsubscribe to. - non-empty
feeds (single item) string Feed name. allowed ("ORDER_BOOK_L2", "ORDER_BOOK_L3", "MARK_PRICE", "ORDER_UPDATE", "STRATEGY_UPDATE", "TRADER_UPDATE") -

Examples of payload

Unsubscriptions

{
    "action": "UNSUBSCRIBE",
    "nonce": "foo",
    "feeds": ["ORDER_UPDATE", "ORDER_BOOK_L2"]
}
Message tags
Name Description
websockets Dealing with or part of the WebSockets protocol.

Response information

Message Acknowledge acknowledge

Acknowledge the receipt of a message.

Acknowledge a message and respond with success or failure.

Payload
Name Type Description Value Constraints
(root) object Acknowledgement of a (un)subscription. - -
action string WebSockets action. allowed ("SUBSCRIBE", "UNSUBSCRIBE") -
nonce string Unique nonce/ID for identification. - -
result ⚠️ object The result. Empty means success. - -
result.error string The error. - -

Examples of payload

Success

{
    "action": "SUBSCRIBE",
    "nonce": "foo",
    "result": {}
}

Failure

{
    "action": "UNSUBSCRIBE",
    "nonce": "bar",
    "result": {
        "error": "Unexpected error."
    }
}

Unknown failure

{
    "result": {
        "error": "Unknown error."
    }
}
Message tags
Name Description
websockets Dealing with or part of the WebSockets protocol.

SEND / Operation: Order Book L2

Code samples

require 'faye/websocket'
require 'eventmachine'
require 'json'

EM.run do
  ws = Faye::WebSocket::Client.new('wss://exchange.derivadex.com/realtime-api')
  ws.on :message do |event|
    data = JSON.parse(event.data)
    next unless data['feed'] == 'ORDER_BOOK_L2'
    puts data['contents']
    ws.close
  end
end
import websocket
import json

ws = websocket.create_connection("wss://exchange.derivadex.com/realtime-api")
while True:
    result = ws.recv()
    data = json.loads(result)
    if data.get("feed") == "ORDER_BOOK_L2":
        print(data["contents"])
        break
ws.close()
const ws = new WebSocket('wss://exchange.derivadex.com/realtime-api');
ws.addEventListener('message', (event) => {
    const data = JSON.parse(event.data);
    if (data.feed === 'ORDER_BOOK_L2') {
        console.log(data.contents);
        ws.close();
    }
});

Push an order book level 2 snapshot.

Operation tags
Name Description
public-data Dealing with public data including but not limited to markets and relevant system information.

Message Order Book L2 orderBookL2

Provides order book level 2 data.

Record order book level 2 data with the given symbol and aggregation.

Upon subscribing, the Order Book L2 Feed will first return a message reflecting the current state of the Order Book (called a PARTIAL). Subsequent messages will contain UPDATEs to that initial state. An amount of "0" is sent in an update to reflect that the order book row is no longer present.

Payload
Name Type Description Value Constraints
(root) object Order book level 2 data. - -
feed ⚠️ string Order book level 2 feed name. const ("ORDER_BOOK_L2") -
params ⚠️ object The parameters for the order book level 2 feed. - -
params.symbol ⚠️ string A product symbol, e.g. ETHP. - -
params.aggregation ⚠️ number Aggregation level for prices. Our aggregations vary by symbol and currently are as follows:
Symbol Aggregations
ETHP 0.1, 1, 10
BTCP 1, 10, 100
- > 0
contents ⚠️ object The contents of the message. - -
contents.messageType ⚠️ string Message type. allowed ("PARTIAL", "UPDATE") -
contents.ordinal ⚠️ integer The sequence number of a message relative to the feed subscription. - >= 0
contents.data ⚠️ array<object> The order book data. - -
contents.data.symbol ⚠️ string A product symbol, e.g. ETHP. - -
contents.data.side ⚠️ integer The side of the order:
Code Description
0 Bid
1 Ask
allowed (0, 1) -
contents.data.amount ⚠️ string The aggregated amount for this price level. Stored as string to preserve decimal precision. - >= 0
contents.data.price ⚠️ string The aggregated price level. Stored as string to preserve decimal precision. - >= 0

Examples of payload

Order Book L2 partial snapshot (ETHP)

{
    "feed": "ORDER_BOOK_L2",
    "params": {
        "symbol": "ETHP",
        "aggregation": 0.1
    },
    "contents": {
        "messageType": "PARTIAL",
        "ordinal": 0,
        "data": [
            {
                "symbol": "ETHP",
                "side": 0,
                "amount": "50.25",
                "price": "2000.0"
            },
            {
                "symbol": "ETHP",
                "side": 1,
                "amount": "100.5",
                "price": "2000.5"
            }
        ]
    }
}

Order Book L2 update with removal (ETHP)

{
    "feed": "ORDER_BOOK_L2",
    "params": {
        "symbol": "ETHP",
        "aggregation": 1
    },
    "contents": {
        "messageType": "UPDATE",
        "ordinal": 1,
        "data": [
            {
                "symbol": "ETHP",
                "side": 0,
                "amount": "0",
                "price": "2100"
            },
            {
                "symbol": "ETHP",
                "side": 1,
                "amount": "15.5",
                "price": "2101"
            }
        ]
    }
}

Order Book L2 partial snapshot (BTCP)

{
    "feed": "ORDER_BOOK_L2",
    "params": {
        "symbol": "BTCP",
        "aggregation": 10
    },
    "contents": {
        "messageType": "PARTIAL",
        "ordinal": 0,
        "data": [
            {
                "symbol": "BTCP",
                "side": 0,
                "amount": "5",
                "price": "30000"
            },
            {
                "symbol": "BTCP",
                "side": 1,
                "amount": "3.5",
                "price": "30050"
            }
        ]
    }
}
Message tags
Name Description
public-data Dealing with public data including but not limited to markets and relevant system information.

SEND / Operation: Order Book L3

Code samples

require 'faye/websocket'
require 'eventmachine'
require 'json'

EM.run do
  ws = Faye::WebSocket::Client.new('wss://exchange.derivadex.com/realtime-api')
  ws.on :message do |event|
    data = JSON.parse(event.data)
    next unless data['feed'] == 'ORDER_BOOK_L3'
    puts data['contents']
    ws.close
  end
end
import websocket
import json

ws = websocket.create_connection("wss://exchange.derivadex.com/realtime-api")
while True:
    result = ws.recv()
    data = json.loads(result)
    if data.get("feed") == "ORDER_BOOK_L3":
        print(data["contents"])
        break
ws.close()
const ws = new WebSocket('wss://exchange.derivadex.com/realtime-api');
ws.addEventListener('message', (event) => {
    const data = JSON.parse(event.data);
    if (data.feed === 'ORDER_BOOK_L3') {
        console.log(data.contents);
        ws.close();
    }
});

Push an order book level 3 snapshot.

Operation tags
Name Description
public-data Dealing with public data including but not limited to markets and relevant system information.

Message Order Book L3 orderBookL3

Provides order book level 3 data.

Record order book level 3 data with the given symbol.

Upon subscribing, the Order Book L3 Feed will first return a message reflecting the current state of the Order Book (called a PARTIAL). Subsequent messages will contain UPDATEs to that initial state. An amount of "0" is sent in an update to reflect that the order book row is no longer present.

Payload
Name Type Description Value Constraints
(root) object Order book level 3 data. - -
feed ⚠️ string Order book level 3 feed name. const ("ORDER_BOOK_L3") -
params ⚠️ object The parameters for the order book level 3 feed. - -
params.symbol ⚠️ string A product symbol, e.g. ETHP. - -
contents ⚠️ object The contents of the message. - -
contents.messageType ⚠️ string Message type. allowed ("PARTIAL", "UPDATE") -
contents.ordinal ⚠️ integer The sequence number of a message relative to the feed subscription. - >= 0
contents.data ⚠️ array<object> The order book data. - -
contents.data.orderHash ⚠️ string The unique hash of an order. - pattern (^0x[0-9a-f]+$)
contents.data.symbol ⚠️ string A product symbol, e.g. ETHP. - -
contents.data.side ⚠️ integer The side of the order:
Code Description
0 Bid
1 Ask
allowed (0, 1) -
contents.data.originalAmount ⚠️ string The original amount of the order (before any fills). - >= 0
contents.data.amount ⚠️ string The amount of an order. Stored as string to preserve decimal precision. - >= 0
contents.data.price ⚠️ string The price of an order. Stored as string to preserve decimal precision. - >= 0
contents.data.traderAddress ⚠️ string The trader address prefixed with the blockchain discriminant. - pattern (^0x[0-9a-f]+$)
contents.data.strategyIdHash ⚠️ string The strategy ID hash. - pattern (^0x[0-9a-f]+$)
contents.data.bookOrdinal ⚠️ integer The ordinal of when this order arrived on the book. - >= 0

Examples of payload

Order Book L3 partial snapshot (ETHP)

{
    "feed": "ORDER_BOOK_L3",
    "params": {
        "symbol": "ETHP"
    },
    "contents": {
        "messageType": "PARTIAL",
        "ordinal": 0,
        "data": [
            {
                "orderHash": "0x92aaeac66831b00d0db66517debb3eac7370105d854420ed82",
                "symbol": "ETHP",
                "side": 0,
                "originalAmount": "50",
                "amount": "50",
                "price": "2000",
                "traderAddress": "0x00112233445566778899aabbccddeeff0011223344",
                "strategyIdHash": "0x2576ebd1",
                "bookOrdinal": 0
            },
            {
                "orderHash": "0x83bcdac12345b00d0eb66517debb3eac7370105d854420ed83",
                "symbol": "ETHP",
                "side": 1,
                "originalAmount": "30",
                "amount": "30",
                "price": "2001",
                "traderAddress": "0x00abcdef0123456789abcdef0123456789abcdef01",
                "strategyIdHash": "0x2576ebd1",
                "bookOrdinal": 1
            }
        ]
    }
}

Order Book L3 update with removal (BTCP)

{
    "feed": "ORDER_BOOK_L3",
    "params": {
        "symbol": "BTCP"
    },
    "contents": {
        "messageType": "UPDATE",
        "ordinal": 1,
        "data": [
            {
                "orderHash": "0x74cdfeaa98765b00d0fb66517debb3eac7370105d854420ed84",
                "symbol": "BTCP",
                "side": 0,
                "originalAmount": "10",
                "amount": "5",
                "price": "30000",
                "traderAddress": "0x00ffeeddccbbaa99887766554433221100ffeeddcc",
                "strategyIdHash": "0x2576ebd1",
                "bookOrdinal": 2
            },
            {
                "orderHash": "0x12ab3cd456ef7890abcd1234ef5678901234567890abcdef12",
                "symbol": "BTCP",
                "side": 1,
                "originalAmount": "5",
                "amount": "0",
                "price": "30000",
                "traderAddress": "0x00f4d1a2b3c4e5f67890abcdeffedcba0987654321",
                "strategyIdHash": "0x2576ebd1",
                "bookOrdinal": 3
            }
        ]
    }
}
Message tags
Name Description
public-data Dealing with public data including but not limited to markets and relevant system information.

SEND / Operation: Mark Price

Code samples

require 'faye/websocket'
require 'eventmachine'
require 'json'

EM.run do
  ws = Faye::WebSocket::Client.new('wss://exchange.derivadex.com/realtime-api')
  ws.on :message do |event|
    data = JSON.parse(event.data)
    next unless data['feed'] == 'MARK_PRICE'
    puts data['contents']
    ws.close
  end
end
import websocket
import json

ws = websocket.create_connection("wss://exchange.derivadex.com/realtime-api")
while True:
    result = ws.recv()
    data = json.loads(result)
    if data.get("feed") == "MARK_PRICE":
        print(data["contents"])
        break
ws.close()
const ws = new WebSocket('wss://exchange.derivadex.com/realtime-api');
ws.addEventListener('message', (event) => {
    const data = JSON.parse(event.data);
    if (data.feed === 'MARK_PRICE') {
        console.log(data.contents);
        ws.close();
    }
});

Push a mark price snapshot.

Operation tags
Name Description
public-data Dealing with public data including but not limited to markets and relevant system information.

Message Mark Price markPrice

Provides mark price updates.

Record mark price data with the given symbol.

Upon subscribing, the Mark Price Feed will first return a message reflecting the most recent mark prices and funding rates (called a PARTIAL). Subsequent messages will contain new mark prices (and funding rates) as UPDATEs.

Payload
Name Type Description Value Constraints
(root) object Latest mark price for a trading product symbol, as well as its updated funding rate. - -
feed ⚠️ string Mark price feed name. const ("MARK_PRICE") -
params ⚠️ object The parameters for the mark price feed. - -
params.symbols ⚠️ array<string> Multiple product symbols for filtering. - non-empty
params.symbols (single item) string A product symbol, e.g. ETHP. - -
contents ⚠️ object The contents of the message. - -
contents.messageType ⚠️ string Message type. allowed ("PARTIAL", "UPDATE") -
contents.ordinal ⚠️ integer The sequence number of a message relative to the feed subscription. - >= 0
contents.data ⚠️ array<object> The mark price chronological data. - -
contents.data.epochId ⚠️ integer The epoch ID. - >= 0
contents.data.price ⚠️ string The mark price. - >= 0
contents.data.fundingRate ⚠️ string The new funding rate for this symbol. Stored as a string to preserve decimal precision. - -
contents.data.symbol ⚠️ string A product symbol, e.g. ETHP. - -
contents.data.createdAt ⚠️ string The timestamp when this object was created. - format (dateTime)

Examples of payload

Mark Price partial snapshot (ETHP)

{
    "feed": "MARK_PRICE",
    "params": {
        "symbols": ["ETHP"]
    },
    "contents": {
        "messageType": "PARTIAL",
        "ordinal": 0,
        "data": [
            {
                "epochId": 43,
                "price": "1986.81",
                "fundingRate": "0.000381",
                "symbol": "ETHP",
                "createdAt": "2023-10-01T12:00:30Z"
            }
        ]
    }
}

Mark Price update (BTCP)

{
    "feed": "MARK_PRICE",
    "params": {
        "symbols": ["BTCP"]
    },
    "contents": {
        "messageType": "UPDATE",
        "ordinal": 1,
        "data": [
            {
                "epochId": 44,
                "price": "30500.57",
                "fundingRate": "0.003532",
                "symbol": "BTCP",
                "createdAt": "2023-10-01T12:01:00Z"
            }
        ]
    }
}
Message tags
Name Description
public-data Dealing with public data including but not limited to markets and relevant system information.

SEND / Operation: Order Update

Code samples

require 'faye/websocket'
require 'eventmachine'
require 'json'

EM.run do
  ws = Faye::WebSocket::Client.new('wss://exchange.derivadex.com/realtime-api')
  ws.on :message do |event|
    data = JSON.parse(event.data)
    next unless data['feed'] == 'ORDER_UPDATE'
    puts data['contents']
    ws.close
  end
end
import websocket
import json

ws = websocket.create_connection("wss://exchange.derivadex.com/realtime-api")
while True:
    result = ws.recv()
    data = json.loads(result)
    if data.get("feed") == "ORDER_UPDATE":
        print(data["contents"])
        break
ws.close()
const ws = new WebSocket('wss://exchange.derivadex.com/realtime-api');
ws.addEventListener('message', (event) => {
    const data = JSON.parse(event.data);
    if (data.feed === 'ORDER_UPDATE') {
        console.log(data.contents);
        ws.close();
    }
});

Push an order update.

Operation tags
Name Description
user-data Dealing with personal user data including but not limited to traders, strategies, and balances.

Message Order Update orderUpdate

Provides updates for order changes.

Record order updates with the given trader addresses (and optionally symbol and strategy ID hash), with all maker and taker/liquidated-trader details (including original order intents). Includes order updates due to trades, liquidations, cancellations, and ADLs, as well as order rejections and cancellation rejections. Note that when the order is fully rejected, some of the fields of makerOrderIntent will be filled with the empty string "" (and side and orderType will be 0), as not all information is available, since the "maker" order intent is not created if the order is fully rejected.

Upon subscribing, the Order Update Feed will first return an empty PARTIAL. Users are expected to get the initial state of one's own orders from our REST API. Subsequent messages will contain order UPDATEs to existing orders.

Payload
Name Type Description Value Constraints
(root) object Order update data. - -
feed ⚠️ string Order update feed name. const ("ORDER_UPDATE") -
params ⚠️ object The parameters for the order update feed. - -
params.orderIdentifiers ⚠️ array<object> Multiple order identifiers for filtering. - non-empty
params.orderIdentifiers.traderAddress ⚠️ string The trader address prefixed with the blockchain discriminant. - pattern (^0x[0-9a-f]+$)
params.orderIdentifiers.strategyIdHash string The strategy ID hash. - pattern (^0x[0-9a-f]+$)
params.orderIdentifiers.symbol string A product symbol, e.g. ETHP. - -
contents ⚠️ object The contents of the message. - -
contents.messageType ⚠️ string Message type. allowed ("PARTIAL", "UPDATE") -
contents.ordinal ⚠️ integer The sequence number of a message relative to the feed subscription. - >= 0
contents.data ⚠️ array<object> The order update data. - -
contents.data.epochId ⚠️ integer The epoch ID. - >= 0
contents.data.orderRejection integer The order rejection reason (if any):
Code Description Details
0 SelfMatch Part or all of the order was self-canceled because the same maker owns the best match.
1 SolvencyGuard Part or all of the order was self-canceled for failing the solvency guards.
2 MaxTakerPriceDeviation Part or all of the order was self-canceled because the marker order's price deviated too much from the mark price.
3 NoLiquidity All of the order was self-canceled since there is no more liquidity in the book.
4 InvalidStrategy All of the order was self-canceled because the strategy is invalid/nonexistent.
5 PostOnlyViolation All of the order was self-canceled because it would have matched immediately.
allowed (0, 1, 2, 3, 4, 5) -
contents.data.cancelRejection integer The cancel rejection reason (if any):
Code Description Details
0 InvalidOrder The cancel/modify request failed because the order does not exist.
allowed (0) -
contents.data.reason ⚠️ integer The type of order update:
Code Description
0 Trade
1 Liquidation
2 Cancellation
3 OrderRejection
4 CancelRejection
allowed (0, 1, 2, 3, 4) -
contents.data.amount string The fill amount. Stored as string to preserve decimal precision. - >= 0
contents.data.quoteAssetAmount string The filled order amount in the quote asset. - >= 0
contents.data.symbol ⚠️ string A product symbol, e.g. ETHP. - -
contents.data.price string The fill price. Stored as string to preserve decimal precision. - >= 0
contents.data.orderMatchOrdinal integer The ordinal of the order match outcome that this order update belongs to. Every order update/trade outcome that resulted from the same order match will have the same orderMatchOrdinal. - >= 0
contents.data.ordinal integer The ordinal of this order update/trade outcome (trade, liquidation, cancellation, or ADL) within its order match outcome. All order updates/trade outcomes that resulted from the same order match will have the same orderMatchOrdinal but different ordinals. - >= 0
contents.data.lastExecutedAmount string The last/previously executed fill amount of a series of trade outcomes (from a single order match). Stored as string to preserve decimal precision. - >= 0
contents.data.lastExecutedPrice string The last/previously executed fill price of a series of trade outcomes (from a single order match). Stored as string to preserve decimal precision. - >= 0
contents.data.cumulativeFilledAmount string The cumulative filled amount of a series of trade outcomes (from a single order match) up to and including this point. Stored as string to preserve decimal precision. - >= 0
contents.data.cumulativeQuoteAssetTransactedAmount string The cumulative transacted amount of the quote asset of a series of trade outcomes (from a single order match) up to and including this point. Stored as string to preserve decimal precision. - >= 0
contents.data.lastQuoteAssetTransactedAmount string The last/previously transacted amount of the quote asset of a series of trade outcomes (from a single order match) up to this point. Stored as string to preserve decimal precision. - >= 0
contents.data.makerOrderIntent ⚠️ object An order intent. - -
contents.data.makerOrderIntent.epochId ⚠️ integer The epoch ID. - >= 0
contents.data.makerOrderIntent.orderHash ⚠️ string The unique hash of an order. - pattern (^0x[0-9a-f]+$)
contents.data.makerOrderIntent.symbol ⚠️ string A product symbol, e.g. ETHP. - -
contents.data.makerOrderIntent.side ⚠️ integer The side of the order:
Code Description
0 Bid
1 Ask
allowed (0, 1) -
contents.data.makerOrderIntent.amount ⚠️ string The amount of an order. Stored as string to preserve decimal precision. - >= 0
contents.data.makerOrderIntent.price ⚠️ string The price of an order. Stored as string to preserve decimal precision. - >= 0
contents.data.makerOrderIntent.traderAddress ⚠️ string The trader address prefixed with the blockchain discriminant. - pattern (^0x[0-9a-f]+$)
contents.data.makerOrderIntent.strategyIdHash ⚠️ string The strategy ID hash. - pattern (^0x[0-9a-f]+$)
contents.data.makerOrderIntent.orderType ⚠️ string The order type:
Code Description
0 Limit
1 Market
2 Stop
3 Limit-PostOnly
allowed (0, 1, 2, 3) -
contents.data.makerOrderIntent.stopPrice ⚠️ string The stop price of an order. Stored as string to preserve decimal precision. NOT CURRENTLY ACTIVE. - >= 0
contents.data.makerOrderIntent.nonce ⚠️ string Unique nonce/ID for identification. - -
contents.data.makerOrderIntent.signature ⚠️ string A signature used to verify the authenticity of the order, when it was sent by the trader. - pattern (^0x[0-9a-f]+$)
contents.data.makerOrderIntent.createdAt ⚠️ string The timestamp when this object was created. - format (dateTime)
contents.data.makerFeeCollateral string The fee for the maker trade in the collateral currency. Stored as string to preserve decimal precision. - >= 0
contents.data.makerFeeDDX string The fee for the maker trade in DDX. Stored as string to preserve decimal precision. - >= 0
contents.data.makerRealizedPnl string The realized PnL for the maker trade in the collateral currency. Stored as string to preserve decimal precision. - -
contents.data.takerOrderIntent object An order intent. - -
contents.data.takerOrderIntent.epochId ⚠️ integer The epoch ID. - >= 0
contents.data.takerOrderIntent.orderHash ⚠️ string The unique hash of an order. - pattern (^0x[0-9a-f]+$)
contents.data.takerOrderIntent.symbol ⚠️ string A product symbol, e.g. ETHP. - -
contents.data.takerOrderIntent.side ⚠️ integer The side of the order:
Code Description
0 Bid
1 Ask
allowed (0, 1) -
contents.data.takerOrderIntent.amount ⚠️ string The amount of an order. Stored as string to preserve decimal precision. - >= 0
contents.data.takerOrderIntent.price ⚠️ string The price of an order. Stored as string to preserve decimal precision. - >= 0
contents.data.takerOrderIntent.traderAddress ⚠️ string The trader address prefixed with the blockchain discriminant. - pattern (^0x[0-9a-f]+$)
contents.data.takerOrderIntent.strategyIdHash ⚠️ string The strategy ID hash. - pattern (^0x[0-9a-f]+$)
contents.data.takerOrderIntent.orderType ⚠️ string The order type:
Code Description
0 Limit
1 Market
2 Stop
3 Limit-PostOnly
allowed (0, 1, 2, 3) -
contents.data.takerOrderIntent.stopPrice ⚠️ string The stop price of an order. Stored as string to preserve decimal precision. NOT CURRENTLY ACTIVE. - >= 0
contents.data.takerOrderIntent.nonce ⚠️ string Unique nonce/ID for identification. - -
contents.data.takerOrderIntent.signature ⚠️ string A signature used to verify the authenticity of the order, when it was sent by the trader. - pattern (^0x[0-9a-f]+$)
contents.data.takerOrderIntent.createdAt ⚠️ string The timestamp when this object was created. - format (dateTime)
contents.data.takerFeeCollateral string The fee for the taker trade in the collateral currency. Stored as string to preserve decimal precision. - >= 0
contents.data.takerFeeDDX string The fee for the taker trade in DDX. Stored as string to preserve decimal precision. - >= 0
contents.data.takerRealizedPnl string The realized PnL for the taker trade in the collateral currency. Stored as string to preserve decimal precision. - -
contents.data.liquidatedTraderAddress string The trader address prefixed with the blockchain discriminant. - pattern (^0x[0-9a-f]+$)
contents.data.liquidatedStrategyIdHash string The strategy ID hash. - pattern (^0x[0-9a-f]+$)
contents.data.createdAt ⚠️ string The timestamp when this object was created. - format (dateTime)

Examples of payload

Order Update - empty partial

{
    "feed": "ORDER_UPDATE",
    "params": {
        "orderIdentifiers": [
            {
                "traderAddress": "0x00aabbccddeeff00112233445566778899aabbccdd",
                "symbol": "ETHP",
                "strategyIdHash": "0x2576ebd1"
            },
            {
                "traderAddress": "0x00f1e2d3c4b5a6978899aabbccddeeff1122334455"
            }
        ]
    },
    "contents": {
        "messageType": "PARTIAL",
        "ordinal": 0,
        "data": []
    }
}

Order Update - trade (with trade outcome cancels)

{
    "feed": "ORDER_UPDATE",
    "params": {
        "orderIdentifiers": [
            {
                "traderAddress": "0x00aabbccddeeff00112233445566778899aabbccdd",
                "symbol": "ETHP",
                "strategyIdHash": "0x2576ebd1"
            },
            {
                "traderAddress": "0x00f1e2d3c4b5a6978899aabbccddeeff1122334455",
                "symbol": "ETHP",
                "strategyIdHash": "0x2576ebd1"
            }
        ]
    },
    "contents": {
        "messageType": "UPDATE",
        "ordinal": 0,
        "data": [
            {
                "epochId": 200,
                "reason": 0,
                "amount": "10",
                "quoteAssetAmount": "2000",
                "symbol": "ETHP",
                "price": "100",
                "orderMatchOrdinal": 10,
                "ordinal": 0,
                "cumulativeFilledAmount": "10",
                "cumulativeQuoteAssetTransactedAmount": "2000",
                "makerRealizedPnl": "30",
                "takerFeeDDX": "0.05",
                "takerRealizedPnl": "50",
                "makerOrderIntent": {
                    "epochId": 200,
                    "orderHash": "0xa1b2c3d4e5f67890abcdef01234567891234567890123456789",
                    "symbol": "ETHP",
                    "side": 0,
                    "amount": "20",
                    "price": "100",
                    "traderAddress": "0x00f1e2d3c4b5a6978899aabbccddeeff1122334455",
                    "strategyIdHash": "0x2576ebd1",
                    "orderType": 0,
                    "stopPrice": "0",
                    "nonce": "nonce-maker-1",
                    "signature": "0xfedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210",
                    "createdAt": "2023-10-01T11:59:50Z"
                },
                "takerOrderIntent": {
                    "epochId": 200,
                    "orderHash": "0xb1c2d3e4f5a67890abcdef0123456789234567890abcdef12",
                    "symbol": "ETHP",
                    "side": 1,
                    "amount": "20",
                    "price": "100",
                    "traderAddress": "0x00aabbccddeeff00112233445566778899aabbccdd",
                    "strategyIdHash": "0x2576ebd1",
                    "orderType": 0,
                    "stopPrice": "0",
                    "nonce": "nonce-taker-1",
                    "signature": "0x0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef",
                    "createdAt": "2023-10-01T11:59:55Z"
                },
                "createdAt": "2023-10-01T12:00:05Z"
            },
            {
                "epochId": 200,
                "reason": 2,
                "amount": "10",
                "quoteAssetAmount": "3000",
                "symbol": "ETHP",
                "makerOrderIntent": {
                    "epochId": 200,
                    "orderHash": "0xa1b2c3d4e5f67890abcdef01234567891234567890123456789",
                    "symbol": "ETHP",
                    "side": 0,
                    "amount": "20",
                    "price": "100",
                    "traderAddress": "0x00f1e2d3c4b5a6978899aabbccddeeff1122334455",
                    "strategyIdHash": "0x2576ebd1",
                    "orderType": 0,
                    "stopPrice": "0",
                    "nonce": "nonce-maker-1",
                    "signature": "0xfedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210",
                    "createdAt": "2023-10-01T11:59:50Z"
                },
                "takerOrderIntent": {
                    "epochId": 200,
                    "orderHash": "0xb1c2d3e4f5a67890abcdef0123456789234567890abcdef12",
                    "symbol": "ETHP",
                    "side": 1,
                    "amount": "20",
                    "price": "100",
                    "traderAddress": "0x00aabbccddeeff00112233445566778899aabbccdd",
                    "strategyIdHash": "0x2576ebd1",
                    "orderType": 0,
                    "stopPrice": "0",
                    "nonce": "nonce-taker-1",
                    "signature": "0x0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef",
                    "createdAt": "2023-10-01T11:59:55Z"
                },
                "createdAt": "2023-10-01T12:00:05Z"
            }
        ]
    }
}

Order Update - order rejection (SelfMatch) with previous trade outcomes

{
    "feed": "ORDER_UPDATE",
    "params": {
        "orderIdentifiers": [
            {
                "traderAddress": "0x00aabbccddeeff00112233445566778899aabbccdd",
                "symbol": "ETHP",
                "strategyIdHash": "0x2576ebd1"
            }
        ]
    },
    "contents": {
        "messageType": "UPDATE",
        "ordinal": 1,
        "data": [
            {
                "epochId": 201,
                "reason": 0,
                "amount": "20",
                "quoteAssetAmount": "2000",
                "symbol": "ETHP",
                "price": "100",
                "orderMatchOrdinal": 10,
                "ordinal": 0,
                "cumulativeFilledAmount": "20",
                "cumulativeQuoteAssetTransactedAmount": "2000",
                "makerRealizedPnl": "30",
                "takerFeeDDX": "0.05",
                "takerRealizedPnl": "50",
                "makerOrderIntent": {
                    "epochId": 201,
                    "orderHash": "0xa1b2c3d4e5f67890abcdef01234567891234567890123456789",
                    "symbol": "ETHP",
                    "side": 0,
                    "amount": "5",
                    "price": "100",
                    "traderAddress": "0x00c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3",
                    "strategyIdHash": "0x2576ebd1",
                    "orderType": 0,
                    "stopPrice": "0",
                    "nonce": "nonce-maker-rej",
                    "signature": "0xfedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210",
                    "createdAt": "2023-10-01T11:59:50Z"
                },
                "takerOrderIntent": {
                    "epochId": 201,
                    "orderHash": "0xb1c2d3e4f5a67890abcdef0123456789234567890abcdef12",
                    "symbol": "ETHP",
                    "side": 1,
                    "amount": "20",
                    "price": "100",
                    "traderAddress": "0x00aabbccddeeff00112233445566778899aabbccdd",
                    "strategyIdHash": "0x2576ebd1",
                    "orderType": 0,
                    "stopPrice": "0",
                    "nonce": "nonce-taker-1",
                    "signature": "0x0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef",
                    "createdAt": "2023-10-01T11:59:55Z"
                },
                "createdAt": "2023-10-01T12:00:05Z"
            },
            {
                "epochId": 201,
                "orderRejection": 0,
                "reason": 3,
                "amount": "0",
                "quoteAssetAmount": "0",
                "symbol": "ETHP",
                "price": "100",
                "orderMatchOrdinal": 11,
                "ordinal": 1,
                "lastExecutedAmount": "20",
                "lastExecutedPrice": "100",
                "cumulativeFilledAmount": "20",
                "cumulativeQuoteAssetTransactedAmount": "2000",
                "lastQuoteAssetTransactedAmount": "2000",
                "makerOrderIntent": {
                    "epochId": 201,
                    "orderHash": "0xa1b2c3d4e5f67890abcdef01234567891234567890123456789",
                    "symbol": "ETHP",
                    "side": 0,
                    "amount": "5",
                    "price": "100",
                    "traderAddress": "0x00c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3",
                    "strategyIdHash": "0x2576ebd1",
                    "orderType": 0,
                    "stopPrice": "0",
                    "nonce": "nonce-maker-rej",
                    "signature": "0xfedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210",
                    "createdAt": "2023-10-01T11:59:50Z"
                },
                "createdAt": "2023-10-01T12:00:10Z"
            }
        ]
    }
}

Order Update - full order rejection (InvalidStrategy)

{
    "feed": "ORDER_UPDATE",
    "params": {
        "orderIdentifiers": [
            {
                "traderAddress": "0x00aabbccddeeff00112233445566778899aabbccdd",
                "symbol": "ETHP",
                "strategyIdHash": "0x2576ebd1"
            }
        ]
    },
    "contents": {
        "messageType": "UPDATE",
        "ordinal": 1,
        "data": [
            {
                "epochId": 201,
                "orderRejection": 4,
                "reason": 3,
                "amount": "0",
                "symbol": "ETHP",
                "price": "100",
                "makerOrderIntent": {
                    "epochId": 201,
                    "orderHash": "0xa1b2c3d4e5f67890abcdef01234567891234567890123456789",
                    "symbol": "ETHP",
                    "side": 0,
                    "amount": "5",
                    "price": "",
                    "traderAddress": "0x00c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3",
                    "strategyIdHash": "0x2576ebd1",
                    "orderType": 0,
                    "stopPrice": "",
                    "nonce": "",
                    "signature": "",
                    "createdAt": "2023-10-01T11:59:50Z"
                },
                "createdAt": "2023-10-01T12:00:10Z"
            }
        ]
    }
}

Order Update - user cancellation

{
    "feed": "ORDER_UPDATE",
    "params": {
        "orderIdentifiers": [
            {
                "traderAddress": "0x00aabbccddeeff00112233445566778899aabbccdd",
                "symbol": "ETHP",
                "strategyIdHash": "0x2576ebd1"
            }
        ]
    },
    "contents": {
        "messageType": "UPDATE",
        "ordinal": 1,
        "data": [
            {
                "epochId": 201,
                "reason": 2,
                "amount": "30",
                "quoteAssetAmount": "3000",
                "symbol": "ETHP",
                "makerOrderIntent": {
                    "epochId": 201,
                    "orderHash": "0xa1b2c3d4e5f67890abcdef01234567891234567890123456789",
                    "symbol": "ETHP",
                    "side": 0,
                    "amount": "5",
                    "price": "100",
                    "traderAddress": "0x00c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3",
                    "strategyIdHash": "0x2576ebd1",
                    "orderType": 0,
                    "stopPrice": "0",
                    "nonce": "nonce-maker-cancel",
                    "signature": "0xfedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210",
                    "createdAt": "2023-10-01T11:59:50Z"
                },
                "createdAt": "2023-10-01T12:00:10Z"
            }
        ]
    }
}

Order Update - user cancellation rejection

{
    "feed": "ORDER_UPDATE",
    "params": {
        "orderIdentifiers": [
            {
                "traderAddress": "0x00aabbccddeeff00112233445566778899aabbccdd",
                "symbol": "ETHP",
                "strategyIdHash": "0x2576ebd1"
            }
        ]
    },
    "contents": {
        "messageType": "UPDATE",
        "ordinal": 1,
        "data": [
            {
                "epochId": 201,
                "cancelRejection": 0,
                "reason": 4,
                "symbol": "ETHP",
                "makerOrderIntent": {
                    "epochId": 201,
                    "orderHash": "0xa1b2c3d4e5f67890abcdef01234567891234567890123456789",
                    "symbol": "ETHP",
                    "side": 0,
                    "amount": "5",
                    "price": "100",
                    "traderAddress": "0x00c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3",
                    "strategyIdHash": "0x2576ebd1",
                    "orderType": 0,
                    "stopPrice": "0",
                    "nonce": "nonce-maker-cancel-rej",
                    "signature": "0xfedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210",
                    "createdAt": "2023-10-01T11:59:50Z"
                },
                "createdAt": "2023-10-01T12:00:10Z"
            }
        ]
    }
}

Order Update - liquidation

{
    "feed": "ORDER_UPDATE",
    "params": {
        "orderIdentifiers": [
            {
                "traderAddress": "0x00aabbccddeeff00112233445566778899aabbccdd",
                "symbol": "ETHP",
                "strategyIdHash": "0x2576ebd1"
            },
            {
                "traderAddress": "0x00f1e2d3c4b5a6978899aabbccddeeff1122334455",
                "symbol": "ETHP",
                "strategyIdHash": "0x2576ebd1"
            }
        ]
    },
    "contents": {
        "messageType": "UPDATE",
        "ordinal": 0,
        "data": [
            {
                "epochId": 200,
                "reason": 1,
                "amount": "20",
                "quoteAssetAmount": "2000",
                "symbol": "ETHP",
                "price": "100",
                "orderMatchOrdinal": 12,
                "ordinal": 4,
                "cumulativeFilledAmount": "20",
                "cumulativeQuoteAssetTransactedAmount": "2000",
                "makerRealizedPnl": "30",
                "makerOrderIntent": {
                    "epochId": 200,
                    "orderHash": "0xa1b2c3d4e5f67890abcdef01234567891234567890123456789",
                    "symbol": "ETHP",
                    "side": 0,
                    "amount": "20",
                    "price": "100",
                    "traderAddress": "0x00f1e2d3c4b5a6978899aabbccddeeff1122334455",
                    "strategyIdHash": "0x2576ebd1",
                    "orderType": 0,
                    "stopPrice": "0",
                    "nonce": "nonce-maker-liq",
                    "signature": "0xfedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210",
                    "createdAt": "2023-10-01T11:59:50Z"
                },
                "liquidatedTraderAddress": "0x00aabbccddeeff00112233445566778899aabbccdd",
                "liquidatedStrategyIdHash": "0x2576ebd1",
                "createdAt": "2023-10-01T12:00:05Z"
            }
        ]
    }
}
Message tags
Name Description
user-data Dealing with personal user data including but not limited to traders, strategies, and balances.

SEND / Operation: Strategy Update

Code samples

require 'faye/websocket'
require 'eventmachine'
require 'json'

EM.run do
  ws = Faye::WebSocket::Client.new('wss://exchange.derivadex.com/realtime-api')
  ws.on :message do |event|
    data = JSON.parse(event.data)
    next unless data['feed'] == 'STRATEGY_UPDATE'
    puts data['contents']
    ws.close
  end
end
import websocket
import json

ws = websocket.create_connection("wss://exchange.derivadex.com/realtime-api")
while True:
    result = ws.recv()
    data = json.loads(result)
    if data.get("feed") == "STRATEGY_UPDATE":
        print(data["contents"])
        break
ws.close()
const ws = new WebSocket('wss://exchange.derivadex.com/realtime-api');
ws.addEventListener('message', (event) => {
    const data = JSON.parse(event.data);
    if (data.feed === 'STRATEGY_UPDATE') {
        console.log(data.contents);
        ws.close();
    }
});

Push an strategy update.

Operation tags
Name Description
user-data Dealing with personal user data including but not limited to traders, strategies, and balances.

Message Strategy Update strategyUpdate

Provides updates for strategy collateral changes.

Record strategy (collateral) updates with the given trader addresses (and optionally strategy ID hash), including positions if PnL was realized. Includes strategy updates due to deposits, withdrawals, withdrawal intents, funding payments, and PnL realization, as well as withdrawal rejections.

Upon subscribing, the Strategy Update Feed will first return an empty PARTIAL. Users are expected to get the initial state of one's own strategies from our REST API. Subsequent messages will contain strategy UPDATEs to existing strategies.

Payload
Name Type Description Value Constraints
(root) object The strategy update data. - -
feed ⚠️ string Strategy update feed name. const ("STRATEGY_UPDATE") -
params ⚠️ object The parameters for the strategy update feed. - -
params.strategyIdentifiers ⚠️ array<object> Multiple strategy identifiers for filtering. - non-empty
params.strategyIdentifiers.traderAddress ⚠️ string The trader address prefixed with the blockchain discriminant. - pattern (^0x[0-9a-f]+$)
params.strategyIdentifiers.strategyIdHash string The strategy ID hash. - pattern (^0x[0-9a-f]+$)
contents ⚠️ object The contents of the message. - -
contents.messageType ⚠️ string Message type. allowed ("PARTIAL", "UPDATE") -
contents.ordinal ⚠️ integer The sequence number of a message relative to the feed subscription. - >= 0
contents.data ⚠️ array<object> The strategy update data. - -
contents.data.epochId ⚠️ integer The epoch ID. - >= 0
contents.data.withdrawRejection integer The withdraw rejection reason (if any):
Code Description Details
0 InvalidStrategy The collateral withdrawal failed because the strategy is invalid/nonexistent.
1 InvalidInsuranceFundContribution The insurance fund withdrawal failed because the insurance fund contribution is invalid/nonexistent.
2 MaxWithdrawalAmount The collateral withdrawal failed because the amount exceeds the maximum withdrawal amount. This only applies to withdrawals of collateral currencies.
3 InsufficientInsuranceFundContribution The insurance fund withdrawal failed because the withdrawal amount exceeds the contribution amount.
4 InsufficientRemainingInsuranceFund The insurance fund withdrawal failed because the remaining insurance fund after the withdrawal would be dangerously low.
allowed (0, 1, 2, 3, 4) -
contents.data.reason ⚠️ integer The type of strategy update:
Code Description Details
0 Deposit Collateral was deposited on-chain.
1 Withdraw Collateral withdrawal was claimed on-chain.
2 WithdrawIntent Collateral was locked for withdrawal.
3 FundingPayment Funding payments were distributed.
4 RealizedPnl PnL was realized.
5 ADL ADL occurred on one or more positions.
6 WithdrawRejection A withdrawal was rejected.
allowed (0, 1, 2, 3, 4, 5, 6) -
contents.data.traderAddress ⚠️ string The trader address prefixed with the blockchain discriminant. - pattern (^0x[0-9a-f]+$)
contents.data.strategyIdHash ⚠️ string The strategy ID hash. - pattern (^0x[0-9a-f]+$)
contents.data.collateralAddress ⚠️ string The collateral address on which this strategy update took place. - pattern (^0x[0-9a-f]+$)
contents.data.collateralSymbol ⚠️ string A collateral symbol, e.g. USDC. Might be subject to additions. allowed ("USDC") -
contents.data.amount string The amount added to the strategy (may be negative). If we are realizing PnL (reason is 4), then amount = sum(positions.realizedPnl) Stored as string to preserve decimal precision. - -
contents.data.newAvailCollateral string If affected, the available collateral amount after this strategy update. Stored as string to preserve decimal precision. - >= 0
contents.data.newLockedCollateral string If affected, the locked collateral amount after this strategy update. Stored as string to preserve decimal precision. - >= 0
contents.data.blockNumber integer The block number in which this strategy update was processed, if applicable. - >= 0
contents.data.positions array<object> The positions following a PnL realization. This field will be null for strategy updates not containing a PnL realization. - -
contents.data.positions.symbol ⚠️ string A product symbol, e.g. ETHP. - -
contents.data.positions.balance ⚠️ string Position balance (after PnL was realized, if applicable). Stored as string to preserve decimal precision. - >= 0
contents.data.positions.side ⚠️ integer The side of the position:
Code Description
0 Long
1 Short
allowed (0, 1) -
contents.data.positions.avgEntryPrice ⚠️ string Average entry price (after PnL was realized, if applicable). Stored as string to preserve decimal precision. - >= 0
contents.data.positions.realizedPnl ⚠️ string The realized PnL from a PnL realization in the collateral currency. Stored as string to preserve decimal precision. If null, then no PnL was realized for this symbol. - -
contents.data.createdAt ⚠️ string The timestamp when this object was created. - format (dateTime)

Examples of payload

Strategy Update - empty partial

{
    "feed": "STRATEGY_UPDATE",
    "params": {
        "strategyIdentifiers": [
            {
                "traderAddress": "0x00aabbccddeeff00112233445566778899aabbccdd",
                "strategyIdHash": "0x2576ebd1"
            },
            {
                "traderAddress": "0x00f1e2d3c4b5a6978899aabbccddeeff1122334455"
            }
        ]
    },
    "contents": {
        "messageType": "PARTIAL",
        "ordinal": 0,
        "data": []
    }
}

Strategy Update - deposit (USDC)

{
    "feed": "STRATEGY_UPDATE",
    "params": {
        "strategyIdentifiers": [
            {
                "traderAddress": "0x00aabbccddeeff00112233445566778899aabbccdd",
                "strategyIdHash": "0x2576ebd1"
            }
        ]
    },
    "contents": {
        "messageType": "UPDATE",
        "ordinal": 1,
        "data": [
            {
                "epochId": 300,
                "reason": 0,
                "traderAddress": "0x00a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9",
                "strategyIdHash": "0x2576ebd1",
                "collateralAddress": "0x00aabbccddeeff00112233445566778899aabbccdd",
                "collateralSymbol": "USDC",
                "amount": "1000",
                "newAvailCollateral": "5000",
                "blockNumber": 150000,
                "createdAt": "2023-10-01T12:05:00Z"
            }
        ]
    }
}

Strategy Update - withdrawal (USDC)

{
    "feed": "STRATEGY_UPDATE",
    "params": {
        "strategyIdentifiers": [
            {
                "traderAddress": "0x00aabbccddeeff00112233445566778899aabbccdd",
                "strategyIdHash": "0x2576ebd1"
            }
        ]
    },
    "contents": {
        "messageType": "UPDATE",
        "ordinal": 4,
        "data": [
            {
                "epochId": 304,
                "reason": 1,
                "traderAddress": "0x00e9f8d7c6b5a4e3f2d1c0b9a8f7e6d5c4b3a2f1e0",
                "strategyIdHash": "0x2576ebd1",
                "collateralAddress": "0x00abc123def4567890abcdef1234567890abcdef",
                "collateralSymbol": "USDC",
                "amount": "-150",
                "newLockedCollateral": "10",
                "blockNumber": 150200,
                "createdAt": "2023-10-01T12:10:00Z"
            }
        ]
    }
}

Strategy Update - withdrawal rejection (USDC)

{
    "feed": "STRATEGY_UPDATE",
    "params": {
        "strategyIdentifiers": [
            {
                "traderAddress": "0x00aabbccddeeff00112233445566778899aabbccdd",
                "strategyIdHash": "0x2576ebd1"
            }
        ]
    },
    "contents": {
        "messageType": "UPDATE",
        "ordinal": 2,
        "data": [
            {
                "epochId": 301,
                "reason": 5,
                "withdrawRejection": 0,
                "traderAddress": "0x00b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9ba",
                "strategyIdHash": "0x2576ebd1",
                "collateralAddress": "0x00aabbccddeeff00112233445566778899aabbccdd",
                "collateralSymbol": "USDC",
                "blockNumber": 150220,
                "createdAt": "2023-10-01T12:06:00Z"
            }
        ]
    }
}

Strategy Update - PnL realization (USDC)

{
    "feed": "STRATEGY_UPDATE",
    "params": {
        "strategyIdentifiers": [
            {
                "traderAddress": "0x00aabbccddeeff00112233445566778899aabbccdd",
                "strategyIdHash": "0x2576ebd1"
            }
        ]
    },
    "contents": {
        "messageType": "UPDATE",
        "ordinal": 5,
        "data": [
            {
                "epochId": 303,
                "reason": 4,
                "traderAddress": "0x00d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9ab1234",
                "strategyIdHash": "0x2576ebd1",
                "collateralAddress": "0x00d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9ab1235",
                "collateralSymbol": "USDC",
                "amount": "5",
                "positions": [
                    {
                        "symbol": "ETHP",
                        "balance": "50",
                        "side": 0,
                        "avgEntryPrice": "95",
                        "realizedPnl": "5"
                    }
                ],
                "createdAt": "2023-10-01T12:08:00Z"
            }
        ]
    }
}
Message tags
Name Description
user-data Dealing with personal user data including but not limited to traders, strategies, and balances.

SEND / Operation: Trader Update

Code samples

require 'faye/websocket'
require 'eventmachine'
require 'json'

EM.run do
  ws = Faye::WebSocket::Client.new('wss://exchange.derivadex.com/realtime-api')
  ws.on :message do |event|
    data = JSON.parse(event.data)
    next unless data['feed'] == 'TRADER_UPDATE'
    puts data['contents']
    ws.close
  end
end
import websocket
import json

ws = websocket.create_connection("wss://exchange.derivadex.com/realtime-api")
while True:
    result = ws.recv()
    data = json.loads(result)
    if data.get("feed") == "TRADER_UPDATE":
        print(data["contents"])
        break
ws.close()
const ws = new WebSocket('wss://exchange.derivadex.com/realtime-api');
ws.addEventListener('message', (event) => {
    const data = JSON.parse(event.data);
    if (data.feed === 'TRADER_UPDATE') {
        console.log(data.contents);
        ws.close();
    }
});

Push an trader update.

Operation tags
Name Description
user-data Dealing with personal user data including but not limited to traders, strategies, and balances.

Message Trader Update traderUpdate

Provides updates for trader DDX balances.

Record trader (DDX balance) updates with the given trader addresses. Includes trader updates due to DDX deposits, DDX withdrawals, DDX withdrawal intents, trade mining rewards, fee distribution rewards, and profile updates as well as DDX withdrawal rejections.

Upon subscribing, the Trader Update Feed will first return an empty PARTIAL. Users are expected to get the initial state of one's own trader balances from our REST API. Subsequent messages will contain trader UPDATEs to existing trader balances.

Payload
Name Type Description Value Constraints
(root) object The trader update data. - -
feed ⚠️ string Trader update feed name. const ("TRADER_UPDATE") -
params ⚠️ object The parameters for the trader update feed. - -
params.traderAddresses ⚠️ array<string> Multiple trader addresses for filtering. - non-empty
params.traderAddresses (single item) string The trader address prefixed with the blockchain discriminant. - pattern (^0x[0-9a-f]+$)
contents ⚠️ object The contents of the message. - -
contents.messageType ⚠️ string Message type. allowed ("PARTIAL", "UPDATE") -
contents.ordinal ⚠️ integer The sequence number of a message relative to the feed subscription. - >= 0
contents.data ⚠️ array<object> The trader update data. - -
contents.data.epochId ⚠️ integer The epoch ID. - >= 0
contents.data.withdrawDDXRejection integer The DDX withdraw rejection reason (if any):
Code Description Details
0 InvalidTrader The DDX withdrawal failed because the trader is invalid/nonexistent.
1 InsufficientDDXBalance The DDX withdrawal failed because the trader has insufficient DDX balance. This only applies to DDX withdrawals.
allowed (0, 1) -
contents.data.reason ⚠️ integer The type of trader update:
Code Description Details
0 DepositDDX DDX was deposited on-chain.
1 WithdrawDDX DDX withdrawal was claimed on-chain.
2 WithdrawDDXIntent DDX was locked for withdrawal.
3 TradeMiningReward DDX was rewarded for participation in trade mining.
4 ProfileUpdate DDX fee preferences were changed.
5 FeeDistribution DDX was rewarded for participation as a custodian during checkpointing.
6 WithdrawDDXRejection A DDX withdrawal was rejected.
allowed (0, 1, 2, 3, 4, 5, 6) -
contents.data.traderAddress ⚠️ string The trader address prefixed with the blockchain discriminant. - pattern (^0x[0-9a-f]+$)
contents.data.amount string The amount added to the strategy (may be negative). Stored as string to preserve decimal precision. - -
contents.data.newAvailDDXBalance string If affected, the available DDX balance after this strategy update. Stored as string to preserve decimal precision. - >= 0
contents.data.newLockedDDXBalance string If affected, the locked DDX balance after this strategy update. Stored as string to preserve decimal precision. - >= 0
contents.data.payFeesInDDX boolean Whether to pay trading fees in DDX or in the collateral currency. - -
contents.data.blockNumber integer The block number in which this strategy update was processed, if applicable. - -
contents.data.createdAt ⚠️ string The timestamp when this object was created. - format (dateTime)

Examples of payload

Trader Update - empty partial

{
    "feed": "TRADER_UPDATE",
    "params": {
        "traderAddresses": ["0x00123456789abcdef0123456789abcdef01234567"]
    },
    "contents": {
        "messageType": "PARTIAL",
        "ordinal": 0,
        "data": []
    }
}

Trader Update - DDX deposit

{
    "feed": "TRADER_UPDATE",
    "params": {
        "traderAddresses": ["0x00112233445566778899aabbccddeeff00112233"]
    },
    "contents": {
        "messageType": "UPDATE",
        "ordinal": 1,
        "data": [
            {
                "epochId": 500,
                "reason": 0,
                "traderAddress": "0x00112233445566778899aabbccddeeff00112233",
                "amount": "150",
                "newAvailDDXBalance": "1150",
                "blockNumber": 123456,
                "createdAt": "2023-10-01T12:15:00Z"
            }
        ]
    }
}

Trader Update - DDX withdraw intent

{
    "feed": "TRADER_UPDATE",
    "params": {
        "traderAddresses": ["0x00abcdefabcdefabcdefabcdefabcdefabcdefabcd"]
    },
    "contents": {
        "messageType": "UPDATE",
        "ordinal": 4,
        "data": [
            {
                "epochId": 503,
                "reason": 2,
                "traderAddress": "0x00abcdefabcdefabcdefabcdefabcdefabcdefabcd",
                "amount": "150",
                "newAvailDDXBalance": "1220",
                "newLockedDDXBalance": "35",
                "createdAt": "2023-10-01T12:16:00Z"
            }
        ]
    }
}

Trader Update - DDX withdrawal rejection

{
    "feed": "TRADER_UPDATE",
    "params": {
        "traderAddresses": ["0x00abcdefabcdefabcdefabcdefabcdefabcdefabcd"]
    },
    "contents": {
        "messageType": "UPDATE",
        "ordinal": 2,
        "data": [
            {
                "epochId": 501,
                "reason": 6,
                "withdrawDDXRejection": 1,
                "traderAddress": "0x00abcdefabcdefabcdefabcdefabcdefabcdefabcd",
                "createdAt": "2023-10-01T12:16:00Z"
            }
        ]
    }
}

Trader Update - profile update

{
    "feed": "TRADER_UPDATE",
    "params": {
        "traderAddresses": ["0x00fedcba9876543210fedcba9876543210fedcba98"]
    },
    "contents": {
        "messageType": "UPDATE",
        "ordinal": 3,
        "data": [
            {
                "epochId": 502,
                "reason": 5,
                "traderAddress": "0x00fedcba9876543210fedcba9876543210fedcba98",
                "payFeesInDDX": true,
                "createdAt": "2023-10-01T12:17:00Z"
            }
        ]
    }
}
Message tags
Name Description
user-data Dealing with personal user data including but not limited to traders, strategies, and balances.

Auditor

The Auditor is a Pythonic application that connects to the DerivaDEX Operators' WebSocket API upon initialization and allows anyone to validate the honesty and integrity of the exchange's operations.

Running the Auditor is not required to trade on the exchange, however can certainly be run in-band or out-of-band with respect to programmatic strategies to ensure you are verifiably up-to-date with the latest exchange data.

DerivaDEX's data model is powered by a Sparse Merkle Tree data store and a transaction log of state-modifying transitions. These are emitted in raw formats by the DerivaDEX Operators API, and the Auditor efficiently processes them to perform validation.

Setup

To run the Auditor from source, follow these steps from the DerivaDEX ddx repository (< 5 minutes):

  1. If you don't already have it, it is recommended you set up Anaconda/Python(>3) on your machine

  2. Initialize and activate a Conda environment (located at the root level of the repo) from which you will run the Auditor: conda env create -f environment.yml && conda activate derivadex

  3. Set your PYTHONPATH: export PYTHONPATH="${PYTHONPATH}:/your/full/path/upto/but/not/including/ddx"

  4. Navigate to the auditor subdirectory and create an .auditor.conf.json file using the template: cp .auditor.conf.json.template .auditor.conf.json

  5. Run the Auditor with: PYTHON_LOG=info python auditor_driver.py --config ".auditor.conf.json"

You will almost immediately see logging messages (should be lots of green) with state initialized and transactions streaming through successfully.

Voila! You now have the Auditor running locally validating the entire DerivaDEX exchange!

Sparse Merkle Tree

DerivaDEX utilizes a Sparse Merkle Tree (SMT) in order to efficiently maintain the state of the exchange at all times. Storing data on-chain (such as user's balances and positions), something most decentralized exchanges do, is very costly and one that is usually passed on to the user, making exchange use prohibitively expensive to most. An SMT, however, allows the system to only store a single root hash (the root of the tree) on-chain, while still allowing for anyone to verify the integrity of the data (leaves) through inclusion (or non-inclusion) proofs.

So what kind of data is stored and where in the SMT? The short answer is - everything. This means any data pertaining to a trader (their account-level data, strategy-level data, positions, and volume statistics), to a given market (the various open orders and the price feed information), and to the system (the insurance fund capitalization) is stored as individual leaf entries in the SMT. The DerivaDEX SMT consists of 2^256 possible leaves, each uniquely located at a specific leaf location (as indicated by its key, which is a 32-byte value). As you might surmise, the vast majority of the SMT will be empty (2^256 is very, very, very large number), but the data that does exist can exist at a location anywhere within these large bounds. For efficient querying and data management (while maintaining practical collision-resistance), the various types of leaf items are prefixed to reside in the same general vicinity as one another. Each leaf item type is described in detail below. The full set of leaf types can be seen in the following table, along with their corresponding numeric discriminants.

Item Discriminant
Empty 0
Trader 1
Strategy 2
Position 3
BookOrder 4
Price 5
InsuranceFund 6
Stats 7
Signer 8
Specs 9
InsuranceFundContribution 10
FeePool 11
EpochMetadata 12

Each leaf type is described in detail below.

Trader

A Trader leaf contains information pertaining to a trader's available and locked DDX balances, referral address, and fee payment mechanism.

Key encoding / decoding

Key encoding / decoding (Python)

from eth_abi.utils.padding import zpad32_right

def encode_key(trader_address: str):
    # ItemType.TRADER == 1
    return zpad32_right(
        ItemType.TRADER.to_bytes(1, byteorder="little")
        + bytes.fromhex(trader_address[2:])
    )

def decode_key(trader_key: bytes):
    # trader_address
    return f"0x{trader_key[1:22].hex()}"

The location of a Trader leaf is determined by its key, which is encoded as follows:

Bytes Value
0 Trader discriminant
[1, 21] Trader's Ethereum address prefixed with the chain discriminant
[22, 31] Zero-padding

The following sample Trader materials generates the following encoded key: 0x0100603699848c84529987e14ba32c8a66def67e9ece00000000000000000000.

field value
trader_address "0x00603699848c84529987E14Ba32C8a66DEF67E9eCE"

Value definition

Value encoding / decoding (Python)

from ddx_python.decimal import Decimal
from eth_abi import encode_single, decode_single
from web3.auto import w3

def round_to_unit(val):
    return val.quantize(6)

def to_base_unit_amount(val, decimals):
    return int(round_to_unit(val) * 10 ** decimals)

def to_unit_amount(val, decimals):
    return Decimal(str(val)) / 10 ** decimals

def abi_encoded_value(self, avail_ddx_balance: Decimal, locked_ddx_balance: Decimal, referral_address: str):
    # Trader item discriminant
    item_type = 1

    # Scale collateral amounts to grains
    return encode_single(
        "(uint8,(uint128,uint128,address,bool))",
        [
            item_type,
            [
                to_base_unit_amount(avail_ddx_balance, 6),
                to_base_unit_amount(locked_ddx_balance, 6),
                referral_address,
            ],
        ],
    )

def abi_decoded_value(abi_encoded_value: str):
    (
        item_type,
        (avail_ddx_balance, locked_ddx_balance, referral_address),
    ) = decode_single(
        "(uint8,(uint128,uint128,address,bool))", w3.toBytes(hexstr=abi_encoded_value),
    )

    # Scale collateral amounts from grains
    return (
        to_unit_amount(avail_ddx_balance, 6),
        to_unit_amount(locked_ddx_balance, 6),
        referral_address,
    )

A Trader leaf holds the following data:

type field description
decimal avail_ddx_balance DDX collateral available for staking/fees
decimal locked_ddx_balance DDX collateral available for on-chain withdrawal
address_s referral_address Referral address pertaining to the Ethereum address who referred this trader (if applicable)
bool pay_fees_in_ddx Whether trader has opted to pay fees in DDX by default or not

These contents are always stored in the tree in ABI-encoded form: (uint8,(uint128,uint128,address,bool)). Meaning, you will want to decode the contents into a more suitable form for your purposes as necessary (for example loading data from a snapshot of the state), and will need to encode it back again if you are saving it back into the tree. A sample of Python code that derives this ABI-encoding, including the grains conversion for certain variables, is shown on the right.

The following sample Trader materials generates the following ABI-encoded value: 0x0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000003b9aca000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a8dda8d7f5310e4a9e24f8eba77e091ac264f8720000000000000000000000000000000000000000000000000000000000000000.

field value
avail_ddx_balance 1000
locked_ddx_balance 0
referral_address "0xA8dDa8d7F5310E4A9E24F8eBA77E091Ac264f872"
pay_fees_in_ddx True

Strategy

A Strategy leaf contains information pertaining to a trader's cross-margined strategy, such as their available and locked collaterals and max leverage.

Key encoding / decoding

Key encoding / decoding (Python)

from eth_abi.utils.padding import zpad32_right, encode_single, decode_single
from web3.auto import w3

def generate_strategy_id_hash(strategy_id: str) -> bytes:
    # Get the first 4 bytes of the hash of the strategy id
    return w3.keccak(
        len(strategy_id).to_bytes(1, byteorder="little")
        + encode_single("bytes32", strategy_id.encode("utf8"))[:-1]
    )[:4]

def encode_key(trader_address: str, strategy_id: str, chain_discriminant: int):
    # ItemType.STRATEGY == 2
    return zpad32_right(
            ItemType.STRATEGY.to_bytes(1, byteorder="little")
            + bytes.fromhex(trader_address[2:])
            + generate_strategy_id_hash(strategy_id)
        )

def decode_key(strategy_key: bytes):
    # trader_address, strategy_id_hash
    return (
            f"0x{strategy_key[1:22].hex()}",
            f"0x{strategy_key[22:26].hex()}",
        )

The location of a Strategy leaf is determined by its key, which is encoded as follows:

Bytes Value
0 Strategy discriminant
[1, 21] Trader's Ethereum address prefixed with the chain discriminant
[22, 25] Abbreviated hash of strategy ID
[26, 25] Zero-padding

The following sample Strategy materials generates the following encoded key: 0x0200603699848c84529987e14ba32c8a66def67e9ece2576ebd1000000000000.

field value
trader_address "0x00603699848c84529987E14Ba32C8a66DEF67E9eCE"
strategy_id "main"

Value definition

Value encoding / decoding (Python)

from typing import Dict
from ddx_python.decimal import Decimal
from eth_abi import encode_single, decode_single
from web3.auto import w3

def round_to_unit(val):
    return val.quantize(6)

def to_base_unit_amount(val, decimals):
    return int(round_to_unit(val) * 10 ** decimals)

def to_base_unit_amount_list(vals, decimals):
    return [to_base_unit_amount(val, decimals) for val in vals]

def to_unit_amount(val: int, decimals: int) -> Decimal:
    return Decimal(str(val)) / 10 ** decimals

def to_unit_amount_list(vals: List[int], decimals: int):
    return [to_unit_amount(val, decimals) for val in vals]

def to_adjusted_encoding_for_negative_val(val: int):
    return 16 ** 32 + abs(val) if val < 0 else val

def to_adjusted_encoding_for_negative_val_list(vals: List[int]):
    return [to_adjusted_encoding_for_negative_val(val) for val in vals]

def from_adjusted_encoding_for_negative_val(val: int):
    return val if val < 16 ** 32 else -(val - 16 ** 32)

def abi_encoded_value(self, strategy_id: str, avail_collateral: Dict[str, Decimal], locked_collateral: Dict[str, Decimal], max_leverage: int, frozen: bool):
    # Strategy item discriminant
    item_type = 2

    # Scale collateral amounts to grains
    return encode_single(
        "((uint8,(bytes32,(address[],uint256[]),(address[],uint128[]),uint64,bool)))",
        [
            [
                item_type,
                [
                    len(strategy_id).to_bytes(1, byteorder="little")
                    + encode_single("bytes32", strategy_id.encode("utf8"))[
                        :-1
                    ],
                    [
                        list(avail_collateral.keys()),
                        to_adjusted_encoding_for_negative_val_list(
                            to_base_unit_amount_list(
                                list(avail_collateral.values()), 6
                            )
                        ),
                    ],
                    [
                        list(locked_collateral.keys()),
                        to_base_unit_amount_list(
                            list(locked_collateral.values()), 6
                        ),
                    ],
                    max_leverage,
                    frozen,
                ],
            ]
        ],
    )

def abi_decoded_value(abi_encoded_value: str):
    (
        (
            item_type,
            (
                strategy_id,
                (avail_collateral_tokens, avail_collateral_amounts),
                (locked_collateral_tokens, locked_collateral_amounts),
                max_leverage,
                frozen,
            ),
        ),
    ) = decode_single(
        "((uint8,(bytes32,(address[],uint256[]),(address[],uint128[]),uint64,bool)))",
        w3.toBytes(hexstr=abi_encoded_value),
    )

    # Scale collateral amounts from grains
    return (
        strategy_id[1 : 1 + strategy_id[0]].decode("utf8"),
        {
            k: to_unit_amount(from_adjusted_encoding_for_negative_val(v), 6)
            for k, v in zip(
                list(avail_collateral_tokens), list(avail_collateral_amounts)
            )
        },
        {
            k: to_unit_amount(v, 6)
            for k, v in zip(
                list(locked_collateral_tokens), list(locked_collateral_amounts)
            )
        },
        max_leverage,
        frozen,
    )

A Strategy leaf holds the following data:

type field description
string strategy_id Identifier for strategy (e.g. "main")
dict<address_s, decimal> avail_collateral Mapping of collateral address to available collateral amount
dict<address_s, decimal> locked_collateral Mapping of collateral address to locked collateral amount
int max_leverage Maximum leverage strategy can take
bool frozen Whether the strategy is frozen or not (relevant for tokenization)

These contents are always stored in the tree in ABI-encoded form: ((uint8,(bytes32,(address[],uint128[]),(address[],uint128[]),uint64,bool))). Meaning, you will want to decode the contents into a more suitable form for your purposes as necessary (for example loading data from a snapshot of the state), and will need to encode it back again if you are saving it back into the tree. A sample of Python code that derives this ABI-encoding, including the grains conversion for certain variables, is shown on the right.

The following sample Strategy materials generates the following ABI-encoded value: 0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040046d61696e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000016000000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000001000000000000000000000000b69e673309512a9d726f87304c6984054f87a93b00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000002e8f3487400000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.

field value
strategy_id "main"
avail_collateral {"0xb69e673309512a9d726f87304c6984054f87a93b": 199971.08}
locked_collateral {}
max_leverage 3
frozen False

Position

A Position leaf contains information pertaining to an open position.

Key encoding / decoding

Key encoding / decoding (Python)

from eth_abi.utils.padding import zpad32_right, encode_single, decode_single
from web3.auto import w3

def generate_strategy_id_hash(strategy_id: str) -> bytes:
    # Get the first 4 bytes of the hash of the strategy id
    return w3.keccak(
        len(strategy_id).to_bytes(1, byteorder="little")
        + encode_single("bytes32", strategy_id.encode("utf8"))[:-1]
    )[:4]

def pack_bytes(text: str):
    charset = "0ABCDEFGHIJKLMNOPQRSTUVWXYZ"
    symbol_bits = ""
    for letter in text:
        for i, char in enumerate(charset):
            if char == letter:
                bits = format(i, "08b")[::-1]
                symbol_bits += bits[:5]

    symbol_bytes = int(symbol_bits[::-1], 2).to_bytes(
        (len(symbol_bits) + 7) // 8, byteorder="little"
    )
    return zpad_right(symbol_bytes, 6)

def unpack_bytes(packed_text: bytes):
    charset = "0ABCDEFGHIJKLMNOPQRSTUVWXYZ"
    symbol_bits = format(int.from_bytes(packed_text, "little"), "030b")[::-1]
    symbol_char_bit_chunks = [
        symbol_bits[i : i + 5] for i in range(0, len(symbol_bits), 5)
    ]
    symbol = ""
    for symbol_char_bit_chunk in symbol_char_bit_chunks:
        reversed_bit_chunk = symbol_char_bit_chunk[::-1]
        char_index = int(reversed_bit_chunk, 2)
        symbol += charset[char_index]
    return symbol

def encode_key(trader_address: str, strategy_id: str, symbol: str, chain_discriminant: int):
    # ItemType.POSITION == 3
    return (
            ItemType.POSITION.to_bytes(1, byteorder="little")
            + pack_bytes(symbol)
            + bytes.fromhex(trader_address[2:])
            + generate_strategy_id_hash(strategy_id)
        )

def decode_key(position_key: bytes):
    # symbol, trader_address, strategy_id_hash
    return (
            unpack_bytes(position_key[1:7]),
            f"0x{position_key[7:28].hex()}",
            f"0x{position_key[28:].hex()}",
        )

The location of a Position leaf is determined by its key, which is encoded as follows:

Bytes Value
0 Position discriminant
[1, 6] Symbol (5-bit encoded/packed)
[7, 27] Trader's Ethereum address prefixed with the chain discriminant
[28, 31] Abbreviated hash of strategy ID

The following sample Position materials generates the following encoded key: 0x0385225824040000603699848c84529987e14ba32c8a66def67e9ece2576ebd1.

field value
trader_address "0x603699848c84529987E14Ba32C8a66DEF67E9eCE"
strategy_id "main"
symbol "ETHP"

Value definition

Value encoding / decoding (Python)

from typing import Dict
from ddx_python.decimal import Decimal
from eth_abi import encode_single, decode_single
from web3.auto import w3

def round_to_unit(val):
    return val.quantize(6)

def to_base_unit_amount(val, decimals):
    return int(round_to_unit(val) * 10 ** decimals)

def to_unit_amount(val, decimals):
    return Decimal(str(val)) / 10 ** decimals

def abi_encoded_value(side: int, balance: Decimal, avg_entry_price: Decimal):
    # Position item discriminant
    item_type = 3

    # Scale balance and average entry price grains
    return encode_single(
        "(uint8,(uint8,uint128,uint128))",
        [
            item_type,
            [
                side,
                to_base_unit_amount(balance, 6),
                to_base_unit_amount(avg_entry_price, 6),
            ],
        ],
    )

def abi_decoded_value(abi_encoded_value: str):
    (item_type, (side, balance, avg_entry_price)) = decode_single(
        "(uint8,(uint8,uint128,uint128))", w3.toBytes(hexstr=abi_encoded_value),
    )

    # Scale balance and average entry price from DDX grains
    return (
        side, to_unit_amount(balance, 6), to_unit_amount(avg_entry_price, 6)
    )

A Position leaf holds the following data:

type field description
int side Side of position (Long=1, Short=2)
decimal balance Size of the position
decimal average_entry_price Average entry price of the position

These contents are always stored in the tree in ABI-encoded form: (uint8,(uint8,uint128,uint128)). Meaning, you will want to decode the contents into a more suitable form for your purposes as necessary (for example loading data from a snapshot of the state), and will need to encode it back again if you are saving it back into the tree. A sample of Python code that derives this ABI-encoding, including the grains conversion for certain variables, is shown on the right.

The following sample Position materials generates the following ABI-encoded value: 0x000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000068155a43676e0000000000000000000000000000000000000000000000000000d4eff354906660000.

field value
side 1
balance 120
avg_entry_price 245.5

Book Order

A BookOrder leaf contains information pertaining to a maker order in the order book.

Key encoding / decoding

Key encoding / decoding (Python)

from eth_abi.utils.padding import zpad32_right, encode_single, decode_single
from web3.auto import w3

def generate_strategy_id_hash(strategy_id: str) -> bytes:
    # Get the first 4 bytes of the hash of the strategy id
    return w3.keccak(
        len(strategy_id).to_bytes(1, byteorder="little")
        + encode_single("bytes32", strategy_id.encode("utf8"))[:-1]
    )[:4]

def pack_bytes(text: str):
    charset = "0ABCDEFGHIJKLMNOPQRSTUVWXYZ"
    symbol_bits = ""
    for letter in text:
        for i, char in enumerate(charset):
            if char == letter:
                bits = format(i, "08b")[::-1]
                symbol_bits += bits[:5]

    symbol_bytes = int(symbol_bits[::-1], 2).to_bytes(
        (len(symbol_bits) + 7) // 8, byteorder="little"
    )
    return zpad_right(symbol_bytes, 6)

def unpack_bytes(packed_text: bytes):
    charset = "0ABCDEFGHIJKLMNOPQRSTUVWXYZ"
    symbol_bits = format(int.from_bytes(packed_text, "little"), "030b")[::-1]
    symbol_char_bit_chunks = [
        symbol_bits[i : i + 5] for i in range(0, len(symbol_bits), 5)
    ]
    symbol = ""
    for symbol_char_bit_chunk in symbol_char_bit_chunks:
        reversed_bit_chunk = symbol_char_bit_chunk[::-1]
        char_index = int(reversed_bit_chunk, 2)
        symbol += charset[char_index]
    return symbol

def encode_key(symbol: str, order_hash: str):
    # ItemType.BOOK_ORDER == 3
    return (
            ItemType.BOOK_ORDER.to_bytes(1, byteorder="little")
            + pack_bytes(symbol)
            + bytes.fromhex(order_hash[2:52])
        )

def decode_key(book_order_key: bytes):
    # symbol, first 25 bytes of order_hash
    return (
            unpack_bytes(book_order_key[1:7]),
            f"0x{book_order_key[7:].hex()}",
        )

The location of a BookOrder leaf is determined by its key, which is encoded as follows:

Bytes Value
0 Book order discriminant
[1, 6] Symbol (5-bit encoded/packed)
[7, 31] First 25 bytes of order's unique hash

The following sample BookOrder materials generates the following encoded key: 0x048522582404009fcf480aa9606f5bbb64ab36e642566bd893f715b346df244e.

field value
symbol "ETHP"
order_hash "0x9fcf480aa9606f5bbb64ab36e642566bd893f715b346df244eABABABABABABAB"

Value definition

Value encoding / decoding (Python)

from typing import Dict
from ddx_python.decimal import Decimal
from eth_abi import encode_single, decode_single
from web3.auto import w3

def round_to_unit(val):
    return val.quantize(6)

def to_base_unit_amount(val, decimals):
    return int(round_to_unit(val) * 10 ** decimals)

def to_unit_amount(val, decimals):
    return Decimal(str(val)) / 10 ** decimals

def abi_encoded_value(self, side: int, amount: Decimal, price: Decimal, trader_address: str, strategy_id_hash: str, book_ordinal: int, time_value: int):
    # BookOrder item discriminant
    item_type = 4

    # Scale amount and price to grains
    return encode_single(
        "(uint8,(uint8,uint128,uint128,bytes21,bytes32,uint64,uint64))",
        [
            item_type,
            [
                side,
                to_base_unit_amount(amount, 6),
                to_base_unit_amount(price, 6),
                bytes.fromhex(trader_address[2:]),
                bytes.fromhex(strategy_id_hash[2:]),
                book_ordinal,
                time_value,
            ],
        ],
    )

def abi_decoded_value(abi_encoded_value: str):
    (
        item_type,
        (side, amount, price, trader_address, strategy_id_hash, book_ordinal, time_value),
    ) = decode_single(
        "(uint8,(uint8,uint128,uint128,bytes21,bytes32,uint64,uint64))",
        w3.toBytes(hexstr=abi_encoded_value),
    )

    # Scale amount and price from grains
    return (
        side,
        to_unit_amount(amount, 6),
        to_unit_amount(price, 6),
        f"0x{trader_address.hex()}",
        f"0x{strategy_id_hash[:4].hex()}",
        book_ordinal,
        time_value,
    )

A BookOrder leaf holds the following data:

type field description
str side Side of order (Bid, Ask)
decimal amount Amount/size of order
decimal price Price the order has been placed at
str trader_address The order creator's Ethereum address prefixed with the chain discriminant
str strategy_id_hash First 4 bytes of strategy ID hash this order belongs to
int book_ordinal Numerical sequencing identifier for a BookOrder, which can be used to sort orders at any given price level
int time_value Time value of order placement since genesis (s)

These contents are always stored in the tree in ABI-encoded form: (uint8,(uint8,uint128,uint128,address,bytes32,uint64)). Meaning, you will want to decode the contents into a more suitable form for your purposes as necessary (for example loading data from a snapshot of the state), and will need to encode it back again if you are saving it back into the tree. A sample of Python code that derives this ABI-encoding, including the grains conversion for certain variables, is shown on the right.

The following sample BookOrder materials generates the following ABI-encoded value: 00000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001158e460913d0000000000000000000000000000000000000000000000000000d8d726b7177a80000603699848c84529987e14ba32c8a66def67e9ece0000000000000000000000002576ebd100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000003e8

field value
side "Bid"
amount 20
price 250
trader_address "0x603699848c84529987E14Ba32C8a66DEF67E9eCE"
strategy_id_hash "0x2576ebd1"
book_ordinal 3
book_ordinal 1000

Price

A Price contains information pertaining to a market's price checkpoint.

Key encoding / decoding

Key encoding / decoding (Python)

from eth_abi.utils.padding import zpad32_right, encode_single, decode_single
from web3.auto import w3

def pack_bytes(text: str):
    charset = "0ABCDEFGHIJKLMNOPQRSTUVWXYZ"
    symbol_bits = ""
    for letter in text:
        for i, char in enumerate(charset):
            if char == letter:
                bits = format(i, "08b")[::-1]
                symbol_bits += bits[:5]

    symbol_bytes = int(symbol_bits[::-1], 2).to_bytes(
        (len(symbol_bits) + 7) // 8, byteorder="little"
    )
    return zpad_right(symbol_bytes, 6)

def unpack_bytes(packed_text: bytes):
    charset = "0ABCDEFGHIJKLMNOPQRSTUVWXYZ"
    symbol_bits = format(int.from_bytes(packed_text, "little"), "030b")[::-1]
    symbol_char_bit_chunks = [
        symbol_bits[i : i + 5] for i in range(0, len(symbol_bits), 5)
    ]
    symbol = ""
    for symbol_char_bit_chunk in symbol_char_bit_chunks:
        reversed_bit_chunk = symbol_char_bit_chunk[::-1]
        char_index = int(reversed_bit_chunk, 2)
        symbol += charset[char_index]
    return symbol

def encode_key(symbol: str, index_price_hash: str):
    # ItemType.PRICE == 5
    return zpad32_right(
            ItemType.PRICE.to_bytes(1, byteorder="little")
            + pack_bytes(symbol)
            + bytes.fromhex(index_price_hash[2:])
        )

def decode_key(price_key: bytes):
    # symbol, index price hash
    return (
            unpack_bytes(price_key[1:7]),
            f"0x{leaf_key[7:].hex()}",
        )

The location of a Price leaf is determined by its key, which is encoded as follows:

Bytes Value
0 Price discriminant
[1, 6] Symbol (5-bit encoded/packed)
[7, 31] 25 bytes of index price's unique hash

The following sample Price materials generates the following encoded key: 0x0585225824040023c2b28e94b9dfcb8630a369fed134cdb6689dcb2528578779.

field value
symbol "ETHP"
index_price_hash "0x23c2b28e94b9dfcb8630a369fed134cdb6689dcb2528578779ABABABABABABAB"

Value definition

Value encoding / decoding (Python)

from typing import Dict
from ddx_python.decimal import Decimal
from eth_abi import encode_single, decode_single
from web3.auto import w3

def round_to_unit(val):
    return val.quantize(6)

def to_base_unit_amount(val, decimals):
    return int(round_to_unit(val) * 10 ** decimals)

def to_unit_amount(val, decimals):
    return Decimal(str(val)) / 10 ** decimals

def abi_encoded_value(self, index_price: Decimal, ema: Decimal, ordinal: int):
    # Price item discriminant
    item_type = 5

    # Scale index price and ema to grains
    price_encoding = encode_single(
        "(uint8,(uint128,uint256,uint64))",
        [
            item_type,
            [
                to_base_unit_amount(index_price, 6),
                to_base_unit_amount(abs(ema), 6),
                ordinal,
            ],
        ],
    )
    if self.ema < 0:
        price_encoding_byte_array = bytearray(price_encoding)
        price_encoding_byte_array[-49] = 1
        price_encoding = bytes(price_encoding_byte_array)

    return price_encoding

def abi_decoded_value(abi_encoded_value: str):
    price_encoding_byte_array = bytearray(bytes.fromhex(abi_encoded_value[2:]))
    multiplier = -1 if price_encoding_byte_array[-49] == 1 else 1
    price_encoding_byte_array[-49] = 0
    abi_encoded_value = bytes(price_encoding_byte_array).hex()

    (item_type, (index_price, ema, ordinal)) = decode_single(
        "(uint8,(uint128,uint256,uint64))", w3.toBytes(hexstr=abi_encoded_value),
    )

    # Scale index price and ema from grains
    return (
        to_unit_amount(index_price, 6),
        to_unit_amount(ema * multiplier, 6),
        ordinal,
    )

A Price leaf holds the following data:

type field description
decimal index_price Composite index price Petual is tracking
decimal ema EMA component of price, tracking the difference between the DerivaDEX order book price and the underlying
int ordinal Numerical sequencing identifier for PriceCheckpoint that created this Price state leaf, can be used to arrange Price leaves in order of entry

These contents are always stored in the tree in ABI-encoded form: (uint8,(uint128,uint256,uint64)). Meaning, you will want to decode the contents into a more suitable form for your purposes as necessary (for example loading data from a snapshot of the state), and will need to encode it back again if you are saving it back into the tree. A sample of Python code that derives this ABI-encoding, including the grains conversion for certain variables, is shown on the right. It's demonstrated in the code sample, but it's worth highlighting that the ema component, which can be a negative value, is ABI-encoded to a 32-byte value where the first 16 bytes will either be 0x00000000000000000000000000000000 (positive) or 0x00000000000000000000000000000001 (negative), and the next 16 bytes is the absolute value of the ema.

The following sample Price materials generates the following ABI-encoded value: 0x00000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000ff439f867f838f4000000000000000000000000000000000000000000000000004d94aaad5556854d300000000000000000000000000000000000000000000000000000000000020e2.

field value
index_price 4708.7925
ema 89.444491182582813907
ordinal 8418

Insurance Fund

An InsuranceFund leaf contains information pertaining to the insurance fund' capitalization.

Key encoding / decoding

Key encoding / decoding (Python)

from eth_abi.utils.padding import zpad32_right

def encode_key():
    # ItemType.INSURANCE_FUND == 6
    return zpad32_right(
        ItemType.INSURANCE_FUND.to_bytes(1, byteorder="little")
        + "OrganicInsuranceFund".encode("utf8")
    )

The location of an InsuranceFund leaf is determined by its key, which is encoded as follows:

Bytes Value
0 Insurance fund discriminant
[1, 20] "OrganicInsuranceFund" bytes-encoded
[21, 31] Zero-padding

The InsuranceFund leaf is located at the encoded key: 0x064f7267616e6963496e737572616e636546756e640000000000000000000000.

Value definition

Value encoding / decoding (Python)

from typing import Dict
from ddx_python.decimal import Decimal
from eth_abi import encode_single, decode_single
from web3.auto import w3

def round_to_unit(val):
    return val.quantize(6)

def to_base_unit_amount(val, decimals):
    return int(round_to_unit(val) * 10 ** decimals)

def to_unit_amount(val, decimals):
    return Decimal(str(val)) / 10 ** decimals

def abi_encoded_value(self, capitalization: Dict[str, Decimal]):
    # InsuranceFund item discriminant
    item_type = 6

    # Scale collateral amounts to grains
    return encode_single(
        "((uint8,(address[],uint128[])))",
        [
            [
                self.item_type,
                [
                    list(capitalization.keys()),
                    to_base_unit_amount_list(
                        list(capitalization.values()), 6
                    ),
                ],
            ]
        ],
    )

def abi_decoded_value(abi_encoded_value: str):
    (
        (item_type, (capitalization_tokens, capitalization_amounts,),),
    ) = decode_single(
        "((uint8,(address[],uint128[])))", w3.toBytes(hexstr=abi_encoded_value),
    )

    # Scale collateral amounts from grains
    return cls(
        {
            k: to_unit_amount(v, 6)
            for k, v in zip(
                list(capitalization_tokens), list(capitalization_amounts)
            )
        },
    )

An InsuranceFund leaf holds the following data:

type field description
dict<address_s, decimal> capitalization Mapping of collateral address to organic insurance fund capitalization

These contents are always stored in the tree in ABI-encoded form: ((uint8,(address[],uint128[]))). Meaning, you will want to decode the contents into a more suitable form for your purposes as necessary (for example loading data from a snapshot of the state), and will need to encode it back again if you are saving it back into the tree. A sample of Python code that derives this ABI-encoding, including the grains conversion for certain variables, is shown on the right.

The following sample InsuranceFund materials generates the following ABI-encoded value: 0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000001000000000000000000000000cfc18cec799fbd1793b5c43e773c98d4d61cc2db000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000532d4737cf8c716f0000.

field value
capitalization {"0xcfc18cec799fbd1793b5c43e773c98d4d61cc2db": 392791.65336}

Stats

A Stats leaf contains data such as volume info for trade mining for any given trader.

Key encoding / decoding

Key encoding / decoding (Python)

from eth_abi.utils.padding import zpad32_right

def encode_key(trader_address: str):
    # ItemType.STATS == 7
    return zpad32_right(
            ItemType.STATS.to_bytes(1, byteorder="little")
            + bytes.fromhex(trader_address[2:])
        )

def decode_key(stats_key: bytes):
    # chain_discriminant, trader_address
    return f"0x{stats_key[1:22].hex()}"

The location of a Stats leaf is determined by its key, which is encoded as follows:

Bytes Value
0 Stats discriminant
[1, 21] Trader' Ethereum address prefixed with the chain discriminant
[22, 31] Zero-padding

The following sample Stats materials generates the following encoded key: 0x0700603699848c84529987e14ba32c8a66def67e9ece00000000000000000000.

field value
trader_address "0x00603699848c84529987E14Ba32C8a66DEF67E9eCE"

Value definition

Value encoding / decoding (Python)

from typing import Dict
from ddx_python.decimal import Decimal
from eth_abi import encode_single, decode_single
from web3.auto import w3

def round_to_unit(val):
    return val.quantize(6)

def to_base_unit_amount(val, decimals):
    return int(round_to_unit(val) * 10 ** decimals)

def to_unit_amount(val, decimals):
    return Decimal(str(val)) / 10 ** decimals

def abi_encoded_value(self, maker_volume: Decimal, taker_volume: Decimal):
    # Stats item discriminant
    item_type = 6

    # Scale volume amounts to grains
    return encode_single(
        "(uint8,(uint128,uint128))",
        [
            item_type,
            [
                to_base_unit_amount(maker_volume, 6),
                to_base_unit_amount(taker_volume, 6),
            ],
        ],
    )

def abi_decoded_value(abi_encoded_value: str):
    (item_type, (maker_volume, taker_volume)) = decode_single(
        "(uint8,(uint128,uint128))", w3.toBytes(hexstr=abi_encoded_value),
    )

    # Scale volumes from DDX grains
    return (to_unit_amount(maker_volume, 6), to_unit_amount(taker_volume, 6))

A Stats leaf holds the following data:

type field description
decimal maker_volume Maker volume of trader during this trade mining epoch
decimal taker_volume Taker volume of trader during this trade mining epoch

These contents are always stored in the tree in ABI-encoded form: (uint8,(uint128,uint128)). Meaning, you will want to decode the contents into a more suitable form for your purposes as necessary (for example loading data from a snapshot of the state), and will need to encode it back again if you are saving it back into the tree. A sample of Python code that derives this ABI-encoding, including the grains conversion for certain variables, is shown on the right.

The following sample Stats materials generates the following ABI-encoded value: 0x000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000032d26d12e980b60000000000000000000000000000000000000000000000000030fe0cfcba2f4700000.

field value
maker_volume 15000
taker_volume 14460

Transactions

Transactions refer to the state-changing events that modify the SMT and its leaves (thus the root hash) described above.

There are several types of transactions on DerivaDEX. The full set of transactions along with their corresponding numeric discrimants can be seen in the table below:

Event Discriminant
PartialFill 0
CompleteFill 1
PostOrder 2
Cancel 3
CancelAll 30
Liquidation 4
StrategyUpdate 5
TraderUpdate 6
Withdraw 7
WithdrawDDX 8
PriceCheckpoint 9
PnlRealization 10
Funding 11
TradeMining 12
SpecsUpdate 13
InsuranceFundUpdate 14
InsuranceFundWithdraw 15
DisasterRecovery 16
SignerRegistered 60
EpochMarker 100
NoTransition 999

Each of these transaction types as received from the Operator WebSocket API are described at length below.

Partial fill

Sample PartialFill (JSON)

{
    "event": [
        {
            "side": "Ask",
            "price": "53008",
            "amount": "7.8",
            "symbol": "BTCP",
            "orderHash": "0xcd69dd0341444be5bc46c0a7e9b305bc4a3a322fae3eedd70e",
            "strategyId": "main",
            "bookOrdinal": 41,
            "traderAddress": "0x00aa6676733e2e259d879127519d973ac71135f797"
        },
        {},
        [
            {
                "Fill": {
                    "price": "53163",
                    "amount": "0.1",
                    "reason": "Trade",
                    "symbol": "BTCP",
                    "takerSide": "Ask",
                    "makerOutcome": {
                        "fee": "0",
                        "trader": "0x000e646446bfd163dc1cb3010754a7e1a5dd73a6de",
                        "strategy": "main",
                        "ddxFeeElection": false
                    },
                    "takerOutcome": {
                        "fee": "10.6326",
                        "trader": "0x00aa6676733e2e259d879127519d973ac71135f797",
                        "strategy": "main",
                        "ddxFeeElection": false
                    },
                    "makerOrderHash": "0xc7aa4937f79ee9fbc3f8c5f00f46157ac0c0ab6a485227e920",
                    "takerOrderHash": "0xcd69dd0341444be5bc46c0a7e9b305bc4a3a322fae3eedd70e",
                    "makerOrderRemainingAmount": "0"
                }
            }
        ]
    ]
}

A PartialFill transaction is a scenario where the taker order has been partially filled across 1 or more maker orders and thus has a remaining order that enters the order book. The event portion of the transaction response consists of a 3-item array. The first item is the remaining Post event, the second item is a dictionary of any relevant price updates, and the third item is a list of trade outcomes, which can either be TradeFill or Cancel events pertaining to maker orders that may have been canceled.

Complete fill

Sample CompleteFill (JSON)

{
    "event": [
        {},
        [
            {
                "Fill": {
                    "price": "53163",
                    "amount": "0.1",
                    "reason": "Trade",
                    "symbol": "BTCP",
                    "takerSide": "Ask",
                    "makerOutcome": {
                        "fee": "0",
                        "trader": "0x000e646446bfd163dc1cb3010754a7e1a5dd73a6de",
                        "strategy": "main",
                        "ddxFeeElection": false
                    },
                    "takerOutcome": {
                        "fee": "10.6326",
                        "trader": "0x00aa6676733e2e259d879127519d973ac71135f797",
                        "strategy": "main",
                        "ddxFeeElection": false
                    },
                    "makerOrderHash": "0xc7aa4937f79ee9fbc3f8c5f00f46157ac0c0ab6a485227e920",
                    "takerOrderHash": "0xcd69dd0341444be5bc46c0a7e9b305bc4a3a322fae3eedd70e",
                    "makerOrderRemainingAmount": "0"
                }
            }
        ]
    ]
}

A CompleteFill is a scenario where the taker order has been completely filled across 1 or more maker orders. The event portion of the transaction response consists of a consists of a trade outcomes, which can either be TradeFill or Cancel events pertaining to maker orders that may have been canceled.

Post order

Sample PostOrder (JSON)

{
    "event": [
        {
            "side": "Bid",
            "price": "1870.25",
            "amount": "1.39",
            "symbol": "ETHP",
            "orderHash": "0x860b1065b629df495de7a0d97432a48b098cadcbb37a1fdbd9",
            "strategyId": "main",
            "bookOrdinal": 0,
            "traderAddress": "0x00e36ea790bc9d7ab70c55260c66d52b1eca985f84",
            "timeValue": 1024
        },
        {},
        []
    ]
}

A PostOrder is a 3-item array where the first item is a Post order that enters the order book, the second item is price checkpoints that may have taken place, and the third item is a list of Cancel events pertaining to maker orders that may have been canceled.

Cancel

Sample Cancel (JSON)

{
    "event": {
        "amount": "1.39",
        "symbol": "ETHP",
        "orderHash": "0x860b1065b629df495de7a0d97432a48b098cadcbb37a1fdbd9"
    }
}

A Cancel is when an existing order is canceled and removed from the order book. The event portion of the transaction has attributes defined as follows:

type field description
dict event The contents of the transaction event
decimal_s event.amount Size of order canceled from the order book
string event.symbol Symbol for the market this order has been canceled (e.g. ETHP)
bytes32_s event.orderHash Hexstr representation of the first 25 bytes of the unique EIP-712 hash of the order being canceled

Liquidation

Sample Liquidation (JSON)

{
    "event": [
        {
            "positions": [
                [
                    "ETHP",
                    {
                        "price": {
                            "ema": "-212.602242612626064356",
                            "ordinal": 157,
                            "indexPrice": "2718.2459",
                            "indexPriceHash": "0x16f0d2a4abfd17f788c900a392cf4297439bae04d0f5a13cd1"
                        },
                        "amount": "6.1",
                        "adlOutcomes": [],
                        "tradeOutcomes": [
                            {
                                "Fill": {
                                    "price": "2322",
                                    "amount": "6.1",
                                    "reason": "Liquidation",
                                    "symbol": "ETHP",
                                    "takerSide": "Ask",
                                    "makerOutcome": {
                                        "fee": "0",
                                        "trader": "0x00e834ec434daba538cd1b9fe1582052b880bd7e63",
                                        "strategy": "main",
                                        "realizedPnl": "595.832921348314606732",
                                        "positionSide": "Short",
                                        "newCollateral": "942709.042921348314605958",
                                        "ddxFeeElection": false,
                                        "newPositionBalance": "2.8",
                                        "newPositionAvgEntryPrice": "2419.677528089887640448"
                                    },
                                    "indexPriceHash": "0x16f0d2a4abfd17f788c900a392cf4297439bae04d0f5a13cd1",
                                    "makerOrderHash": "0x63d8e48a6536760deaf29e5f2f2e0039356fc77a437ccc47f7",
                                    "makerOrderRemainingAmount": "4.7"
                                }
                            }
                        ],
                        "newInsuranceFundCap": "734.512240000000000005"
                    }
                ]
            ],
            "strategyId": "main",
            "traderAddress": "0x00d9a605a32d920d90d8119ffd5fe1fd247c500479",
            "canceledOrders": []
        }
    ]
}

A Liquidation is when a set of strategies are under-collateralized and closed out forcibly closed out:

type field description
list event The contents of the transaction event
dict event[n] Liquidation entry
address_s event[n].traderAddress Liquidated trader'prefixed Ethereum address
string event[n].strategyId Liquidated trader's strategy id
dict event[n].strategyId Liquidated trader's strategy id
list event[n].canceledOrders Cancel events pertaining to canceled orders for the liquidated trader
list event[n].positions List of tuples pertaining to liquidated positions
string event[n].positions[n][0] Liquidated position symbol
dict event[n].positions[n][1] Liquidated position details
dict event[n].positions[n][1].price Latest PriceCheckpoint corresponding to this position being liquidated
decimal_s event[n].positions[n][1].amount Amount of position being liquidated
list event[n].positions[n][1].adlOutcomes ADL outcomes as a result of liquidation
list event[n].positions[n][1].tradeOutcomes Trade outcomes as a result of liquidation
decimal_s event[n].positions[n][1].newInsuranceFundCap New insurance fund capitalization after position has been liquidated

Strategy update

Sample StrategyUpdate (JSON)

{
    "event": {
        "amount": "1000000",
        "trader": "0x00e36ea790bc9d7ab70c55260c66d52b1eca985f84",
        "txHash": "0x239a452c6abc453e153c8c53e4bdb995c558619b3aa1980c8977cbc4c283618f",
        "strategyId": "main",
        "updateType": "Deposit",
        "collateralAddress": "0xb69e673309512a9d726f87304c6984054f87a93b"
    }
}

A StrategyUpdate is an update to a trader's strategy (such as depositing or withdrawing collateral). The event portion of the transaction has attributes defined as follows:

type field description
dict event The contents of the transaction event
decimal_s event.amount Amount deposited or withdrawn
address_pre_s event.trader Trader's Ethereum address prefixed with the chain discriminant
bytes32_s event.txHash Ethereum transaction hash for the on-chain deposit / withdrawal
string event.strategyId Strategy ID deposited to or withdrawn from (e.g. "main")
string event.updateType Action corresponding to either "Deposit" or "Withdraw"
address_s event.collateralAddress Deposited / withdrawn collateral token'Ethereum address

Trader update

Sample TraderUpdate (JSON)

{
    "event": {
        "amount": "1000000",
        "trader": "0x00e36ea790bc9d7ab70c55260c66d52b1eca985f84",
        "txHash": "0x239a452c6abc453e153c8c53e4bdb995c558619b3aa1980c8977cbc4c283618f",
        "updateType": "Deposit"
    }
}

A TraderUpdate is an update to a trader'DDX account (such as depositing or withdrawing DDX). The event portion of the transaction has attributes defined as follows:

type field description
dict event The contents of the transaction event
decimal_s event.amount Amount of DDX deposited or withdrawn
address_pre_s event.trader Trader's Ethereum address prefixed with the chain discriminant
bytes32_s event.txHash Ethereum transaction hash for the on-chain deposit / withdrawal
string event.updateType Action corresponding to either "Deposit" or "Withdraw"

Withdraw

Sample Withdraw (JSON)

{
    "event": {
        "amount": "1000",
        "currency": "0xb69e673309512a9d726f87304c6984054f87a93b",
        "strategy": "main",
        "signerAddress": "0x6ecbe1db9ef729cbe972c83fb886247691fb6beb",
        "traderAddress": "0x006ecbe1db9ef729cbe972c83fb886247691fb6beb"
    }
}

A Withdraw is when a withdrawal of a collateral token is signaled. The event portion of the transaction has attributes defined as follows:

type field description
dict event The contents of the transaction event
decimal_s event.amount Amount of collateral token withdrawal has been signaled for
address_s event.currency Collateral ERC-20 token address
string event.strategy Strategy ID the withdrawal applies to
address_s event.signerAddress Signer'Ethereum address withdrawal is taking place from
address_pre_s event.traderAddress Trader's Ethereum address prefixed with the chain discriminant collateral is being withdrawn to

Withdraw DDX

Sample WithdrawDDX (JSON)

{
    "event": {
        "amount": "100",
        "signerAddress": "0xa8dda8d7f5310e4a9e24f8eba77e091ac264f872",
        "traderAddress": "0x00603699848c84529987e14ba32c8a66def67e9ece"
    }
}

A WithdrawDDX is when a withdrawal of DDX is signaled. The event portion of the transaction has attributes defined as follows:

type field description
dict event The contents of the transaction event
decimal_s event.amount Amount of DDX withdrawal has been signaled for
address_s event.signerAddress Signer'Ethereum address withdrawal is taking place from
address_pre_s event.traderAddress Trader's Ethereum address prefixed with the chain discriminant DDX is being withdrawn to

Price checkpoint

Sample PriceCheckpoint (JSON)

{
    "event": {
        "ETHP": {
            "ema": "0",
            "indexPrice": "1874.075454545454545454",
            "indexPriceHash": "0xa35d3dac391cc18671daacab1c393554aac1546a2cbfe630da1e4e86fb44f542"
        }
    }
}

A PriceCheckpoint is when a market registers an update to the composite index price a Petual is tracking along with the ema component. The event portion of the transaction essentially emits the latest Price leaf contents, and is defined as follows:

type field description
dict event The contents of the transaction event
string event.symbol The market name for which this PriceCheckpoint transaction applies
decimal_s event.symbol.ema Captures a smoothed average of the spread between the underlying index price and the DerivaDEX order book for the market
decimal_s event.symbol.indexPrice Composite index price (a weighted average across several price feed sources)
bytes32_s event.symbol.indexPriceHash Index price hash

PNL Realization

Sample PnlRealization (JSON)

{
    "event": {
        "settlementEpochId": 19
    }
}

A PnlRealization is when a there is a PNL realization event. This event realizes the PNL of all open positions and adjusts the average entry price to the current mark price. The event portion of the transaction has attributes defined as follows:

type field description
dict event The contents of the transaction event
int event.settlementEpochId The epoch id for the PNL realization event

Funding

Sample Funding (JSON)

{
    "event": [
        {
            "settlementEpochId": 9
        },
        []
    ]
}

A Funding is when a there is a funding rate distribution. At this time, all strategies are either credited or debited an amount based on the current funding rate and their position notional values and side. The event portion of the transaction has attributes defined as follows:

type field description
list event The contents of the transaction event
int_s event[0].settlementEpochId The epoch id for the funding event
list event[1] Liquidation events that have taken place as a result of funding distributions

Trade mining

Sample TradeMining (JSON)

{
    "event": {
        "totalVolume": {
            "makerVolume": "41249.393239489105059823",
            "takerVolume": "40101.194995030184814398"
        },
        "ddxDistributed": "3192.388588391993848193",
        "tradeMiningEpochId": 15
    }
}

A TradeMining is when there is a trade mining distribution. Traders will receive a portion of the overall DDX distributed proportional to their volume traded that interval. Makers will receive 20% of the DDX allocation and takers will receive 80% of the allocation. The event portion of the transaction has attributes defined as follows:

type field description
dict event The contents of the transaction event
dict event.totalVolume Holds the total volume information for this trade mining interval
decimal_s event.totalVolume.makerVolume Maker volume total for this trade mining interval
decimal_s event.totalVolume.takerVolume Taker volume total for this trade mining interval. Note that this number may be <= the makerTotalVolume, and any discrepancy is due to liquidations only counting towards maker allocation (i.e. the liquidation engine does not receive any DDX per trade mining)
decimal_s event.ddxDistributed Total DDX distributed for trade mining for this interval
int event.tradeMiningEpochId Interval counter for when trade mining occurred

Post

Sample Post (JSON)

{
    "event": {
        "side": "Bid",
        "price": "1870.25",
        "amount": "1.39",
        "symbol": "ETHP",
        "orderHash": "0x860b1065b629df495de7a0d97432a48b098cadcbb37a1fdbd9",
        "strategyId": "main",
        "bookOrdinal": 0,
        "traderAddress": "0x00e36ea790bc9d7ab70c55260c66d52b1eca985f84",
        "timeValue": 1024
    }
}

A Post is an order that enters the order book. The transaction has attributes defined as follows:

type field description
dict event The contents of the transaction event
decimal_s event.amount Size of order posted to the order book
bytes32_s event.orderHash Hexstr representation of the first 25 bytes of the unique EIP-712 hash of the order being placed
decimal_s event.price Price the order has been placed at
string event.side Side of order (Bid or Ask)
string event.strategyId Strategy ID this order belongs to (e.g. "main")
string event.symbol Symbol for the market this order has been placed (e.g. ETHP)
int event.bookOrdinal Numerical value signifying sequence of order placement, which can be used to arrange multiple orders at the same price level to achieve FIFO priority in a local order book
address_pre_s event.traderAddress Trader's Ethereum address prefixed with the chain discriminant
timeValue event.timeValue Time value

Trade fill

Sample TradeFill (JSON)

{
    "event": {
        "price": "1860",
        "amount": "1.23",
        "reason": "Trade",
        "symbol": "ETHP",
        "takerSide": "Ask",
        "makerOutcome": {
            "fee": "0",
            "trader": "0x006ecbe1db9ef729cbe972c83fb886247691fb6beb",
            "strategy": "main",
            "ddxFeeElection": false
        },
        "takerOutcome": {
            "fee": "4.5756",
            "trader": "0x00e36ea790bc9d7ab70c55260c66d52b1eca985f84",
            "strategy": "main",
            "newPositionBalance": "2.46"
        },
        "makerOrderHash": "0x542ad7f2640447d3e93723253099fd45ae721925e0df64702e",
        "takerOrderHash": "0x100d1edd45edede9eedc0e3aac28e7df17168fbef9b459ffc8",
        "makerOrderRemainingAmount": "2.54"
    }
}

A TradeFill is when there is a fill / match that has taken place. Technically, a TradeFill is not a transaction in it of itself, but rather a part of CompleteFill and PartialFill transactions. We often look to these individual TradeFill events as their own dedicated transaction type, however, for Traders to subscribe to and follow as they would other transactions. The event portion of the transaction has attributes defined as follows:

type field description
dict event The contents of the transaction event
decimal event.price Price the fill took place
decimal event.amount Size of the fill
string event.reason Reason for fill (Trade, Liquidation)
string event.symbol Market symbol for which this fill took place
string event.takerSide Taker / aggressor side (Bid, Ask)
dict event.makerOutcome Data containing the some relevant information pertaining to the maker in the trade
address_pre_s event.makerOutcome.traderAddress Maker trader's Ethereum address prefixed with the chain discrimimant
string event.makerOutcome.strategyId Cross-margined strategy identifier for the maker trader
decimal_s event.makerOutcome.fee Fees paid by the maker as a result of the trade
bool event.makerOutcome.ddxFeeElection Whether maker fees are being paid in DDX (true) or USDC (false)
dict event.takerOutcome Data containing the some relevant information pertaining to the taker in the trade
address_pre_s event.takerOutcome.traderAddress Taker trader's Ethereum address prefixed with the chain discrimimant
string event.takerOutcome.strategyId Cross-margined strategy identifier for the taker trader
decimal_s event.takerOutcome.fee Fees paid by the taker as a result of the trade
bool event.takerOutcome.ddxFeeElection Whether taker fees are being paid in DDX (true) or USDC (false)

Types

The types labeled throughout this document in the request and response parameters may be familiar to those who have a background in Ethereum. In any case, please refer to the table below for additional information on the terminology used here. This reference in conjunction with the JSON samples should provide enough clarity:

type description example
string Literal of a sequence of characters surrounded by quotes "ETHP"
address_s 20-byte "0x"-prefixed hexadecimal string literal (i.e. 40 digits long) corresponding to an address ETH type "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"
address_pre_s 21-byte "0x"-prefixed hexadecimal string literal (i.e. 42 digits long) corresponding to an address ETH type prefixed with a single byte for the chain discriminant "0x00A0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"
decimal Numerical value with up to, but no more than 18 decimals of precision 10.031500000000000000
decimal_s String representation of decimal "10.031500000000000000"
bool Boolean value, either true or false True
bytes_s "0x"-prefixed hexadecimal string literal corresponding to a bytes ETH type "0x00000001"
bytes32_s 32-byte "0x"-prefixed hexadecimal string literal (i.e. 64 digits long) corresponding to an bytes32 ETH type "0x0000000000000000000000000000000000000000000000000000000000000001"
timestamp_s_i String representation of numerical UNIX timestamp representing the number of seconds since 1/1/1970 "1616667513875"
timestamp_s String representation representing the ISO 8601 UTC timestamp "2021-03-25T10:38:09.503654"