Seamless Trades and Platform Growth Metrics with uniswappeR

Introduction

Uniswap is a decentralized cryptocurrency exchange that allows for the permissionless trading of Ethereum based ERC-20 tokens. Through their grants program, the protocol’s governance has funded initiatives that support the creation of community infrastructure that lower the barriers of entry for those seeking to interact with the platform from within alternative development environments. Consistent with that mandate, through our grant we created an open source software library for the R language that allows developers, traders, researchers and enthusiasts the ability to query, analyze, export and model data generated from the Uniswap platform. Our uniswappeR R package includes the functionality to trade and query prices from the Uniswap platform. To interact with the Uniswap through this language we’ll first need to configure the environment and then use package defined functions to perform swaps and collect data. This blog post provides an overview of the motivation behind the creation of the package, who we expect our primary users to be, the steps needed to configure the environment, and a survey of the functionality contained within the package.

Motivation

The growth of the Uniswap platform has come with both a need for tools that help enable interaction with the platform, as well as higher-level analytics about the growth of the platform itself. We’ve built uniswappeR to target both of these key areas.

  1. uniswappeR maintains a broad set of trading and utility functions. Because these have been abstracted into simple R-based functions, the possibilities are significant in terms of automation. For example, perhaps a trader on the Uniswap platform wishes to execute a particular trade given a sit of criteria, or at a specific time. The automation afforded to us by the R language and this package means that workflows such as this are now easy and seamless. Perhaps another trader wishes to perform an analysis of their current positions in order to help decide on a trade. The suite of visualization and data analysis tools in R makes the process of doing so significantly more seamless. These could even be abstracted into an API – imagine a simple web-based REST API which allows the inputting of a list of tokens and quickly retrieves statistics on pool liquidity with respect to these tokens.

  2. At a platform level, uniswappeR allows for a visualization and statistical assessment of the growth and trends in growth of users and usage. This has implications both from the perspective of a Uniswap user and for the Uniswap community / development team as a whole. For the user, the easy to access metrics about platform usage help lend confidence in the platform itself, and to help indicate potential trends in when trades may be most lucrative. For the broader Uniswap community, our package provides a simple way of accessing growth metrics that can help with the governance and direction of the platform, and can be chained to down-stream analysis in order to make more informed and data-driven decisions.

Setup

Full use of uniswappeR requires a Python environment available. Fortunately, thanks to the reticulate package, we can easily interact with Python code within an R session. To setup your session, perform the following steps:

  1. Install the reticulate package using library(reticulate)
  2. Install python to use as backend using install_python("3.8.7")
  3. Create a Virtual Environment to keep the backend sandboxed using: virtualenv_create("uniswappeR-env", version = "3.8.7")
  4. Install uniswap-python package using virtualenv_install(envname="uniswappeR-env",packages=c("uniswap-python==0.4.6"))
  5. Use the Virtual Environment using use_virtualenv("uniswappeR-env",required=TRUE)
  6. Extract checksum function from Web3 module using Web3_checksum <- import("web3",convert=FALSE)$Web3$toChecksumAddress

All together, the code looks as follow:

library(reticulate)

install_python("3.8.7")

virtualenv_create("uniswappeR-env", version = "3.8.7")
virtualenv_install(envname="uniswappeR-env",packages=c("uniswap-python==0.4.6"))
use_virtualenv("uniswappeR-env", required = TRUE)

Web3_checksum <- import("web3",convert=FALSE)$Web3$toChecksumAddress

Now, we need to simply activate the virtual environment:

library(reticulate)
library(uniswappeR)

Web3_checksum <- import("web3",convert=FALSE)$Web3$toChecksumAddress

To configure your Infura node, you use the following:

## [1] TRUE
set_infura_node("https://mainnet.infura.io/v3/XXXXXXXXXXXXXXXXXXX")

At this stage, we need to set our address and private key:

u_w <- uniswap_session(user_add="<your_address>",pvt_key="<your_private_key>")

Now, we are ready to begin!

Helper Functions

The package includes a variety of helper functions which perform queries against the uniswap API. For instance, with the following we can check our balance in ETH:

check_eth_balance(u_w)
## [1] 18.32611

We can use the Uniswap Token Address, along with the number of decimals, to check our token balance:

t_a <- Web3_checksum("0x1f9840a85d5af5bf1d1762f925bdaddc4201f984")
t_d <- 18

check_tok_balance(t_a,t_d,u_w)
## [1] 17.81118

Suppose we wish to determine how much ETH we would need in order to get 2 UNI tokens. We can do that simple check easily:

