{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Uniswap V2 Tutorial\n", "\n", "This tutorial shows how to use Uniswap V2 with Dexsnake. Let's start by connecting to the blockchain (here, we use [Base](https://www.base.org/) for its relatively low transaction fees)." ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "import os\n", "\n", "from web3 import Web3\n", "\n", "\n", "# the code below assumes you have configured the required environment variables\n", "account = os.getenv(\"WEB3_PUBLIC_KEY\")\n", "private_key = os.getenv(\"WEB3_PRIVATE_KEY\")\n", "provider_url = os.getenv(\"WEB3_PROVIDER_URL\")\n", "\n", "web3 = Web3(Web3.HTTPProvider(provider_url))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now, let's import `UniswapV2Factory` and find the pair with USDC and WETH." ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "0x88A43bbDF9D098eEC7bCEda4e2494615dfD9bB9C\n" ] } ], "source": [ "from dexsnake.uniswap_v2 import UniswapV2Factory\n", "\n", "\n", "factory = UniswapV2Factory(web3)\n", "\n", "USDC_address = \"0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913\"\n", "WETH_address = \"0x4200000000000000000000000000000000000006\"\n", "\n", "pair_address = factory.get_pair(USDC_address, WETH_address)\n", "\n", "print(pair_address)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now, let's initialize the pair object and fetch the pair's reserves and price." ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Reserves of WETH: 440.61604517871905\n", "Reserves of USDC: 1139872.568688\n", "Price of 1 WETH: 2586.9974122836456 USDC\n" ] } ], "source": [ "from dexsnake.uniswap_v2 import UniswapV2Pair\n", "\n", "\n", "pair = UniswapV2Pair(web3, pair_address)\n", "\n", "reserves_0, reserves_1 = pair.get_reserves()\n", "\n", "price = pair.get_price()\n", "\n", "print(f\"Reserves of {pair.token_0.symbol}: {reserves_0}\")\n", "print(f\"Reserves of {pair.token_1.symbol}: {reserves_1}\")\n", "print(f\"Price of 1 {pair.token_0.symbol}: {price} {pair.token_1.symbol}\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now that we know the pair has good liquidity at a good price, let's use the router to swap one USDC for WETH. Note that before you can make the trade, you must approve the router contract to spend your USDC." ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "AttributeDict({'blockHash': HexBytes('0x29e248dd6d22b55343c5a9d6405d142093629b7be675cab5e7ae857f11ec23f0'),\n", " 'blockNumber': 18640731,\n", " 'contractAddress': None,\n", " 'cumulativeGasUsed': 4174043,\n", " 'effectiveGasPrice': 5355749,\n", " 'from': '0x011b7DD4cAA8E48FbBaef548dB349dfB3D09aA3F',\n", " 'gasUsed': 110559,\n", " 'l1BaseFeeScalar': '0x8dd',\n", " 'l1BlobBaseFee': '0x1',\n", " 'l1BlobBaseFeeScalar': '0x101c12',\n", " 'l1Fee': '0x224dcb614',\n", " 'l1GasPrice': '0x686a9e2a',\n", " 'l1GasUsed': '0x90c',\n", " 'logs': [AttributeDict({'address': '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913',\n", " 'topics': [HexBytes('0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef'),\n", " HexBytes('0x000000000000000000000000011b7dd4caa8e48fbbaef548db349dfb3d09aa3f'),\n", " HexBytes('0x00000000000000000000000088a43bbdf9d098eec7bceda4e2494615dfd9bb9c')],\n", " 'data': HexBytes('0x00000000000000000000000000000000000000000000000000000000000f4240'),\n", " 'blockNumber': 18640731,\n", " 'transactionHash': HexBytes('0x35b8a3e88b00143a79a1c8883938ce37f4ac23a848c774f7604520daea003b6c'),\n", " 'transactionIndex': 38,\n", " 'blockHash': HexBytes('0x29e248dd6d22b55343c5a9d6405d142093629b7be675cab5e7ae857f11ec23f0'),\n", " 'logIndex': 102,\n", " 'removed': False}),\n", " AttributeDict({'address': '0x4200000000000000000000000000000000000006',\n", " 'topics': [HexBytes('0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef'),\n", " HexBytes('0x00000000000000000000000088a43bbdf9d098eec7bceda4e2494615dfd9bb9c'),\n", " HexBytes('0x000000000000000000000000011b7dd4caa8e48fbbaef548db349dfb3d09aa3f')],\n", " 'data': HexBytes('0x00000000000000000000000000000000000000000000000000015f2cb61aeba9'),\n", " 'blockNumber': 18640731,\n", " 'transactionHash': HexBytes('0x35b8a3e88b00143a79a1c8883938ce37f4ac23a848c774f7604520daea003b6c'),\n", " 'transactionIndex': 38,\n", " 'blockHash': HexBytes('0x29e248dd6d22b55343c5a9d6405d142093629b7be675cab5e7ae857f11ec23f0'),\n", " 'logIndex': 103,\n", " 'removed': False}),\n", " AttributeDict({'address': '0x88A43bbDF9D098eEC7bCEda4e2494615dfD9bB9C',\n", " 'topics': [HexBytes('0x1c411e9a96e071241c2f21f7726b17ae89e3cab4c78be50e062b03a9fffbbad1')],\n", " 'data': HexBytes('0x000000000000000000000000000000000000000000000017e8959c6f95181adc00000000000000000000000000000000000000000000000000000109256a9c99'),\n", " 'blockNumber': 18640731,\n", " 'transactionHash': HexBytes('0x35b8a3e88b00143a79a1c8883938ce37f4ac23a848c774f7604520daea003b6c'),\n", " 'transactionIndex': 38,\n", " 'blockHash': HexBytes('0x29e248dd6d22b55343c5a9d6405d142093629b7be675cab5e7ae857f11ec23f0'),\n", " 'logIndex': 104,\n", " 'removed': False}),\n", " AttributeDict({'address': '0x88A43bbDF9D098eEC7bCEda4e2494615dfD9bB9C',\n", " 'topics': [HexBytes('0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822'),\n", " HexBytes('0x0000000000000000000000004752ba5dbc23f44d87826276bf6fd6b1c372ad24'),\n", " HexBytes('0x000000000000000000000000011b7dd4caa8e48fbbaef548db349dfb3d09aa3f')],\n", " 'data': HexBytes('0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f424000000000000000000000000000000000000000000000000000015f2cb61aeba90000000000000000000000000000000000000000000000000000000000000000'),\n", " 'blockNumber': 18640731,\n", " 'transactionHash': HexBytes('0x35b8a3e88b00143a79a1c8883938ce37f4ac23a848c774f7604520daea003b6c'),\n", " 'transactionIndex': 38,\n", " 'blockHash': HexBytes('0x29e248dd6d22b55343c5a9d6405d142093629b7be675cab5e7ae857f11ec23f0'),\n", " 'logIndex': 105,\n", " 'removed': False})],\n", " 'logsBloom': HexBytes('0x00200000000000000000000080000000000000000000000000040000000000000000000000200000000000100000100000000000000000000002000000000000000000000008000400000008000000202000000000080000000000000000000400800020000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000002100080000004000000000000000000000000000000000000000000000000000000000000000000000000000000002000100400000000000000000000000000000001000000000000008000000000100000000000000000000000000000000000000000000000000000000'),\n", " 'status': 1,\n", " 'to': '0x4752ba5DBc23f44D87826276BF6Fd6b1C372aD24',\n", " 'transactionHash': HexBytes('0x35b8a3e88b00143a79a1c8883938ce37f4ac23a848c774f7604520daea003b6c'),\n", " 'transactionIndex': 38,\n", " 'type': 0})" ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from dexsnake.uniswap_v2 import UniswapV2Router\n", "\n", "\n", "router = UniswapV2Router(web3)\n", "\n", "tx_receipt_approval = pair.token_1.approve(router.contract.address, 1, account, private_key)\n", "\n", "tx_receipt_swap = router.swap_exact_tokens_for_tokens(\n", " amount_in=1,\n", " amount_out_min=1 / price * 0.99, # max 1% slippage\n", " path=[USDC_address, WETH_address],\n", " to=account,\n", " account=account,\n", " private_key=private_key,\n", ")\n", "\n", "tx_receipt_swap" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "You can inspect the transaction on the block explorer: https://basescan.org/tx/0x35b8a3e88b00143a79a1c8883938ce37f4ac23a848c774f7604520daea003b6c." ] } ], "metadata": { "kernelspec": { "display_name": "base", "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.11.7" } }, "nbformat": 4, "nbformat_minor": 2 }