diff --git a/hydradx/notebooks/Stableswap/ImpermanentGainAttack.ipynb b/hydradx/notebooks/Stableswap/ImpermanentGainAttack.ipynb new file mode 100644 index 00000000..02bc0da8 --- /dev/null +++ b/hydradx/notebooks/Stableswap/ImpermanentGainAttack.ipynb @@ -0,0 +1,254 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "

Relationship between IL and price change in a stableswap pool

\n" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "tags": [], + "ExecuteTime": { + "end_time": "2023-07-06T20:50:06.289107809Z", + "start_time": "2023-07-06T20:50:06.245262315Z" + } + }, + "outputs": [], + "source": [ + "import sys\n", + "import os\n", + "import glob\n", + "import random\n", + "import copy\n", + "sys.path.append('../..')\n", + "\n", + "from model import processing\n", + "from matplotlib import pyplot as plt\n", + "\n", + "from model import run\n", + "from model import plot_utils as pu\n", + "from model.amm.omnipool_amm import OmnipoolState, cash_out_omnipool, value_assets, usd_price, lrna_price\n", + "from model.amm.stableswap_amm import StableSwapPoolState\n", + "from model.amm.agents import Agent\n", + "from model.amm.trade_strategies import omnipool_arbitrage, invest_all, price_sensitive_trading\n", + "from model.amm.global_state import GlobalState, fluctuate_prices, historical_prices\n", + "\n", + "# same seed, same parameters = same simulation result\n", + "random.seed(42)\n", + "# price_list = processing.import_binance_prices(['BTC', 'ETH', 'DOT'], start_date='Jan 1 2023', days = 120)\n", + "\n", + "assets = {\n", + " 'USDA': {'usd price': 1, 'weight': 0.5},\n", + " 'USDB': {'usd price': 1, 'weight': 0.5}\n", + "}\n", + "\n", + "assert sum([t['weight'] for t in assets.values()]) == 1\n", + "\n", + "initial_tvl = 1000000\n", + "\n", + "initial_state = GlobalState(\n", + " pools={\n", + " 'stableswap': StableSwapPoolState(\n", + " tokens={\n", + " tkn: initial_tvl * assets[tkn]['weight'] for tkn in assets\n", + " },\n", + " amplification=1000,\n", + " trade_fee=0\n", + " )\n", + " },\n", + " agents = {\n", + " 'LP': Agent(\n", + " holdings={'USDA': 5100, 'USDB': 0},\n", + " trade_strategy=invest_all('stableswap')\n", + " ),\n", + " 'Trader': Agent(\n", + " holdings={tkn: 10000000000000 for tkn in assets}\n", + " )\n", + " },\n", + " external_market={tkn: assets[tkn]['usd price'] for tkn in assets},\n", + " # archive_all=False\n", + ")\n" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": { + "tags": [], + "ExecuteTime": { + "end_time": "2023-07-06T20:50:06.289443943Z", + "start_time": "2023-07-06T20:50:06.288961439Z" + } + }, + "outputs": [ + { + "data": { + "text/plain": "global state \npools: \n\n Stable Swap Pool: stableswap\n ********************************\n trade fee: 0\n shares: 1000000.0\n amplification constant: 1000\n tokens: (\n \n USDA\n quantity: 500000.0\n weight: 0.5\n \n USDB\n quantity: 500000.0\n weight: 0.5\n \n )\n error message:Agent has insufficient funds.\n\nagents: \n\n Agent: LP\n ********************************\n trade strategy: invest all (stableswap)\n holdings: (\n \n *USDA*: 5100.0\n \n *USDB*: 0\n \n *USD*: 0\n \n *stableswap*: 0.0\n price: 1.0000012679\n )\n \n Agent: Trader\n ********************************\n trade strategy: None\n holdings: (\n \n *USDA*: 10000000000000\n \n *USDB*: 10000000000000\n \n *USD*: 0\n )\n \nmarket prices: \n\n USDA: $1\n USDB: $1\n USD: $1\n\nevolution function: None" + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# steps = 201\n", + "# # price_min = 0.2\n", + "# # price_max = 5\n", + "# trade_size_min, trade_size_max = -1000000, 1000000\n", + "# step_factor = (trade_size_max / trade_size_min) ** (1 / (steps - 1))\n", + "# trade_sizes = [trade_size_min + i * (trade_size_max - trade_size_min) / steps for i in range(steps)]\n", + "# # [-trade_size_min * step_factor ** i for i in range(steps)][::-1] + [trade_size_min * step_factor ** i for i in range(steps)]\n", + "\n", + "trade_size = 1000000\n", + "\n", + "events = []\n", + "\n", + "initial_holdings = copy.deepcopy(initial_state.agents['LP'].holdings)\n", + "initial_trader_holdings = copy.deepcopy(initial_state.agents['Trader'].holdings)\n", + "first_state = initial_state.copy()\n", + "\n", + "events.append(\n", + " run.run(initial_state, time_steps=1, silent=True)[-1].execute_swap(\n", + " pool_id='stableswap',\n", + " agent_id='LP',\n", + " tkn_sell='USDA' if trade_size > 0 else 'USDB',\n", + " tkn_buy='USDB' if trade_size > 0 else 'USDA',\n", + " sell_quantity=max(abs(trade_size), 0),\n", + " )\n", + ")\n", + "\n", + "new_state = events[-1].copy()\n", + "\n", + "# StableSwapPoolState.execute_remove_uniform(\n", + "# state=event.pools['stableswap'],\n", + "# agent=event.agents['LP'],\n", + "# shares_removed=event.agents['LP'].holdings['stableswap']\n", + "# )\n", + "\n", + "StableSwapPoolState.execute_remove_liquidity(\n", + " state=new_state.pools['stableswap'],\n", + " agent=new_state.agents['LP'],\n", + " shares_removed=new_state.agents['LP'].holdings['stableswap'],\n", + " tkn_remove='USDA'\n", + ")\n", + "\n", + "final_state = new_state.copy()\n", + "\n", + "trade_size2 = -trade_size\n", + "\n", + "final_state.execute_swap(\n", + " pool_id='stableswap',\n", + " agent_id='LP',\n", + " tkn_sell='USDA' if trade_size2 > 0 else 'USDB',\n", + " tkn_buy='USDB' if trade_size2 > 0 else 'USDA',\n", + " sell_quantity=abs(trade_size2),\n", + " )\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[1, 1.0]\n" + ] + } + ], + "source": [ + "final_prices = [1, final_state.pools['stableswap'].spot_price]\n", + "print(final_prices)" + ], + "metadata": { + "collapsed": false, + "ExecuteTime": { + "end_time": "2023-07-06T20:50:06.289617582Z", + "start_time": "2023-07-06T20:50:06.289242369Z" + } + } + }, + { + "cell_type": "code", + "execution_count": 7, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'USDA': 5100, 'USDB': 0}\n" + ] + } + ], + "source": [ + "print(initial_holdings)" + ], + "metadata": { + "collapsed": false, + "ExecuteTime": { + "end_time": "2023-07-06T20:50:27.177343274Z", + "start_time": "2023-07-06T20:50:27.171229893Z" + } + } + }, + { + "cell_type": "code", + "execution_count": 8, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'USDA': 5100.0, 'USDB': 0, 'USD': 0, 'stableswap': 0.0}\n" + ] + } + ], + "source": [ + "print(final_state.agents['LP'].holdings)" + ], + "metadata": { + "collapsed": false, + "ExecuteTime": { + "end_time": "2023-07-06T20:50:32.313529007Z", + "start_time": "2023-07-06T20:50:32.290166910Z" + } + } + }, + { + "cell_type": "code", + "execution_count": null, + "outputs": [], + "source": [], + "metadata": { + "collapsed": false + } + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.7" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +}