NAV
shell javascript

Introduction

Alcor Exchange has HTTP and WebSocket api. Which can get information on various markets, orderboos, prices, events, and charts. WebSocket allows streaming for orderbook updates, new deals, and account events.

Interaction with Alcor is divided into 2 types:

Basic documentation can be found here: docs.alcor.exchange

URL Structure

HTTP API URL are separated by chains using following structute. The UI are following same structute as api, they are splitted by subdomains named by chain.

Chain URL
WAX https://wax.alcor.exchange/api/v2/
EOS https://eos.alcor.exchange/api/v2/
Proton https://proton.alcor.exchange/api/v2/
Telos https://telos.alcor.exchange/api/v2/

Node API

import fetch from 'node-fetch'
import { Api, JsonRpc, RpcError, JsSignatureProvider } from 'eosjs'

const rpc = new JsonRpc('https://eos.greymass.com', { fetch })
const signatureProvider = new JsSignatureProvider(['private key of order owner'])
const api = new Api({ rpc, signatureProvider, textDecoder: new TextDecoder(), textEncoder: new TextEncoder() });

Alcor is DEX, so, intereations with exchange, such as placing new order or order cancel, requires work with blockchain node api directly. Examples can be found in Trading API section.

Alcor support multiple EOSIO blockchains. Here is dex contract accounts across supported cahins:

You can easly interacting with alcor contracts using EOSJS library.

Alternatives:

Tokens

Token price

curl https://alcor.exchange/api/v2/tokens/tlm-alien.worlds

The above command returns JSON structured like this:

{
  "contract": "alien.worlds",
  "decimals": 4,
  "symbol": "TLM",
  "id": "tlm-alien.worlds",
  "system_price": 0.252009,
  "usd_price": 0.010197
}

Get single token price by id

HTTP Request

GET https://alcor.exchange/api/v2/tokens/:<token_id>

Responce

Name Type Description
contract string token contract
decimals number token precision
symbol string token symbol
id string token-id
system_price number token price in chain system token
usd_price number token price in USD

All tokens prices

curl https://alcor.exchange/api/v2/tokens

The above command returns JSON structured like this:

[
  {
    "contract": "alien.worlds",
    "decimals": 4,
    "symbol": "TLM",
    "id": "tlm-alien.worlds",
    "system_price": 0.252009,
    "usd_price": 0.010197
  },
  ...
]

Get all tokens with it's prices

HTTP Request

GET https://alcor.exchange/api/v2/tokens

Responce

Name Type Description
contract string token contract
decimals number token precision
symbol string token symbol
id string token-id
system_price number token price in chain system token
usd_price number token price in USD
curl https://wax.alcor.exchange/api/v2/tokens/wax-eosio.token/logo

Get token logo image (PNG) by token id.

HTTP Request

GET https://alcor.exchange/api/v2/tokens/<token_id>/logo

URL Parameters

Name Type Description
token_id string Token identifier (symbol-contract)

Response

Returns PNG image file if logo exists, or 404 error if not found.

Global Data

Stats

Returns global data on TVL, volumes, number of trading pairs, and so on

curl "https://alcor.exchange/api/v2/analytics/global"

The above command returns JSON structured like this:

{
  "_id": "wax",
  "totalValueLocked": 2240718.758763486,
  "swapValueLocked": 943995.9929317994,
  "spotValueLocked": 1296722.7658316866,
  "swapTradingVolume": 344377.66920321307,
  "spotTradingVolume": 26406.316737205285,
  "swapFees": 1063.6217236406346,
  "spotFees": 409.7303415365396,
  "dailyActiveUsers": 4063,
  "swapTransactions": 26347,
  "spotTransactions": 3163,
  "totalLiquidityPools": 1483,
  "totalSpotPairs": 808,
  "totalTradingVolume": 370783.9859404183
}

HTTP Request

GET https://alcor.exchange/api/v2/analytics/global

Query params:

Name Type Description Default
resolution string Accumulate results over a certain period of time 1D

Supported resolutions:

1D, 1W, 1M

Responce

Name Type Description
totalValueLocked number Exchange TVL
swapValueLocked number Total AMM Value locked in USD
spotValueLocked number Total spot value locked in open orders
swapTradingVolume number AMM trading volume
spotTradingVolume number Spot trading volume
swapFees number AMM fees
spotFees number Spot fees
dailyActiveUsers number avg Daily active users
swapTransactions number Total AMM swaps for period(resolution)
spotTransactions number Total spot trades for period(resolution)
totalLiquidityPools number Count of AMM pairs
totalSpotPairs number Count of spot pairs
totalTradingVolume number Total trading volume for given period(resolution)

Market Data

Token symbol repesented as SYMBOL_contract following the eosio.token standard. As the one symbol can be deployed by multiple contracts.

Trading pairs

Provides a list of all trading pairs on the Alcor DEX.

curl "https://alcor.exchange/api/v2/pairs"

The above command returns JSON structured like this:

[
  {
    "base": {
      "id": "pgl-prospectorsw",
      "contract": "prospectorsw",
      "symbol": "PGL",
      "precision": 4
    },
    "target": {
      "id": "wax-eosio.token",
      "contract": "eosio.token",
      "symbol": "WAX",
      "precision": 8
    },
    "ticker_id": "pgl-prospectorsw_wax-eosio.token"
  }
]

HTTP Request

GET https://alcor.exchange/api/v2/pairs

Query params:

Name Type Description
base string Filter pair by base currency id
target string Filter pair by target currency id

ie: https://alcor.exchange/api/v2/pairs?base=tlm-alien.worlds

Responce

Name Type Description
ticker_id string Identifier of a ticker with delimiter to separate base/target
base string Symbol code of a the base cryptoasset
target string Symbol code of the target cryptoasset

Ticker

curl "https://alcor.exchange/api/v2/tickers/tlm-alien.worlds_wax-eosio.token"

The above command returns JSON structured like this:

{
    "ticker_id": "tlm-alien.worlds_wax-eosio.token",
    "market_id": 26,
    "target_currency": "wax-eosio.token",
    "base_currency": "tlm-alien.worlds",
    "global_ticker_id": "TLM_WAX",
    "target_cmc_ucid": 825,
    "base_cmc_ucid": 2300
    "min_buy": "0.50000000 WAX",
    "min_sell": "1.0000 TLM",
    "last_price": 0.32448004,
    "change24": 3.42,
    "high24": 0.34088342,
    "low24": 0.30488872,
    "bid": 0.32448004,
    "ask": 0.32580358,
    "base_volume": 100178.36015088,
    "target_volume": 314152.7801
    "frozen": false,
    "fee": 20,
    "base_amm_liquidity": 3710.6035,
    "target_amm_liquidity": 649.92427661
}

Endpoint provides pricing and volume information on sprcific ticker.

Ticker ID represented as base token (Symbol-contract) _ quote_token (Symbol-contract) example: rda-deadcitytokn_wax-eosio.token

HTTP Request

GET https://alcor.exchange/api/v2/tickers/:ticker_id

Query Parameters

Parameter Mandatory Type Description
ticker_id true string Ticker id

Responce

Name Type Description
ticker_id string Identifier of a ticker
global_ticker_id string The ticker ID according to the standard of centralized exchanges (null for unpopular tokens)
base_currency string Symbol code of a the base cryptoasset
target_currency string Symbol code of the target cryptoasset
target_cmc_ucid number CMC integration target token UCID
base_cmc_ucid number CMC integration base token UCID
min_buy string Minimum amount of target currency
min_sell string Minimum amount of base currency
last_price number Price of the latest deal
change24 number Price change in 24 hours positive/negative
high24 number Highest price in 24 hours
low24 number Lowest price in 24
bid number Price of current highest buy order
ask number Price of current cheapest sell order
base_volume number 24H Volume of base currency
target_volume number 24H Volume of target currency
frozen boolean Trading are frozen
fee number Market fees represented as % of 1000 (fee / 1000)
base_amm_liquidity number Total base token liqiudity available on AMM contract
target_amm_liquidity number Total target token liqiudity available on AMM contract

