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
+}