Uniswap is a new take on a fully decentralized exchange (DEX) on Ethereum, one which provides immediate, fully on-chain settlement without requiring liquidity providers to coordinate off-chain or operate any market-making bots. Allowing anyone to provide liquidity significantly opens up the pool of liquidity beyond advanced users, increasing total Uniswap liquidity, which has risen quickly, hosting about $10M in liquidity with daily volumes exceeding $1M.

Leveraging Ethereum on-chain balances which Amberdata already collects for every block, Amberdata now provides an API to access Uniswap liquidity details and a “materialized” order book. Uniswap does not host an order book in the conventional sense, but given these on-chain balances and the exchange formula, we can materialize an order book, showing offer depth at various prices.

About Uniswap

To understand this API, let’s first look under the hood at how Uniswap works.

Uniswap operates under the “Constant Product” model, where the exchange rate for tokens is based on an extremely simple formula that considers the current contract balance of Ether against the contract balance of tokens being exchanged. For instance, on the ETH-DAI market, if the contract had a balance of 1,000 ether and 100,000 DAI, the “price” at that moment would be 1 ETH = 100 DAI (100,000 DAI divided by 1,000 ether). However, as users either buy or sell DAI, that rate changes at the moment of sale; the more you buy, the more each costs. As an example, given our above balances: 1,000 ETHER * 100,000 DAI = 100,000,000 (constant product).

If you wanted to exchange 100 ether for DAI, you deposit the Ether, and see how much DAI you can withdraw without impacting the product:

(1,000 + 100) * (100,000-x) = 100,000,000

1,100 * 90,909 = 100,000,000 100,000 - x = 90,909

x = 9091 DAI (how much you can draw)

Price: 1 Ether = 90.91 DAI

Notice this exchange rate isn’t the 1 ether = 100 DAI mid-point we mentioned above; we are operating on a significant portion of the total liquidity and the purchase itself changed the price significantly. 1 ETH = 90.91 DAI becomes the new mid-point price available for the next purchase; buying and selling into this market is the only way price changes. Instead of relying on market makers to set the price and spread, you rely exclusively on trades.

If we instead decided to sell more Ether, say 200, we would get a significantly different price:

(1,000 + 200) * (100,000-x) = 100,000,000

1,200 * 83,333 = 100,000,000 100,000 - x = 83,333

x = 16,667 DAI (how much you can draw)

Price: 1 Ether = 83.35 DAI

A more liquid Uniswap market will cause prices to move slowly with the same volume. The below table maps Uniswap liquidity to volume/price. Both of these charts are assuming a mid-point price of 100 DAI:ETH. Top row is Ether balance of contract (with an implied `100 * Ether balance` of tokens), left column is volume of order in Ether, value is how much DAI you must provide to buy that volume of Ether.

Those same values as a line chart:

Users who provide this liquidity do so as a pair of Ether and tokens. For instance, the Uniswap ETH-DAI contract would require liquidity providers to supply both Ether AND DAI, keeping the ratio of those tokens the same while increasing the balance of both (changing the product). If the current balance of each was 1,000 ETH : 100,000 DAI, you could provide liquidity by depositing 1 ETH and 100 DAI. Providing liquidity mints Uniswap liquidity tokens to be claimed from the market for your stake in the liquidity pool.

Users who provide this liquidity do so as a pair of Ether and tokens. For instance, the Uniswap ETH-DAI contract would require liquidity providers to supply both Ether AND DAI, keeping the ratio of those tokens the same while increasing the balance of both (changing the product). If the current balance of each was 1,000 ETH : 100,000 DAI, you could provide liquidity by depositing 1 ETH and 100 DAI. Providing liquidity mints Uniswap liquidity tokens to be claimed from the market for your stake in the liquidity pool.

Uniswap trades will cause the ETH-DAI balance ratio to change, but not the product of the balances

Adding or removing liquidity to Uniswap will cause the product to change, but leave the ratio unchanged

Fees

We did not cover fees in the above formulas for simplicity, but there is a 0.3% fee on all trades that goes entirely to the liquidity providers. The fee is calculated on input, if you deposit 1 Ether, you are only given tokens proportional to a deposit of 0.997 Ether.

Uniswap API Endpoints

The above formulas relating both to the current price, and how much the price changes as volume increases requires knowing only 2 values at a point in time: Ether balance and token balance of the market contract. This would normally require an archive node and many off-chain calls for historical perspective. Having already collected and indexed this data for all accounts and contracts, Amberdata is releasing a new endpoint for retrieving these values over time. Calling this liquidity endpoint returns a time-ordered array of each time the etherBalance or tokenBalance on this market changed, indicating a new mid-point price and volume curve.

Liquidity Endpoint