Tickers

curl "https://alcor.exchange/api/v2/tickers"

The above command returns JSON structured like this:

[
    {
        "ticker_id": "tlm-alien.worlds_wax-eosio.token",
        "market_id": 26,
        "target_currency": "wax-eosio.token",
        "base_currency": "tlm-alien.worlds",
        "min_buy": "0.50000000 WAX",
        "min_sell": "1.0000 TLM",
        "last_price": 0.32448004,
        "change24": 3.42,
        "high24": 0.34088342,
        "low24": 0.30488872,
        "bid": 0.32448004,
        "ask": 0.32580358,
        "base_volume": 100178.36015088,
        "target_volume": 314152.7801
        "frozen": false,
        "fee": 20,
        "global_ticker_id": "TLM_WAX",
        "target_cmc_ucid": 2300,
        "base_cmc_ucid": 9119
        "base_amm_liquidity": 3710.6035,
        "target_amm_liquidity": 649.92427661
    }
]

Endpoint provides pricing and volume information on each market pair available on an exchange.

HTTP Request

GET https://alcor.exchange/api/v2/tickers

Without parameters returns all available tickers

Query Parameters

Parameter Mandatory Type Description
tickers false array Array of ticker_id's, for getting only selected tickers

Responce

Name Type Description
ticker_id string Identifier of a ticker
base_currency string Symbol code of a the base cryptoasset
target_currency string Symbol code of the target cryptoasset
min_buy string Minimum amount of target currency
min_sell string Minimum amount of base currency
last_price number Price of the latest deal
change24 number Price change in 24 hours positive/negative
high24 number Highest price in 24 hours
low24 number Lowest price in 24
bid number Price of current highest buy order
ask number Price of current cheapest sell order
base_volume number 24H Volume of base currency
target_volume number 24H Volume of target currency
frozen boolean Trading are frozen
fee number Market fees represented as 0.01%
global_ticker_id string The ticker ID according to the standard of centralized exchanges (null for unpopular tokens)
target_cmc_ucid number target Unified Cryptoasset ID if exist or null
base_cmc_ucid numer base Unified Cryptoasset ID if exist or null
base_amm_liquidity number Total base token liqiudity available on AMM contract
target_amm_liquidity number Total target token liqiudity available on AMM contract

Orderbook

curl "https://alcor.exchange/api/v2/tickers/pgl-prospectorsw_wax-eosio.token/orderbook?depth=3"

The above command returns JSON structured like this:

{
    "ticker_id": "PGL-prospectorsw_WAX-eosio.token",
    "asks": [
        [
            "0.66299999", // PRICE
            "111.8101" // QTY
        ],
        [
            "0.66300000",
            "237.5000"
        ],
        [
            "0.66400000",
            "500.0000"
        ],
    ],
    "bids": [
        [
            "0.64800031",
            "74.51997085"
        ],
        [
            "0.64800030",
            "87.64158563"
        ],
        [
            "0.64598927",
            "150.00000000"
        ],
    ]
}

Endpoint using to provide order book information with at least depth = 3 returned for a given ticker.

HTTP Request

GET https://alcor.exchange/api/v2/tickers/:ticker_id/orderbook

Query Parameters

Parameter Mandatory Default Description
ticker_id true string ticker id
depth false 300 The number of market depth to return on each side

Responce

Name Type Description
ticker_id string Identifier of a ticker with delimiter to separate base/target
bids array Array of bids. bid structure: [price, quantity]
asks array Array of asks. ask structure: [price, quantity]

Latest Trades

Retrieve the most recent deals of a ticker, sorted by time from latest to oldest.

curl "https://alcor.exchange/api/v2/tickers/pgl-prospectorsw_wax-eosio.token/latest_trades?limit=2"

The above command returns JSON structured like this:

[
    {
        "trade_id": "61a0fd5b5f0f4674848b26ae",
        "base_volume": 48.8126,
        "target_volume": 29.52941386,
        "price": 0.604955,
        "time": 1637929769500,
        "type": "buy"
    },
    {
        "trade_id": "61a0fcf65f0f4674848b0cf4",
        "base_volume": 12.9939,
        "target_volume": 7.86070962,
        "price": 0.60495104,
        "time": 1637929668000,
        "type": "sell"
    }
]

HTTP Request

GET https://alcor.exchange/api/v2/tickers/:ticker_id/latest_trades

Query Parameters

Parameter Mandatory Default Description
limit false 300 The number of latest trades to return

Trade history

Retrieve the recent transactions of an instrument, sorted by time from earlyer to latest.

curl "https://alcor.exchange/api/v2/tickers/pgl-prospectorsw_wax-eosio.token/historical_trades?limit=2"

The above command returns JSON structured like this:

[
    {
        "base_volume": 48.8126,
        "price": 0.604955,
        "target_volume": 29.52941386,
        "time": 1637929769500,
        "trade_id": "61a0fd5b5f0f4674848b26ae",
        "type": "buy"
    },
    {
        "base_volume": 12.9939,
        "price": 0.60495104,
        "target_volume": 7.86070962,
        "time": 1637929668000,
        "trade_id": "61a0fcf65f0f4674848b0cf4",
        "type": "sell"
    }
]

Endpoint using to return data on historical completed trades for a given ticker.

HTTP Request

GET https://alcor.exchange/api/v2/tickers/:ticker_id/historical_trades

Sorting from lasted to oldest deals

Query Parameters

Parameter Type Description
type string Filter by "sell" or "buy" trades
limit integer Number of trades to retrieve
step integer Offset, used for step-by-step loading of the entire history
from timestamp Start time from which to query trades (milliseconds)
to timestamp End time for historical trades (milliseconds)

Responce

Name Type Description
trade_id string A unique ID associated with the trade
price decimal Transaction price.
base_volume decimal Transaction amount in base pair volume
target_volume decimal Transaction amount in target pair volume.
time timestamp Unix timestamp in milliseconds for when the transaction occurred.
type string Type of the transaction that was completed.

Klines (Candles)

curl "https://alcor.exchange/api/v2/tickers/pgl-prospectorsw_wax-eosio.token/charts?resolution=60&from=1637856799500&to=1637869859000"

The above command returns JSON structured like this:

[
    {
        "close": 0.57009415,
        "high": 0.58999718,
        "low": 0.57009415,
        "open": 0.58999718,
        "time": 1637856799500,
        "volume": 1.34580567 // Volume in TARGET currency
    },
    {
        "close": 0.5889,
        "high": 0.5889,
        "low": 0.553,
        "open": 0.57009415,
        "time": 1637859602500,
        "volume": 817.85241392
    }
]

This endpoint retrieves klines for specific ticker in a specific range.

HTTP Request

GET https://alcor.exchange/api/v2/tickers/:ticker_id/charts

Query Parameters

from, to, resolution, limit

Parameter Mandatory Type Description
ticker_id true string Ticker id
resolution true string Resolution
from false timestamp Start time for getting historical candles
to false timestamp End time till which query candles

Supported resolutions:

1, 5, 15, 30, 60, 240, 1D, 1W, 1M

Swap

Alcor is a protocol based on the AMM concept using concentrated liquidity. Allowing you to change one eosio.token to another.

Pool

curl https://alcor.exchange/api/v2/swap/pools/0

Get pool by ID

The above command returns JSON structured like this:

{
  "chain": "wax",
  "id": 1095,
  "active": true,
  "fee": 3000,
  "feeGrowthGlobalAX64": "212803631582389957186",
  "feeGrowthGlobalBX64": "1171129874747599",
  "feeProtocol": 3,
  "liquidity": "951789470700",
  "maxLiquidityPerTick": "1247497401346422",
  "protocolFeeA": 10681.09414088,
  "protocolFeeB": 703.6308,
  "sqrtPriceX64": "45802571509710763",
  "tick": -119973,
  "tickSpacing": 60,
  "tokenA": {
    "contract": "eosio.token",
    "decimals": 8,
    "symbol": "WAX",
    "id": "wax-eosio.token",
    "quantity": 1413257.13064633
  },
  "tokenB": {
    "contract": "usdt.alcor",
    "decimals": 4,
    "symbol": "USDT",
    "id": "usdt-usdt.alcor",
    "quantity": 81673.5964
  },
  "volumeA24": 60225.61186526,
  "volumeAMonth": 12102207.71289808,
  "volumeAWeek": 2865840.95504714,
  "volumeB24": 3703.4195999999997,
  "volumeBMonth": 823163.2468,
  "volumeBWeek": 175806.8865,
  "volumeUSD24": 7440.385309538387,
  "volumeUSDMonth": 1649849.915091903,
  "volumeUSDWeek": 353479.23752087017,
  "tvlUSD": 168895.21809226653,
  "change24": 0.3,
  "changeWeek": -0.49,
  "high24": 0,
  "low24": 0,
  "priceA": 0.0623307,
  "priceB": 16.0435
}

Query params:

Pool id should be provided inside the URL structure

Name Type Description required
pool_id number Pool ID true

HTTP Request

GET https://alcor.exchange/api/v2/swap/pools/:<pool_id>

Responce

Name Type Description
id number pool ID
active number is pool active
fee number fee percent as part of (fee / 10000)
feeGrowthGlobalAX64 number Global accumulated fee for token A
feeGrowthGlobalBX64 number Global accumulated fee for token B
feeProtocol number Protocol fee percent
liquidity number Pool liquidity amount
maxLiquidityPerTick number Pool max liquidity ber one tick
protocolFeeA asset Protocol earned fees
protocolFeeB asset Protocol earned fees
sqrtPriceX64 number Pool price as sqrtPriceX64
tick number Pool current tick
tickSpacing number Pool tick spacing
tokenA object Token A
tokenB object Token B
volumeUSD24 number USD Volume for 24H
volumeUSDWeek number USD Volume for 7D
volumeUSDMonth number USD Volume for 30D
volumeA24 number 24H volume of token A
volumeAWeek number 7D volume of token A
volumeAMonth number 30D volume of token A
volumeB24 number 24H volume of token B
volumeBWeek number 7D volume of token B
volumeBMonth number 30D volume of token B
volumeUSD24 number USD Volume for 24H
volumeUSDWeek number USD Volume for 7D
volumeUSDMonth number USD Volume for 30D
tvlUSD number Total Value Locked in USD
change24 number 24H price change
changeWeek number 7D price change
high24 number 24H price high
low24 number 24H price low
priceA number token A price in terms of token B
priceB number token B price in terms of token A

Pools

curl https://alcor.exchange/api/v2/swap/pools

Get all swap pools

The above command returns JSON structured like this:

[
  {
    "chain": "wax",
    "id": 1095,
    "active": true,
    "fee": 3000,
    "feeGrowthGlobalAX64": "212803631582389957186",
    "feeGrowthGlobalBX64": "1171129874747599",
    "feeProtocol": 3,
    "liquidity": "951789470700",
    "maxLiquidityPerTick": "1247497401346422",
    "protocolFeeA": 10681.09414088,
    "protocolFeeB": 703.6308,
    "sqrtPriceX64": "45802571509710763",
    "tick": -119973,
    "tickSpacing": 60,
    "tokenA": {
      "contract": "eosio.token",
      "decimals": 8,
      "symbol": "WAX",
      "id": "wax-eosio.token",
      "quantity": 1413257.13064633
    },
    "tokenB": {
      "contract": "usdt.alcor",
      "decimals": 4,
      "symbol": "USDT",
      "id": "usdt-usdt.alcor",
      "quantity": 81673.5964
    },
    "volumeA24": 60225.61186526,
    "volumeAMonth": 12102207.71289808,
    "volumeAWeek": 2865840.95504714,
    "volumeB24": 3703.4195999999997,
    "volumeBMonth": 823163.2468,
    "volumeBWeek": 175806.8865,
    "volumeUSD24": 7440.385309538387,
    "volumeUSDMonth": 1649849.915091903,
    "volumeUSDWeek": 353479.23752087017,
    "tvlUSD": 168895.21809226653,
    "change24": 0.3,
    "changeWeek": -0.49,
    "high24": 0,
    "low24": 0,
    "priceA": 0.0623307,
    "priceB": 16.0435
  }
  ...
]

HTTP Request

GET https://alcor.exchange/api/v2/swap/pools

Responce

Name Type Description
id number pool ID
active number is pool active
fee number fee percent as part of (fee / 10000)
feeGrowthGlobalAX64 number Global accumulated fee for token A
feeGrowthGlobalBX64 number Global accumulated fee for token B
feeProtocol number Protocol fee percent
liquidity number Pool liquidity amount
maxLiquidityPerTick number Pool max liquidity ber one tick
protocolFeeA asset Protocol earned fees
protocolFeeB asset Protocol earned fees
sqrtPriceX64 number Pool price as sqrtPriceX64
tick number Pool current tick
tickSpacing number Pool tick spacing
tokenA object Token A
tokenB object Token B
volumeA24 number 24H volume of token A
volumeAWeek number 7D volume of token A
volumeAMonth number 30D volume of token A
volumeB24 number 24H volume of token B
volumeBWeek number 7D volume of token B
volumeBMonth number 30D volume of token B
volumeUSD24 number USD Volume for 24H
volumeUSDWeek number USD Volume for 7D
volumeUSDMonth number USD Volume for 30D
tvlUSD number Total Value Locked in USD
change24 number 24H price change
changeWeek number 7D price change
high24 number 24H price high
low24 number 24H price low
priceA number token A price in terms of token B
priceB number token B price in terms of token A

Pool Swaps

Retrieve swap transactions for a specific pool.

curl "https://alcor.exchange/api/v2/swap/pools/1095/swaps"

The above command returns JSON structured like this:

[
  {
    "_id": "6528d7e4eef91d4d098a39ef",
    "pool": 1095,
    "recipient": "jollewaxacc1",
    "trx_id": "35b62eb272381b6482272f0022d5778e6154a29b334a87a1bda37251c6acbb2e",
    "sender": "jollewaxacc1",
    "sqrtPriceX64": "44952921109377512",
    "totalUSDVolume": 0.9253599213188954,
    "tokenA": 17.60908915,
    "tokenB": -1.0907,
    "time": "2023-05-06T08:59:51.000Z"
  },
]

HTTP Request

GET https://alcor.exchange/api/v2/swap/pools/:id/swaps

Query Parameters

Name Type Description Required
from timestamp Start time from which to query swaps (milliseconds) false
to timestamp End time till which to query swaps (milliseconds) false
recipient string Account that received the swap false
sender string Account that sent the swap false
limit integer Number of swaps to retrieve false
skip integer Number of swaps to skip false

Response

Name Type Description
pool number Pool ID
recipient string Account that received the swap
trx_id string Transaction ID
sender string Account that sent the swap
sqrtPriceX64 string Sqrt price X64
totalUSDVolume number Total USD volume
tokenA object Token A amount
tokenB object Token B amount
time timestamp Time of the swap (milliseconds)

Pool Positions

curl https://alcor.exchange/api/v2/swap/pools/0/positions

The above command returns JSON structured like this:

[
  {
    "id": 0,
    "owner": ".11dm.wam",
    "tickLower": -443580,
    "tickUpper": 443580,
    "liquidity": 843101,
    "feeGrowthInsideALastX64": "0",
    "feeGrowthInsideBLastX64": "0",
    "feesA": 0,
    "feesB": 0,
    "pool": 0,
    "amountA": "1.6781 TLM",
    "amountB": "0.42356913 WAX"
  },
  ...
]

API for getting all positions of pool

HTTP Request

