The eosfinex Exchange Contract

Facilitating Secure & Instantaneous On-chain Exchange

At the heart of eosfinex lies the exchange contract. Designed to allow for the instantaneous and secure exchange of on-chain value, the eosfinex exchange contract acts as the very core of eosfinex.

In this article we focus on interacting directly with the exchange contract through the contract ABI.

Join our newly-created eosfinex Telegram channel for more information as we approach our launch.


The exchange contract supports fully on-chain limit order books, as well as matching and trade settlement. A user can interact with the exchange contract through a WebSocket gateway as described in the last installment of our weekly blog series, or directly with the contract ABI through a public facing EOS node that is running the standard HTTP plugin.

The following examples use cleos — the default EOS command line tool — but the examples are easily extendable to other clients and libraries.

To get a feel for the exchange contract, we can start off by querying its ABI through a public node.

cleos -u http://[public_eosfinex_node] get abi [exchange_account]

“actions”: [{
“name”: “place”,
“type”: “place”,
“ricardian_contract”: “”
},{
“name”: “cancel”,
“type”: “cancel”,
“ricardian_contract”: “”
},{
“name”: “withdraw”,
“type”: “withdraw”,
“ricardian_contract”: “”
}, …]

“tables”: [{
“name”: “orders”,
“index_type”: “i64”,
“key_names”: [
“id”,
“price”
],
“key_types”: [
“uint64”,
“uint64”
],
“type”: “order”
},{
“name”: “accounts”,
“index_type”: “i64”,
“key_names”: [
“currency”
],
“key_types”: [
“uint64”
],
“type”: “account”
}
]

Above is an excerpt from the response, and highlights the essential exchange contract actions and tables.

We are interested in three actions: place, cancel and withdraw and two tables: orders and accounts. Once we understand these, we will be ready to begin trading. So let’s take a closer look at each through some examples.

For brevity, the following examples exclude the URL to the public endpoint and continue to use place holders for account names. These examples also assume the user has an unlocked wallet containing the necessary private keys.


Accounts Table

The accounts table stores a user’s available balance for a particular currency on the exchange. Before a user can trade, the user must first transfer funds onto the exchange.

cleos transfer [user_account] [exchange_account] “20.00000000 EOS” “Transfer some EOS onto the exchange”
cleos transfer [user_account] [exchange_account] “5.00000000 EOX” “Transfer some EOX onto the exchange”

Now that the funds have been transferred, the user can query their exchange account balance(s). Simply query the account balance on the exchange in the same way as you would any standard token contract.

cleos get currency balance [exchange_account] [user_account]
20.00000000 EOS
5.00000000 EOX

With some funds on the exchange, the user is now ready to send orders.


Place Action

Orders are sent to the exchange using the contract’s place action. Below are the details of the place action as defined in the ABI.

