Skip to content

zhenweigc/Uniswap

Repository files navigation

Uniswap

Overview

Uniswap is an automated liquidity protocol powered by a constant product formula. This project simulates simplified Uniswap V2 pools, allowing for adding/removing liquidity, swapping tokens, and performing arbitrage calculations between pools. Some concepts such as Flash Swap, Oracles, Pool Tokens are not implemented.

Assumptions

  • The input format for the simulation includes: Action Pool_ID(not required for addPool) Amount_1 Amount_2 Timestamp, Sleep time, removePool Pool_ID, calculateArbitrage Pool_ID1 Pool_ID2.
  • Actions can be: addPool, addLiquidity, removeLiquidity, swapDaiToEth, swapEthToDai.
  • Pool IDs are uint64_t type variables, which start from 0 and are managed by the Pool_Manager.
  • This program can support V3 protocol in the future, but for now there is only V2 implemented.
  • calculateArbitrage only supports two pools at each time.
  • There could be more than one input file read by the program, files to read and log file to write in should be given at the start via argv.

Environment

  • C++17 compiler (e.g., g++)
  • Make (for building the project using the provided Makefile)
  • Linux and Valgrind (if the user would like to run the Valgrind checking option)
  • Python3 (If the user would like to run the benchmark test)

Design Patterns and Structure

  • Singleton Pattern: Ensures a single instance of the Pool_Manager throughout the application.
+----------------+       +----------------+
|                |       |                |
| Uniswap_V2     |------>|  LiquidityPool |
|                |       |                |
+----------------+       +----------------+
       ^
       |
       |     +----------------+
       |     |                |
       +---->|  Pool_Manager  |
             |                |
             +----------------+
                ^         ^
                |         |
                |         |
    +-------------+     +---------------+
    |             |     |               |
    |             |     |               |
    | Arbitrage_V2| <-- |Trade_Processor|
    |             |     |               |
    +-------------+     +---------------+

Functions and Methods

  • LiquidityPool: Base class representing a liquidity pool, with basic getter/setter methods implemented.
  • Uniswap_V2: Derived class implementing Uniswap V2 specific operations. Previous virtual methods such as swap/addLiquidity are implemented. Trading actions related methods are guarded by a Mutex.
  • Pool_Manager: Manages multiple pools, each pool can be accessed via Pool ID(uint64_t). Id starts from 0, and is recycled when a pool is removed.
    • uint64_t addPool(std::shared_ptr<LiquidityPool> pool)
    • std::weak_ptr<LiquidityPool> getPool(uint64_t id)
    • std::shared_ptr<LiquidityPool> removePool(uint64_t id)
  • Arbitrage_V2: Calculates arbitrage opportunities between two pools, return <0.0, 0.0> if there is either no profit, or at least one pool does not exist any more.
    • std::tuple<double, double> calculateArbitrage2Pools(uint64_t poolAId, uint64_t poolBId) const

Compiling and Running the Program

  1. Navigate to the project directory.
  2. Run make to compile the program.
  3. Run ./uniswap_simulator V2 <log_file> <input_file1> <input_file2> ... to run the simulation.
  4. Run make clean to clean object files and the executable.
  5. Run make valgrind to perform memory checks with Valgrind.
  6. Run make benchmark to run benchmarking tests.(Make sure benchmark test files are generated in the Tests folder. If not, run make generate_tests first)
  7. Run make clean_benchmark_tests and make clean_logs to clean generated benchmark test files and logs.

Benchmark Results

The following benchmark compares the execution time of processing a single large file versus multiple smaller files concurrently. Both scenarios involve 10 pools and a total of 10000 actions.

time ./uniswap_simulator V2 Tests/logs.txt Tests/mega_benchmark_test.txt

real    0m1.089s
user    0m0.054s
sys     0m0.035s

time ./uniswap_simulator V2 Tests/logs.txt Tests/Benchmark_non_blocking_1.txt Tests/Benchmark_non_blocking_2.txt Tests/Benchmark_non_blocking_3.txt Tests/Benchmark_non_blocking_4.txt Tests/Benchmark_non_blocking_5.txt Tests/Benchmark_non_blocking_6.txt Tests/Benchmark_non_blocking_7.txt Tests/Benchmark_non_blocking_8.txt Tests/Benchmark_non_blocking_9.txt Tests/Benchmark_non_blocking_10.txt

real    0m1.107s
user    0m0.153s
sys     0m0.054s

These results indicate that the concurrency implementation is effective, with the concurrent processing time being comparable to the single file processing time.

Benchmark Output

Miscellaneous

  • Several test files are provided in the Tests folder, including arbitrage and multi-file scenarios. These are not randomly generated by the python script.
  • Swap computation can have different result upon how to calculated the fee. In this program, we will substract the fee from input ETH/DAI, then compute the DAI/ETH out from the pool. Check the blog reference below for an example.

Reference List

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published