GET https://alcor.exchange/api/v2/swap/pools/<:pool_id>/positions

Query params:

Pool id should be provided inside the URL structure

Name Type Description required
pool_id number Pool ID true

Responce

Name Type Description
id number position id
owner string position owner account
tickLower number lower tick of position
tickUpper number upper tick of position
liquidity number position liquidity amount
feeGrowthInsideALastX64 number token A fees grow value
feeGrowthInsideBLastX64 number token B fees grow value
feesA number token A accumulated fees
feesB number token B accumulated fees
pool number pool ID
amountA asset Positoin token A amount
amountB asset Positoin token B amount

Output & Route calculation

curl "https://alcor.exchange/api/v2/swapRouter/getRoute?trade_type=EXACT_INPUT&input=wax-eosio.token&output=tlm-alien.worlds&amount=1.00000000&slippage=0.30&receiver=alcordexfund&maxHops=2"

The above command returns JSON structured like this:

{
    "executionPrice": {
        "denominator": "100000000",
        "numerator": "39285"
    },
    "input": "1.00000000",
    "maxSent": "1.00000000",
    "memo": "swapexactin#0#alcordexfund#3.9167 TLM@alien.worlds#0",
    "minReceived": "3.9167",
    "output": "3.9285",
    "priceImpact": "0.3",
    "route": [
        0
    ]
}

Finding the best route for given input/output

To calculate output amount based on input amount use trade_type EXACT_INPUT To calculate input amount based on output amount use trade_type EXACT_OUTPUT

HTTP Request

GET https://alcor.exchange/api/v2/swapRouter/getRoute

Query params:

Name Type Description required
trade_type string EXACT_OUTPUT or EXACT_INPUT true
input string Input token ID true
output string Output token ID true
amount number Amount of input/output(depends on trade_type) true
slippage number permissible slippage false
receiver string Account to receive output false
maxHops number Maximum number of intermediate pools for exchange route false

Responce

Name Type Description
executionPrice object Execution price in format for Price object from Swap-SDK.
input number Input Amount
output number Output Amount
maxSent number Amount(with slippage included) to get exact output
memo string Memo for the transfer action
minReceived number Amount to receive with max slippage
priceImpact number Swap price impact percent
route array[number] Sequence of the pools id's that swap will use

Account

Account data api

Account Spot Deals

curl https://alcor.exchange/api/v2/account/<account>/deals

The above command returns JSON structured like this:

[
  {
    "_id": "6675d517cbc8490fd50823ab",
    "market": 763,
    "type": "buymatch",
    "trx_id": "14169e8d274786b984917c79f14cefa4e13d2dc823604d47f88a11c116d9e901",
    "unit_price": 0.0410099,
    "ask": 2.75797508,
    "asker": "foreverstone",
    "bid": 0.1131,
    "bidder": "alcordexfund",
    "time": "2024-06-21T19:31:33.000Z"
  },
  ...
]

API for getting the spot deals history of a specific account.

HTTP Request

GET https://alcor.exchange/api/v2/account/<account>/deals

Query params:

Name Type Description Required
account string Account ID true
from number Start time in seconds false
to number End time in seconds false
limit number Limit of records to return false
skip number Number of records to skip false
market number Market ID false

Response

Name Type Description
_id string Deal ID
market number Market ID
type string Type of the deal
trx_id string Transaction ID
unit_price number Unit price
ask number Ask amount
asker string Asker account
bid number Bid amount
bidder string Bidder account
time string Time of the deal

Account Positions

curl https://alcor.exchange/api/v2/account/<account>/positions

The above command returns JSON structured like this:

[
 {
    "id": 13095,
    "owner": "alcordexfund",
    "tickLower": 40140,
    "tickUpper": 65520,
    "liquidity": "1009363631498",
    "feeGrowthInsideALastX64": "0",
    "feeGrowthInsideBLastX64": "0",
    "feesA": "41789.8580 BRWL",
    "feesB": "1873.58385095 WAX",
    "pool": 667,
    "depositedUSDTotal": 9782.8141,
    "closed": false,
    "collectedFees": {
      "tokenA": 0,
      "tokenB": 0,
      "inUSD": 0
    },
    "inRange": false,
    "amountA": "0.0000 BRWL",
    "amountB": "192032.76838783 WAX",
    "totalValue": 7755.19,
    "pNl": -2027.6241
  },
  ...
]

API for getting all positions belong to specific account

HTTP Request

GET https://alcor.exchange/api/v2/swap/pools/<:pool_id>/positions

Query params:

Pool id should be provided inside the URL structure

Name Type Description required
pool_id number Pool ID true

Responce

Name Type Description
id number position id
owner string position owner account
tickLower number lower tick of position
tickUpper number upper tick of position
liquidity number position liquidity amount
feeGrowthInsideALastX64 number token A fees grow value
feeGrowthInsideBLastX64 number token B fees grow value
feesA number token A accumulated fees
feesB number token B accumulated fees
pool number pool ID
amountA asset Positoin token A amount
amountB asset Positoin token B amount

depositedUSDTotal | number | total USD value deposited to position closed | number | is position closed collectedFees | object | Fees collected by position inRange | Boolean | is position in range totalValue | number | Total position value in USD pNl | number | Profit & Loss (totalValue - depositedUSDTotal)

Account Positions History

curl https://alcor.exchange/api/v2/account/<account>/positions-history

The above command returns JSON structured like this:

[
  {
    "_id": "666fe1a9248953a275e29568",
    "tokenAUSDPrice": 0.04254746,
    "tokenBUSDPrice": 0.622996928304,
    "owner": "alcordexfund",
    "type": "collect",
    "id": 43827,
    "pool": 1259,
    "tokenA": 740.63011288,
    "tokenB": 39.0449,
    "totalUSDValue": 55.8368,
    "trx_id": "cee97277979cee5ffcfa7df078050ecce9026e87b7b3eced7e517e6b10c9348c",
    "time": "2024-06-17T07:11:35.000Z"
  },
  ...
]

API for getting the position history of a specific account.

HTTP Request

GET https://alcor.exchange/api/v2/account/<account>/positions-history

Query params:

Name Type Description Required
account string Account ID true
limit number Limit of records to return false
skip number Number of records to skip false

Response

Name Type Description
_id string Position history ID
tokenAUSDPrice number Token A USD price
tokenBUSDPrice number Token B USD price
owner string Position owner account
type string Type of the position history
id number Position history ID
pool number Pool ID
tokenA number Token A amount
tokenB number Token B amount
totalUSDValue number Total USD value
trx_id string Transaction ID
time string Time of the position history

Account Swap History

curl https://alcor.exchange/api/v2/account/<account>/swap-history

The above command returns JSON structured like this:

[
  {
    "_id": "6670108cebb327bcc470ffc3",
    "pool": 1166,
    "trx_id": "e9815f8ca7af5d56d08a0163ec98f1142db097ee0d356b49cb3fb2182d596006",
    "sender": "alcordexfund",
    "sqrtPriceX64": "335692961505657228690",
    "totalUSDVolume": 20.3636278111581,
    "tokenA": 14027.5692,
    "tokenB": -480.37435682,
    "time": "2024-06-17T10:31:37.500Z"
  },
  ...
]

API for getting the swap history of a specific account.

HTTP Request

GET https://alcor.exchange/api/v2/account/<account>/swap-history

Query params:

Name Type Description Required
account string Account ID true
limit number Limit of records to return false
skip number Number of records to skip false

Response

Name Type Description
_id string Swap history ID
pool number Pool ID
trx_id string Transaction ID
sender string Swap sender account
sqrtPriceX64 string Square root price X64
totalUSDVolume number Total USD volume
tokenA number Token A amount
tokenB number Token B amount
time string Time of the swap history

OnChain Data

To fetch data (orders/markets) directly from blockchain you have to use NodeAPI

Contract tables structute can be found here https://docs.alcor.exchange

Markets

