
{"id":49743,"date":"2025-03-05T10:33:34","date_gmt":"2025-03-05T10:33:34","guid":{"rendered":"https:\/\/mycryptomania.com\/?p=49743"},"modified":"2025-03-05T10:33:34","modified_gmt":"2025-03-05T10:33:34","slug":"uniswap-v2-math-tutorial-using-uniswappy","status":"publish","type":"post","link":"https:\/\/mycryptomania.com\/?p=49743","title":{"rendered":"Uniswap V2 Math Tutorial using UniswapPy"},"content":{"rendered":"<p>Constant product price (CPT) curve pre- and post-swap; which is a core tool useful for Decentralized FinanceA Uniswap V2 math walk-through tutorialWe will be covering: swaps, double-sided withdraw \/ deposits, and single-sided withdraw \/\u00a0depositsUtilizes the <a href=\"https:\/\/defipy.readthedocs.io\/en\/latest\/\">DeFiPy python\u00a0suite<\/a><\/p>\n<h3>1. Introduction<\/h3>\n<p>In 2016, <a href=\"https:\/\/x.com\/VitalikButerin\">Vitalik Buterin<\/a> (ie, the founder of <a href=\"https:\/\/ethereum.org\/\">Ethereum<\/a>) submitted a <a href=\"https:\/\/www.reddit.com\/r\/ethereum\/comments\/55m04x\/lets_run_onchain_decentralized_exchanges_the_way\/\">Reddit post<\/a> where he proposed his raw idea of the automated market maker (AMM). A year later, <a href=\"https:\/\/x.com\/haydenzadams\">Hayden Adams<\/a> began working on turning this idea into a functional product and founded <a href=\"https:\/\/uniswap.org\/\">Uniswap<\/a>, which was launched on the Ethereum mainnet in November\u00a02018.<\/p>\n<p>An automated market maker (AMM) protocol is the mechanism used by decentralized exchanges (DEXs). These DEXs consist of liquidity pools (LPs) represented by various trading pairs (eg. ETH\/USDC, ETH\/WBTC, etc.) acting as the AMM. Trading activity within these LPs are governed via smart contract through a simple and elegant concept called the <em>constant product trading (CPT) <\/em>formula denoted\u00a0as:<\/p>\n<p>In this article, we walk through the basic underpinning mathematical concepts behind the Uniswap V2 AMM protocol while using the <a href=\"https:\/\/github.com\/defipy-devs\/uniswappy\">UniswapPy<\/a> python package to guide the discussion. This is useful for anyone who is unfamiliar with Uniswap V2 and is looking to onboard themselves into AMMs for the first\u00a0time.<\/p>\n<h3>2. Swap derivation<\/h3>\n<p>A swap is when someone comes to the LP with an amount of one of the pair assets, say \u0394y, and expects to receive an amount of the opposing asset, \u0394x. Since we are not providing any new liquidity to the pool, the liquidity, L, should remain unchanged post exchange. This operation results in a new position on the CPT curve, as per image to the intro of this article. To start, let\u2019s setup our mock\u00a0LP:<\/p>\n<p>dai = ERC20(&#8220;DAI&#8221;, &#8220;0x111&#8221;)<br \/>eth = ERC20(&#8220;ETH&#8221;, &#8220;0x09&#8221;)<br \/>exchg_data = UniswapExchangeData(tkn0 = eth, tkn1 = dai, symbol=&#8221;LP&#8221;, address=&#8221;0x011&#8243;)<\/p>\n<p>factory = UniswapFactory(&#8220;ETH pool factory&#8221;, &#8220;0x2&#8221;)<br \/>lp = factory.deploy(exchg_data)<br \/>Join().apply(lp, user_nm, eth_amount, dai_amount)<br \/>lp.summary()<\/p>\n<p>Exchange ETH-DAI (LP)<br \/>Reserves: ETH = 1000.0, DAI = 1000000.0<br \/>Liquidity: 31622.776601683792 <\/p>\n<p>Given the CPT\u00a0formula:<\/p>\n<p>with 0.3% swap\u00a0fee:<\/p>\n<p>Since L is unchanged when performing a swap, the CPT swap formula with fee is given\u00a0as:<\/p>\n<p>where \u0394y is the amount swapped into the LP and \u0394x is the receive amount. To determine this receive amount, we isolate\u00a0\u0394x:<\/p>\n<p>After performing some additional algebra, we get the swap derivation:<\/p>\n<p>Now, we can manually calculate:<\/p>\n<p>dy = 1000<br \/>gamma = 997\/1000<br \/>x = lp.get_reserve(eth)<br \/>y = lp.get_reserve(dai)<\/p>\n<p>dx = (gamma*x*dy)\/(y + gamma*dy)<\/p>\n<p>print(f&#8217;We receive {dx:.5f} ETH for {dy} DAI&#8217;)<\/p>\n<p>We receive 0.99601 ETH for 1000 DAI<\/p>\n<p>Next, we perform a swap using <a href=\"https:\/\/github.com\/defipy-devs\/uniswappy\">UniswapPy<\/a> as confirmation:<\/p>\n<p>out = Swap().apply(lp, dai, user_nm, dy)<br \/>lp.summary()<\/p>\n<p>print(f&#8217;We receive {out:.5f} ETH for {dy} DAI&#8217;)<\/p>\n<p>Exchange ETH-DAI (LP)<br \/>Reserves: ETH = 999.00399301896, DAI = 1001000.0<br \/>Liquidity: 31622.776601683792 <\/p>\n<p>We receive 0.99601 ETH for 1000 DAI<\/p>\n<h3>3. Doubled-sided withdraw derivation<\/h3>\n<p>When a liquidity provider wishes to withdraw their funds from an LP, they must withdraw both x and y simultaneously. Doing this will reduce the amount of Liquidity within the pool by \u0394L and will push the CPT curve down. This will result in no change in the price post withdrawal. Let\u2019s again setup our mock\u00a0LP:<\/p>\n<p>dai = ERC20(&#8220;DAI&#8221;, &#8220;0x111&#8221;)<br \/>eth = ERC20(&#8220;ETH&#8221;, &#8220;0x09&#8221;)<br \/>exchg_data = UniswapExchangeData(tkn0 = eth, tkn1 = dai, symbol=&#8221;LP&#8221;, address=&#8221;0x011&#8243;)<\/p>\n<p>factory = UniswapFactory(&#8220;ETH pool factory&#8221;, &#8220;0x2&#8221;)<br \/>lp = factory.deploy(exchg_data)<br \/>Join().apply(lp, user_nm, eth_amount, dai_amount)<br \/>lp.summary()<\/p>\n<p>Exchange ETH-DAI (LP)<br \/>Reserves: ETH = 1000.0, DAI = 1000000.0<br \/>Liquidity: 31622.776601683792 <\/p>\n<p>Given CPT\u00a0formula:<\/p>\n<p>Price is determined as\u00a0such:<\/p>\n<p>Given P above, calculate \u0394x and \u0394y while maintaining price integrity:<\/p>\n<p>To maintain price integrity, we take the RHS of CPT formula and deduct \u0394x and \u0394y from both x and y\u00a0:<\/p>\n<p>CPT withdraw\u00a0formula:<\/p>\n<p>Now, we can manually calculate a withdraw using this derivation:<\/p>\n<p>dL = dx*L\/x<br \/>dy = y*dL\/L<br \/>new_x = (x-dx)<br \/>new_y = (y-dy) <br \/>new_L = L-dL<\/p>\n<p>print(f&#8217;The updated reserves are {new_x} ETH and {new_y} DAI, and the updated liquidity is {new_L:8f}&#8217;)<\/p>\n<p>The updated reserves are 999.0 ETH and 999000.0 DAI, and the updated liquidity is 31591.153825<\/p>\n<p>Next, we perform a withdraw using <a href=\"https:\/\/github.com\/defipy-devs\/uniswappy\">UniswapPy<\/a> as confirmation:<\/p>\n<p>RemoveLiquidity().apply(lp, eth, user_nm, dx)<br \/>lp.summary()<\/p>\n<p>Exchange ETH-DAI (LP)<br \/>Reserves: ETH = 999.0, DAI = 999000.0<br \/>Liquidity: 31591.15382508211 <\/p>\n<h3>4. Doubled-sided deposit derivation<\/h3>\n<p>When a liquidity provider wishes to deposit their funds into an LP, they must deposit both x and y simultaneously. Doing this will increase the amount of Liquidity within the pool by \u0394L and will push the CPT curve up. This will result in no change in the price post deposit. Let\u2019s again setup our mock\u00a0LP:<\/p>\n<p>dai = ERC20(&#8220;DAI&#8221;, &#8220;0x111&#8221;)<br \/>eth = ERC20(&#8220;ETH&#8221;, &#8220;0x09&#8221;)<br \/>exchg_data = UniswapExchangeData(tkn0 = eth, tkn1 = dai, symbol=&#8221;LP&#8221;, address=&#8221;0x011&#8243;)<\/p>\n<p>factory = UniswapFactory(&#8220;ETH pool factory&#8221;, &#8220;0x2&#8221;)<br \/>lp = factory.deploy(exchg_data)<br \/>Join().apply(lp, user_nm, eth_amount, dai_amount)<br \/>lp.summary()<\/p>\n<p>Exchange ETH-DAI (LP)<br \/>Reserves: ETH = 1000.0, DAI = 1000000.0<br \/>Liquidity: 31622.776601683792 <\/p>\n<p>We know from above, to maintain price integrity, double-sided change amounts \u0394x and \u0394y are determined as\u00a0such:<\/p>\n<p>Take RHS of CPT formula and add \u0394x, \u0394y to both x and y to maintain price integrity:<\/p>\n<p>Next, we perform algebra similar to above and get the CPT deposit\u00a0formula:<\/p>\n<p>Now, we can manually calculate a deposit using this derivation:<\/p>\n<p>dL = dx*L\/x<br \/>dy = y*dL\/L<br \/>new_x = (x+dx)<br \/>new_y = (y+dy) <br \/>new_L = L+dL<\/p>\n<p>print(f&#8217;The updated reserves are {new_x} ETH and {new_y} DAI, and the updated liquidity is {new_L:8f}&#8217;)<\/p>\n<p>The updated reserves are 1001.0 ETH and 1001000.0 DAI, and the updated liquidity is 31654.399378<\/p>\n<p>Next, we perform a deposit using <a href=\"https:\/\/github.com\/defipy-devs\/uniswappy\">UniswapPy<\/a> as confirmation:<\/p>\n<p>AddLiquidity().apply(lp, eth, user_nm, dx)<br \/>lp.summary()<\/p>\n<p>Exchange ETH-DAI (LP)<br \/>Reserves: ETH = 1001.0, DAI = 1001000.0<br \/>Liquidity: 31654.399378285478 <\/p>\n<h3>5. Single-sided withdraw derivation<\/h3>\n<p>Instead of withdrawing both x and y simultaneously, here we derive the math on how to withdraw just one of the assets (x or y); this is what we call a single-sided withdraw. This is done by performing a withdraw followed by a swap on one of the undesired assets in one autonomous procedure. This operation is not found in the original Uniswap V2 pairing code, and is an innovation specific to the <a href=\"https:\/\/github.com\/defipy-devs\/uniswappy\">UniswapPy<\/a> python package known as a <a href=\"https:\/\/medium.com\/coinmonks\/handle-uniswap-withdrawals-like-an-og-389fe74be18c\">WithdrawSwap<\/a>. Let\u2019s again setup our mock\u00a0LP:<\/p>\n<p>dai = ERC20(&#8220;DAI&#8221;, &#8220;0x111&#8221;)<br \/>eth = ERC20(&#8220;ETH&#8221;, &#8220;0x09&#8221;)<br \/>exchg_data = UniswapExchangeData(tkn0 = eth, tkn1 = dai, symbol=&#8221;LP&#8221;, address=&#8221;0x011&#8243;)<\/p>\n<p>factory = UniswapFactory(&#8220;ETH pool factory&#8221;, &#8220;0x2&#8221;)<br \/>lp = factory.deploy(exchg_data)<br \/>Join().apply(lp, user_nm, eth_amount, dai_amount)<br \/>lp.summary()<\/p>\n<p>Exchange ETH-DAI (LP)<br \/>Reserves: ETH = 1000.0, DAI = 1000000.0<br \/>Liquidity: 31622.776601683792<\/p>\n<p>Given \u0394x, \u0394y for withdraw:<\/p>\n<p>Also, given swap equation:<\/p>\n<p>A single-sided withdraw constitutes of the sum total of a withdraw and a swap, otherwise known as a <a href=\"https:\/\/medium.com\/coinmonks\/handle-uniswap-withdrawals-like-an-og-389fe74be18c\">WithdrawSwap<\/a>, and is given\u00a0by:<\/p>\n<p>Plug \u0394x, \u0394y into \u0394y\u209b and after performing some algebra we\u00a0get:<\/p>\n<p>Given the fact we know our desired withdraw amount, \u0394y\u209b, we solve the above quadratic to determine our single-sided settlement amount in terms of \u0394L; for more detailed information, see my previous <a href=\"https:\/\/medium.com\/coinmonks\/handle-uniswap-withdrawals-like-an-og-389fe74be18c\">medium article<\/a>. Now we can perform a single-sided withdraw using <a href=\"https:\/\/github.com\/defipy-devs\/uniswappy\">UniswapPy<\/a>:<\/p>\n<p>dy = 1<br \/>amount_out = WithdrawSwap().apply(lp, eth, user_nm, dy)<br \/>lp.summary()<\/p>\n<p>Exchange ETH-DAI (LP)<br \/>Reserves: ETH = 999.0, DAI = 1000000.0<br \/>Liquidity: 31606.937511796754 <\/p>\n<h3>6. Single-sided deposit derivation<\/h3>\n<p>Instead of depositing both x and y simultaneously, here we derive the math on how to deposit just one of the assets (x or y); this is what we call a single-sided deposit. This is down by performing a swap followed by a deposit in one autonomous procedure. This operation is not found in the original Uniswap V2 pairing code, and is an innovation specific to the <a href=\"https:\/\/github.com\/defipy-devs\/uniswappy\">UniswapPy<\/a> python package known as a <a href=\"https:\/\/medium.com\/coinmonks\/setup-your-uniswap-deposits-like-a-baller-b99340ea302f\">SwapDeposit<\/a>. Let\u2019s again setup our mock\u00a0LP:<\/p>\n<p>dai = ERC20(&#8220;DAI&#8221;, &#8220;0x111&#8221;)<br \/>eth = ERC20(&#8220;ETH&#8221;, &#8220;0x09&#8221;)<br \/>exchg_data = UniswapExchangeData(tkn0 = eth, tkn1 = dai, symbol=&#8221;LP&#8221;, address=&#8221;0x011&#8243;)<\/p>\n<p>factory = UniswapFactory(&#8220;ETH pool factory&#8221;, &#8220;0x2&#8221;)<br \/>lp = factory.deploy(exchg_data)<br \/>Join().apply(lp, user_nm, eth_amount, dai_amount)<br \/>lp.summary()<\/p>\n<p>Exchange ETH-DAI (LP)<br \/>Reserves: ETH = 1000.0, DAI = 1000000.0<br \/>Liquidity: 31622.776601683792 <\/p>\n<p>A single-sided deposit constitutes of the sum total of a swap followed by a deposit, otherwise known as a SwapDeposit, and is given\u00a0by:<\/p>\n<p>Given swap equation:<\/p>\n<p>Thus, we get this system of equations:<\/p>\n<p>where \u03b3 = 997\/1000. To solve for ratio \u03b1, we plug \u0394y\u209b into \u0394x\u209b, and after some algebra, we get this quadratic:<\/p>\n<p>For more detailed information on this, see my previous <a href=\"https:\/\/medium.com\/coinmonks\/setup-your-uniswap-deposits-like-a-baller-b99340ea302f\">medium article<\/a>. Now we can perform a single-sided deposit using <a href=\"https:\/\/github.com\/defipy-devs\/uniswappy\">UniswapPy<\/a>:<\/p>\n<p>dy = 1<br \/>dep = SwapDeposit().apply(lp, eth, user_nm, dy)<br \/>lp.summary()<\/p>\n<p>Exchange ETH-DAI (LP)<br \/>Reserves: ETH = 1001.0, DAI = 1000000.0<br \/>Liquidity: 31638.56029234534 <\/p>\n<h3>7. Summary<\/h3>\n<p>In this article we cover the fundamental math concepts behind the Uniswap V2 protocol using the <a href=\"https:\/\/github.com\/defipy-devs\">DeFiPy python suite<\/a>, the code behind this presentation is readily available on the <a href=\"https:\/\/github.com\/defipy-devs\/uniswappy\/blob\/main\/notebooks\/medium_articles\/univ2_math.ipynb\">DeFiPy Github repos<\/a>. The math behind single-sided withdraws and deposits are also introduced, which have not been previously discussed in the Uniswap community nor have they been covered in the research literature (to our knowledge). The utility of these autonomous operations are very useful as only one of the pair assets are required to make the deposit or withdrawal.<\/p>\n<p>Please keep and eye out for our next article, where we will be covering the math behind Uniswap\u00a0V3.<\/p>\n<p><a href=\"https:\/\/medium.com\/coinmonks\/uniswap-v2-math-tutorial-using-uniswappy-abb23cdef005\">Uniswap V2 Math Tutorial using UniswapPy<\/a> was originally published in <a href=\"https:\/\/medium.com\/coinmonks\">Coinmonks<\/a> on Medium, where people are continuing the conversation by highlighting and responding to this story.<\/p>","protected":false},"excerpt":{"rendered":"<p>Constant product price (CPT) curve pre- and post-swap; which is a core tool useful for Decentralized FinanceA Uniswap V2 math walk-through tutorialWe will be covering: swaps, double-sided withdraw \/ deposits, and single-sided withdraw \/\u00a0depositsUtilizes the DeFiPy python\u00a0suite 1. Introduction In 2016, Vitalik Buterin (ie, the founder of Ethereum) submitted a Reddit post where he proposed [&hellip;]<\/p>\n","protected":false},"author":0,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[2],"tags":[],"class_list":["post-49743","post","type-post","status-publish","format-standard","hentry","category-interesting"],"_links":{"self":[{"href":"https:\/\/mycryptomania.com\/index.php?rest_route=\/wp\/v2\/posts\/49743"}],"collection":[{"href":"https:\/\/mycryptomania.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/mycryptomania.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"replies":[{"embeddable":true,"href":"https:\/\/mycryptomania.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=49743"}],"version-history":[{"count":0,"href":"https:\/\/mycryptomania.com\/index.php?rest_route=\/wp\/v2\/posts\/49743\/revisions"}],"wp:attachment":[{"href":"https:\/\/mycryptomania.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=49743"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/mycryptomania.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=49743"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/mycryptomania.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=49743"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}