$ curl -s 'https://web3api.io/api/v1/market/orders/uniswap/eth_dai/liquidity' -H "x-api-key: $API_KEY" | jq . | head -n 23

{

"status": 200,

"title": "OK",

"description": "Successful request",

"payload": [

{

"timestamp": 1559865532000,

"blockNumber": "7908742",

"etherBalance": "3324430283894099142288",

"tokenBalance": "828792193254129030902677"

},

{

"timestamp": 1559865517000,

"blockNumber": "7908740",

"etherBalance": "3322930303743208056464",

"tokenBalance": "829165190040182952588747"

},

{

"timestamp": 1559865500000,

"blockNumber": "7908734",

"etherBalance": "3322120127262793325731",

"tokenBalance": "829366794677970374451162"

},

With options:

$ curl -s 'https://web3api.io/api/v1/market/orders/uniswap/eth_zrx/liquidity?timeFormat=iso&startDate=1559815500000&endDate=1559865532000' -H "x-api-key: $API_KEY" | jq . | head -n 23

{

"status": 200,

"title": "OK",

"description": "Successful request",

"payload": [

{

"timestamp": "2019-06-06T23:01:42.000Z",

"blockNumber": "7908472",

"etherBalance": "347660842874075342316",

"tokenBalance": "267458136974184976315471"

},

{

"timestamp": "2019-06-06T22:32:48.000Z",

"blockNumber": "7908344",

"etherBalance": "337111576953296679754",

"tokenBalance": "259342506274184979058454"

},

{

"timestamp": "2019-06-06T19:38:49.000Z",

"blockNumber": "7907611",

"etherBalance": "347660842834227753835",

"tokenBalance": "267458136943529922701354"

},

Using this data, one could get current and all prior Uniswap mid-point prices and volume curves. Using these values, and a knowledge of the on-chain formula, you could calculate what buying or selling on Uniswap would cost and yield at any point in time. For instance, in late June, the the mid-point price was about 300 DAI per ETH, but the liquidity was lower than it is today, in July, by ~25%. Depending on the volume you are looking to exchange, it could be better to exchange at a lower price, but with more liquidity, as your order would not move the market nearly as much.

Having access to these numbers help drive that decision

Standard Order Book Endpoint

Instead of simply serving up the raw ether/token balance information, Amberdata can also use these balances server-side to reconstruct an order book by iterating through various volumes and reporting which prices were being offered. Since Amberdata already provides order book data for many of the top crypto exchanges, we simply added “uniswap” as an exchange option (along with “gdax”, “binance”, “bitfinex”, etc), ensuring its output matches our standard order book snapshot endpoint:

$ curl -s 'https://web3api.io/api/v1/market/orders/eth_zrx?exchange=uniswap' -H "x-api-key: $API_KEY" | jq .

{

"status": 200,

"title": "OK",

"description": "Successful request",

"payload": {

"metadata": {

"columns": [

"price",

"volume",

"numOrders"

],

"requestedTimestamp": 1559942084862,

"returnedTimestamp": 1559931517000

},

"data": {

"bid": [

[ 661.3182737611725, 49, 1 ],

[ 662.9167671038554, 48, 1 ],

...

[ 743.8230930428307, 3, 1 ],

[ 745.8459262955631, 2, 1 ],

[ 747.8797917751368, 1, 1 ],

[ 749.7197780376213, 0.1, 1 ]

],

"ask": [

[ 754.6495528334601, 0.1, 1 ],

[ 756.5174080836109, 1, 1 ],

[ 758.6036772163081, 2, 1 ],

[ 760.7014848941935, 3, 1 ],

...

[ 863.3643269502593, 46, 1 ],

[ 866.0825798918668, 47, 1 ],

...

This standardized order book snapshot response is a convenient format for those already integrated into the standard order book API or already have logic for interpreting an order book as a list of orders. There is no more information in this endpoint than the liquidity one, it’s simply server-side processing of the balances. Due to the sampling, this response is slightly inaccurate, as there aren’t “steps” in price; the Uniswap order book price is perfectly continuous across any volume that it can fulfill.

The Uniswap Depth UI

To demonstration this new API, we created a simple UI based on jQuery and Amcharts to retrieve Uniswap balance pairs over a range of time, and view them as if they were a standard depth chart, continuously. This utilizes the above “liquidity” endpoint and implements the Uniswap volume/price curve logic locally, with each chart being powered only by 2 values: Ether balance and token balance.

The color fade here happens at 2% of the price. Because the chart is continuous, it is difficult to visualize the volume/price curve, as the shape is nearly identical. That dark colored bar shows how much volume the market supports before crossing 2% off the mid-point price.

Check it out

To see this chart and API in action for yourself, see the demo hosted on github. If you want to see what’s running under the hood, check out the demo repo and open up index.html in your browser. All assets are self-contained and there is no build process.

More Resources