cleos -u https://wax.greymass.com get table alcordexmain alcordexmain markets
import fetch from 'node-fetch'
import { Api, JsonRpc, RpcError } from 'eosjs'

const rpc = new JsonRpc('https://wax.greymass.com', { fetch })

// Get markets
const { rows } = await rpc.get_table_rows({
  code: 'alcordexmain', // dex account
  table: 'buyorder', // side
  limit: 1000,
  scope: 'alcordexmain', // scope same as contract name
})

The above command returns JSON structured like this:

{
  "rows": [{
      "id": 0,
      "base_token": {
        "sym": "8,WAX",
        "contract": "eosio.token"
      },
      "quote_token": {
        "sym": "4,PGL",
        "contract": "prospectorsw"
      },
      "min_buy": "0.00000100 WAX",
      "min_sell": "0.0001 PGL",
      "frozen": 0,
      "fee": 0
    }, ...]
}

Markets are stored in markets table, scoped by contract name.

market_id are used as scope for orders table and should be provided as parameter for canceling order.

Table structute

key description
id market_id
base_token target currency
quote_token base_token currency
min_buy Min buy amount
min_sell Min sell amount
frozen Market are frozen if 1
fee Market fee

Orders

cleos -u https://wax.greymass.com get table alcordexmain 26 buyorder -l 2
import fetch from 'node-fetch'
import { Api, JsonRpc, RpcError } from 'eosjs'

const rpc = new JsonRpc('https://wax.greymass.com', { fetch })

// Get buy orderbook from conract table

const { rows } = await rpc.get_table_rows({
  code: 'alcordexmain',
  table: 'buyorder',
  limit: 1000, // limit up to 1000
  scope: 26, // Market id from /api/markets or markets table
  key_type: 'i128', // we are using it for getting order sorted by price.
  index_position: 2
})

The above command returns JSON structured like this:

{
  "rows": [{
      "id": 28,
      "account": "pxawpxawpxaw",
      "bid": "10.00000000 WAX",
      "ask": "1999.9560 TLM",
      "unit_price": "500012",
      "timestamp": 1603653505
    },{
      "id": 276,
      "account": "e43am.waa",
      "bid": "35.00000000 WAX",
      "ask": "5000.0000 TLM",
      "unit_price": "700000",
      "timestamp": 1609173873
    }
  ],
  "more": true,
  "next_key": "558"
}

Orders are stored in buyorder and sellorder tables. Scoped by market_id(you can find one in markets table)

Table structute

key description
id order id
account order owner account
unit_price Price in integer
timestamp Order time creation

WebSocket

import { io } from 'socket.io-client'

const socket = io('https://alcor.exchange')

Alcor using Socket.IO for interact via WebSocket technology.

There are two commands for subscribing to and channel with specific information.

You can subscribe to rooms to receive specific event information.

Deals

// Subscribe to deals
socket.emit('subscribe', {
    room: 'deals',
    params: {
        chain: 'wax', // Chain
        market: 26 // Market id
    }
})

// Handle new deals
socket.on('new_deals', deals => { ... })

// Unsubscribe from deals (will unsubscribe from all markets)
socket.emit('unsubscribe', { room: 'deals', params: { chain: 'wax' } })

Responce:

[
    {
      "time": 1674820074000,
      "ask": 3.5771,
      "bid": 0.99799129,
      "type": "buymatch",
      "unit_price": 0.27899985,
      "trx_id": "d4acaa5ae75bccad12ca82dd2d1d3fa5822cece1307ced10ee0daefaeb6d5009"
    }
]

Subscribing to new deals for specific market.

Room name: deals

Params:

Key Value
chain chain id
market market id

Orderbook

// Subscribe to buy orderbook of 26 (TLM on wax) market.
socket.emit('subscribe', {
    room: 'deals',
    params: {
        chain: 'orderbook', // Chain
        market: 26, // Market id,
        side: 'buy'
    }
})

// On orderbook bid side update
socket.on('orderbook_buy', bids => { ... })

// On orderbook ask side update
socket.on('orderbook_sell', asks => { ... })

// Unsubscribe from orderbook (all, buy and sell)
socket.emit('unsubscribe', { room: 'orderbook', params: { chain: 'wax', market: 26 } })

Responce:

[
    [
      27899985,
      3044158,
      8493196253
    ]
]

Subscribe to orderbook updates. First update is full order book state.

Room name: orderbook

Params:

Key Value
chain chain id
market market id
side sell or buy

Ticker

// Subscribe
socket.emit('subscribe', {
  room: 'ticker',
  params: {
    chain: 'wax',
    market: 26,
    resolution: '30'
  }
})

// Unsubscribe
socket.emit('unsubscribe', {
  room: 'ticker',
  params: {
    chain: 'wax',
    market: 26,
    resolution: '30'
  }
})

Responce:

[
  "tick",
  {
    "close": 0.01175084,
    "open": 0.01175084,
    "high": 0.01175084,
    "low": 0.01175084,
    "volume": 0.11727339,
    "time": 1674821301500
  }
]

Subscribe for chart updates.

Room name: ticker

Params:

Key Value
chain chain id
market market id
resolution Resolution (see list below)

Supported resolutions:

1, 5, 15, 30, 60, 240, 1D, 1W, 1M

Account

socket.emit('subscribe', {
    room: 'account', params: {
        chain: 'wax',
        'name': 'randomuser' // Account for listen events
    }
})

Responce

[
  "match",
  {
    "ask": 0.11727339,
    "market_id": 156,
    "price": 0.01175084
  }
]

Subscribe to account events/notifications. Only order matches for now.

Room name: account

Params:

Key Value
chain chain id
name Account

Trade API

To trade assets you sould use Blockchain API directly. More information on Interaction/NodeAPI.

Place order

cleos push action tktoken transfer \
    '[bob, alcordexmain, "0.5000 TKT", "0.0010 EOS@eosio.token"]' -p bob
const actions = [{
  account: 'tktoken', // token contract
  name: 'transfer',
  authorization: [{
    actor: 'useraaaaaaaa', // account placing order (owner)
    permission: 'active',
  }],
  data: {
    from: 'useraaaaaaaa',
    to: 'alcordexmain',
    quantity: '0.5000 TKT', // Bid
    memo: '0.0001 EOS@eosio.token' // Ask
  }
}]

// Result of transaction
const r = await api.transact(actions)

Bob are selling 0.5 TKT and buying 0.001 EOS.

Send the amount(bid) you want to sell to dex contract account, and specify the amount you ask in the memo, the price and market will be automatically determined in the contract.

Memo format(ask token): <token_amount> <token_symbol>@<token_contract>

Place multiple orders

Same way as described but transaction may contain multiple actions(array).

Cancel order

cleos push action alcordexmain cancelsell \
    '[bob, 262, 1284277]' -p bob
const result = await api.transact([
    {
        account: 'tktoken',
        name: 'transfer',
        authorization: [{
          actor: 'useraccountname',
          permission: 'active',
        }],
        data: {
          from: 'useraccountname',
          to: 'alcordexmain',
          quantity: '0.5000 TKT',
          memo: '0.0010 EOS@eosio.token'
        }
    }
]);

Bob are canceling sell order on 262 market.

Call action cancelsell or cancelbuy with parameters:

CPU Payer (WAX only)

Alcor provides a free CPU payer service for WAX blockchain that covers transaction CPU costs for users interacting with Alcor contracts. This uses the ONLY_BILL_FIRST_AUTHORIZER mechanism.

