Overview
Introduction
This documentation is intended for developers who want to write applications to interact with Switcheo programatically.
Before you proceed with the API documentation, be sure to explore Switcheo Exchange at https://switcheo.exchange.
Switcheo Exchange offers both a fully featured REST API for exchange information, order placement, historical and current data, as well as a Streaming API for real-time trading data.
Official language bindings for Javascript (API wrapper) can be found at switcheo-js.
You may wish to visit the Awesome Switcheo repo which contains multiple API wrappers for other languages, and also hosts every awesome project relating to Switcheo development.
Sandbox
TestNet (Sandbox) Endpoints
Type | Base URL |
---|---|
UI | https://beta.switcheo.exchange |
API | https://test-api.switcheo.network |
WS | wss://test-ws.switcheo.io |
MainNet (Production Exchange) Endpoints
Type | Base URL |
---|---|
UI | https://switcheo.exchange |
API | https://api.switcheo.network |
WS | wss://ws.switcheo.io |
REST
Introduction
The REST APIs are feature complete, allowing developers to build their own applications on top of Switcheo Exchange.
All API requests and responses use the JSON format.
There are two types of REST API endpoints available:
Public
These public endpoints include:
- GET Announcements
- GET Candlesticks
- GET Contract Balances
- GET Contracts
- GET Fees
- GET Last 24 Hours
- GET Last Price
- GET Offer Book
- GET Order
- GET Order Book
- GET Orders
- GET Pairs
- GET Recent Trades
- GET Timestamp
- GET Tokens
- GET Trades
Private
All private endpoints must be authenticated.
These private endpoints include:
- POST Create Cancellation
- POST Create Deposit
- POST Create Order
- POST Create Withdrawal
- POST Execute Cancellation
- POST Execute ETH Deposit
- POST Execute NEO Deposit
- POST Execute Order
- POST Execute Withdrawal
The base URLs for the REST API are:
Type | Base URL |
---|---|
Sandbox / TestNet | https://test-api.switcheo.network/ |
Production / MainNet | https://api.switcheo.network |
Rate Limits
All endpoints are rate-limited. We use a dynamic algorithm for determining these limits. The HTTP error code 429
will be returned if this limit is exceeded. You should implement an exponential backoff strategy when encountering this error code.
Exchange Information
This section consists of endpoints that allows retrieval of Switcheo Exchange information.
Authentication is not required for these endpoints.
GET Timestamp
Retrieve the current epoch timestamp in the exchange.
HTTP Request
GET /v2/exchange/timestamp
Example response
{
"timestamp": 1534392760908
}
Notes
This value should be fetched and used when a timestamp parameter is required for API requests.
If the timestamp used for your API request is not within an acceptable range of the exchange's timestamp then an invalid signature error will be returned. The acceptable range might vary, but it should be less than one minute.
GET Contracts
HTTP Request
GET /v2/exchange/contracts
Example response
{
"NEO": {
"V1": "<contract hash NEO 1>",
"V1_5": "<contract hash NEO 1.5>",
"V2": "<contract hash NEO 2>"
},
"ETH": {
"V1": "<contract address ETH V1>"
}
}
Returns the current deployed contract hashes by Switcheo Exchange.
Please note that a different set of contract hashes should be used depending on the network you intend to interact with.
Network | URL |
---|---|
TestNet | Retrieve contract hashes from [TestNet_URL]/v2/exchange/contracts |
MainNet | Retrieve contract hashes from [MainNet_URL]/v2/exchange/contracts |
ETH contract hashes should always include a 0x
prefix, while NEO contract hashes should never
includes a 0x
prefix.
GET Latest Contracts
HTTP Request
GET /v2/exchange/latest_contracts
Example response
{
"NEO": "d524fbb2f83f396368bc0183f5e543cae54ef532",
"ETH": "0x6ee18298fd6bc2979df9d27569842435a7d55e65",
"EOS": "oboluswitch4",
"QTUM": "0x2b25406b0000c3661e9c88890690fd4b5c7b4234"
}
Returns the latest deployed contract hashes by Switcheo Exchange.
Please note that a different set of contract hashes should be used depending on the network you intend to interact with.
Network | URL |
---|---|
TestNet | Retrieve contract hashes from [TestNet_URL]/v2/exchange/latest_contracts |
MainNet | Retrieve contract hashes from [MainNet_URL]/v2/exchange/latest_contracts |
ETH contract hashes should always include a 0x
prefix, while NEO contract hashes should never
includes a 0x
prefix.
GET Pairs
Retrieve available trading pairs on Switcheo Exchange filtered by the base
parameter. Defaults to all pairs.
HTTP Request
GET /v2/exchange/pairs
Example response without details
// GET /v2/exchange/pairs?bases=["NEO"]&show_details=0
[
"GAS_NEO",
"SWTH_NEO",
...
]
Example response with details
// GET /v2/exchange/pairs?bases=["NEO"]&show_details=1
[
{
"name": "GAS_NEO",
"price_precision": 3
},
{
"name": "SWTH_NEO",
"price_precision": 6,
},
...
]
Request parameters
Parameter | Type | Required | Description |
---|---|---|---|
bases | Array<string> | no | Provides pairs for these base symbols. |
show_details | Boolean | no | Show further details for token. Defaults to 0 |
Response parameters for show_details=0
Parameter | Description |
---|---|
Array | List of token pairings (ticker) <QUOTE>_<BASE> where <QUOTE> is the trading token symbol (e.g. SWTH ), while <BASE> is the base token symbol (e.g. NEO ) |
Response parameters for show_details=1
Parameter | Description |
---|---|
name | The ticker name as <QUOTE>_<BASE> where <QUOTE> is the trading token symbol (e.g. SWTH ), while <BASE> is the base token symbol (e.g. NEO ) |
precision | The maximum price precision that can be submitted (e.g. if precision is 2 , an order on this pair for 1.99 or 1.90000000 price is valid, but 1.999 is not) |
GET Tokens
Retrieve a list of supported tokens on Switcheo.
HTTP Request
GET /v2/exchange/tokens
Example response
// GET /v2/exchange/tokens?show_listing_details=1&show_inactive=1
{
"NEO": {
"hash": "c56f33fc6ecfcd0c225c4ab356fee59390af8560be0e930faebe74a6daff7c9b",
"decimals": 8,
"precision": 3,
"trading_active": true
"active": true,
"listing_info": {
"deposits": {
"start": 1514764800,
"end": 7983792000,
"paused": false
},
"trading": {
"start": 1514764800,
"end": 7983792000,
"paused": false
},
"cancellations": {
"start": 1514764800,
"end": 7983792000,
"paused": false
},
"withdrawals": {
"start": 1514764800,
"end": 7983792000,
"paused": false
}
}
},
...
"SWC": {
"hash": "0x00bb907302e508707108cd835621dfd2b44ca7cf",
"decimals": 18,
"precision": 1,
"trading_active": true
"active": true,
"listing_info": {
"deposits": {
"start": 1514764800,
"end": 7983792000,
"paused": false
},
"trading": {
"start": 1514764800,
"end": 7983792000,
"paused": false
},
"cancellations": {
"start": 1514764800,
"end": 7983792000,
"paused": false
},
"withdrawals": {
"start": 1514764800,
"end": 7983792000,
"paused": false
}
}
}
...
}
Request parameters
Parameter | Type | Required | Description |
---|---|---|---|
show_listing_details | Boolean | no | Show all details for each token. If false , only hash & decimals are returned, otherwise all parameters below are returned. Defaults to false |
show_inactive | Boolean | no | Show inactive tokens. Default to false ) |
Response parameters
Parameter | Description |
---|---|
hash | Contract hash of the token |
decimals | Number of decimal places to use when submitting order amounts (e.g. if a token has 8 decimals , then an order for 1.2 tokens should be submitted as 120000000 ) |
precision | The maximum amount precision that can be submitted in orders (e.g. if a token has 8 decimals and 2 precision, 123000000 would be a valid order amount to submit, but not 12340000 ) |
minimum_quantity | The minimum order amount for any orders submitted involving this token. Note that this applies to both the order want_amount and offer_amount (or quantity , if using new format). |
trading_active | Whether this token is currently actively trading |
active | Whether this token is currently visible on the Switcheo Exchange UI |
listing_info | Status of the token for trading activities ["deposits", "trading", "cancellations", "withdrawals"] (only returned if show_listing_details is truthy) |
start | Starting time for the activity (in epoch seconds) |
end | Ending time for the activity (in epoch seconds) |
paused | Whether the trading of the token is temporarily paused |
GET Fees
Example response
[
{
"maker": {
"default": 0
},
"taker": {
"default": 0.002
},
"network_fee_subsidy_threshold": {
"neo": 0.1,
"eth": 0.1
},
"max_taker_fee_ratio": {
"neo": 0.005,
"eth": 0.1
},
"native_fee_discount": 0.75,
"native_fee_asset_id": "ab38352559b8b203bde5fddfa0b07d8b2525e132",
"enforce_native_fees": [
"RHT",
"RHTC"
],
"native_fee_exchange_rates": {
"NEO": "952.38095238",
"GAS": "297.14285714",
...
"ETH": "0",
"JRC": "0",
"SWC": "0"
},
"network_fees": {
"eth": "2466000000000000",
"neo": "200000"
},
"network_fees_for_wdl": {
"eth": "873000000000000",
"neo": "0"
}
}
]
Returns fee data for various blockchains and pairs
HTTP Request
GET /v2/fees
Response parameters
Parameter | Description |
---|---|
maker / default | Default trading fee rate for maker orders, before any discount and network fees |
taker / default | Default trading rate for taker orders, before any discount and network fees |
network_fee_subsidy_threshold | The rate used against your trade proceeds at which network fees will be capped at. (E.g. Assuming network_fee_subsidy_threshold is 0.1 and the your total trade proceeds is 0.2 ETH, the payable network fee will not exceed 0.02 ETH.) |
native_fee_discount | Discount applied to fee for use of native token (as a multiplier). Discount Rate is 1 - native_fee_discount |
native_fee_asset_id | NEO contract hash of the Native Token (i.e. SWTH ) |
enforce_native_fee | List of asset tickers where fee must be paid in Native Tokens |
native_fee_exchange_rates | List of token:value tuples, containing the exchange rate in Native Token |
network_fees | Network Trading fee in the smallest denomination of the native network token |
network_fees_for_wdl | Network Withdrawal fee in the smallest denomination of the native network token |
GET Announcements
Retrieve the currently active Switcheo Exchange Announcement
HTTP Request
GET /v2/exchange/announcement_message
Example response
{
"messages": [
{
"message": "<span>Welcome onboard to <a href=\"https://medium.com/switcheo/callisto-is-now-live-de940a62f1a4\" target=\\\"blank\\\">Switcheo</a>, the first decentralized exchange on Ethereum and NEO.</span>",
"message_type": "alert"
},
{
"message": "<span>To access the legacy UI, please visit: <a href=\"https://legacy.switcheo.exchange\" target=\\\"blank\\\">https://legacy.switcheo.exchange/</a></span>",
"message_type": "info"
}
],
"updated_at": "20181203"
}
Response parameters
Parameter | Description |
---|---|
messages | A list of messages |
updated_at | Last updated date in YYYYMMDD format |
GET Swap Pairs
Retrieve available swap pairs on Switcheo Exchange.
HTTP Request
GET /v2/exchange/swap_pairs
Example response
// GET /v2/exchange/swap_pairs
[
"SWTH_ETH",
...
]
GET Swap Pricing
Atomic Swap orders can be submitted using the create order endpoint. The amount that will be received for an offer amount is calculated by the Constant Product formula:
x_receive = x - k / (y + y_give)
- x is the amount of asset X in the liquidity pool
- y is the amount of asset Y in the liquidity pool
- x_receive is the amount of asset X that the order submitter will receive
- y_give is the amount of asset Y that the order submitter wants to give
- k is x * y
For example, if the pair is SWTH / ETH, and the amount of SWTH in the liquidity pool is 3.6 million SWTH, and the amount of ETH in the liquidity pool is 100 ETH, then for buying SWTH with 1 ETH, the order submitter would receive 35643.56436 SWTH:
3.6 million - 360 million / (100 + 1) = 35643.56436 SWTH
The values of x and y can be fetched from the swap pricing endpoint.
HTTP Request
GET /v2/exchange/swap_pricing
Example response
// GET /v2/exchange/swap_pricing?pair=SWTH_ETH
{
"buy": {
"x": "449293223000000",
"y": "122561935387988990000",
"k": "55066246967587328805614770000000000"
},
"sell": {
"x": "122561935387988990000",
"y": "449293223000000",
"k": "55066246967587328805614770000000000"
}
}
Request parameters
Parameter | Type | Required | Description |
---|---|---|---|
pair | String | yes | The swap pair to get the swap pricing of |
GET Atomic Swap Contracts
HTTP Request
GET /v2/exchange/atomic_swap_contracts
Example response
{
"ETH": {
"V1": "<contract hash>"
}
}
Returns the current atomic swap contract hashes.
Please note that a different set of contract hashes should be used depending on the network you intend to interact with.
Network | URL |
---|---|
TestNet | Retrieve contract hashes from [TestNet_URL]/v2/exchange/atomic_swap_contracts |
MainNet | Retrieve contract hashes from [MainNet_URL]/v2/exchange/atomic_swap_contracts |
Tickers
Ticker endpoints allow retrieval of aggregated market data.
Authentication is not required for these endpoints.
GET Candlesticks
Returns candlestick chart data filtered by url parameters.
HTTP Request
GET /v2/tickers/candlesticks
Example request
{
"pair": "SWTH_NEO",
"interval": 1,
"start_time": 1531213200,
"end_time": 1531220400
}
Example response
[
{
"time": "1531215240",
"open": "0.00049408",
"close": "0.00049238",
"high": "0.000497",
"low": "0.00048919",
"volume": "110169445.0",
"quote_volume": "222900002152.0"
},
{
"time": "1531219800",
"open": "0.00050366",
"close": "0.00049408",
"high": "0.00050366",
"low": "0.00049408",
"volume": "102398958.0",
"quote_volume": "205800003323.0"
},
...
]
Request parameters
Parameter | Type | Required | Description |
---|---|---|---|
pair | string | yes | Only show chart data of this trading pair |
start_time | integer | yes | Start of time range for data in epoch seconds |
end_time | integer | yes | End of time range for data in epoch seconds |
interval | integer | yes | Candlestick period in minutes Possible values are: 1, 5, 30, 60, 360, 1440 |
Response parameters
Parameter | Description |
---|---|
time | Epoch time for the beginning of the interval (in seconds). |
open | Opening price at the start of the interval. |
close | Closing price at the end of the interval. |
high | Highest price during the interval. |
low | Lowest price during the interval. |
volume | Volume in base token traded during the interval. |
quote_volume | Volume in quoted token traded during the interval. |
GET Last 24 Hours
Returns 24-hour data for all pairs and markets.
HTTP Request
GET /v2/tickers/last_24_hours
Example response
[
{
"pair": "SWTH_NEO",
"open": "0.00047221",
"close": "0.00049769",
"high": "1.2",
"low": "0.0004563",
"volume": "11897236125.0",
"quote_volume": "19927606119564.0"
},
{
"pair": "GAS_NEO",
"open": "0.0",
"close": "0.0",
"high": "0.0",
"low": "0.0",
"volume": "0.0",
"quote_volume": "0.0"
}
]
Response parameters
Parameter | Description |
---|---|
time | Epoch time for the beginning of the interval (in seconds). |
open | Opening price at the start of the interval. |
close | Closing price at the end of the interval. |
high | Highest price during the interval. |
low | Lowest price during the interval. |
volume | Volume in base token traded during the interval. |
quote_volume | Volume in quoted token traded during the interval. |
GET Last Price
Returns last price of the requested symbol(s) / base(s). Defaults to all symbols & bases.
HTTP Request
GET v2/tickers/last_price
Example request
{
"symbols": ["SWTH","GAS"]
}
Example response
{
"GAS": {
"NEO": "0.31200000"
},
"SWTH": {
"GAS": "0.00410000",
"NEO": "0.00106600"
}
}
Request parameters
Parameter | Type | Required | Description |
---|---|---|---|
symbols | array | no | Return the price for only these symbols. |
bases | array | no | Return the price for only these bases. |
Response parameters
Parameter | Description |
---|---|
symbol | JSON Object containing a list of base:price tuples |
base | Base token symbol |
price | Price of symbol in base units with 8 decimal precision |
Authentication
As a non-custodian exchange, Switcheo does not use passwords as we do not have custody of user funds. Instead, authentication is done by signing the request payload or blockchain transaction using the blockchain-specific digital signature with the user's private key.
Overview
Currently, all supported blockchains uses the ellipitic curve digital signature algorithim (ECDSA). However, the curves and hashing algorithim used for each blockchain differs slightly.
Blockchain | Signature Algo | Curve | Hash Function |
---|---|---|---|
ETH | ECDSA | secp256k1 | SHA-3 (Keccak) |
EOS | ECDSA | secp256k1 | SHA-256 |
NEO | ECDSA | NIST P-256 | SHA-256 |
In the first step:
- Sign the parameters of the request using the user's private key
- Send both the raw parameters and the result of signing the parameters to the first API endpoint
- A response with either a message or transaction will be returned
In the second step:
- Sign the returned message or transaction with the user's private key
- Send the signed message or transaction to the second API endpoint
Signing Messages for ETH
Signing a message for ETH
const Web3 = require('web3')
const web3 = new Web3()
function signMessage(message, privateKey) {
return web3.eth.accounts.sign(message, privateKey).signature
}
signMessage('Hello', '<private key>')
When signing messages for ETH, the message should first be hex encoded, and the prefixed as
"\x19Ethereum Signed Message:\n" + message.length + message
before being signed. This is the canonical way of ensuring an arbitrary message is not also a valid Ethereum transaction.
The web3.js library [docs] can be used to sign messages for ETH. Refer to the library's implementation details should you wish to sign messages directly.
Signing Request Parameters
Signing parameters for API requests
// 1. Serialize parameters into a string
// Note that parameters must be ordered alphanumerically
const rawParams = { blockchain: 'eth', timestamp: 1529380859, apple: 'Z', }
const stableStringify = require('json-stable-stringify')
const parameterString = stableStringify(rawParams)
// parameterString: '{"apple":"Z","blockchain":"neo","timestamp":1529380859}'
// 2. Sign the parameterString with the user's privateKey
const signature = signMessage(parameterString, '<private key>')
// 3. Combine the raw parameters with the signature
// to get the final parameters to send
const parametersToSend = { ...rawParams, signature }
To perform an action, request parameters have to be signed to generate a signature parameter. This signature parameter should then be sent together with the other parameters in the request.
- Convert the API parameters into a string, with parameters ordered alphanumerically
- Sign the result of (1) with the user's private key
- Send the result of (2) together with the raw parameters to the API endpoint
Example
Using the following parameters as an example:
{ blockchain: 'eth', timestamp: 1529380859, apple: 'Z' }
- Convert the parameters into a string with parameters ordered alphanumerically:
{"apple":"Z","blockchain":"eth","timestamp":1529380859}
- Let the user's private key be
0x98c193239bff9eb53a83e708b63b9c08d6e47900b775402aca2acc3daad06f24
- Sign the result from (1) with the private key in (2) to get
0xbcff177dba964027085b5653a5732a68677a66c581f9c85a18e1dc23892c72d86c0b65336e8a17637fd1fe1def7fa8cbac43bf9a8b98ad9c1e21d00e304e32911c
Signing Transactions for ETH
Signing a transaction for ETH
// Send the parameters for the first step of an action
// and retrieve the response
const response = ...
const { transaction } = response
// verify the transaction data to ensure that it matches the user's intention
...
const Web3 = require('web3')
const web3 = new Web3()
function signTransaction(transaction, privateKey) {
return web3.eth.accounts.signMessage(transaction.message, user.privateKey)
}
// send the result to the second API endpoint
const signatureToSend = signTransaction(transaction, '<private key>')
The second step of an action usually requires the returned transaction to be signed. This is done by:
- Checking the returned transaction data to ensure it matches the user's intention
- Signing the
message
in the transaction with the user's private key - An exception to this is the deposit endpoint, which requires the client to sign and broadcast the transaction, this is covered in more detail in the Deposits section.
Signing Messages for EOS
Signing a message for EOS
const ecc = require('eosjs-ecc')
function signMessage(message, privateKey) {
ecc.sign(message, privateKey)
}
signMessage('Hello', '<private key>')
EOS messages can be signed directly without additional formatting as long as each word in the string is less than twelve characters long.
The eosjs-ecc library can be used to sign messages for EOS. Refer to the library's implementation details should you wish to sign messages directly.
Signing Request Parameters
Signing parameters for API requests
const ecc = require('eosjs-ecc')
// 1. Acquire a short-lived API key
const now = new Date()
// The message text must be exactly followed, while the time in square brackets `[]`
// should be a parseable datetime format (e.g. ISO8601) that does not contain words
// longer than 12 characters.
const message = `Issue me a 30min Switcheo API key [${now.toUTCString()}]`
const signature = signMessage(message, '5JN...privatekey')
const apiKeyParams = {
blockchain: 'eos',
address: 'accountname1'
public_key: 'EOS5...',
message,
signature,
}
const response = await axios.post('/api_keys', JSON.stringify(apiKeyParams),
{ headers: { 'Content-Type': 'application/json' } })
// Note that `expiresAt` is the time the `apiKey` will expire in unix **seconds**
const { key: apiKey, expires_at: expiresAt } = response
// 2. You can now use the API key for all authenticated requests for 30 minutes
// Ensure the API key is still valid
const timestamp = new Date().getTime()
if (expiresAt <= timestamp / 1000 + 5000) { // 5 second request time buffer
// app should handle getting a new API key
throw new Error('New API key required!')
}
// Make your request by including the API key in the `Authorization` HTTP header
const actualRequestParams = { blockchain: 'eos', address: 'switcheotest', apple: 'Z', timestamp }
const response = await axios.post('/api_keys', JSON.stringify(actualRequestParams),
{
headers: {
Authorization: `Token ${apiKey}`,
'Content-Type': 'application/json'
}
}
)
Because fully arbitrary messages are conventionally not allowed for the safety of normal users, and there is no canonical way to form a message that cannot be an EOS transaction, we issue short-lived API keys for authenticating EOS API requests.
The API key lasts for 30 minutes and should be passed in the Authorization
HTTP header in the requests that require authentication. See the example for full details.
Note: This API key authentication strategy is supported when signing on other blockchains as well.
Signing Transactions for EOS
const { JsSignatureProvider } = require('eosjs/dist/eosjs-jssig')
const signatureProvider = new JsSignatureProvider([privateKey])
// 1. Verify transaction
const { Api, JsonRpc } = require('eosjs')
const { TextEncoder, TextDecoder } = require('util')
const fetch = require('node-fetch')
const chainId = production ?
'aca376f206b8fc25a6ed44dbdc66547c36c6c33e3a119ffbeaef943642f0e906' : // mainnet
'e70aaab8997e1dfce58fbfac80cbbb8fecec7b99cf982a9444273cbc64c41473' // jungle
const host = production ?
'nodes.get-scatter.com' : // mainnet
'jungle.obolus.com' // jungle
const api = new Api({ rpc, signatureProvider, textDecoder: new TextDecoder(), textEncoder: new TextEncoder() })
// Send the parameters for the first step of an action
// and retrieve the response
const response = ...
const { transaction } = response
// Verify the transaction data to ensure that it matches the user's intention
const txnObj = api.deserializeTransactionWithActions(transaction)
...
// 2. Sign transaction
function signTransaction(transaction, privateKey, production = false): Promise<string> {
const serializedTransaction = new Uint8Array(new Buffer(transaction, 'hex'))
const availableKeys = await signatureProvider.getAvailableKeys()
const txn = await signatureProvider.sign({
abis: [],
requiredKeys: availableKeys,
chainId,
serializedTransaction,
})
// Note that multi-signature accounts are not supported at this time
// (as implied by the return value below).
return txn.signatures[0]
}
}
// Send the result to the second API endpoint/ bob
const signatureToSend = signTransaction(transaction)
The second step of an action usually requires the returned transaction to be signed, this is done by:
- Deserializing the returned transaction data to ensure it matches the user's intention, this can be done using the eosjs library and referring to the contract's ABI
- Signing the serialized transaction with the user's private key
Signing Messages for NEO
When signing messages for NEO, the message should first be hex encoded and enveloped in an invalid transaction via: '010001f0' + message + '0000'
before being signed. This is the canonical way of ensuring an arbitrary message is not also a valid NEO transaction.
Signing a message for NEO
const { wallet } = require('@cityofzion/neon-js')
function signMessage(message, privateKey) {
return wallet.generateSignature(message, privateKey)
}
signMessage('Hello', '<private key>')
The neon-js library can be used to sign messages for NEO. Refer to the library's implementation details should you wish to sign messages directly.
Signing Request Parameters
Signing parameters for API requests
// 1. Serialize parameters into a string
// Note that parameters must be ordered alphanumerically
const rawParams = { blockchain: 'neo', timestamp: 1529380859, apple: 'Z', }
const stableStringify = require('json-stable-stringify')
const parameterString = stableStringify(rawParams)
// parameterString: '{"apple":"Z","blockchain":"neo","timestamp":1529380859}'
// 2. Serialize the parameter string into a hex string
const Neon = require('@cityofzion/neon-js')
const parameterHexString = Neon.u.str2hexstring(parameterString)
// 3. Convert into a prefixed hex string that represents length of parameterString
const lengthHex = Neon.u.num2VarInt(parameterHexString.length / 2)
// lengthHex: 37
// 4. Concat lengthHex and parameterHexString
const concatenatedString = lengthHex + parameterHexString
// 5. Wrap concatenatedString in an empty neo transaction and serialize it
const serializedTransaction = '010001f0' + concatenatedString + '0000'
// 6. Sign serializedTransaction with the user's privateKey
const signature = signMessage(serializedTransaction, '<private key>')
// 7. Combine the raw parameters with the signature
// to get the final parameters to send
const parametersToSend = { ...rawParams, signature }
To perform an action, request parameters have to be signed to generate a signature parameter. This signature parameter should then be sent together with the other parameters in the request.
- Convert the API parameters into a string, with parameters ordered alphanumerically
- Serialize the parameter string into a hex string ()
- Zero pad and prefix the length / 2 of the result from (2) using neon-js.u.num2varint()
- Concat the result of (3) and (2)
- Wrap the result of (4) in a neo transaction
- Sign the result of (5) with the user's private key
- Send the result of (6) together with the raw parameters to the API endpoint
Example
Using the following parameters as an example:
{ blockchain: 'neo', timestamp: 1529380859, apple: 'Z' }
- Convert the parameters into a string with parameters ordered alphanumerically:
{"apple":"Z","blockchain":"neo","timestamp":1529380859}
- Serialize the parameter into a hex string to get:
7b226170706c65223a225a222c22626c6f636b636861696e223a226e656f222c2274696d657374616d70223a313532393338303835397d
- The length of this string is
110
, divide this by 2 to get55
- Convert
55
to hexadecimal to get37
- Convert
37
into a prefixed, zero padded hex string using neon-js.u.num2varint(). In this case37
is already two digits so no padding or prefix is needed. If the value was something like8
then it must be padded to become08
. Lengths greater than 0xfc will have a prefix byte prepended (0xfd-0xff depending on length). - Form a string by concatenating
37
, and the result of (2) to get:377b226170706c65223a225a222c22626c6f636b636861696e223a226e656f222c2274696d657374616d70223a313532393338303835397d
- Prepend
010001f0
and append0000
to (6) to get:010001f0377b226170706c65223a225a222c22626c6f636b636861696e223a226e656f222c2274696d657374616d70223a313532393338303835397d0000
- Let the user's private key be
cd7b887c29a110e0ce53e81d6dd02805fc7b912718ff8b6659d8da42887342bd
- Sign the result from (7) with the private key in (8) to get
f3831797cbd4244d1ccffafc42739e662e8b06c7a6f98efe5155d0eab1cf5c50fbac6d2a4c4487cbf71498b81e1e9478f06bef02d32da5d8f8bb7fdfc449879a
View a full example implementation
Signing Transactions for NEO
Signing a transaction for NEO
// Send the parameters for the first step of an action
// and retrieve the response
const response = ...
const { transaction } = response
// verify the transaction data to ensure that it matches the user's intention
...
const { tx, wallet } = require('@cityofzion/neon-js')
function signTransaction(transaction, privateKey) {
const serializedTxn = tx.serializeTransaction(transaction, false)
return wallet.generateSignature(serializedTxn, privateKey)
}
// send the result to the second API endpoint
const signatureToSend = signTransaction(transaction, '<private key>')
The second step of an action usually requires the returned transaction to be signed, this is done by:
- Checking the returned transaction data to ensure it matches the user's intention
- Serializing the transaction, this can be done with neon-js (View implementation details)
- Signing the serialized transaction with the user's private key
Offers
An offer represents an open order on the Switcheo Exchange order book.
Funds that are used to make an offer are locked in the contract until the order is cancelled or filled.
GET Order Book
Example request
{
"pair": "SWTH_NEO",
"contract_hash": "eed0d2e14b0027f5f30ade45f2b23dc57dd54ad2"
}
Example response
{
asks: [
{
"price": "0.00046103",
"quantity": "9378.0"
},
{
"price": "0.00046759",
"quantity": "1084.30496802"
}
],
bids: [
{
"price": "0.00045645",
"quantity": "6678.0"
},
{
"price": "0.0004534",
"quantity": "12279.38328187"
},
]
}
Example request 2 (normalizing quantity key to amount)
{
"pair": "SWTH_NEO",
"contract_hash": "eed0d2e14b0027f5f30ade45f2b23dc57dd54ad2",
"normalize_keys": "true"
}
Example response 2 (normalize quantity key to amount)
{
asks: [
{
"price": "0.00046103",
"amount": "9378.0"
},
{
"price": "0.00046759",
"amount": "1084.30496802"
}
],
bids: [
{
"price": "0.00045645",
"amount": "6678.0"
},
{
"price": "0.0004534",
"amount": "12279.38328187"
},
]
}
Retrieves the order book with formatted price and quantity.
HTTP Request
GET /v2/offers/book
Request Parameters
Parameter | Type | Required | Description |
---|---|---|---|
pair | string | yes | Only return offers from this pair. |
contract_hash | string | no | Only return offers for this contract hash. |
normalize_keys | string | no | Normalize default "quantity" key to "amount" |
Response parameters
Parameter | Description |
---|---|
price | Bid or Ask price. |
quantity / amount | If bids side, returns amount of tokens being bought. If asks side, returns amount of tokens that is being sold. |
GET Offer Book
Example request - ETH Pair
{
"pair": "JRC_ETH",
"contract_hash": "0x607af5164d95bd293dbe2b994c7d8aef6bec03bf"
}
Example response
[
{
"id": "e4a76e85-53dc-4a25-ab44-4eed504ce0e0",
"address": "0x0fc8f7bab5feb402ed624b5f5fc88a0648a7f3ae",
"available_amount": 2.4043723e+24,
"offer_amount": 1e+25,
"want_amount": 1500000000000000000,
"offer_asset": "JRC",
"want_asset": "ETH"
},
....
]
Retrieves the raw data for 70 best offers (per side) of the offer book.
HTTP Request
GET /v2/offers
Request Parameters
Parameter | Type | Required | Description |
---|---|---|---|
pair | string | yes | Only return offers from this pair. |
contract_hash | string | no | Only return offers for this contract hash. |
Response parameters
Parameter | Description |
---|---|
id | Unique identifier for the offer object. |
address | Address of the offer maker |
available_amount | Remaining amount of the offer_asset that has not been taken by other orders. |
offer_amount | Total amount of the offer_asset . |
want_amount | Total amount of the want_asset . |
offer_asset | Symbol of the token that the offer maker is offering. |
want_asset | Symbol of the token that the offer maker wants . |
Example
Trades
A trade represents a fill of an offer.
This happens when an incoming order matches an offer on the opposite side of the order book in price.
Trades can be seen on the Trade History column on Switcheo Exchange.
GET Trades
Example request
{
"blockchain": "neo",
"pair": "SWTH_NEO",
"limit": 3,
"contract_hash": "<contract hash>"
}
Example response
[
{
"id": "712a5019-3a23-463e-b0e1-80e9f0ad4f91",
"fill_amount": 9122032316,
"take_amount": 20921746,
"creation_time": "2018-06-08T11:32:03.219Z",
"event_time": "2018-06-08T11:32:03.219Z",
"is_buy": false
},
{
"id": "5d7e42a2-a8f3-40a9-bce5-7304921ff691",
"fill_amount": 280477933,
"take_amount": 4207169,
"event_time": "2018-06-08T11:31:42.200Z",
"creation_time": "2018-06-08T11:31:39.200Z",
"is_buy": false
},
...
]
Retrieves raw trades that occurred on Switcheo Exchange, filtered by the request parameters.
The event_time
refers to the trade execution time while the creation_time
refers to the time the trade was first created.
These two times can be significantly different for Atomic Swap trades as the user is allowed a grace period to confirm the trade.
HTTP Request
GET /v2/trades
Request Parameters
Parameter | Type | Required | Description |
---|---|---|---|
contract_hash | string | yes | Only return trades for this contract hash. |
pair | string | yes | Only return trades for this pair. |
from | integer | no | Only return trades after this time in epoch seconds. |
to | integer | no | Only return trades before this time in epoch seconds. |
limit | integer | no | Only return this number of trades (min: 1 , max: 10000 , default: 5000 ). |
Response parameters
Parameter | Description |
---|---|
id | Unique identifier for the trade object. |
fill_amount | Amount of tokens that is given by the trade to the offer that it is filling. |
take_amount | Amount of tokens that the trade takes from the offer's available_amount that it is filling. |
event_time | Datetime that the trade occurs in Zulu Time (UDT+0) |
is_buy | Whether the side of the trade is a buy. |
Example
GET Recent Trades
Returns 20
most recent formatted trades on the selected pair sorted by executed time in descending order (most recent first).
HTTP Request
GET /v2/trades/recent
Request Parameters
Parameter | Type | Required | Description |
---|---|---|---|
pair | string | yes | Only return trades for this pair. |
Response parameters
Example response
[
{
"id": "dc1c8926-dda1-4f39-afae-0872da950340",
"pair": "SWTH_NEO",
"side": "sell",
"price": "0.00046835",
"quantity": "84.0",
"total": "0.0393414",
"timestamp": 1537924944
},
...
]
Parameter | Description |
---|---|
id | Unique identifier for the trade object. |
pair | The pair on which the trade occurred. |
side | Whether the trade was a buy or sell on this pair. Possible values are: buy , sell . If the pair is SWTH_NEO and the side is buy then the trade bought SWTH using NEO . If the side is sell then the trade sold SWTH for NEO . |
price | Buy or sell price to 8 decimal places precision. |
quantity | If buy side, returns amount of tokens that the trade takes from the offer's available_amount that it is filling. If sell side, returns amount of tokens that the trade gives the offer that it is filling |
total | If buy side, returns amount of tokens that the trade gives the offer that it is filling. If sell side, returns amount of tokens that the trade takes from the offer's available_amount that it is filling |
timestamp | Time that trade was broadcasted in epoch seconds |
Deposits
Deposits are a transfer of tokens from your wallet into the Switcheo smart contract.
Overview
Trading on Switcheo Exchange can only be done using funds that have been successfully deposited into the smart contract.
Deposits are not instantaneous. Once a deposit has been executed, funds in your wallet balance would be deducted by the amount of tokens you chose to deposit.
Funds deducted from your wallet balance will be added to your contract balance but put on hold until Switcheo has determined that it has been successfully broadcasted to the blockchain.
Testing with TestNet Faucet
For the convenience of testing API endpoints, tokens can be received through our TestNet faucet. To use the faucet:
- Go to https://legacy.switcheo.exchange/
- Click on the TestNet/MainNet selector at the bottom of the page
- Select TestNet V2
- Click on WALLET LOGIN to login
- Click on the FAUCET button to receive tokens for testing
POST Create Deposit
Create a deposit
function createDeposit ({ blockchain, address, assetID, amount, privateKey }) {
const signableParams = { blockchain, assetID, amount, timestamp: getTimestamp(),
contractHash: CONTRACT_HASH }
const signature = signParams(signableParams, privateKey)
const apiParams = { ...signableParams, address, signature }
return api.post(API_URL + '/deposits', apiParams)
}
// NOTE: in this example, the parameters can be in camel case because
// the `signParams` and `api.post` method automatically convert param keys
// to snake case
createDeposit({
blockchain: 'neo',
address: user.address,
assetID: 'SWTH',
amount: toNeoAssetAmount(7),
privateKey: user.privateKey
})
Example request
{
"blockchain": "neo",
"asset_id": "SWTH",
"amount": "100000000",
"timestamp": 1531543361074,
"contract_hash": "<contract hash>",
"address": "87cf67daa0c1e9b6caa1443cf5555b09cb3f8e5f",
"signature": "<signature>"
}
Example response
{
"id": "ad5a6e05-d992-47c0-9f52-79ca173dccd1",
"transaction": {
"hash": "a53f26b21f2ede25909e8ac3bf094ac3318e31d5cd654bde4ba734478f1368b2",
"sha256": "caa6727a795ef2dba75c7ea143b6020ffc0d2d4164d7be9639ebb9a1bbd7a6d1",
"type": 209,
"version": 1,
"attributes": [
[
null
]
],
"inputs": [
[
null
]
],
"outputs": [
[
null
]
],
"scripts": [],
"script": "0800e1f505000000001432e125258b7db0a0dffde5bd03b2b859253538ab145f8e3fcb095b55f53c44a1cab6e9c1a0da67cf8753c1076465706f73697467d24ad57dc53db2f245de0af3f527004be1d2d0ee",
"gas": 0
},
"script_params": {
"scriptHash": "eed0d2e14b0027f5f30ade45f2b23dc57dd54ad2",
"operation": "deposit",
"args": [
"5f8e3fcb095b55f53c44a1cab6e9c1a0da67cf87",
"32e125258b7db0a0dffde5bd03b2b859253538ab",
100000000
]
}
}
This endpoint creates a deposit which can be executed through Execute Deposit. To be able to make a deposit, sufficient funds are required in the depositing wallet.
HTTP Request
POST /v2/deposits
Request Parameters
Parameter | Type | Required | Description |
---|---|---|---|
blockchain | string | yes | Blockchain that the token to deposit is on. Possible values are: neo . |
asset_id | string | yes | The asset symbol or ID to deposit. |
amount | amount | yes | Amount of tokens to deposit. |
contract_hash | string | yes | Switcheo Exchange contract hash to execute the deposit on. |
timestamp | timestamp | yes | The exchange's timestamp to be used as a nonce. |
signature | string | yes | Signature of the request payload. See Authentication for more details. |
address | address | yes | The depositer's address. Do not include this in the parameters to be signed. |
Example
POST Execute ETH Deposit
Execute a deposit
const Web3 = require('web3')
const provider = new Web3.providers.HttpProvider('https://mainnet.infura.io')
const web3 = new Web3(provider)
function executeDeposit ({ deposit, privateKey }) {
const { rawTransaction } = await web3.eth.accounts.signTransaction(deposit.transaction, privateKey)
const transactionHash = web3.utils.keccak256(rawTransaction)
web3.eth.sendSignedTransaction(rawTransaction)
const url = `${API_URL}/deposits/${deposit.id}/broadcast`
return api.post(url, { transactionHash })
}
Example request
{
"transaction_hash": "<transaction_hash>"
}
This is the second endpoint required to execute a deposit.
After using the Create Deposit endpoint,
you will receive a response which contains a transaction
.
The transaction
in the response should be signed and directly broadcasted by the client,
the transaction hash of the broadcasted transaction should then be sent to the broadcast endpoint.
HTTP Request
POST /v2/deposits/:id/broadcast
Request Parameters
Parameter | Type | Description |
---|---|---|
transaction_hash | string | The transaction hash of the broadcasted transaction |
POST Execute EOS Deposit
Execute a deposit
function executeDeposit ({ deposit, privateKey }) {
const signature = signTransaction(deposit.transaction, privateKey)
const url = `${API_URL}/deposits/${deposit.id}/broadcast`
return api.post(url, { signature })
}
Example request
{
"signature": "<signature>"
}
This is the second endpoint required to execute a deposit. After using the Create Deposit endpoint, you will receive a response which requires additional signing.
The signature should then be attached as the signature
parameter in the request payload.
Please see the Authentication section for details on how to sign an EOS transaction.
POST Execute NEO Deposit
Execute a deposit
function executeDeposit ({ deposit, privateKey }) {
const signature = signTransaction(deposit.transaction, privateKey)
const url = `${API_URL}/deposits/${deposit.id}/broadcast`
return api.post(url, { signature })
}
Example request
{
"signature": "<signature>"
}
This is the second endpoint required to execute a deposit. After using the Create Deposit endpoint, you will receive a response which requires additional signing.
The signature should then be attached as the signature
parameter in the request payload.
Note that a sha256
parameter is provided for convenience to be used directly as part of the ECDSA signature process.
In production mode, this should be recalculated for additional security.
HTTP Request
POST /v2/deposits/:id/broadcast
Request Parameters
Parameter | Type | Description |
---|---|---|
signature | string | Signed response from create deposit endpoint. (See how and what to sign for different blockchains above) |
Withdrawals
Withdrawals are a transfer of tokens from the Switcheo smart contract into your wallet.
Overview
Once a withdrawal has been executed, tokens in your contract balance would be deducted. Tokens that are put on hold by orders cannot be withdrawn.
Withdrawals are not instantaneous. Tokens deducted from your contract balance will be added to your wallet balance but put on hold until the withdrawal has been fully executed.
POST Create Withdrawal
Create a withdrawal
function createWithdrawal ({ blockchain, address, assetID, amount, privateKey }) {
const signableParams = { blockchain, assetID, amount,
contractHash: CONTRACT_HASH, timestamp: getTimestamp() }
const signature = signParams(signableParams, privateKey,)
const apiParams = { ...signableParams, address, signature }
return api.post(API_URL + '/withdrawals', apiParams)
}
// NOTE: in this example, the parameters can be in camel case because
// the `signParams` and `api.post` method automatically convert param keys
// to snake case
createWithdrawal({
blockchain: 'neo',
address: user.address,
assetID: 'SWTH',
amount: (toNeoAssetAmount(1)),
privateKey: user.privateKey
})
Example request
{
"blockchain": "neo",
"asset_id": "SWTH",
"amount": "100000000",
"timestamp": 1531544358560,
"contract_hash": "<contract hash>",
"signature": "<signature>",
"address": "87cf67daa0c1e9b6caa1443cf5555b09cb3f8e5f"
}
Example response
{
"id": "e0f56e23-2e11-4848-b749-a147c872cbe6"
}
This endpoint creates a withdrawal which can be executed through Execute Withdrawal. To be able to make a withdrawal, sufficient funds are required in the contract balance.
A signature of the request payload has to be provided for this API call.
HTTP Request
POST /v2/withdrawals
Request Parameters
Parameter | Type | Required | Description |
---|---|---|---|
blockchain | string | yes | Blockchain that the token to withdraw is on. Possible values are: neo . |
asset_id | string | yes | The asset symbol or ID to withdraw. |
amount | amount | yes | Amount of tokens to withdraw. |
timestamp | timestamp | yes | The exchange's timestamp to be used as a nonce. |
contract_hash | string | yes | Switcheo Exchange contract hash to execute the withdraw on. |
signature | string | yes | Signature of the request payload. See Authentication for more details. |
address | address | yes | The withdrawer's address. Do not include this in the parameters to be signed. |
Example
Full create withdrawal example
POST Execute Withdrawal
Executing a withdrawal
function executeWithdrawal ({ withdrawal, privateKey }) {
const signableParams = { id: withdrawal.id, timestamp: getTimestamp() }
const signature = signParams(signableParams, privateKey)
const url = `${API_URL}/withdrawals/${withdrawal.id}/broadcast`
return api.post(url, { ...signableParams, signature })
}
Example request
{
"id": "998f1bdc-f26f-44f2-b204-403e24d5777f",
"timestamp": 1531545149715,
"signature": "<signature>"
}
Example response
{
"event_type": "withdrawal",
"amount": -100000000,
"asset_id": "ab38352559b8b203bde5fddfa0b07d8b2525e132",
"status": "confirming",
"id": "998f1bdc-f26f-44f2-b204-403e24d5777f",
"blockchain": "neo",
"reason_code": 9,
"address": "87cf67daa0c1e9b6caa1443cf5555b09cb3f8e5f",
"transaction_hash": null,
"created_at": "2018-07-14T05:12:29.699Z",
"updated_at": "2018-07-14T05:12:29.765Z",
"contract_hash": "<contract hash>"
}
This is the second endpoint required to execute a withdrawal. After using the Create Withdrawal endpoint, you will receive a response which requires additional signing.
HTTP Request
POST /v2/withdrawals/:id/broadcast
Request Parameters
Parameter | Type | Required | Description |
---|---|---|---|
id | string | yes | id parameter in the response from create withdrawal endpoint. |
timestamp | timestamp | yes | The exchange's timestamp to be used as a nonce. |
signature | string | yes | Signature of the request payload. See Authentication for more details. |
Example
Full execute withdrawal example
Orders
Orders are instructions to trade tokens on Switcheo Exchange.
Overview
limit
, market
and otc
type orders are available. Fill-Or-Kill, Post-Only, etc. strategies are not yet available.
Orders will contain a combination of zero or one make and/or zero or more fills once matched.
When an order is executed, the funds required to fulfill the order is debited from the user's confirmed balance and will be locked up in their locked balance until the order is filled or cancelled.
Order Fees
There are zero fees for maker orders and a small fee for taker orders, please refer to https://support.switcheo.network/en/articles/3686578-trading-fees for details.
The exact fee that will be deducted for an order can be calculated by summing the fee_asset_id
and fee_amount
of every item in the fills
array that is returned in the response of create order. If the fee is acceptable, execute order can be called to execute the order. Balances are not deducted until the execute order
endpoint is called.
Order Object
A breakdown of attributes in an order object returned from our API is described below.
Example order
[
{
"id": "c415f943-bea8-4dbf-82e3-8460c559d8b7",
"blockchain": "neo",
"contract_hash": "c41d8b0c30252ce7e8b6d95e9ce13fdd68d2a5a8",
"address": "20abeefe84e4059f6681bf96d5dcb5ddeffcc377",
"side": "buy",
"offer_asset_id": "c56f33fc6ecfcd0c225c4ab356fee59390af8560be0e930faebe74a6daff7c9b",
"want_asset_id": "602c79718b16e442de58778e148d0b1084e3b2dffd5de6b7b16cee7969282de7",
"offer_amount": "100000000",
"want_amount": "20000000",
"transfer_amount": "0",
"priority_gas_amount": "0",
"use_native_token": false,
"native_fee_transfer_amount": 0,
"deposit_txn": null,
"created_at": "2018-05-15T10:54:20.054Z",
"status": "processed",
"order_status": "completed",
"fills": ["... refer to Fill Object section for details"],
"fill_groups": ["... refer to Fill Group Object section for details"],
"makes": ["... refer to Make Object section for details"]
}
]
Attribute | Description |
---|---|
id | Unique identifier for the order object. |
blockchain | The blockchain that the order exists on. |
contract_hash | Switcheo Exchange contract hash that the order is on. |
address | Wallet Address of the order maker. |
side | Whether the order maker is buying or selling. |
offer_asset_id | Asset ID of the token that the order maker is offering. |
want_asset_id | Asset ID of the token that the order maker wants. |
offer_amount | Total amount of the token that the order maker is offering. |
want_amount | Total amount of the token that the order maker wants. |
use_native_token | Whether GAS / ETH tokens was used by the order maker to pay taker fees. |
order_status | Status of the order in the context of the exchange. Possible values are open (on orderbook waiting to be filled),cancelled (cancelled open order), completed (maker order that is entirely filled or broadcasted filler order) |
txn | Serialized blockchain transaction that will execute this order. Used for EOS only. |
fills | Refer to the fills section for more details. |
fill groups | Refer to the fills groups section for more details. |
makes | Refer to the makes section for more details. |
created_at | Time when the order was created. |
transfer_amount | DEPRECATED. Amount (out of the offer_amount ) that was deposited into the contract in order to create the order. |
native_fee_transfer_amount | DEPRECATED. Amount of SWTH that was deposited into the contract in order to pay the taker fees of the order. |
priority_gas_amount | DEPRECATED. Amount of gas paid by the order maker as priority. |
status | DEPRECATED. Status of the order in the context of the blockchain. Possible values are pending (after creation), processed (after broadcast), expired (created but not broadcasted for a long time) |
deposit_txn | DEPRECATED. Transaction that was used for deposits related to the order creation. |
Fill Object
Example fill
{
"id": "6531a67c-6b2e-49b6-8a33-20dfb32b5d8e",
"offer_hash": "fcc8ef7fa17cd540b2e0cbbed9e231db9994279b08618208a4dee292370b38b9",
"offer_asset_id": "ab38352559b8b203bde5fddfa0b07d8b2525e132",
"want_asset_id": "c56f33fc6ecfcd0c225c4ab356fee59390af8560be0e930faebe74a6daff7c9b",
"fill_amount": "100000000",
"want_amount": "1000000",
"filled_amount": "100000000",
"fee_asset_id": "c56f33fc6ecfcd0c225c4ab356fee59390af8560be0e930faebe74a6daff7c9b",
"fee_amount": "1500",
"price": "0.01",
"txn": [Object],
"status": "success",
"created_at": "2018-06-08T07:23:32.299Z",
"transaction_hash": "c51232abf42935a52d6c27122e5de5f92b33ffc43f9a85c5ee6353009c81f80c"
}
When an order is created, the order matching engine will match the order against existing offers.
If any matching offers are found, then fills
are created.
These fills
represent the filling of the order by the matching offers.
Attribute | Description |
---|---|
id | Unique identifier for the fill object. |
offer_hash | The hash of the corresponding offer for this fill object. |
offer_asset_id | Asset ID of the token that the order maker is offering. |
want_asset_id | Asset ID of the token that the order maker wants. |
fill_amount | Amount of tokens that the target offer wants. |
want_amount | Amount of tokens that is being taken from the target offer. |
filled_amount | Amount of tokens that is given to the target offer. |
fee_asset_id | Asset id of the token used for fees. |
fee_amount | Amount of fees paid for the fill. |
price | The buy or sell price of order. |
txn | The transaction representing this fill. |
status | Status of the fill. Possible values are pending (after order creation), confirming (after order broadcast), success (after broadcast success), expired (after order creation but not broadcasted for a long while) |
created_at | Time when the fill was created. |
transaction_hash | Transaction hash of the transaction representing this fill. |
Fill Group Object
Example fill group
{
"id": "7193c1e3-c9ab-429c-881c-429169880cfc",
"address": "0x0f936dce97a9a5c50becc3f58a4842b4c607e722",
"fill_ids": [
"dd08787b-242c-4eb5-8c53-3e9d2f4be4cd"
],
"txn": [Object],
"fee_amount": "4242000000000000",
"fee_asset_id": "0x0000000000000000000000000000000000000000"
}
Fills are grouped into sets for ETH.
This reduces the number of signature requests needed for an order, instead of signing multiple fills individually, a group of fills can be signed with one signature request.
This feature also minimizes ETH network gas costs.
Attribute | Description |
---|---|
id | Unique identifier for the fill group object. |
address | Address of the filler. |
fill_ids | The IDs grouped under this fill group. |
txn | The transaction representing this fill group. |
fee_amount | Amount of fees paid for this fill group. |
fee_asset_id | Asset id of the token used for the fee. |
Make Object
Example make
{
"id": "dc8a36dd-c405-4999-875a-ce619aecbb5c",
"offer_hash": "3423bd82c6e2ec36ccba7a949d5732905e5c6b179517c8aebd9caf72977d817d",
"available_amount": "1000",
"offer_asset_id": "ab38352559b8b203bde5fddfa0b07d8b2525e132",
"offer_amount": "1234567800",
"want_asset_id": "c56f33fc6ecfcd0c225c4ab356fee59390af8560be0e930faebe74a6daff7c9b",
"want_amount": "111111102",
"filled_amount": "1234567800",
"txn": [Object],
"cancel_txn": [Object],
"price": "0.09",
"status": "success",
"created_at": "2018-06-08T07:21:19.988Z",
"transaction_hash": "ff6e73805aed42d445ec0e8d47375e024a7d8c99cd5b8c375d607fec61b80567",
"trades": [...]
}
When an order is created, the order matching engine will match the order against existing offers.
If the order is not fully filled by existing offers, a make
is created.
This make
represents the unfilled amount of the order.
Attribute | Description |
---|---|
id | Unique identifier for the make object. |
offer_hash | The hash of the corresponding offer for this make object. |
available_amount | Remaining amount of the offered tokens in the make that has not been filled by other offers. |
offer_asset_id | Asset ID of the token that the make is offering. |
offer_amount | Amount of tokens that the make is offering. |
want_asset_id | Asset ID of the token that the make wants. |
want_amount | Amount of tokens that the make wants. |
filled_amount | Amount of tokens out of the make's offer_amount that has been taken by other orders. |
txn | The transaction representing this make. |
cancel_txn | If this make was cancelled, this parameter would be the transaction that represents the cancellation. |
price | Buy or sell price of order. |
status | Status of the make. Possible values are pending (after order creation), confirming (after order broadcast), success (after broadcast success), cancelling (after cancellation broadcasted), cancelled (after cancellation broadcast success), expired (after order creation but not broadcasted for a long while) |
created_at | Time when the make was created. |
transaction_hash | Transaction hash of the transaction representing this make. |
Trade Object
Existing Trades for a Make are returned within the Makes of an Order.
Attribute | Description |
---|---|
id | Unique identifier for the trade object. |
status | Status of the trade. Possible values are confirming (after order broadcast), and success (after broadcast success). |
want_amount | Amount of tokens taken from the Make's maker. |
filled_amount | Amount of tokens given to the Trade's taker. |
fee_asset_id | Asset id of the token used for fees. |
fee_amount | Amount of fees that was paid. |
price | The buy or sell price of the trade's order. |
created_at | Time when the trade was created. |
GET Order
Example request
{
"order": "995cfc34-8fb8-41e6-bccd-1695086267d1",
}
Example Response
{
"id": "995cfc34-8fb8-41e6-bccd-1695086267d1",
"blockchain": "eth",
"contract_hash": "0xba3ed686cc32ffa8664628b1e96d8022e40543de",
"address": "0x7c819b61b3a35ab718f66508d31e2cf3c25eb624",
"pair": "DAI_ETH",
"side": "buy",
"price": "0.00662",
"quantity": "62000000000000000000",
"use_native_token": false,
"created_at": "2018-11-20T03:43:48.035Z",
"order_status": "cancelled",
"offer_asset_id": "0x0000000000000000000000000000000000000000",
"want_asset_id": "0x89d24a6b4ccb1b6faa2625fe562bdd9a23260359",
"offer_amount": "410440000000000000",
"want_amount": "62000000000000000000",
"status": "processed",
"deposit_txn": null,
"transfer_amount": "0",
"priority_gas_amount": "0",
"native_fee_transfer_amount": 0,
"fill_groups": [...],
"fills": [...],
"makes": [...]
}
Retrieves a specific order
HTTP Request
GET /v2/orders/:order_id
Request Parameters
Parameter | Type | Required | Description |
---|---|---|---|
order_id | string | yes | Return order details for a specific order id |
GET Orders
Example request
{
"address": "87cf67daa0c1e9b6caa1443cf5555b09cb3f8e5f",
"contract_hash": "<contract hash>"
}
Example Response
[
{
"id": "c415f943-bea8-4dbf-82e3-8460c559d8b7",
"blockchain": "neo",
"contract_hash": "c41d8b0c30252ce7e8b6d95e9ce13fdd68d2a5a8",
"address": "20abeefe84e4059f6681bf96d5dcb5ddeffcc377",
"side": "buy",
"offer_asset_id": "c56f33fc6ecfcd0c225c4ab356fee59390af8560be0e930faebe74a6daff7c9b",
"want_asset_id": "602c79718b16e442de58778e148d0b1084e3b2dffd5de6b7b16cee7969282de7",
"offer_amount": "100000000",
"want_amount": "20000000",
"transfer_amount": "0",
"priority_gas_amount": "0",
"use_native_token": false,
"native_fee_transfer_amount": 0,
"deposit_txn": null,
"created_at": "2018-05-15T10:54:20.054Z",
"status": "processed",
"order_status": "processed",
"fills": [...],
"makes": [...]
}
]
Retrieves orders from a specific address filtered by the given parameters.
HTTP Request
GET /v2/orders
Request Parameters
Parameter | Type | Required | Description |
---|---|---|---|
address | address | yes | Only return orders made by this address. |
pair | string | no | Only return orders from this pair. |
contract_hash | string | yes | Only return orders from this contract hash. |
from | integer | no | Only return orders that are last updated at or after this time in UNIX timestamp format |
order_status | string | no | Only return orders have this status. Possible values are open , cancelled , completed |
before_id | string | no | Only return orders that are created before the order with this id |
limit | integer | no | Only return up to this number of orders (min: 1 , max: 200 , default: 50 ). |
Example
POST Create Order
This endpoint creates an order which can be executed through Broadcast Order. Orders can only be created after sufficient funds have been deposited into the user's contract balance. A successful order will have zero or one make and/or zero or more fills.
Atomic Swap Orders
Atomic Swap orders can be created through this endpoint. The swap pricing endpoint can be used to determine the expected amount that will be received for a swap.
HTTP Request
POST /v2/orders
Request Parameters
For the below descriptions, the order maker
refers to your API user.
Create an order
function createOrder({ pair, blockchain, side, price,
quantity, useNativeTokens, orderType,
privateKey, address }) {
const signableParams = { pair, blockchain, side, price, quantity,
useNativeTokens, orderType, timestamp: getTimestamp(),
contractHash: CONTRACT_HASH }
const signature = signParams(signableParams, privateKey)
const apiParams = { ...signableParams, address, signature }
return api.post(API_URL + '/orders', apiParams)
}
// NOTE: in this example, the parameters can be in camel case because
// the `signParams` and `api.post` method automatically convert param keys
// to snake case
createOrder({
pair: 'SWTH_NEO',
blockchain: 'neo',
address: user.address,
side: 'buy',
price: (0.001).toFixed(8),
quantity: toAssetAmount(1000, 'SWTH'),
useNativeTokens: true,
orderType: 'limit',
privateKey: user.privateKey
})
Example request
{
"pair": "SWTH_NEO",
"blockchain": "neo",
"side": "buy",
"price": "0.00100000",
"quantity": "100000000000",
"use_native_tokens": true,
"order_type": "limit",
"timestamp": 1531541888559,
"contract_hash": "<contract hash>",
"address": "87cf67daa0c1e9b6caa1443cf5555b09cb3f8e5f",
"signature": "<signature>"
}
Example response
{
"id": "cfd3805c-50e1-4786-a81f-a60ffba33434",
"blockchain": "neo",
"contract_hash": "eed0d2e14b0027f5f30ade45f2b23dc57dd54ad2",
"address": "87cf67daa0c1e9b6caa1443cf5555b09cb3f8e5f",
"side": "buy",
"price": "0.00100000",
"quantity": "100000000000",
"offer_asset_id": "c56f33fc6ecfcd0c225c4ab356fee59390af8560be0e930faebe74a6daff7c9b",
"want_asset_id": "ab38352559b8b203bde5fddfa0b07d8b2525e132",
"offer_amount": "100000000",
"want_amount": "100000000000",
"transfer_amount": "0",
"priority_gas_amount": "0",
"use_native_token": true,
"native_fee_transfer_amount": 0,
"deposit_txn": null,
"created_at": "2018-07-13T07:58:11.340Z",
"status": "pending",
"order_status": "nil",
"fills": [
{
"id": "2eaa3621-0e7e-4b3d-9c8c-454427f20949",
"offer_hash": "bb70a40e8465596bf63dbddf9862a009246e3ca27a4cf5140d70f01bdd107277",
"offer_asset_id": "c56f33fc6ecfcd0c225c4ab356fee59390af8560be0e930faebe74a6daff7c9b",
"want_asset_id": "ab38352559b8b203bde5fddfa0b07d8b2525e132",
"fill_amount": "1031498",
"want_amount": "2050000000",
"filled_amount": "",
"fee_asset_id": "ab38352559b8b203bde5fddfa0b07d8b2525e132",
"fee_amount": "1537500",
"price": "0.00050317",
"txn": [Object],
"status": "pending",
"created_at": "2018-07-13T07:58:11.353Z",
"transaction_hash": "97ad8c0af68d22304e7f2d09d04f3beed29a845fe57de53444fff1507b752b99"
}
],
"makes": [],
"fill_groups": []
}
Parameter | Type | Required | Description |
---|---|---|---|
blockchain | string | yes | Blockchain that the pair is on. Possible values are: neo , eth . This should be the blockchain of the offer_asset for Atomic Swap orders. |
contract_hash | string | yes | Switcheo Exchange contract hash to execute the order on. For Atomic Swap orders, this should be the contract_hash for the blockchain of the offer_asset . |
pair | string | yes | Pair to trade, e.g. SWTH_NEO . |
side | string | yes | Whether to buy or sell on this pair. Possible values are: buy , sell . If the pair is SWTH_NEO and the side is buy then the order is to buy SWTH using NEO . If the side is sell then the order is to sell SWTH for NEO . |
price | string | yes | Buy or sell price rounded to the pair's price precision, found on Get Pairs. Set value to null for market type and Atomic Swap orders. |
quantity | amount | yes | The amount of tokens you want to trade. Set value to null for Atomic Swap orders. |
offer_amount | amount | no | The amount of tokens to offer for an Atomic Swap. Must be provided if and only if the order pair is an Atomic Swap pair. |
use_native_tokens | boolean | yes | true if you want to pay fees in GAS for Neo orders or ETH for Ethereum orders. |
order_type | string | yes | Order type, possible values are: limit , market , otc . This type must be set as market for Atomic Swap orders. |
otc_address | address | no | Address of the counterparty in OTC trades. Must be provided if and only if order_type is otc . |
timestamp | timestamp | yes | The exchange's timestamp to be used as a nonce. |
signature | string | yes | Signature of the request payload. See Authentication for more details. |
address | address | yes | Address of the order maker. Do not include this in the parameters to be signed. |
receiving_address | address | no | Address to receive the want_asset . Must be provided if and only if the order pair is an Atomic Swap pair. |
worst_acceptable_price | string | no | The worst acceptable price of an Atomic Swap. If the Atomic Swap pricing changes to be worse than this, then the order will not be created. Must be provided if and only if the order pair is an Atomic Swap pair. |
Example
POST Execute Order
This is the second endpoint required to execute an order. After using the Create Order endpoint, you will receive a response which needs to be signed.
Format of signatures parameter
{
// NEO & ETH:
makes: {
<make_id>: <signature>
},
// NEO only:
fills: {
<fill_id_1>: <signature_1>,
<fill_id_2>: <signature_2>
},
// ETH only:
fill_groups: {
<fill_group_id_1>: <signature_3>,
<fill_group_id_2>: <signature_4>
},
// EOS only:
order: {
<id>: <order_signature>,
}
}
Every txn
in the fills
, fill_groups
and makes
of the Create Order response should be signed,
and structured in the signatures
format shown on the right.
NOTE: The txn
of fills
for ETH will be empty, only the txn
of the fill_groups
need to be signed for ETH-based orders. Please see Fill Groups for more details.
NOTE: The makes
, fills
and fill_groups
arrays for EOS will initially be empty as orders are matched on-chain.
Only the root txn
needs to be signed for EOS-based orders.
Please see the Authentication section on how to perform the signTransaction
operation.
HTTP Request
POST /v2/orders/:id/broadcast
Request Parameters
Broadcast an order
function signArray(array, privateKey) {
return array.reduce((map, item) => {
if (item.txn) {
map[item.id] = signTransaction(item.txn, privateKey)
}
return map
}, {})
}
function broadcastOrder({ order, privateKey }) {
const { fills, makes } = order
const signatures = {
makes: signArray(order.makes, privateKey),
fills: signArray(order.fills, privateKey),
fill_groups: signArray(order.fill_groups, privateKey),
order: signArray([order], privateKey)
}
const url = `${API_URL}/orders/${order.id}/broadcast`
return api.post(url, { signatures })
}
Example request
{
"signatures": {
"makes": {
"ufdh03kt-23jg-h6k5-45fd-56dfy7ks0g9a": "<signature_3>"
},
// NEO only:
"fills": {
"c821c814-d4a3-475b-b461-e909d8c8a59a": "<signature_1>",
"d034djb1-9sd8-5b6k-1f9g-40fd9jntk86k": "<signature_2>",
},
// ETH only:
"fill_groups": {
"6f9afaeb-1866-47d5-b7d8-061eab1b5fbc": "<signature_4>",
"94a282ed-bf89-40e2-b0ea-7d3a0dac3c68": "<signature_5>"
},
// EOS only:
"order": {
"cfd3805c-50e1-4786-a81f-a60ffba33434": "<order_signature>"
}
}
}
Parameter | Type | Required | Description |
---|---|---|---|
signatures | hash | yes | See the section description and example for the format. |
Example
POST Create Cancellation
Create a cancellation
function createCancellation({ order, address, privateKey }) {
const signableParams = { orderId: order.id, timestamp: getTimestamp() }
const signature = signParams(signableParams, privateKey)
const apiParams = { ...signableParams, signature, address }
return api.post(API_URL + '/cancellations', apiParams)
}
This is the first API call required to cancel an order.
Only orders with makes and with an available_amount
of more than 0 can be cancelled.
HTTP Request
POST /v2/cancellations
URL Parameters
Example request
{
"order_id": "69c60da5-5832-4705-8390-de4bb4ed62c5",
"timestamp": 1531471743957,
"signature": "<signature>",
"address": "87cf67daa0c1e9b6caa1443cf5555b09cb3f8e5f"
}
Example response
{
"id": "e4cf0472-59e3-4887-b2d3-720b98da0de6",
"transaction": {
"hash": "b4013bdfde6370198f043f2a5fb235242d20280361241d85ee0774c63856f65b",
"sha256": "f760aaa9efe99059af46a2a9640e91527119e78f18322729ab620e20116b3cf8",
"type": 209,
"version": 1,
"attributes": [
[
null
]
],
"inputs": [
[
null
]
],
"outputs": [
[
null
]
],
"scripts": [],
"script": "206e62f9555edc1f791d36f6f081d44b249e8696ab73f41cc809db73316eff6e65349b7cffdaa674beae0f930ebe6085af9093e5fe56b34a5c220ccdcf6efc336fc532e125258b7db0a0dffde5bd03b2b859253538ab52c10b63616e63656c4f6666657267d24ad57dc53db2f245de0af3f527004be1d2d0ee",
"gas": 0
},
"script_params": {
"scriptHash": "eed0d2e14b0027f5f30ade45f2b23dc57dd54ad2",
"operation": "cancelOffer",
"args": [
"9b7cffdaa674beae0f930ebe6085af9093e5fe56b34a5c220ccdcf6efc336fc532e125258b7db0a0dffde5bd03b2b859253538ab",
"6e62f9555edc1f791d36f6f081d44b249e8696ab73f41cc809db73316eff6e65"
]
}
}
Parameter | Type | Required | Description |
---|---|---|---|
order_id | string | yes | The ID of the order to cancel. |
timestamp | timestamp | yes | The exchange's timestamp to be used as a nonce. |
signature | string | yes | Signature of the request payload. See Authentication for more details. |
address | address | yes | Address of the order maker. Do not include this in the parameters to be signed. |
Example
Full create cancellation example
POST Execute Cancellation
Execute a cancellation
function executeCancellation({ cancellation, privateKey }) {
const signature = signTransaction(cancellation.transaction, privateKey)
const url = `${API_URL}/cancellations/${cancellation.id}/broadcast`
return api.post(url, { signature })
}
This is the second endpoint that must be called to cancel an order. After calling the Create Cancellation endpoint, you will receive a transaction in the response which must be signed.
Note that a sha256
parameter is provided for convenience to be used directly as part of the ECDSA signature process.
In production mode, this should be recalculated for additional security.
Example request
{
"signature": "<signature>"
}
HTTP Request
POST /v2/cancellations/:id/broadcast
URL Parameters
Parameter | Type | Required | Description |
---|---|---|---|
signature | string | yes | Signature of the transaction. See Authentication for more details. |
Example
Full execute cancellation example
Computing Offer Hash (NEO)
Computing the offer_hash
const invoke = {
scriptHash: contractHash,
operation: 'makeOffer',
args: [
u.reverseHex(userHash),
u.reverseHex(offerAssetID), new BigNumber(offerAmount).toNumber(),
u.reverseHex(wantAssetID), new BigNumber(wantAmount).toNumber(),
u.str2hexstring(uuid),
],
}
const offerKeyBytes = invoke.args[0] + invoke.args[1] + invoke.args[3] +
numToHex(invoke.args[2]) + numToHex(invoke.args[4]) + invoke.args[5]
const offerHash = u.reverseHex(u.hash256(offerKeyBytes))
const numToHex = (num) => {
if (typeof num !== 'number') throw new Error('numToHex received a non-number')
if (num < 0) throw Error.new(`numToHex received a negative number (${num})!`)
if (num <= 16) {
return u.num2hexstring(num)
}
return u.num2hexstring(num, 8, true)
}
In the previous sections, you may have noticed that offer_hashes are generated for fills and makes right after creation.
To compute the offer_hash, please take reference from the sample code snippet that is shown on the right.
You can find the u
library from neon-js.
Balances
Description
There are two types of balances.
Balance | Description |
---|---|
Wallet balance | Number of tokens present in your wallet. |
Contract balance | Number of tokens present in the Switcheo smart contract. |
Trading on Switcheo Exchange can only be done using your contract balance.
GET Contract Balances
List contract balances of the given address and contract.
The purpose of this endpoint is to allow convenient querying of a user's balance across multiple blockchains, for example, if you want to retrieve a user's NEO and ethereum balances.
As such, when using this endpoint, balances for the specified addresses and contract hashes will be merged and summed.
Contract balances are divided into three types in the response. The following table describes their differences.
Type | Description |
---|---|
confirming | Confirming balances cannot be used as they are awaiting confirmation and may be reverted. This can either be a deposit has been executed and is awaiting on-chain confirmations, or a withdrawal that has been executed and is being processed. |
confirmed | Confirmed balances under this key are can be used to trade. |
locked | Locked balances are balances that are withheld due to an open order and cannot be used to trade. |
HTTP Request
Example request:
{
"addresses": [
"<address 1>"
],
"contract_hashes": [
"<contract hash 1>",
"<contract hash 2>"
]
}
// The URL should be:
// /v2/balances?addresses[]=address_1&contract_hashes[]=contract_hash_1&contract_hashes[]=contract_hash_2
/v2/balances
URL parameters
Parameter | Type | Required | Description |
---|---|---|---|
addresses | array | yes | Only return balances for these addresses |
contract_hashes | array | yes | Only return balances from these contract hashes. |
Example
Example response:
{
"confirming": {
"GAS": [
{
"event_type": "withdrawal",
"asset_id": "602c79718b16e442de58778e148d0b1084e3b2dffd5de6b7b16cee7969282de7",
"amount": -100000000,
"transaction_hash": null,
"created_at": "2018-07-12T10:48:48.866Z"
}
]
},
"confirmed": {
"GAS": "47320000000.0",
"SWTH": "421549852102.0",
"NEO": "50269113921.0"
},
"locked": {
"GAS": "500000000.0",
"NEO": "1564605000.0"
}
}
Errors
The Switcheo REST API uses the following error codes:
Error Code | Meaning |
---|---|
400 | Bad Request -- Your request is badly formed. |
401 | Unauthorized -- You did not provide a valid signature. |
404 | Not Found -- The specified endpoint or resource could not be found. |
406 | Not Acceptable -- You requested a format that isn't json. |
422 | Unprocessible Entity -- Your request had validation errors. |
429 | Too Many Requests -- Slow down requests using an exponential backoff strategy. |
500 | Internal Server Error -- We had a problem with our server. Try again later. |
503 | Service Unavailable -- We're temporarily offline for maintenance. Please try again later. |
Websocket
Introduction
Switcheo offers 3 APIs for streaming data:
- a public Offer Book API
- a public Trade Events API
- a private Order Events API
Advantages include:
- receive notifications in real time
- reduce the amount of data you have to transfer over the network
- reduce latency introduced by polling interval
For example, to maintain an order book on your client and react to changes on it, you may be polling the Get Offer Book endpoint every three seconds:
- request
/v2/offers
- bring back HTTP header data and a response body
- parse the JSON in the response body
- compare the latest response against the previous response to see what has changed
Using the public Offer Book API, you can instead subscribe once and receive real time notifications of all offer book changes.
The Switcheo Streaming API uses the Socket.IO protocol. It is recommended to use a Socket.IO client for connecting the API.
For more information on how the Socket.IO protocol works in general, refer to:
Connection Endpoints
Example
const client = io('wss://test-ws.switcheo.io/<namespace>');
The connection endpoints are:
Type | Base URL |
---|---|
Sandbox / TestNet | wss://test-ws.switcheo.io/ |
Production / MainNet | wss://ws.switcheo.io |
Event Types
Below are the event types that may be emitted by WebSocket server. In addition, all standard Socket.IO events are also emitted.
Name | Type | Description |
---|---|---|
all |
Server | Emitted when initially joining a room |
more |
Server | Emitted in response to additional data requested by client |
updates |
Server | Emitted when a new event occurs |
Below are the event types that can be emitted by the client and are processed by the WebSocket server.
Name | Type | Description |
---|---|---|
join |
Client | Emit to join a room (i.e. subscribe to a channel) |
leave |
Client | Emit to leave a room (i.e. unsubscribe from a channel) |
more |
Client | Emit to fetch more data |
Rooms
Example
io.on('connection', function(socket){
socket.join({ ... });
});
After connecting to the Switcheo API, clients need to join the appropriate room in order to send or receive data.
Note that the room to join is always an object. The namespace and room parameters are described in each API section below. To learn more about Room and Namespaces, see the Socket.io docs.
Offer Book
The Offer Book API allows clients to maintain an offer book, with diff-ing support to ensure data integrity.
Socket Connection
Example
const client = io('wss://test-ws.switcheo.io/books');
io.on('connection', function(socket){
socket.join({
contractHash: "91b83e96f2a7c4fdf0c1688441ec61986c7cae26",
pair: "SWTH_NEO"
});
});
To subscribe to the offer book API, connect to the offers
namespace and join the room with the following parameters:
Parameter | Description |
---|---|
contractHash | Contract hash of the exchange |
pair | Pair of the offer book to subscribe |
All Event
Example Event
{
book: {
buys: [ // i.e. bids
{ price: '0.01000000', amount: '100' }, // amount refers to the quote quantity
{ price: '0.09000000', amount: '50' },
...
],
sells: [ // i.e. asks
...
]
}
digest: '2fd4e1c67a2d28fced849ee1bb76e7391b93eb12',
}
Upon joining the appropriate room, you will receieve an all
event on your socket, which will contain the full data of the offer book for the subscribed pair, as well as a SHA-1 digest.
The SHA-1 digest can be used to maintain offer book integrity after future updates are applied.
Response Fields
Parameter | Description |
---|---|
book | The offer book data |
digest | A SHA-1 digest of the stringified JSON book |
Updates Event
Example Event
{
events: [
{ price: '0.01000000', side: 'buy', delta: '-1' },
...
],
digest: '62d7beb325a49df2c323c45fd27e119d524468e0',
}
Example Handling
socket.on('all', ({ events, digest }) => {
events.forEach(event => {
const index = book[event.side].findIndex(o => o.price === event.price)
oldBook[event.side].amount += event.delta
})
const computedDigest = computeDigest(book)
if (computedDigest !== digest) {
throw new Error('offer book desynchronized!') // handle by rejoining room
}
});
Whenever there is a change to the offer book, an updates
event will be emitted, containing the update events and a SHA-1 digest.
Response Fields
Field | Description |
---|---|
events | An array of event s to apply against the existing offer book. |
digest | A SHA-1 digest of the stringified JSON book after events have been applied. |
event
Fields
Field | Description |
---|---|
delta | The difference in quantity, which may be negative. |
price | The offer book price point that is being updated. |
side | The side of the offer book that has changed, either buy or sell . |
If the SHA-1 digest of the offer book does not match after applying updates, the room should be rejoined in order to refetch the full offer book.
The digest should be computed by constructing a sorted JSON string and applying the SHA-1 hash algorithm.
Keys in any JSON object should be sorted alphanumerically. Arrays should be sorted from highest price to lowest price.
Take note that when changing numeric values, and recomputing the offer book digest, amounts should be stringified, and exponentiated when the exponent is less than -6
or more than 19
.
Number to string formatting
Number | String | Info |
---|---|---|
12345678 |
'12345678' |
// e is only 8 |
0.000000123 |
'1.23e-7' |
// e is < -6 |
Trade Events
The Trade Events API allows clients to subscribe and listen to trade events that happen on Switcheo Exchange. There is diff-ing support to ensure that no trade events are missed.
Socket Connection
Example
const client = io('wss://test-ws.switcheo.io/trades');
io.on('connection', function(socket){
socket.join({
contractHash: "91b83e96f2a7c4fdf0c1688441ec61986c7cae26",
pair: "SWTH_NEO"
});
});
To subscribe to the trade events API, connect to the trades
namespace and join the room with the following parameters:
Parameter | Description |
---|---|
contractHash | Contract hash of the exchange |
pair | Pair to listen to trade events for |
All Event
Example Event
{
trades: [
{ price: '0.01000000', side: 'buy', timestamp: '-1', amount: '100' },
...
]
digest: '2fd4e1c67a2d28fced849ee1bb76e7391b93eb12',
}
Upon joining the appropriate room, you will receieve an all
event on your socket, which will contain the last 50 trade events for the subscribed pair, as well as a SHA-1 digest.
The SHA-1 digest can be used to ensure that trade events were not missed.
Response Fields
Field | Description |
---|---|
trades | The trade events |
digest | A SHA-1 digest of the stringified JSON trades |
trade
Fields
Field | Description |
---|---|
amount | The amount of tokens traded (in quote quantity) |
price | The price of the trade |
side | The taker side of the trade, either buy or sell |
timestamp | The trade execution time |
Updates Event
Example Event
{
events: [...],
digest: '62d7beb325a49df2c323c45fd27e119d524468e0',
limit: 50,
}
Whenever there is a new trade event, an updates
event will be emitted.
The digest should be computed by stringifying the last limit
trades of JSON data, and applying the SHA-1 hash algorithm.
The data array should be sorted from the largest to smallest timestamp
. Keys in each object should be sorted alphanumerically.
Take note that to compute the digest, only the last limit
trades should be used. Earlier trades events should be trimmed, before stringifying and hashing the data.
Event Fields
Field | Description |
---|---|
events | An array of event s, in the same format as trade |
digest | A SHA-1 digest of the stringified JSON trades after events have been applied. |
limit | The number of trades to hash in order to compute the SHA-1 digest. If this is less than the number of trades given in the all event and updates event, all trades should be used. |
Order Events
The Order Events API allows clients to subscribe and listen to order events that happen on Switcheo Exchange.
Socket Connection
Example
const client = io('wss://test-ws.switcheo.io/orders');
io.on('connection', function(socket){
socket.join({
contractHash: "91b83e96f2a7c4fdf0c1688441ec61986c7cae26",
pair: "SWTH_NEO",
address: "20abeefe84e4059f6681bf96d5dcb5ddeffcc377"
});
});
To subscribe to the order events API, connect to the orders
namespace and join the room with the following parameters:
Parameter | Description |
---|---|
address | Address to listen to order events for |
contractHash | Contract hash of the exchange |
All Event
Example Event
{
orders: [
{
baseAmount: "6147810",
baseAsset: "NEO",
blockchain: "neo",
fee: "0",
feeAsset: "NEO",
filledAmount: "12345000000",
fills: [
{
amount: "2345000000",
fee: "1758750",
id: "353e8e0e-581c-4207-9cdb-718144d0ce0e",
price: "0.000498",
timestamp: 1541582687
},
...
],
id: "06105c4c-9ed1-43fb-be79-d65c9e40c7fa",
makeFills: [
amount: "12345000000",
fee: "78791",
id: "2e8da960-10f6-439f-9ec2-36f5eeb1f179",
price: "0.00034",
timestamp: 1540528856,
...
],
price: "0.000498",
side: "sell",
status: "completed",
timestamp: 1541582603,
tradeAmount: "12345000000",
tradeAsset: "SWTH",
type: "limit"
},
...
]
}
Clients can emit an all
event to receive the last 50 orders. To receive more orders, emit a more
event.
Request Fields
Field | Type | Required | Description |
---|---|---|---|
address | Array<string> | yes | Addresses to listen to order events for |
contractHash | Array<string> | yes | Contract hashes of the exchange |
pair | string | no | Pair to listen to order events for |
status | string | no | The status of the order, either cancelled , completed , or open |
Response Fields
Field | Description |
---|---|
orders | The order events |
order
Fields
Field | Description |
---|---|
baseAmount | The quoted quantity of base asset |
baseAsset | The base asset |
blockchain | The blockchain, either neo or eth |
fee | The fee incurred |
feeAsset | The fee asset |
filledAmount | The filled amount of the order |
fills | The orders fill ed by this order |
id | The order id |
makeFills | The orders that fill s this order |
price | The quoted price if it's a limit order or null if it's a market order |
side | The side of the order, either buy or sell |
status | The status of the order, either cancelled , completed , or open |
timestamp | The order time |
tradeAmount | The quoted quantity of trade asset |
tradeAsset: | The trade asset |
type | The type of order, either limit or market |
fill
Fields
Field | Description |
---|---|
amount | The filled amount |
fee | The fee incurred by the taker |
id | The fill id |
price | The executed price |
timestamp | The executed time |
More Event
The more event is exactly the same as the all
event with the exception of an additional request parameter, beforeId
.
Request Fields
Field | Type | Required | Description |
---|---|---|---|
address | Array<string> | yes | Addresses to listen to order events for |
contractHash | Array<string> | yes | Contract hashes of the exchange |
pair | string | no | Pair to listen to order events for |
status | string | no | The status of the order, either cancelled , completed , or open |
beforeId | string | no | The id of the last order in the order history |
Updates Event
Example Event
{
events: [...],
}
Whenever there is a new order event, an updates
event will be emitted.
Event Fields
Field | Description |
---|---|
events | An array of event s, in the same format as order |
Troubleshooting
The following steps can be used to troubleshoot potential issues:
Check the Data Types section and ensure your parameters have the correct formatting. Possible issues include the address format, amount format, parameter casing, private key format, wrong parameters included to be signed, wrong timestamp.
Trace each step of signing parameters using the example in Signing Request Parameters, this example has the expected inputs and outputs at each step of generating a signature.
If you have further technical questions, please join our slack channel where you can field your questions to Switcheo developers or the Switcheo dev community.
Data Types
There are some data types and attributes which Switcheo Exchange uses that have specific meanings and formats.
Here is a list of important data types:
Data Type |
---|
Addresses |
Amounts |
Contract Hashes |
Private Keys |
Signature |
Timestamp |
Addresses
An address
in Switcheo is always represented by a hex string, and is prefixed by a 0x
only if it is
an Ethereum address. Addresses should always be in a lowercase hex string representation.
NEO Addresses
Getting the user's address
const { wallet } = require('@cityofzion/neon-js')
wallet.getScriptHashFromPublicKey('031c37f6cce9627dc635d026deddd1200013c1b78dac767cdb507339a831183fd9')
// Result: 87cf67daa0c1e9b6caa1443cf5555b09cb3f8e5f
// you can also retrieve the script hash from a wallet address directly with:
wallet.getScriptHashFromAddress('AQV8FNNi2o7EtMNn4etWBYx1cqBREAifgE')
// Result: 87cf67daa0c1e9b6caa1443cf5555b09cb3f8e5f
For NEO, an address
refers to the RIPEMD160 hash of the the user's ECDSA public key.
An example implemention to derive an address
from a user's public key can be found in the
neon-js javascript library.
Please note the difference in terminology between Switcheo and neon-js. Switcheo's address
is equivalent to neon-js's scriptHash
.
Ethereum Addresses
For Ethereum, an addresses
refers to the Keccak hash of the right-most 160-bits of the user's ECDSA public key, as specified in the Ethereum Yellow Paper.
Ethereum addresses are sometimes displayed with uppercase letters for verification purposes. When submitting addresses through the Switcheo API however, the address should always be fully lowercased.
Amounts
When specifying amounts as request parameters, the amounts should first be converted by following these steps:
- Multiply the original amount by 10 to the power of the precision allowed by the given token.
- Drop any decimals, and convert the resulting integer to a string
For example, if the token's precision is 8
, and the original amount is 9.12345678
:
- Following the above steps:
9.12345678 * (10 ^ 8)
=912345678.00
- Drop any decimals to get:
912345678
- Convert the result to a string to get
"912345678"
The list of supported assets and their corresponding precisions can be found in the Tokens section.
Private Keys
Please check the documentation of the respective blockchains for signing with private keys.
For NEO, there is both a WIF and a private key.
Example WIF:
L479CJz4ZyxHiumy2viAjBFk8nixKeMY45DCQa5p4n4AT6M6WsWq
Example private key:
cd7b887c29a110e0ce53e81d6dd02805fc7b912718ff8b6659d8da42887342bd
The private key should be used for signing, not the WIF.
Contract Hashes
Use Get Contracts to get the correct blockchain smart contract you are referring to. There may be more than one version for a given blockchain, due to upgrades, as smart contracts are immutable. The correct contract hash must be used depending on whether you are using the TestNet or MainNet endpoints.
Signatures
Take note that not all parameters should be included to generate the signature, excluded parameters are specified in their respective endpoint's documentation. See signing request parameters for more information on how to sign each request based on the required blcokchain.
Timestamps
If a timestamp parameter is required, then it should first be fetched from the server using Get Timestamp. If the timestamp is not within an acceptable range of the exchange's timestamp then an invalid signature error will be returned.