Skip to content

feewet/defi-tournament

Repository files navigation

DeFi Trading Tournament

Trading game based on Uniswap V2. In this game, 8 differnet tokens go head-to-head in a tournament-style bracket where the highest price pool is the winner. A forked version of uniswap with a 1% fee is used to collect interest on trading volume.

Run & Test

nvm install 16.10.0 && nvm use 16.10.0
yarn && yarn build && yarn test

Configuration

  1. Copy env example to env:

cp .env.example .env

  1. Insert Alchemy API key, Polygonscan API Key, and Etherscan API key into .env

Running Scripts & Deployment

In hardhat.config.ts change default network to your desired network

defaultNetwork: '{network}'

Copy your private key (starting with 0x) and run the following commands:

# make sure ts-node is installed
npm install -g typescript
npm install -g ts-node

# mock deployment (testnet)
ts-node scripts/deploy_mock.ts "{private_key}" "{network}"

# mainnet deployment
ts-node scripts/deploy_mainnet.ts "{private_key}" "{network}"

# mock start tournament
ts-node scripts/deploy_mainnet.ts "{private_key}" "{network}"

Front End

In order to interact with this game, a custom front end will need to be deployed using the modified Uniswap V2 contracts in this repository. In the future, a cloned version of the Uniswap front end can be quickly changed to support the modified contracts.

Smart Contracts

TournamentManager

This contract contains all the logic to run a tournament. This includes:

  • Deploy tokens & uniswap pools
  • Track winning & losing tokens each round
  • Redeem winning tokens for USDC
  • Collect Fees

Bracket Logic

  • Tournament bracket is a uint8[16]
  • Each byte contains a uint8 representing tokenId
  • 0xff represents unresolved game state uint8(-1)
  • Winner of each round is stored in the next empty slot
Round      0               1               2
		 0: (0,1) -> A   4: (A,B) -> E   6: (E,F) -> Winner
		 1: (2,3) -> B   5: (C,D) -> F
		 2: (4,5) -> C
		 3: (6,7) -> D

Bracket: [0, 1, 2, 3, 4, 5, 6, 7, A, B, C, D, E, F, W]

 0 \
    8 
 1 /  \
       12
 2 \  /  \
    9     \
 3 /       \
           14 (winner)
 4 \       /
    10    /
 5 /  \  /
       13
 6 \  /
    11
 7 /

Examples

Simple Tournament Example
Note: Fee model causes it to be difficult to predict exact fees without further testing
Initial USDC: 800 (100 USDC per pool)
In Round 0, users purchase 100 * (tokenId + 1) so that token0 has +100, token1 has +200, etc.
Keep in mind, Each round subtracts the initial liquidity provided from the losing pool
---------------------------------------------------------------------------------------------------------------|
|    Round 0    |  -  |  +  |     Round 1      |  -  |  +  |    Round 2   |           |  -  |      Winner      |
|---------------| Fee | Buy |------------------| Fee | Buy |--------------|-----------| Fee |------------------|
| 200 (0) \                                                                                                    |
|          500  - 103 + 100 ->  497 (1)                                                                        |
| 300 (1) /                            \                                                                       |
|                                       1490 - 107.87 + 100 -> 1,482.13 (3)                                    |
| 400 (2) \                            /                                  \                                    |
|          900  - 107 + 200 ->  993 (3)                                    \                                   |
| 500 (3) /                                                                 \                                  |
|                                                                            5,034.35 - 232.73 -> 4,901.62 (7) |
| 600 (4) \                                                                 /                                  |
|          1300 - 111 + 300 -> 1489 (5)                                    /                                   |
| 700 (5) /                            \                                  /                                    |
|                                       3474 - 121.78 + 200 -> 3,552.22 (7)                                    |
| 800 (6) \                            /                                                                       |
|          1700 - 115 + 400 -> 1985 (7)                                                                        |
| 900 (7) /                                                                                                    |
|--------------------------------------------------------------------------------------------------------------|
| Round Fee    | 35.80 |                       | 29.65 |                              | 21.74 |                |
|--------------------------------------------------------------------------------------------------------------|
Total Fees: 35.80 + 29.65 + 21.75 = 87.20

ChainlinkRandomInterval

  • A delay is added before there is a chance a round can end
  • Trading is divided into 30 minute epochs (e)
  • Random number is generated by chainlink VRF
  • Every 30 minutes a public function update() can be called
  • update() has a e/120 chance of ending a round
  • As e increases, the chance of the round ending also increases
  • p(e) = 1 - Σ(n = 0, e) ( (120 - e) / 120 )
  • Epoch (e), minutes (t), probability (p)
 |----------------|
 |  e    t    p   |
 |----------------|
 |  0    0   0.00 |
 |  1    30  0.01 | ~ 1% chance round has ended
 |  2    60  0.02 |
 |  3    90  0.05 |
 |  4    120 0.08 |
 |  5    150 0.12 |
 |  6    180 0.16 |
 |  7    210 0.21 |
 |  8    240 0.26 | ~25% chance round has ended
 |  9    270 0.32 |
 | 10    300 0.38 |
 | 11    330 0.43 |
 | 12    360 0.49 | ~50% chance round has ended
 | 13    390 0.55 |
 | 14    420 0.60 |
 | 15    450 0.65 |
 | 16    480 0.70 |
 | 17    510 0.74 | ~75% chance round had ended
 | 18    540 0.78 |
 | 19    570 0.81 |
 | 20    600 0.84 |
 | 21    630 0.87 |
 | 22    660 0.90 |
 | 23    690 0.92 |
 | 24    720 0.93 |
 | 25    750 0.95 |
 | 26    780 0.96 |
 | 27    810 0.97 |
 | 28    840 0.97 |
 | 29    870 0.98 |
 | 30    900 0.99 | ~99% chance round has ended
 |----------------|

Fee Structure

The fee model is designed to collect a fee based on the volume of swaps during the rournament. Using the growth in k, fees can be tracked by storing the original k value at the last time fees were collected, and updating it after fees are collected. The original liquidity provided by the tournament is subtracted from the losing pool at the end of each round.

Resolving a Match and collecting fees

After each round the following steps are taken:

  1. Calculate winning/losing tokens based on highest uniswap price
  2. Calculate LP fee
  3. Remove fee liquidity and swap tokens for USDC
  4. Remove losing token liquidity
  5. Swap USDC from losing pair (minus initial liquidity) for winning tokens
  6. Burn remaining tokens and return winning ID

Uniswap Custom Fee

Uses forked & modified uniswap v2 smart contracts to allow for a custom fee. Custom fee is set in the factory when the owner calls setFee. All future pools deployed after the fee change will implement the custom fee. Existing pool fees cannot be changed, only future pools.

The new uniswap smart contracts are located in contracts/uniswap and are minimally changed from the original. If reviewing or auditing this code, the contracts can be diffed against the original to asses any security risks relating to changing the fees.

Uniswap Tests

Uniswap v2 tests were copied from the original repository into tests/uniswap with minor changes to allow support in hardhat. The original packages & test environment were added in package.json as {package}-uniswap.

About

DeFi Trading Tournament with Uniswap V2 Pools

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published