How it works

  1. Client checks /status endpoint to see if service is available
  2. If available, client builds transaction with liquid.alcor::noop as first action
  3. Client signs the transaction (only their actions, noop has payer's auth)
  4. Client sends serialized transaction to /cosign endpoint
  5. Worker validates and cosigns for liquid.alcor@bw
  6. Client combines signatures and pushes to blockchain
  7. CPU cost is billed to liquid.alcor (first authorizer)

Status

curl -X POST https://wax.alcor.exchange/api/v2/cpu/status \
  -H "Content-Type: application/json"

The above command returns JSON structured like this:

{
  "available": true,
  "signing": true,
  "throttled": false,
  "cpu": {
    "used": 100000,
    "max": 400000,
    "percent": 25.0
  },
  "lastCheck": 1705123456789
}

Check if CPU payer service is available and signing.

HTTP Request

POST https://wax.alcor.exchange/api/v2/cpu/status

Response

Name Type Description
available boolean Whether the service is available
signing boolean Whether the service is currently signing transactions
throttled boolean Whether rate limiting is in effect
cpu object Current CPU usage info
cpu.used number Current CPU usage in microseconds
cpu.max number Maximum CPU available in microseconds
cpu.percent number CPU usage percentage
lastCheck number Timestamp of last CPU status check

Cosign

curl -X POST https://wax.alcor.exchange/api/v2/cpu/cosign \
  -H "Content-Type: application/json" \
  -d '{"serializedTransaction": "..."}'

The above command returns JSON structured like this:

{
  "signature": "SIG_K1_..."
}

Cosign a pre-built transaction. The transaction must have liquid.alcor::noop as the first action with liquid.alcor@bw authorization.

HTTP Request

POST https://wax.alcor.exchange/api/v2/cpu/cosign

Request Body

Name Type Description Required
serializedTransaction string Hex-encoded serialized transaction true

Response

Name Type Description
signature string The payer's signature (SIG_K1_...)

Errors

{
  "error": "Rate limit exceeded"
}
Error Description
Rate limit exceeded Too many requests from this IP or account
Invalid transaction Transaction format is invalid
First action must be noop Transaction doesn't start with liquid.alcor::noop
Unauthorized contract Transaction contains actions to non-whitelisted contracts
Service unavailable CPU payer is currently disabled or overloaded

Rate Limits

Limit Default Description
Per IP (hourly) 500 Requests per IP per hour
Per Account (hourly) 300 Requests per WAX account per hour
Per IP (daily) 5000 Requests per IP per day
Per Account (daily) 2000 Requests per WAX account per day
Global (hourly) 10000 Total requests per hour
Global (daily) 80000 Total requests per day

Allowed Contracts

Transactions can only contain actions to whitelisted Alcor contracts:

Any transfer actions where the recipient (to) is one of the Alcor contracts above are also allowed.

Bridge

The Alcor bridge moves tokens between Ethereum, BNB Smart Chain, Telos and WAX. For partners the interesting route is Ethereum → WAX. The user signs one transaction on Ethereum and the bridge delivers the tokens to their WAX account by itself: there is nothing to claim and no WAX wallet involved. Small deposits usually arrive in 13–20 minutes. The live estimate is in Chains.

There are four ways to integrate it:

https://alcor.exchange/v/wax/bridge?from=ethereum&to=wax&recipient=alice.wam&token=USDC&amount=50&partner=mygame&return_url=https://mygame.io/play

A plain URL to the bridge page with the transfer already filled in. No code is needed on your side.

Query Parameters

Parameter Example Description
from ethereum Chain to start on. The user can still change it.
to wax Chain the tokens land on.
recipient alice.wam Receiving account, prefilled. The user can edit it on this page.
token USDC Asset, by the symbol the bridge lists (USDC, USDT, ETH).
amount 50 Prefilled amount, in token units.
partner mygame Your id, so the deposits you bring are attributed to you.
return_url https://mygame.io/play Shows a "← Back to mygame.io" link. https only (http is allowed on localhost).

All parameters are optional. A malformed value is ignored rather than guessed at.

Deposit widget

// <script src="https://alcor.exchange/sdk/bridge/v1.js"></script>

document.getElementById('deposit').onclick = function () {
  AlcorBridge.open({
    to: 'wax',
    recipient: 'alice.wam',   // fixed: the user cannot change it
    token: 'USDC',
    amount: '50',
    partner: 'mygame',
    onSent: function (e) { console.log('on its way', e.transactions) },
    onFinished: function (e) {
      if (e.outcome === 'delivered') refreshBalance()
    },
    onClose: function () {},
  })
}
# Without the script: embed the widget yourself
<iframe src="https://alcor.exchange/embed/bridge?to=wax&recipient=alice.wam&token=USDC&partner=mygame&mode=inline"
        style="width:100%;max-width:480px;height:640px;border:0"></iframe>

Load https://alcor.exchange/sdk/bridge/v1.js and call one of its functions. The script is tiny and has no dependencies. The path is versioned: v1.js keeps its options and events for as long as anyone uses it.

Functions

Function Shows Returns
AlcorBridge.open(options) Modal over your page { close() }
AlcorBridge.popup(options) Separate window. Call it from a click handler. { close() }, or null if the popup was blocked
AlcorBridge.mount(element, options) Inline iframe that grows with its content { destroy() }
AlcorBridge.url(options) Nothing. Returns the widget address for your own iframe or link. string

Browser extension wallets (MetaMask, Rabby) and WalletConnect work in all modes. In the popup the user's existing Alcor session and wallet connection carry over.

Options

Option Required Description
to true Chain the tokens land on: wax, telos or ethereum. Into WAX the bridge pays out by itself. A deposit to Telos ends with a Collect step signed on Telos, and a withdrawal to Ethereum with a Release step signed on Ethereum. The widget shows that button when its turn comes.
recipient false Receiving account. When given, it is fixed in the widget. For WAX, the widget checks that the account exists before anything is signed.
from false Chain to start on. Defaults to ethereum, or telos when to is Ethereum.
token false USDC, USDT, ETH.
amount false Prefilled amount, in token units.
partner false Your id, for attribution.
origin false Where the widget is served from. Defaults to the origin of the script itself.
onReady, onSent, onFailed, onFinished, onClose false Event callbacks, see below.

Events

onSent receives:

{
  "direction": "hop",
  "from_chain": "ethereum",
  "to_chain": "wax",
  "token": "USDC",
  "amount": "50",
  "sender": "0x285202c8db763db06ab42e0705104cb7919ef95e",
  "recipient": "alice.wam",
  "partner": "mygame",
  "embed": "iframe",
  "transactions": [
    { "chain": "Ethereum", "label": "Send", "ref": "0x0af8…2917", "url": "https://etherscan.io/tx/0x0af8…2917" }
  ]
}

onFinished receives:

{
  "key": "d:1:12",
  "outcome": "delivered",
  "token": "USDC",
  "amount": "50",
  "transactions": [ … ]
}
Callback When Data
onReady The widget has loaded and is prefilled { to, recipient }
onSent The user signed and the transfer is on its way Transfer details and the first transaction
onFailed The transfer could not be started, e.g. rejected in the wallet Transfer details plus errorCode, error
onFinished The transfer reached its end { key, outcome, token, amount, transactions }
onClose The user closed the widget {}

outcome is delivered, or returned if the destination refused the tokens and they went back to the sender. key identifies the transfer in Transfer status.

Messages

If you embed the iframe yourself, listen for postMessage events from https://alcor.exchange:

{ source: "alcor-bridge", version: 1, type, data }

Type Data
ready, sent, failed, finished, close Same as the callbacks above
resize { height }, the content height in pixels, so you can size the iframe

Add mode=inline to the widget URL to hide its close button. Everything in the messages is public on-chain data.

Bridge API

Read-only HTTP API of the bridge indexer, open to any origin (CORS *).

https://telos.alcor.exchange/api/bridge/v1/

Chains are named by id: mainnet (Ethereum), bsc (BNB Smart Chain), telos-production (Telos), wax (WAX). Amounts are integers in the asset's smallest unit. Divide by 10^precision.

Routes

curl https://telos.alcor.exchange/api/bridge/v1/routes

The above command returns JSON structured like this:

{
  "routes": [
    {
      "symbol": "USDC",
      "precision": 6,
      "from": "mainnet",
      "to": "wax",
      "via": "telos-production",
      "open": true,
      "min": "5000000",
      "max": "98735000000",
      "how": {
        "deposit": {
          "token": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48",
          "telosTo": "hop.alcor",
          "memo": "1181148696416462999:<account>|1:<your address>"
        }
      }
    }
  ]
}

Every way each asset can travel right now, with its limits.

HTTP Request

GET https://telos.alcor.exchange/api/bridge/v1/routes

Response

Name Type Description
symbol string Asset symbol
precision number Decimals of min and max
from, to string Chain ids of both ends
via string Chain the transfer passes through, or null for a direct route
open boolean Whether the route accepts transfers now
min, max string Amount limits, in the smallest unit
how object How the transfer is started. Used by the widget, and by your own code if you send the transaction yourself.

Chains

curl https://telos.alcor.exchange/api/bridge/v1/chains

Relevant part of the response:

{
  "sources": [
    {
      "id": "mainnet",
      "name": "Ethereum",
      "chainId": 1,
      "timing": {
        "deposit": {
          "seconds": 990,
          "range": [768, 1212],
          "measured": true,
          "human": "about 17 min (13 min–20 min)"
        }
      }
    }
  ]
}

State of each chain the bridge reaches, including how long a transfer from it currently takes. Timing is measured on recent transfers, not configured.

HTTP Request

GET https://telos.alcor.exchange/api/bridge/v1/chains

Response

Name Type Description
sources[].id string Chain id
sources[].name string Display name
sources[].timing.deposit.seconds number Typical time for a deposit from this chain
sources[].timing.deposit.range number[] Fastest and slowest recent times, in seconds
sources[].timing.deposit.measured boolean true when measured on recent transfers
sources[].timing.deposit.human string The same, phrased for people

Transfer status

curl https://telos.alcor.exchange/api/bridge/v1/hops/d:1:12
curl "https://telos.alcor.exchange/api/bridge/v1/hops?party=alice.wam"

The above command returns JSON structured like this:

{
  "key": "d:1:12",
  "status": "delivered",
  "progress": {
    "stage": "delivered on WAX",
    "percent": 100,
    "etaSeconds": null
  },
  "from": { "chain": "mainnet", "address": "0x285202c8db763db06ab42e0705104cb7919ef95e" },
  "to": { "chain": "wax", "recipient": "alice.wam" },
  "back": { "chain": "mainnet", "recipient": "0x285202c8db763db06ab42e0705104cb7919ef95e" },
  "deposit": {
    "symbol": "USDC",
    "amount": "50000000",
    "precision": 6,
    "src_tx": "0x0af8049909488c9ebb129dbc30db39ca0c7dc7009978756a8562e38970f92917"
  }
}

A transfer from Ethereum to WAX, by its key (the key from the widget's onFinished), or every transfer an account or address took part in. The list form returns { "hops": [ … ] }, newest first.

HTTP Request

GET https://telos.alcor.exchange/api/bridge/v1/hops/<key>

GET https://telos.alcor.exchange/api/bridge/v1/hops?party=<account or address>

Status

Status Meaning
arriving Locked on Ethereum, waiting for Ethereum to finalize
sending Passed through Telos, on its way to the destination
delivered Paid out to the recipient
bounced Refused by the destination, sent back
returning Coming back to the sender
returned Back with the sender

Bridge contracts

Everything the widget does is a public contract call. Bots, wallets and exchanges can make the same calls themselves: no API key, no allowlist, no Alcor page involved.

How the bridge is built:

Addresses

Chain Contract Address What it is
Ethereum AlcorVault 0x3e447d533321ad6a8412f97034ac295a9ff8d858 Deposits in, withdrawals paid out
Ethereum AlcorWithdrawals 0x04fb700b93eb68cadd88d8e8d4dfe4857d5cb3c6 Verifies a withdrawal proof and tells the vault to pay
Ethereum USDC, USDT 0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48, 0xdac17f958d2ee523a2206206994597c13d831ec7 ETH is native: token 0x0000000000000000000000000000000000000000
BSC AlcorVault 0x53f18eaa8bf8099b5ba21bb7e11ed311b677690e Same contract as on Ethereum
BSC AlcorWithdrawals 0x6132b4d02e02f1b378f0fc67c3d4f553eb76acb5 Same contract as on Ethereum. BNB is native
Telos bridge.alcor The ledger: credits deposits, opens withdrawals
Telos wrap.alcor Bridged tokens on Telos: USDC and USDT (6 decimals), ETH, BNB and WAX (8)
Telos hop.alcor Carries a transfer between two chains through Telos
WAX bridge.alcor The vault on WAX: holds WAX, mints and burns the mirrors
WAX wrap.alcor Mirror tokens on WAX: USDC, USDT, ETH, BNB. WAX itself is eosio.token

ABIs of the EVM contracts: AlcorVault.json, AlcorWithdrawals.json. The Antelope contracts publish theirs on chain (get_abi).

Domains and units

Chain Domain
Ethereum 1
BSC 56
WAX 1181148696416462999 (first 8 bytes of the WAX chain id)

The domain names the far chain in every memo and key. It is a decimal string in the API: the WAX one is larger than a JSON number holds exactly.

Amounts. The ledger counts in Telos units (the token's precision on Telos). On an EVM chain, amount = canonical × scale: scale is 1 for USDC and USDT and 10^10 for ETH and BNB (18 decimals there, 8 on Telos). A remainder below scale is not taken: an ERC-20 deposit pulls only canonical × scale, and the excess of a native deposit is sent back in the same transaction.

Telos accounts on EVM. telosTo is an Antelope account name packed into a uint64, the standard Antelope encoding. With wharfkit: BigInt(Name.from('hop.alcor').value.toString()).

Deposit from Ethereum or BSC

import { Contract, toUtf8Bytes, hexlify } from 'ethers'   // ethers v6
import { Name } from '@wharfkit/antelope'

const API = 'https://telos.alcor.exchange/api/bridge/v1'
const vaultAbi = await (await fetch('https://api.alcor.exchange/abi/AlcorVault.json')).json()

const { sources } = await (await fetch(`${API}/chains`)).json()
const vault = new Contract(sources.find(s => s.id === 'mainnet').contracts.vault, vaultAbi, signer)

const telosName = n => BigInt(Name.from(n).value.toString())
const me = await signer.getAddress()

// ETH to the WAX account alice.wam, back to me if WAX never pays
const memo = hexlify(toUtf8Bytes(`1181148696416462999:alice.wam|1:${me}`))
await vault.depositNative(telosName('hop.alcor'), me, 0, 0, memo, { value: 10n ** 16n })

// 50 USDC to the Telos account alice (approve the vault first)
const USDC = '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48'
await vault.deposit(USDC, 50_000000n, telosName('alice'), me, 0, 0, '0x')

deposit(token, amount, telosTo, refundTo, fillFee, filler, memo) for an ERC-20, after approve(vault, amount). depositNative(telosTo, refundTo, fillFee, filler, memo) payable, for ETH or BNB.

Parameter Type Description
token address ERC-20 address from Routes (how.deposit.token)
amount uint256 Raw token units
telosTo uint64 Who receives on Telos: an account, or hop.alcor to go on to another chain
refundTo address Where the deposit goes back if it cannot be delivered. Must not be zero
fillFee, filler uint64 Reserved. Pass 0
memo bytes Up to 256 bytes, see below

Where it lands depends on telosTo and memo:

USDT on Ethereum refuses to change a non-zero allowance: set it to 0 first.

A deposit the vault refuses reverts with a custom error from the ABI: DepositsPaused, AssetDisabled, BelowMinimum(minDeposit), CapExceeded, AmountTooSmall, MemoTooLong, ZeroAccount, ZeroRefundAddress, UseDepositNative (the native coin through deposit).

The Deposit event gives the key: d:<chainId>:<nonce>.

Deposit from WAX

# 100 USDC from WAX to the Telos account alice
cleos -u https://wax.greymass.com push action wrap.alcor transfer \
  '["bob.wam", "bridge.alcor", "100.000000 USDC", "alice"]' -p bob.wam

# 100 USDC from WAX to an Ethereum address
cleos -u https://wax.greymass.com push action wrap.alcor transfer \
  '["bob.wam", "bridge.alcor", "100.000000 USDC", "hop.alcor:1:0x285202c8db763db06ab42e0705104cb7919ef95e|1181148696416462999:bob.wam"]' -p bob.wam
// wharfkit session on WAX
await session.transact({
  action: {
    account: 'wrap.alcor', name: 'transfer',
    authorization: [session.permissionLevel],
    data: { from: session.actor, to: 'bridge.alcor', quantity: '100.000000 USDC', memo: 'alice' },
  },
})

A plain transfer to bridge.alcor on WAX. The token is the route's antelopeToken in Chains: eosio.token for WAX, wrap.alcor for the mirrors. The memo says where it goes:

The deposit's key is d:1181148696416462999:<nonce>, the nonce from the vault's deplog action in your transaction.

Withdraw from Telos

# 50 USDT from Telos to an Ethereum address
cleos -u https://mainnet.telos.net push action wrap.alcor transfer \
  '["alice", "bridge.alcor", "50.000000 USDT", "1:0x285202c8db763db06ab42e0705104cb7919ef95e"]' -p alice

# 10 WAX from Telos to the WAX account bob.wam
cleos -u https://mainnet.telos.net push action wrap.alcor transfer \
  '["alice", "bridge.alcor", "10.00000000 WAX", "1181148696416462999:bob.wam"]' -p alice

A transfer of a wrap.alcor token to bridge.alcor on Telos, with the destination in the memo: <domain>:<recipient>[:<fee>].

The amount must not exceed withdrawableNow of the route in Chains: each vault lets only so much out per day.

To attach data for the receiver, use wrap.alcor::withdraw(owner, quantity, domain, recipient, fee, memo) instead of a transfer: recipient is the 20 address bytes, fee an asset in the same token, and memo up to 1024 bytes. The memo is proved with the amount and comes out in the Released event of AlcorWithdrawals.

The withdrawal id is in the inline bridge.alcor::wdlog action of your transaction: wdlog(id, domain, vault, token, recipient, amount, deadline, fee, memo). The key is w:<id>.

Release on Ethereum or BSC

const wdAbi = await (await fetch('https://api.alcor.exchange/abi/AlcorWithdrawals.json')).json()
const p = await (await fetch(`${API}/proofs/w:${id}`)).json()   // 404 until the proof exists

if (p.track === 'light') {
  // a root covering this burn is already trusted: ~145-180k gas
  await new Contract(p.light.releaseTo, wdAbi, signer).release(p.light.release)
} else {
  // the root is submitted in the same transaction: ~2.6M gas
  const s = p.hard.submitRoot
  await new Contract(p.hard.releaseTo, wdAbi, signer)
    .submitAndRelease(s.finality, s.bits, s.signature, s.policyKeys, s.pending, p.hard.release)
}

A withdrawal to an EVM chain is paid out when someone sends its proof to AlcorWithdrawals. Anyone may send it: every field is checked against a root signed by Telos finalizers, and the tokens go only to the recipient the burn named.

  1. Wait until GET /v1/transfers/w:<id> shows hasProof: true, about a minute after the burn.
  2. Fetch GET /v1/proofs/w:<id>. Its objects are in Solidity struct order and carry both contract addresses. Pass them through unchanged.
  3. Send release on the light track or submitAndRelease on the hard track. One transaction either way.

Deadline. The proof carries a deadline, about a week after the burn. Past it release reverts with PastDeadline. Send the same body to expire (or submitAndExpire) instead, and the tokens come back to their owner on Telos.

Daily limit. A release over the vault's remaining daily allowance reverts with OutflowLimited and consumes nothing. The same proof works once the allowance refills, any time before the deadline.

Fees. When the withdrawal set a fee, msg.sender receives it in the same transaction. GET /v1/pending lists every withdrawal ready to settle right now, with action saying release or expire.

Telos actions

# Collect a credited deposit
cleos -u https://mainnet.telos.net push action bridge.alcor claim '["alice", "USDC"]' -p alice
Action Who may call What it does
bridge.alcor::claim(owner, sym_code) The owner Transfers a credited deposit to its owner. Table claims, scope = owner
bridge.alcor::forward(domain, nonce) Anyone Delivers a deposit that carried a memo. The relayer does it; call it if you do not want to wait
bridge.alcor::bounce(domain, nonce) Anyone, an hour after arrival Sends an undeliverable deposit back to its refundTo
hop.alcor::recover(id) Anyone Sends a hop that came back from its destination on to its way-back address
<gateway>::credit Anyone, with a proof Credits a deposit. The relayer does it. To do it yourself, send the actions of GET /v1/proofs/d:<domain>:<nonce> in one transaction

Tables worth reading on bridge.alcor: routes (limits and backing per route), claims (credited, not yet collected), wdraws (withdrawals and their status).

Contract events

Contract Event Meaning
AlcorVault Deposit(token, from, amount, canonical, telosTo, nonce, refundTo, fillFee, filler, memo) Deposit locked. Key d:<chainId>:<nonce>
AlcorVault Released(id, token, to, amount, feeTo, fee) Withdrawal w:<id> paid out, raw units
AlcorVault Voided(id) Withdrawal w:<id> expired, refunded on Telos
AlcorWithdrawals Released(id, token, to, amount, memo) The same payout with the Telos memo, in Telos units
AlcorWithdrawals Expired(id) expire accepted
WAX bridge.alcor action deplog(nonce, bridge, token_contract, token_symbol, from, raw, canonical, beneficiary, memo) Deposit from WAX. Key d:1181148696416462999:<nonce>
Telos bridge.alcor action wdlog(id, domain, vault, token, recipient, amount, deadline, fee, memo) Withdrawal opened. Key w:<id>

Transfers and timing

curl https://telos.alcor.exchange/api/bridge/v1/transfers/d:56:1
curl "https://telos.alcor.exchange/api/bridge/v1/transfers?address=0x285202c8db763db06ab42e0705104cb7919ef95e&limit=20"

GET /v1/transfers/<key> is one leg; GET /v1/transfers?account=&address=&direction=&status=&limit=&before= lists legs, newest first (before is the src_time of the last row, for paging). Transfer status follows a whole Ethereum ↔ WAX journey instead. A leg moves through these statuses:

deposit      seen ──▶ provable ──▶ credited
                               └─▶ parked ──▶ forwarded
                                          └─▶ bounced
withdrawal   burned ──▶ provable ──▶ released
                                └─▶ expired ──▶ refunded

Typical times, measured on recent transfers. The live figures are in Chains under timing:

From → to Time Your transactions
Ethereum → Telos about 17 min, Ethereum finality Deposit
Ethereum → WAX about 20 min Deposit
BSC → Telos about 30 s Deposit
BSC → WAX about 3 min Deposit
WAX → Telos about 50 s Transfer
Telos → WAX about 2 min Transfer
Telos → Ethereum or BSC about 1 min to the proof Transfer, then release
WAX → Ethereum or BSC about 2–3 min to the proof Transfer, then release

Poll every 10–15 seconds: a transfer changes state on the scale of minutes.

Errors

The Kittn API uses the following error codes:

Error Code Meaning
400 Bad Request -- Your request is invalid.
401 Unauthorized -- Your API key is wrong.
403 Forbidden -- The kitten requested is hidden for administrators only.
404 Not Found -- The specified kitten could not be found.
405 Method Not Allowed -- You tried to access a kitten with an invalid method.
406 Not Acceptable -- You requested a format that isn't json.
410 Gone -- The kitten requested has been removed from our servers.
418 I'm a teapot.
429 Too Many Requests -- You're requesting too many kittens! Slow down!
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.