t_q <- 2
check_eth.to.tok_tok.fix(t_a,t_d,t_q,u_w)
## [1] 2.451879

A class of similar functions are available:

  • check_eth.to.tok_tok.fix: How much ETH you would get for 2 UNI Tokens, When you Swap UNI for ETH
  • check_tok.to.eth_tok.fix: How much UNI Token you need to get .5 ETH Tokens, When you Swap UNI for ETH
  • check_tok.to.eth_eth.fix: How much DAI Token you would get for 2 UNI, When you Swap UNI for DAI (Uses UNI->ETH->DAI Route)
  • check_tok1.to.tok2_tok1.fix: How much UNI Token you would need to get 50 DAI, When you Swap UNI for DAI (Uses UNI->ETH->DAI Route)

Making Trades

One of the fundamental components of the package is the ability to make trades. The basic trading functionality is encapsulated in a set of trade_* functions:

  • trade_eth.to.tok_eth.fix: Swap ETH for UNI Tokens
  • trade_eth.to.tok_tok.fix: Swap as much ETH required to get N UNI Tokens
  • trade_tok.to.eth_tok.fix: Swap UNI Tokens for ETH
  • trade_tok.to.eth_eth.fix: Swap as much UNI Tokens required to get N ETH
  • trade_tok1.to.tok2_tok1.fix: Swap UNI Tokens for other Tokens

For example, suppose I wanted to swap .5 ETH for UNI tokens. I would simply execute:

e_q <- .5
trade_eth.to.tok_eth.fix(t_a,t_d,e_q,u_w)

Pulling Historical Data

In addition to lower-level functions for checking balances and performing trades, uniswappeR has rich functionality to pull historical data to perform a down-stream analysis or produce visualizations. We provide the factory_stats_v2() function which gives statistics across all pairs generated by the Uniswap Factory. There is also a corresponding uniswap_stats_hist_v2() function which has the historical data.

factory_stats_v2()
id pairCount totalLiquidityETH totalLiquidityUSD totalVolumeETH totalVolumeUSD txCount
0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f 52135 1421653 4310303951 279881002 3.47819e+11 61602306
uniswap_stats_hist_v2() 
dailyVolumeETH dailyVolumeUSD dailyVolumeUntracked date totalLiquidityETH totalLiquidityUSD totalVolumeETH totalVolumeUSD txCount
179300.5 558029103 2721549429 1632096000 1421653 4310303951 0 0 61602306
121586.4 410670904 1823649220 1632009600 1403587 4654001671 0 0 61532178
103734.4 358961182 949614434 1631923200 1390544 4766547009 0 0 61460138
122927.6 426859530 1016250380 1631836800 1382503 4694619054 0 0 61385296
130864.5 470205526 1779515409 1631750400 1369737 4887351102 0 0 61319618
134899.2 467252991 69839801636 1631664000 1371344 4939990712 0 0 61246300

We can look at the stats for a specific token by calling token_stats_v2 or token_stats_hist_v2 and passing in the corresponding address. For example:

token_stats_v2(token_address = "0x1f9840a85d5af5bf1d1762f925bdaddc4201f984")
Variable Value
decimals 18
derivedETH 0.006996118649801181784999804392223752
id 0x1f9840a85d5af5bf1d1762f925bdaddc4201f984
name Uniswap
symbol UNI
totalLiquidity 2144853.7738
tradeVolume 781380949.3267
tradeVolumeUSD 7099187441.8701
txCount 773068
untrackedVolumeUSD 7104532201.7246

Similarly, we can get statistics for pairs following the same convention as previous:

pair_stats_v2(pair_address = "0xf00e80f0de9aea0b33aa229a4014572777e422ee")
Variable Value
createdAtBlockNumber 10881896
createdAtTimestamp 1600374417
id 0xf00e80f0de9aea0b33aa229a4014572777e422ee
liquidityProviderCount 351
reserve0 940.901506190946009069
reserve1 19916.661133515222782723
reserveETH 13.05078217841610887592210387849377
reserveUSD 40053.79913499987141134046709123516
token0Price 0.04724192975335721350901947925432114
token1Price 21.16763657244411622590365979032975
totalSupply 3882.86847708394650094
trackedReserveETH 13.05078217841610887592210387849378
txCount 15617
untrackedVolumeUSD 2917996.449041687701456679972555839
volumeToken0 350124.063511150688205857
volumeToken1 2922904.154447062735234883
volumeUSD 2917102.314312241474338116627477814
tok0 UNI
tok1 DAI

Likewise for the liquidity positions:

pair_liq_positions_v2(pair_address = "0xf00e80f0de9aea0b33aa229a4014572777e422ee")
id liquidityTokenBalance pair user
0xf00e80f0de9aea0b33aa229a4014572777e422ee-0x000e0079afa2a5aad5ff05b145abf4777b1707ac 380.308033046897392563 0xf00e80f0de9aea0b33aa229a4014572777e422ee 0x000e0079afa2a5aad5ff05b145abf4777b1707ac
0xf00e80f0de9aea0b33aa229a4014572777e422ee-0x01ebedf403c19bf4f1f6317ef64bf80a2a704701 2.477708698357644268 0xf00e80f0de9aea0b33aa229a4014572777e422ee 0x01ebedf403c19bf4f1f6317ef64bf80a2a704701
0xf00e80f0de9aea0b33aa229a4014572777e422ee-0x0220b3a3c7f41566a89c28d8fa763276038ebeb4 0 0xf00e80f0de9aea0b33aa229a4014572777e422ee 0x0220b3a3c7f41566a89c28d8fa763276038ebeb4
0xf00e80f0de9aea0b33aa229a4014572777e422ee-0x03b8941448adfd421b7617455c314aa1abdf5b18 0 0xf00e80f0de9aea0b33aa229a4014572777e422ee 0x03b8941448adfd421b7617455c314aa1abdf5b18
0xf00e80f0de9aea0b33aa229a4014572777e422ee-0x04c689d31d3e3e64f871330d412e35fe66553507 0 0xf00e80f0de9aea0b33aa229a4014572777e422ee 0x04c689d31d3e3e64f871330d412e35fe66553507
0xf00e80f0de9aea0b33aa229a4014572777e422ee-0x0552c166c914837d138741893d9820e3de2b9995 0 0xf00e80f0de9aea0b33aa229a4014572777e422ee 0x0552c166c914837d138741893d9820e3de2b9995

All of these datasets can be exported into a standard CSV file with a general data_export function, like this:

export_data(uniswap_stats_hist_v2(), "my_file.csv")

Data Exploration

Last but not least, we turn to an exploration of growth metrics on the platform, using data visualization.

There are a suite of functions designed to illustrate the growth of the platform as a whole, at a high level. These functions produce visualizations. Here is a quick survey. The first provides a view of the growth in terms of volume, liquidity, and number of transactions of the platform. This can be shown both in terms of the Uniswap platform, and with respect to particular tokens by passing in an address. At the platform level, we can see some very obvious patterns. The total liquidity in ETH peaked during the late 2020 time frame, while the total liquidity when measured in USD peaked along with the overall crypto market in spring 2021. Transactions on the platform have steadily rose as a function of time, though over the past couple of months have tended to level off some compared to the more rapid growth prior. As illustrated, these metrics can be obtained at the per-token level, in this case UNI, which allows for an even more fine-grained assessment of how use of the platform is evolving over time.

There is also a set of visualization functions that are designed to operate on pairs, for visualization of the number of pairs, the growth in terms of the aforementioned metrics of volume with respect to the pairs, and in terms of the liquidity token distribution. Here we look at these stats for the UNI/DAI pair. The first plot illustrates UNI as both the first and the second token in the pair has seen a large increase, particularly in the late 2020 time frame. The latter two plots tell a consistent story: While the overall number of daily transactions with this pair has declined, there are still several daily spikes that indicate the pair is seeing significant volume on the platform. This is just one example of the type of visualizations that uniswappeR can produce, which illustrates how this can be used to derive insights and metrics across the platform, including determining which pairs have seen the most recent growth, and so much more.

Finally, there is a function swap_visualizations which creates a pre-set panel of visualizations designed to illustrate the amount of swaps over time, and by token. Here we pass in a set of addresses and the corresponding swap data is pulled. This allows a per-user view of the performance, so we can quickly at-a-glance see how the usage of the platform has changed at the per-user, per-pair level. You can imagine this could be used to produce per-user dashboards with respect to trades / swaps done on the Uniswap platform, so users can quickly use analytics to assess their own trading behavior.

Video Tutorials

We have encapsulated much of the content of this walkthrough into two video tutorials. The first covers the setup of the package itself, and the second covers the ability to make trades with the package. Those videos can be seen below:

Conclusion

As you can see, the uniswappeR package provides a large host of functionality, ranging from smaller helper utilities, to functions for initializing trades, to aggregation and visualization functions. This package operates on both a micro / account level, but also provides a statistical overview that is useful from the perspective of the platform itself. While still early in its infancy, we do hope that this package serves as a useful tool for those familiar with the R language and opens up the Uniswap platform to more use.

Leave a Reply

Your email address will not be published. Required fields are marked *