Skip to content
Open
Show file tree
Hide file tree
Changes from 18 commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
4c42f1f
V4 support (#418)
liquid-8 Jul 28, 2026
4542f83
docs: update README with v4 support — remove stale CTA, add to Suppor…
TimeToBuildBob Jul 28, 2026
de275ed
docs: v4 narrative guide, v2/v3 examples, and runnable example tests …
TimeToBuildBob Jul 28, 2026
2ef33e2
refactor(tests): replace ganache with anvil for v1–v3 tests (#472)
TimeToBuildBob Jul 28, 2026
e771a29
fix: avoid duplicate WETH in swap path when input/output is WETH (clo…
botbikamordehai2-sketch Jul 29, 2026
dee6a77
build(deps): bump minimum Python to 3.12, update deps, drop typed_ast…
TimeToBuildBob Jul 29, 2026
dc31cca
Merge branch 'master' of https://github.com/uniswap-python/uniswap-py…
liquid-8 Jul 30, 2026
bdd2dfd
Merge pull request #2 from liquid-8/uniswap-python-master
liquid-8 Jul 30, 2026
8a52b4c
Merge branch 'uniswap4_RC' into master_sync
liquid-8 Jul 30, 2026
c6cd59c
Merge pull request #3 from liquid-8/master_sync
liquid-8 Jul 30, 2026
56ba3eb
docs: disclose project funding history in README (#476)
ErikBjare Aug 5, 2026
bc8fdf4
fix(deps): bump lru-dict to 1.2.0 in lockfile for Python 3.13 (#475)
ErikBjare Aug 5, 2026
c95bf09
Merge branch 'uni_v4_final' of https://github.com/liquid-8/uniswap-py…
liquid-8 Sep 2, 2026
e178519
Deps: web3py bump to 8.0.0; codebase migration;
liquid-8 Sep 28, 2026
2837957
Review fixes; check_approval support dropped.
liquid-8 Oct 1, 2026
2bfdece
v2 multihop fix
liquid-8 Oct 1, 2026
36f1fcc
missed part
liquid-8 Oct 1, 2026
84476b5
contructor fix
liquid-8 Oct 1, 2026
abf554c
sync version constructor fix
liquid-8 Oct 2, 2026
c91a37a
Migration fixes
liquid-8 Oct 2, 2026
a3542d3
v4 test_get_position_info() fix
liquid-8 Oct 2, 2026
3154149
Drop v1 tests; adds v2-v3 manual approve tests; multihop logic fix
liquid-8 Oct 2, 2026
743752f
Some more migration fix
liquid-8 Oct 2, 2026
90ee9a2
Adds async tests; async pool discovery
liquid-8 Oct 5, 2026
05105bd
Update dependencies
liquid-8 Oct 5, 2026
2728fb3
fix
liquid-8 Oct 5, 2026
0952b7c
review fix
liquid-8 Oct 5, 2026
f9c2e6c
async _build_and_send() migration fix
liquid-8 Oct 5, 2026
4783ea8
Fix async get_minted_token_id()
liquid-8 Oct 5, 2026
b5e0ce5
fix test.yml ; fix balance condition in make_swap() tests
liquid-8 Oct 5, 2026
6617a1f
fix async make_trade()/make_trade_output() routing
liquid-8 Oct 5, 2026
7a54246
Add async pools discovery export; restote pool discovery tests;
liquid-8 Oct 6, 2026
dda8f9a
fix missed parameterization
liquid-8 Oct 6, 2026
5c7affb
test params optimization; async pools discovery logs fetching fix
liquid-8 Oct 6, 2026
76374d4
fixes v3 multihop ETH swaps
liquid-8 Oct 6, 2026
403bd96
v2 mutihop ETH fix
liquid-8 Oct 6, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions .github/workflows/docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,13 @@ jobs:

steps:
- uses: actions/checkout@v4
- name: Set up Python 3.8
- name: Set up Python 3.12
uses: actions/setup-python@v5
with:
python-version: '3.8'
python-version: '3.12'
- name: Install dependencies
run: |
python -m pip install --upgrade pip poetry
poetry config installer.modern-installation false
poetry install
- name: Docs
run: |
Expand Down
15 changes: 5 additions & 10 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,7 @@ jobs:
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.8'
- name: Set up Node
uses: actions/setup-node@v4
with:
node-version: '20'

python-version: '3.12'
# Set up poetry cache, from https://github.com/python-poetry/poetry/blob/45a9b8f20384591d0a33ae876bcf23656f928ec0/.github/workflows/main.yml
- name: Get full python version
id: full-python-version
Expand All @@ -56,7 +51,6 @@ jobs:
run: |
python -m pip install --upgrade pip poetry
poetry config virtualenvs.in-project true
poetry config installer.modern-installation false

- name: Set up cache
uses: actions/cache@v4
Expand All @@ -72,7 +66,9 @@ jobs:
- name: Install dependencies
run: |
poetry install
npm install -g ganache@7.5.0

- name: Install Foundry
uses: foundry-rs/foundry-toolchain@v1
Comment thread
liquid-8 marked this conversation as resolved.

- name: Install Foundry
uses: foundry-rs/foundry-toolchain@v1
Expand Down Expand Up @@ -100,7 +96,7 @@ jobs:
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.8'
python-version: '3.12'

# Set up poetry cache, from https://github.com/python-poetry/poetry/blob/45a9b8f20384591d0a33ae876bcf23656f928ec0/.github/workflows/main.yml
- name: Get full python version
Expand All @@ -113,7 +109,6 @@ jobs:
run: |
python -m pip install --upgrade pip poetry
poetry config virtualenvs.in-project true
poetry config installer.modern-installation false

- name: Set up cache
uses: actions/cache@v4
Expand Down
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ typecheck:
poetry run mypy --pretty

lint:
poetry run flake8
poetry run ruff check uniswap

format:
black uniswap
poetry run ruff format uniswap

format-abis:
npx prettier --write --parser=json uniswap/assets/*/*.abi
Expand Down
25 changes: 17 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,6 @@ The unofficial Python client for [Uniswap](https://uniswap.io/).

Documentation is available at https://uniswap-python.com/

**Want to help implement support for Uniswap v4?** See [issue #337](https://github.com/uniswap-python/uniswap-python/issues/337)

## Functionality

* A simple to use Python wrapper for all available contract functions and variables
Expand All @@ -30,6 +28,9 @@ Documentation is available at https://uniswap-python.com/

### Supports

- Uniswap v4 (as of v0.8.0, beta)
- Swaps, price quoting, liquidity management
- Pool discovery via pool cache service
- Uniswap v3 (as of v0.5.0)
- Including beta support for Arbitrum & Optimism deployments (as of v0.5.4)
- Uniswap v2 (as of v0.4.0)
Expand All @@ -47,7 +48,13 @@ See our [Getting started guide](https://uniswap-python.com/getting-started.html)

Unit tests are under development using the pytest framework. Contributions are welcome!

Test are run on a fork of the main net using ganache-cli. You need to install it with `npm install -g ganache-cli` before running tests.
Tests run on a fork of mainnet using [Anvil](https://getfoundry.sh) (part of Foundry). Install Foundry with:

```sh
curl -L https://foundry.paradigm.xyz | bash
export PATH="$PATH:$HOME/.foundry/bin"
foundryup
```

To run the full test suite, in the project directory set the `PROVIDER` env variable to a mainnet provider, and run:

Expand All @@ -59,9 +66,13 @@ make test
poetry run pytest --capture=no # doesn't capture output (verbose)
```

## Support our continued work!
## Funding

Development of this library has been funded by:

You can support us on [Gitcoin Grants](https://gitcoin.co/grants/2631/uniswap-python).
* The **[Uniswap Grants Program](https://www.uniswapfoundation.org/grants)**, which awarded a $15k grant (2021) that funded the development of Uniswap v3 support.
* **Community donations** through [Gitcoin Grants](https://gitcoin.co/grants/2631/uniswap-python), which were used to compensate contributors (see [#181](https://github.com/uniswap-python/uniswap-python/discussions/181)).
* **[Superuser Labs](https://superuserlabs.org/)**, Erik's company, which has sponsored continued development and maintenance, including funding [@liquid-8](https://github.com/liquid-8)'s work on Uniswap v4 support.

## Authors

Expand All @@ -70,8 +81,6 @@ You can support us on [Gitcoin Grants](https://gitcoin.co/grants/2631/uniswap-py
* [@liquid-8](https://github.com/liquid-8)
* ...and [others](https://github.com/uniswap-python/uniswap-python/graphs/contributors)

*Want to help out with development? We have funding to those that do! See [#181](https://github.com/uniswap-python/uniswap-python/discussions/181)*

Contributors also earn this beautiful [GitPOAP](https://gitpoap.notion.site/What-s-a-GitPOAP-5b085daac4b4429994b5231be028b3d9) for their contributions!

<a href="https://www.gitpoap.io/gh/uniswap-python/uniswap-python">
Expand Down Expand Up @@ -161,7 +170,7 @@ _A huge thank you [Erik Bjäreholt](https://github.com/ErikBjare) for adding Uni
* Switched from setup.py to pyproject.toml/poetry
* Switched from Travis to GitHub Actions
* For CI to work in your repo, you need to set the secret MAINNET_PROVIDER. I use Infura.
* Running tests on a local fork of mainnet using ganache-cli (started as a fixture)
* Running tests on a local fork of mainnet using Anvil/Foundry (started as a fixture)
* Fixed tests for make_trade and make_trade_output
* Added type annotations to the entire codebase and check them with mypy in CI
* Formatted entire codebase with black
Expand Down
2 changes: 1 addition & 1 deletion docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@
exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"]

extlinks = {
"issue": ("https://github.com/shanefontaine/uniswap-python/issues/%s", "issue #"),
"issue": ("https://github.com/shanefontaine/uniswap-python/issues/%s", "issue #%s"),
}


Expand Down
194 changes: 192 additions & 2 deletions docs/examples.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,196 @@
Examples
========

No examples here yet! Why don't you contribute some?
This page shows common usage patterns for Uniswap v2 and v3. For v4 examples,
see the dedicated :doc:`v4` guide.

In the meantime, see the :ref:`Getting started` guide.
The code snippets here mirror the `test suite
<https://github.com/uniswap-python/uniswap-python/tree/master/tests>`_, which
runs every example against a live mainnet fork using
`Anvil <https://book.getfoundry.sh/anvil/>`_.

.. contents:: Table of contents
:local:
:depth: 2

Uniswap v2
----------

Initialization
``````````````

.. code:: python

from uniswap import Uniswap

ETH = "0x0000000000000000000000000000000000000000"
USDC = "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"
DAI = "0x6B175474E89094C44Da98b954EedeAC495271d0F"

uni = Uniswap(
address="0xYOUR_ADDRESS",
private_key="0xYOUR_PRIVATE_KEY", # or None for read-only
version=2,
provider="https://mainnet.infura.io/v3/YOUR_PROJECT_ID",
)

Getting prices
``````````````

.. code:: python

ONE_ETH = 10**18

# How much USDC do I get for 1 ETH?
usdc_out = uni.get_price_input(ETH, USDC, ONE_ETH)
print(f"1 ETH → {usdc_out / 10**6:.2f} USDC")

# How much ETH do I need to buy exactly 1000 USDC?
eth_needed = uni.get_price_output(ETH, USDC, 1000 * 10**6)
print(f"ETH needed for 1000 USDC: {eth_needed / ONE_ETH:.4f}")

Making swaps
````````````

.. code:: python

# Sell 0.1 ETH, receive USDC (exact input)
tx = uni.make_trade(ETH, USDC, ONE_ETH // 10)

# Buy exactly 100 USDC, pay in ETH (exact output)
tx = uni.make_trade_output(ETH, USDC, 100 * 10**6)

# Sell ETH → DAI with a custom recipient
tx = uni.make_trade(ETH, DAI, ONE_ETH // 10, recipient="0xSOME_OTHER_ADDRESS")

Multi-hop swaps
```````````````

For pairs without a direct v2 pool, route through an intermediate token:

.. code:: python

WBTC = "0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599"

# ETH → WBTC (routed automatically through WETH by the v2 router)
wbtc_out = uni.get_price_input(ETH, WBTC, ONE_ETH // 10)
tx = uni.make_trade(ETH, WBTC, ONE_ETH // 10)

Uniswap v3
----------

v3 adds concentrated liquidity pools at multiple fee tiers. Always specify
``fee`` to select the pool — the right tier depends on the pair's volatility.

Initialization
``````````````

.. code:: python

from uniswap import Uniswap

ETH = "0x0000000000000000000000000000000000000000"
USDC = "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"
WBTC = "0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599"
DAI = "0x6B175474E89094C44Da98b954EedeAC495271d0F"

uni = Uniswap(
address="0xYOUR_ADDRESS",
private_key="0xYOUR_PRIVATE_KEY",
version=3,
provider="https://mainnet.infura.io/v3/YOUR_PROJECT_ID",
)

Fee tiers
`````````

Common v3 fee tiers:

- ``500`` — 0.05% (stablecoin pairs, e.g. USDC/USDT)
- ``3000`` — 0.30% (most pairs, e.g. ETH/USDC)
- ``10000`` — 1.00% (exotic/volatile pairs)

Getting prices
``````````````

.. code:: python

ONE_ETH = 10**18

# Quote using the 0.30% ETH/USDC pool
usdc_out = uni.get_price_input(ETH, USDC, ONE_ETH, fee=3000)
print(f"1 ETH → {usdc_out / 10**6:.2f} USDC (0.30% pool)")

# Compare with the 0.05% pool (better rate for large trades)
usdc_out_low = uni.get_price_input(ETH, USDC, ONE_ETH, fee=500)
print(f"1 ETH → {usdc_out_low / 10**6:.2f} USDC (0.05% pool)")

# Exact output quote
eth_needed = uni.get_price_output(ETH, USDC, 1000 * 10**6, fee=500)

Making swaps
````````````

.. code:: python

# Sell 0.1 ETH for USDC via the 0.05% pool
tx = uni.make_trade(ETH, USDC, ONE_ETH // 10, fee=500)

# Buy exactly 100 USDC, paying in ETH
tx = uni.make_trade_output(ETH, USDC, 100 * 10**6, fee=500)

Multi-hop swaps
```````````````

The v3 client does not expose a multi-hop path parameter in ``make_trade``.
For pairs without a direct pool, execute two single-hop trades in sequence.
Wait for the first transaction and use the wallet's confirmed balance increase,
not its quote, as the second hop's input:

.. code:: python

DAI = "0x6B175474E89094C44Da98b954EedeAC495271d0F"

# ETH → USDC (first hop, 0.05% pool)
usdc_before = uni.get_token_balance(USDC)
tx1 = uni.make_trade(ETH, USDC, ONE_ETH // 10, fee=500)
uni.w3.eth.wait_for_transaction_receipt(tx1)
usdc_received = uni.get_token_balance(USDC) - usdc_before

# USDC → DAI (second hop, 0.01% stable pool)
tx2 = uni.make_trade(USDC, DAI, usdc_received, fee=100)

Liquidity management (v3)
`````````````````````````

.. code:: python

from uniswap.util import default_tick_range

ETH = "0x0000000000000000000000000000000000000000"
USDC = "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"
ONE_ETH = 10**18

# Get the pool contract instance
pool = uni.get_pool_instance(ETH, USDC, fee=500)

# Sensible full-range tick bounds for this fee tier
tick_lower, tick_upper = default_tick_range(fee=500)

# Mint a liquidity position (returns TxReceipt)
receipt = uni.mint_liquidity(
pool,
amount0=ONE_ETH // 10,
amount1=340 * 10**6,
tick_lower=tick_lower,
tick_upper=tick_upper,
deadline=2**64,
)
assert receipt["status"]

# Get your token IDs (ERC-721 NFTs representing positions)
positions = uni.get_liquidity_positions()
token_id = positions[0]

# Close the position (collects fees + withdraws liquidity in one call)
receipt = uni.close_position(token_id, deadline=2**64)
3 changes: 2 additions & 1 deletion docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,9 @@ A good place to start is the :doc:`getting-started` guide.
:caption: Contents:

getting-started
v4
api
cli
cli
examples
supported-deployments

Expand Down
Loading
Loading