{
“name”: “place”,
“base”: “”,
“fields”: [
       {“name”:”account”, “type”:”name”},
{“name”:”clId”, “type”:”uint64"},
{“name”:”scope”, “type”:”name”},
{“name”:”price”, “type”:”uint64"},
{“name”:”qty”, “type”:”uint64"},
{“name”:”flags”, “type”:”uint8"}
]
}

Let’s take a closer look at each of these fields.

Account: This is the account that is placing the order. The transaction must be signed using the private key for this account, and the user must have sufficient funds available within their exchange wallet.

Clid: This is the client order id, a unique id that the client assigns to each order request. This id allows the user to identify the order after the exchange contract process it.

Scope: Order scope is the amalgamation of the trading pair and order side. Scope follows the pattern: X.Y.Z. All values are lower case and X is the trading pair base currency, Y is the trading pair quote currency, and Z is the order side (either ‘b’ for bid or ‘a’ for ask). For example, setting scope to eox.eos.b would place a buy order for the eox.eos trading pair.

Price: This is an integer representation of the limit price for the order. eosfinex orders support 4 digits of price precision to the right of the decimal point. The integer representation is obtained by simply multiplying the floating point price by 10000. For example, the integer representation of the limit price 4.1250 is 41250 (4.1250 * 10000).

Qty: This is an integer representation of the order size. Like prices, eosfinex orders support 4 digits of size precision to the right of the decimal point. To convert from decimal to integer representation, again simply multiply by 10000. For example, the integer representation of the order size 100.05 is 1000500 (100.05 * 10000).

Flags: The flags field is used to specify order options. Each bit in the 8-bit field represents a different option and can be enabled by setting that bit to true. This allows enabling multiple options on the same order.

Here is a list of each option and its corresponding bit:

00000001 Post Only: The order will receive a price reflecting the maker rebate.
00000010 Immediate or Cancel: Any size that does not fill immediately will be canceled.
00000100 Market: Ignore limit price and trade at the best available price.
00001000 Self Trade Prevention: Do not trade with an order having the same account.
01000000 Release on Trade: Transfer new funds out of the exchange after a trade.
10000000 Sweep Collateral: Transfer collateral balance out of exchange when canceled.

For example, if flags = 11000010, this will be an Immediate or Cancel order that will transfer the full collateral balance, as well as any funds acquired due to a trade, out of the exchange upon order completion.

Let’s attempt to make this more clear through an example. We will assume the user has the following exchange balances.

cleos get currency balance [exchange_account] [user_account]
20.00000000 EOS
5.00000000 EOX

Let’s also assume that the user wants to buy 3.0000 EOX using EOS, and that the user wants to pay no more than 1.5 EOS for each EOX. In that case, the user would send the following command.

cleos push action exchange_account place ‘[user_account 1 eox.eos.b 15000 30000 0]’

Let’s assume that the order did not fill after it was placed, and it is resting in the order book waiting to be filled. If we query the user’s exchange wallet balances we see that some EOS has been reserved as collateral to support the order that was just placed.

cleos get currency balance [exchange_account] [user_account]
15.50000000 EOS
5.00000000 EOX

Next, we can query the orders table to see the order we just placed.


Orders Table

This table stores the limit order book for each trading pair. Any portion of a limit order that does not fill will be placed in the limit order book. The limit order book can be queried by using the following command.

cleos get table [exchange_account] [order_scope] orders

Above, order_scope is identical to the scope used to place the order. For example, let’s assume a user places the following eox.eos buy order.

cleos push action exchange_account place ‘[user_account 1 eox.eos.b 15000 30000 0]’

If the order does not fill, then it will be placed into the eox.eos buy limit order book, and we can query the limit order book like this.

cleos get table [exchange_account] eox.eos.b orders
{
“rows”: [{
“id”: “1234567”,
“account”: “user_account”,
“clId”: 1,
“price”: 15000,
“qty”: 30000,
“reserved”: 0,
“flags”: 0
}],
“more”: false
}

All the fields of the stored limit order are exactly as we would expect them to be.

The only field in the stored order structure that we do not recognize is the ‘id’ field. This field is assigned by the exchange. Notice that both price and qty are stored as integers, in the same way the order was placed. The order will remain in the order book until someone trades with it or it is canceled.


Cancel Action

The cancel action is used to cancel an order in the order book. The cancel action has the following ABI definition.

{
“name”: “cancel”,
“base”: “”,
“fields”: [
{“name”:”account”, “type”:”name”},
{“name”:”id”, “type”:”uint64"},
{“name”:”clId”, “type”:”uint64"},
{“name”:”scope”, “type”:”name”}
]
}

These fields are a subset of the fields in the place order action with the addition of the exchange assigned ‘id’ field. Assuming our eox.eos buy order with ‘id’ 1234567 was resting in the order book, we can cancel that order using the following command.

cleos push action [exchange_account] cancel ‘[user_account 1234567 1 eox.eos.b]’

As expected, querying the orders table after canceling the order leaves us with an empty orders table.

cleos get table [exchange_account] eox.eos.b orders
{
“rows”: [],
“more”: false
}

Withdraw Action

“name”: “withdraw”,
“base”: “”,
“fields”: [
{“name”:”to”, “type”:”name”},
{“name”:”amount”, “type”:”asset”}
]
}

As an example, let’s assume a user has the following exchange wallet balances.

cleos get currency balance [exchange_account] [user_account]
20.00000000 EOS
5.00000000 EOX

If the user wants to withdraw half of the available EOS, then he/she would issue the following command.

cleos push action exchange_account withdraw ‘[user_account “10.00000000 EOS”]’

By querying the exchange balance after the withdraw, we can see that the withdraw completed as expected.

cleos get currency balance [exchange_account] [user_account]
10.00000000 EOS
5.00000000 EOX

Summary

In the second installment of our weekly eosfinex blog series we looked at the eosfinex exchange contract, as well as how one can interact with the contract directly via the ABI.

In case you missed last weeks article — interacting with eosfinex using WebSockets — find it here:

Stay up to date with developments below as we approach our March 2019 launch.