{ "cells": [ { "cell_type": "code", "execution_count": 1, "id": "c7c6bbb5-9a8c-4133-b604-bee1d9c0b362", "metadata": {}, "outputs": [], "source": [ "%config InlineBackend.figure_format = 'svg'\n", "\n", "import os, sys\n", "sys.path.insert(1, os.path.realpath(os.path.pardir))\n", "\n", "from typing import Sequence, Dict, Tuple\n", "\n", "from abm1559.utils import (\n", " constants,\n", ")\n", "\n", "gamma = 500000\n", "constants[\"SIMPLE_TRANSACTION_GAS\"] = gamma\n", "\n", "from abm1559.txpool import TxPool\n", "\n", "from abm1559.users import (\n", " User1559,\n", " User\n", ")\n", "\n", "from abm1559.config import rng\n", "\n", "from abm1559.txs import Tx1559\n", "\n", "from abm1559.userpool import UserPool\n", "\n", "from abm1559.chain import (\n", " Chain,\n", " Block1559,\n", " BlockAMMImplied,\n", " eth_qty,\n", ")\n", "\n", "from abm1559.simulator import (\n", " spawn_poisson_demand,\n", " update_basefee,\n", " generate_gbm,\n", " apply_block_time_variance,\n", " generate_poisson_process,\n", " generate_abm,\n", " generate_jump_process,\n", ")\n", "\n", "import matplotlib.pyplot as plt\n", "import pandas as pd\n", "pd.set_option('display.max_rows', 1000)\n", "import numpy as np\n", "import seaborn as sns\n", "from tqdm.notebook import tqdm\n", "from itertools import product" ] }, { "cell_type": "markdown", "id": "7f00177a-4aa9-4f8a-ab21-19e2842d4432", "metadata": {}, "source": [ "Model assumptions:\n", "\n", "- All transactions use 500,000 gas, block limit is 25,000,000 gas (i.e., 50 transactions).\n", "- Simulation lasts for 200 steps.\n", "- Each step, a random number of users $N_t$ is drawn from a Poisson distribution of size 100.\n", "- User value is drawn from uniform distribution between 0 and 20 Gwei per gas unit.\n", "- Users bid the miner fee as premium, = 1 Gwei.\n", "- Excess gas issued starts from an arbitrary value set to 3,600 Mgas (~0.06 Gwei implied basefee)\n", "- Implied basefee in a block providing `gas_used`, given `excess_gas_issued` is\n", "\n", "$$ b = \\frac{\\text{ethqty}(\\text{excess gas issued} + \\text{gas used}) - \\text{ethqty}(\\text{excess gas issued})}{\\text{gas used}} $$\n", "\n", "where\n", "\n", "$$ \\text{ethqty}(g) = \\exp \\Big( \\frac{g}{\\text{target gas used} \\times \\text{adjustment quotient}} \\Big) $$" ] }, { "cell_type": "markdown", "id": "d6450a82-8a3d-4311-b47f-8891cae21164", "metadata": {}, "source": [ "## Transaction pool\n", "\n", "- Evicts transactions whenever there are more than 500 pending in the queue (reminder: we set transaction such that a full block = 50 transactions)\n", "- Given the current `excess_gas_issued`, miner computes their revenue should they include 0 transaction, 1 transaction, 2 transactions, ..., 50 transactions. Number of transactions included is set so that max revenue is achieved." ] }, { "cell_type": "code", "execution_count": 2, "id": "53d30544-0006-4945-bb3b-30b9aa7438c1", "metadata": {}, "outputs": [], "source": [ "MAX_TX_POOL = 500\n", "MIN_PREMIUM = 1e9\n", "\n", "class TxPoolLimit(TxPool):\n", " \n", " def __init__(self, max_txs=MAX_TX_POOL, min_premium=MIN_PREMIUM, **kwargs):\n", " super().__init__(**kwargs)\n", " self.max_txs = max_txs\n", " self.min_premium = MIN_PREMIUM\n", " \n", " def add_txs(self, txs: Sequence[Tx1559], env: dict) -> Sequence[Tx1559]:\n", " for tx in txs:\n", " self.txs[tx.tx_hash] = tx\n", " \n", " if self.pool_length() > self.max_txs:\n", " sorted_txs = sorted(self.txs.values(), key = lambda tx: -tx.tip(env))\n", " self.empty_pool()\n", " self.add_txs(sorted_txs[0:self.max_txs], env)\n", " return sorted_txs[self.max_txs:]\n", " \n", " return []\n", "\n", "class TxPool1559(TxPoolLimit):\n", " \n", " def select_transactions(self, env, user_pool=None, rng=rng) -> Sequence[Tx1559]:\n", " # Miner side\n", " max_tx_in_block = int(constants[\"MAX_GAS_EIP1559\"] / constants[\"SIMPLE_TRANSACTION_GAS\"])\n", "\n", " valid_txs = [tx for tx in self.txs.values() if tx.is_valid(env) and tx.tip(env) >= self.min_premium]\n", " rng.shuffle(valid_txs)\n", "\n", " sorted_valid_demand = sorted(\n", " valid_txs,\n", " key = lambda tx: -tx.tip(env)\n", " )\n", " selected_txs = sorted_valid_demand[0:max_tx_in_block]\n", "\n", " return selected_txs\n", "\n", "class TxPoolAMMImplied(TxPoolLimit):\n", " \n", " def select_transactions(self, env, user_pool=None, rng=rng) -> Sequence[Tx1559]:\n", " # Miner side\n", " max_tx_in_block = int(constants[\"MAX_GAS_EIP1559\"] / constants[\"SIMPLE_TRANSACTION_GAS\"])\n", " excess_gas_issued = env[\"excess_gas_issued\"]\n", " revenues = [0]\n", " \n", " for i in range(1, max_tx_in_block + 1): \n", " implied_basefee = eth_qty(excess_gas_issued + i * constants[\"SIMPLE_TRANSACTION_GAS\"]) - eth_qty(excess_gas_issued)\n", " implied_basefee = implied_basefee / (i * constants[\"SIMPLE_TRANSACTION_GAS\"])\n", " valid_txs = [tx for tx in self.txs.values() if tx.is_valid({ \"basefee\": implied_basefee }) and tx.tip({ \"basefee\": implied_basefee }) >= self.min_premium]\n", " sorted_valid_demand = sorted(\n", " valid_txs,\n", " key = lambda tx: -tx.tip({ \"basefee\": implied_basefee })\n", " )\n", " revenues += [sum([tx.tip({ \"basefee\": implied_basefee }) for tx in sorted_valid_demand[0:(i-1)]])]\n", " \n", " max_revenue = max(revenues)\n", " \n", " if max_revenue == 0:\n", " return []\n", " \n", " opt_n_tx = len(revenues) - 1 - revenues[::-1].index(max_revenue)\n", " implied_basefee = eth_qty(excess_gas_issued + opt_n_tx * constants[\"SIMPLE_TRANSACTION_GAS\"]) - eth_qty(excess_gas_issued)\n", " implied_basefee = implied_basefee / (opt_n_tx * constants[\"SIMPLE_TRANSACTION_GAS\"])\n", " valid_txs = [tx for tx in self.txs.values() if tx.is_valid({ \"basefee\": implied_basefee }) and tx.tip({ \"basefee\": implied_basefee }) >= self.min_premium]\n", " sorted_valid_demand = sorted(\n", " valid_txs,\n", " key = lambda tx: -tx.tip({ \"basefee\": implied_basefee })\n", " )\n", " selected_txs = sorted_valid_demand[0:opt_n_tx]\n", "\n", " return selected_txs" ] }, { "cell_type": "markdown", "id": "44752398-41d8-43aa-83fa-5fc79eb70427", "metadata": {}, "source": [ "## Main simulation loop" ] }, { "cell_type": "code", "execution_count": 3, "id": "bc1f68b9-5673-4d46-999f-a273fdf00bfd", "metadata": {}, "outputs": [], "source": [ "def simulate_amm_implied(demand_scenario, txpool, UserClass, extra_metrics = None, rng = rng, silent=False):\n", " # Instantiate a couple of things\n", " chain = Chain()\n", " metrics = []\n", " user_pool = UserPool()\n", " \n", " # `env` is the \"environment\" of the simulation\n", " env = {\n", " \"basefee\": 0,\n", " \"current_block\": None,\n", " \"excess_gas_issued\": 3625 * 1e6,\n", " }\n", "\n", " for t in tqdm(range(len(demand_scenario)), disable=silent, desc=\"simulation loop\", leave=False):\n", " if demand_scenario[t] > 5 * MAX_TX_POOL:\n", " break\n", " \n", " # Sets current block\n", " env[\"current_block\"] = t\n", " \n", " # Reset the random number generator with new seed to generate users with same values across runs\n", " rng = np.random.default_rng((2 ** t) * (3 ** 1))\n", " \n", " ### SIMULATION ###\n", "\n", " # We return some demand which on expectation yields `demand_scenario[t]` new users per round\n", " users = spawn_poisson_demand(t, demand_scenario[t], User1559, rng=rng)\n", " \n", " # Add new users to the pool\n", " # We query each new user with the current basefee value\n", " # Users either return a transaction or None if they prefer to balk\n", " decided_txs = user_pool.decide_transactions(users, env)\n", "\n", " # New transactions are added to the transaction pool\n", " # `evicted_txs` holds the transactions removed from the pool for lack of space\n", " pool_limit_evicted_txs = txpool.add_txs(decided_txs, env)\n", "\n", " # The best valid transactions are taken out of the pool for inclusion\n", " selected_txs = txpool.select_transactions(env, rng = rng)\n", " \n", " txpool.remove_txs([tx.tx_hash for tx in selected_txs])\n", "\n", " # We create a block with these transactions\n", " block = BlockAMMImplied(\n", " txs = selected_txs, parent_hash = chain.current_head,\n", " height = t, excess_gas_issued = env[\"excess_gas_issued\"]\n", " )\n", " \n", " env[\"excess_gas_issued\"] = max(0, env[\"excess_gas_issued\"] + block.gas_used() - constants[\"TARGET_GAS_USED\"])\n", " env[\"basefee\"] = eth_qty(env[\"excess_gas_issued\"])\n", " env[\"basefee\"] = env[\"basefee\"] / constants[\"BASEFEE_MAX_CHANGE_DENOMINATOR\"] / constants[\"TARGET_GAS_USED\"]\n", " \n", " # The block is added to the chain\n", " chain.add_block(block)\n", " \n", " ### METRICS ### \n", " row_metrics = {\n", " \"block\": t,\n", " \"users\": len(users),\n", " \"decided_txs\": len(decided_txs),\n", " \"pool_limit_evictions\": len(pool_limit_evicted_txs),\n", " \"included_txs\": len(selected_txs),\n", " \"basefee\": env[\"basefee\"] / 1e9, # to Gwei\n", " \"excess_gas_issued\": env[\"excess_gas_issued\"] / 1e6, # in Mgas\n", " \"pool_length\": txpool.pool_length(),\n", " \"gas_used\": block.gas_used(),\n", " }\n", " \n", " if not extra_metrics is None:\n", " row_metrics = {\n", " **row_metrics,\n", " **extra_metrics(env, users, user_pool, txpool),\n", " }\n", " \n", " metrics.append(row_metrics)\n", "\n", " return (pd.DataFrame(metrics), user_pool, chain)" ] }, { "cell_type": "code", "execution_count": 4, "id": "5048ee6c-1e2f-4f83-b165-c41a8328ea8c", "metadata": {}, "outputs": [], "source": [ "%%capture\n", "demand_scenario = [100 for i in range(200)]\n", "txpool = TxPoolAMMImplied()\n", "(df, user_pool, chain) = simulate_amm_implied(demand_scenario, txpool, User1559)" ] }, { "cell_type": "markdown", "id": "fb93e79f-8653-4e26-ad52-7add6aaac5ba", "metadata": {}, "source": [ "## Plots\n", "\n", "### Basefee over time" ] }, { "cell_type": "code", "execution_count": 5, "id": "729f099f-0cff-4b11-b33a-df4fac2e0536", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" }, { "data": { "image/svg+xml": [ "\n", "\n", "\n", " \n", " \n", " \n", " \n", " 2021-05-13T17:28:09.678121\n", " image/svg+xml\n", " \n", " \n", " Matplotlib v3.4.2, https://matplotlib.org/\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "\n" ], "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "df[\"basefee\"].plot()" ] }, { "cell_type": "markdown", "id": "d4f3e68d-624c-4316-bf3f-ca3be0c490bb", "metadata": {}, "source": [ "### Transaction pool over time" ] }, { "cell_type": "code", "execution_count": 6, "id": "5c79ab18-8876-4dc8-bb50-ec295ddf7411", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" }, { "data": { "image/svg+xml": [ "\n", "\n", "\n", " \n", " \n", " \n", " \n", " 2021-05-13T17:28:09.791869\n", " image/svg+xml\n", " \n", " \n", " Matplotlib v3.4.2, https://matplotlib.org/\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "\n" ], "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "df[\"pool_length\"].plot()" ] }, { "cell_type": "markdown", "id": "bfbd76b9-bad9-401f-ad6b-f69eae65cfa0", "metadata": {}, "source": [ "### Excess gas issued over time" ] }, { "cell_type": "code", "execution_count": 7, "id": "fa8fdc8b-27c4-441c-86a5-7a9ac5ba53aa", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" }, { "data": { "image/svg+xml": [ "\n", "\n", "\n", " \n", " \n", " \n", " \n", " 2021-05-13T17:28:09.966068\n", " image/svg+xml\n", " \n", " \n", " Matplotlib v3.4.2, https://matplotlib.org/\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "\n" ], "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "df[\"excess_gas_issued\"].plot()" ] }, { "cell_type": "markdown", "id": "f6867c38-7721-496c-8b98-1c3a2345aa3a", "metadata": {}, "source": [ "## Oscillations revisited\n", "\n", "- Users have value between 10 and 11 Gwei per gas unit.\n", "- 1000 users show up each step." ] }, { "cell_type": "code", "execution_count": 8, "id": "6a0bf03a-ae67-44f6-b5c1-daad314f56cc", "metadata": {}, "outputs": [], "source": [ "class NarrowUser(User1559):\n", " def __init__(self, wakeup_block, **kwargs):\n", " super().__init__(wakeup_block, cost_per_unit = 0, **kwargs)\n", " self.value = self.rng.uniform(low=10, high=11) * (10 ** 9)" ] }, { "cell_type": "markdown", "id": "dca19a85-9e8b-4d7f-ac1d-5fc650bf5826", "metadata": {}, "source": [ "### With AMM design" ] }, { "cell_type": "code", "execution_count": 9, "id": "2ae91d8d-dd25-4755-a3d9-1d52ac2f5ed1", "metadata": {}, "outputs": [], "source": [ "%%capture\n", "demand_scenario = [1000 for i in range(200)]\n", "txpool = TxPoolAMMImplied()\n", "(df_amm, _, _) = simulate_amm_implied(demand_scenario, txpool, NarrowUser)" ] }, { "cell_type": "markdown", "id": "f27573a9-4a86-4b90-a374-1249dcf050ee", "metadata": {}, "source": [ "#### Basefee over time" ] }, { "cell_type": "code", "execution_count": 10, "id": "515334e6-ac5f-42f8-8ff9-f52fcb6c267f", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "" ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" }, { "data": { "image/svg+xml": [ "\n", "\n", "\n", " \n", " \n", " \n", " \n", " 2021-05-13T17:28:21.763912\n", " image/svg+xml\n", " \n", " \n", " Matplotlib v3.4.2, https://matplotlib.org/\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "\n" ], "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "df_amm[\"basefee\"].plot()" ] }, { "cell_type": "markdown", "id": "6f6b8799-faad-400a-ae4a-96a4c27d19d0", "metadata": {}, "source": [ "#### Gas used per block" ] }, { "cell_type": "code", "execution_count": 11, "id": "e4e81e9c-c4a3-4429-84e4-2948710c0d1b", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" }, { "data": { "image/svg+xml": [ "\n", "\n", "\n", " \n", " \n", " \n", " \n", " 2021-05-13T17:28:21.902317\n", " image/svg+xml\n", " \n", " \n", " Matplotlib v3.4.2, https://matplotlib.org/\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "\n" ], "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "df_amm[\"gas_used\"].plot()" ] }, { "cell_type": "markdown", "id": "fbcfd2f2-b820-4ceb-b32d-e28a1831d9ac", "metadata": {}, "source": [ "### With classic 1559" ] }, { "cell_type": "code", "execution_count": 12, "id": "f7291bd0-5067-4691-8662-30bbe93aaa16", "metadata": {}, "outputs": [], "source": [ "def simulate_1559(demand_scenario, txpool, UserClass, extra_metrics = None, rng = rng, silent=False):\n", " # Instantiate a couple of things\n", " chain = Chain()\n", " metrics = []\n", " user_pool = UserPool()\n", " \n", " # `env` is the \"environment\" of the simulation\n", " env = {\n", " \"basefee\": 0.06 * 1e9,\n", " \"current_block\": None,\n", " }\n", "\n", " for t in tqdm(range(len(demand_scenario)), disable=silent, desc=\"simulation loop\", leave=False):\n", " \n", " # Sets current block\n", " env[\"current_block\"] = t\n", " \n", " # Reset the random number generator with new seed to generate users with same values across runs\n", " rng = np.random.default_rng((2 ** t) * (3 ** 1))\n", " \n", " ### SIMULATION ###\n", "\n", " # We return some demand which on expectation yields `demand_scenario[t]` new users per round\n", " users = spawn_poisson_demand(t, demand_scenario[t], User1559, rng=rng)\n", " \n", " # Add new users to the pool\n", " # We query each new user with the current basefee value\n", " # Users either return a transaction or None if they prefer to balk\n", " decided_txs = user_pool.decide_transactions(users, env)\n", "\n", " # New transactions are added to the transaction pool\n", " # `evicted_txs` holds the transactions removed from the pool for lack of space\n", " pool_limit_evicted_txs = txpool.add_txs(decided_txs, env)\n", "\n", " # The best valid transactions are taken out of the pool for inclusion\n", " selected_txs = txpool.select_transactions(env, rng = rng)\n", " \n", " txpool.remove_txs([tx.tx_hash for tx in selected_txs])\n", "\n", " # We create a block with these transactions\n", " block = Block1559(\n", " txs = selected_txs, parent_hash = chain.current_head,\n", " height = t, basefee = env[\"basefee\"]\n", " )\n", " \n", " # The block is added to the chain\n", " chain.add_block(block)\n", " \n", " ### METRICS ### \n", " row_metrics = {\n", " \"block\": t,\n", " \"users\": len(users),\n", " \"decided_txs\": len(decided_txs),\n", " \"pool_limit_evictions\": len(pool_limit_evicted_txs),\n", " \"included_txs\": len(selected_txs),\n", " \"basefee\": env[\"basefee\"] / 1e9, # to Gwei\n", " \"pool_length\": txpool.pool_length(),\n", " \"gas_used\": block.gas_used(),\n", " }\n", " \n", " if not extra_metrics is None:\n", " row_metrics = {\n", " **row_metrics,\n", " **extra_metrics(env, users, user_pool, txpool),\n", " }\n", " \n", " metrics.append(row_metrics)\n", " \n", " # Finally, basefee is updated and a new round starts\n", " env[\"basefee\"] = update_basefee(block, env[\"basefee\"])\n", "\n", " return (pd.DataFrame(metrics), user_pool, chain)" ] }, { "cell_type": "code", "execution_count": 13, "id": "3f38dcb6-c649-46ed-8944-0efc03fa5719", "metadata": {}, "outputs": [], "source": [ "%%capture\n", "demand_scenario = [1000 for i in range(200)]\n", "txpool = TxPool1559()\n", "(df_1559, _, _) = simulate_1559(demand_scenario, txpool, NarrowUser)" ] }, { "cell_type": "markdown", "id": "79db5813-71d4-4aa3-a318-add9f208eac6", "metadata": {}, "source": [ "#### Basefee over time" ] }, { "cell_type": "code", "execution_count": 14, "id": "d7335a03-f50f-4028-bbec-288a09183f75", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "" ] }, "execution_count": 14, "metadata": {}, "output_type": "execute_result" }, { "data": { "image/svg+xml": [ "\n", "\n", "\n", " \n", " \n", " \n", " \n", " 2021-05-13T17:28:30.087550\n", " image/svg+xml\n", " \n", " \n", " Matplotlib v3.4.2, https://matplotlib.org/\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "\n" ], "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "df_1559[\"basefee\"].plot()" ] }, { "cell_type": "markdown", "id": "d11e5ddf-4d4c-48cd-8439-54b6ad9f63a2", "metadata": {}, "source": [ "#### Gas used per block" ] }, { "cell_type": "code", "execution_count": 15, "id": "c4cc83ef-e722-4963-b319-a4682a8f138e", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "" ] }, "execution_count": 15, "metadata": {}, "output_type": "execute_result" }, { "data": { "image/svg+xml": [ "\n", "\n", "\n", " \n", " \n", " \n", " \n", " 2021-05-13T17:28:30.215250\n", " image/svg+xml\n", " \n", " \n", " Matplotlib v3.4.2, https://matplotlib.org/\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "\n" ], "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "df_1559[\"gas_used\"].plot()" ] }, { "cell_type": "markdown", "id": "a6b2b7d0-8ce7-42a6-851a-e619c2bbbf0f", "metadata": {}, "source": [ "Oscillations do seem more violent in the classic 1559 case, though they do not completely disappear with the AMM design." ] }, { "cell_type": "raw", "id": "0328ecdd-622f-4480-8d77-fe907b3a357b", "metadata": {}, "source": [ "Make EIP 1559 more like an AMM curve" ] }, { "cell_type": "raw", "id": "113fac64-dab0-49ed-8e97-a636c043b265", "metadata": {}, "source": [ "Exploring https://ethresear.ch/t/make-eip-1559-more-like-an-amm-curve/9082" ] }, { "cell_type": "raw", "id": "65cc6755-784a-4f40-bd48-ee5de5e470ea", "metadata": {}, "source": [ "// References + footnotes\n", "\n", "// Authors\n", "let authorData = [\"barnabe\"];" ] }, { "cell_type": "raw", "id": "351c7dda-65ff-45b9-bc0a-4dbea72b8940", "metadata": {}, "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "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": 5 }