{"id":29089642,"url":"https://github.com/openzeppelin/exploit-uniswap","last_synced_at":"2025-06-28T04:04:19.669Z","repository":{"id":38329475,"uuid":"194928004","full_name":"OpenZeppelin/exploit-uniswap","owner":"OpenZeppelin","description":"Exploiting a Uniswap exchange that uses an ERC777 token by leveraging the reentrant microtrading attack vector","archived":false,"fork":false,"pushed_at":"2022-12-11T02:36:53.000Z","size":383,"stargazers_count":165,"open_issues_count":10,"forks_count":36,"subscribers_count":6,"default_branch":"master","last_synced_at":"2023-11-07T18:19:35.556Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://blog.openzeppelin.com/exploiting-uniswap-from-reentrancy-to-actual-profit/","language":"JavaScript","has_issues":false,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/OpenZeppelin.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2019-07-02T20:08:07.000Z","updated_at":"2023-09-24T13:50:35.000Z","dependencies_parsed_at":"2023-01-26T13:30:28.503Z","dependency_job_id":null,"html_url":"https://github.com/OpenZeppelin/exploit-uniswap","commit_stats":null,"previous_names":[],"tags_count":0,"template":null,"template_full_name":null,"purl":"pkg:github/OpenZeppelin/exploit-uniswap","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/OpenZeppelin%2Fexploit-uniswap","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/OpenZeppelin%2Fexploit-uniswap/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/OpenZeppelin%2Fexploit-uniswap/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/OpenZeppelin%2Fexploit-uniswap/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/OpenZeppelin","download_url":"https://codeload.github.com/OpenZeppelin/exploit-uniswap/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/OpenZeppelin%2Fexploit-uniswap/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":262371684,"owners_count":23300595,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-06-28T04:04:18.190Z","updated_at":"2025-06-28T04:04:19.655Z","avatar_url":"https://github.com/OpenZeppelin.png","language":"JavaScript","readme":"# Exploiting an ERC777-token Uniswap Exchange\n\n[![standard-readme compliant](https://img.shields.io/badge/readme%20style-standard-brightgreen.svg?style=flat-square)](https://github.com/RichardLitt/standard-readme)\n\n\u003e Exploiting any Uniswap exchange that trades an ERC777 token by leveraging the reentrant microtrading attack vector\n\n## Table of Contents\n\n- [Install](#install)\n- [Run](#run)\n- [Exploit details](#exploit-details)\n  - [Why it works](#why-it-works)\n- [Learning resources](#learning-resources)\n- [Disclaimer](#disclaimer)\n\n## Install\n\n1. Setup a Python virtual environment\n~~~\n$ pip3 install virtualenv\n$ virtualenv -p python3 venv\n~~~\n\n2. Activate virtual env \u0026 install Python dependencies (just Vyper)\n~~~\n$ source venv/bin/activate\n$ pip install -r requirements.txt\n~~~\n\nIf `source venv/bin/activate` does not work for you, try out with `bash venv/bin/activate`.\n\n3. Install NPM dependencies\n~~~\n$ npm install\n~~~\n\n## Run\n\nOnce in the virtual environment (where Vyper must be installed), run\n~~~\n(venv)$ npm test\n~~~\n\n## Exploit details\n\nThe proof of concept for the exploit is located in the `test/uniswap.exploit.js` file. It takes care of setting up the entire environment and running three test case scenarios.\n\n[The environment consists of](test/uniswap.exploit.js#L85):\n\n- A \"template\" Exchange\n- A Uniswap Exchange Factory (see [`uniswap_factory.vy`](contracts/uniswap_factory.vy) - taken from [Uniswap's repository](https://github.com/Uniswap/contracts-vyper/blob/c10c08d81d6114f694baa8bd32f555a40f6264da/contracts/uniswap_factory.vy))\n- The ERC777 token to be exchanged\n- The ERC1820 registry to register interfaces\n- The actual Exchange for the token (see [`uniswap_exchange.vy`](contracts/uniswap_exchange.vy) - taken from [Uniswap's repository](https://github.com/Uniswap/contracts-vyper/blob/c10c08d81d6114f694baa8bd32f555a40f6264da/contracts/uniswap_exchange.vy))\n- Sending / approving the necessary ETH and tokens to all actors\n\nThe three test cases are:\n\n1. [Legitimate trading with a single external sale:](test/uniswap.exploit.js#L133) a user that holds tokens wants to operate on the exchange, to deposit tokens and receive ETH. This is done in a single transaction calling the `tokenToEthSwapInput` function. This is the regular use case for a Uniswap exchange.\n\n2. [Legitimate trading with multiple external sales:](test/uniswap.exploit.js#L174) same as case (1), but now the user submits multiple transactions instead of just 1. Therefore, this results in less profit than (1).\n\n3. [Exploiting:](test/uniswap.exploit.js#L191) the attacker deploys an attacker contract that will be in charge of operating in the exchange. The exploit is executed in a single transaction, reentering several times in the vulnerable function `tokenToEthSwapInput` by leveraging the ERC777 `tokensToSend` hook.\n\n### Why it works\n\nBy leveraging the `tokensToSend` hook, the attacker contract is called _after_ receiving ETH (_i.e._ the exchange ETH balance has decreased) but _before_ the token balance is modified (_i.e. the exchange token balance has not decreased_). As a consequence, reentering the vulnerable `tokenToEthSwapInput` will re-calculate the token-ETH exchage price, but this time with less ETH and same amount of tokens in reserves. Thus, the exchange will be buying the attacker tokens, paying in ETH, at a higher price than it should.\n\n## Learning resources\n- [Uniswap docs](https://docs.uniswap.io/)\n- [EIP 777 - tokensToSend hook](https://eips.ethereum.org/EIPS/eip-777#erc777tokenssender-and-the-tokenstosend-hook)\n- Reentrancy attack: [SWC 107](https://smartcontractsecurity.github.io/SWC-registry/docs/SWC-107)\n\n## Disclaimer\nThis is a proof-of-concept exploit of an already [public, disclosed](https://github.com/ConsenSys/Uniswap-audit-report-2018-12#31-liquidity-pool-can-be-stolen-in-some-tokens-eg-erc-777-29) and [acknowledged](https://twitter.com/UniswapExchange/status/1120423109440438275) vulnerability in Uniswap related to reentrancy attacks. Were that not the case, under no circumstances this proof-of-concept exploit would have been made public. Should you find any 0-day vulnerability in these contracts, please report directly to [Uniswap](https://github.com/Uniswap/contracts-vyper).\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fopenzeppelin%2Fexploit-uniswap","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fopenzeppelin%2Fexploit-uniswap","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fopenzeppelin%2Fexploit-uniswap/lists"}