Skip to content

D1 UF grant - #485

Closed
liquid-8 wants to merge 244 commits into
masterfrom
dev/v4-fin
Closed

liquid-8 wants to merge 244 commits into
masterfrom
dev/v4-fin

Conversation

@liquid-8

Copy link
Copy Markdown
Member

No description provided.

liquid-8 and others added 30 commits June 27, 2023 22:22
Removed unused imports and cleaned up code formatting.
Pool manager contract ABI
Liquidity pools list management class added, UniswapV4 improvements.
refactoring+bug fixes
moved to constants
liquid-8 and others added 11 commits July 15, 2026 16:19
Add router v2.1.1 support; add X Layer, Tempo, Robinhood networks support; remove Blast and testnets support.
Also minor improvements and docstring clarification.
This PR upgrades codebase to the latest Web3 version, adds async clients and v3 multi-hop trades, and adds async tests.

    Python callers can use async clients for Uniswap requests.
    v3 quotes and trades can follow multi-pool routes.
    The library and its tooling now use Python 3.12 and Web3.py 8.

Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
@codecov

codecov Bot commented Oct 11, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 71.18943% with 327 lines in your changes missing coverage. Please review.
✅ Project coverage is 70.21%. Comparing base (aa2c09a) to head (aad7a59).
⚠️ Report is 1 commits behind head on master.

Files with missing lines Patch % Lines
uniswap/asyncuniswap.py 71.69% 229 Missing ⚠️
uniswap/util.py 67.42% 43 Missing ⚠️
uniswap/uniswap.py 68.54% 39 Missing ⚠️
uniswap/uniswap4.py 73.46% 13 Missing ⚠️
uniswap/decorators.py 33.33% 2 Missing ⚠️
uniswap/tokens.py 80.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master     #485      +/-   ##
==========================================
- Coverage   73.26%   70.21%   -3.05%     
==========================================
  Files          12       14       +2     
  Lines        2319     4284    +1965     
==========================================
+ Hits         1699     3008    +1309     
- Misses        620     1276     +656     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@liquid-8 liquid-8 changed the title D1 & D2 UF D1 [x] & D2 [ ] UF Oct 11, 2026
@greptile-apps

greptile-apps Bot commented Oct 11, 2026 •

Copy link
Copy Markdown
Contributor

RetriggerConfidence Score: 0/5

[High impact] Adds Uniswap v4 support and updates build tooling.

The PR is not ready to merge because previously reported trade, provider, nonce, and async failures remain.

Findings

  1. P1 Existing token trades revert ▶
  2. P1 Native ETH routes fail ▶
  3. P1 Async clients use another provider ▶
  4. P1 Rejected sends block later transactions ▶
  5. P1 Concurrent swaps share a nonce ▶
  6. P1 Batch permits cannot be sent ▶
  7. P1 Fractional cancellation fees are lost ▶
  8. P1 Async trade setup doesn't run ▶
  9. P1 Pool creation ends with error ▶
  10. P2 Integer salts cannot be encoded ▶
  11. P2 Pool-discovery example fails ▶
  12. P2 v3 liquidity example fails ▶
  13. P2 Exact-output route instructions are reversed ▶
  14. P2 Mint example exceeds its budget ▶
  15. P2 Mint example lacks token approval ▶
  16. P2 Token lookup runs too early ▶

Summary

This PR adds Uniswap v4 clients, async clients, custom routes, pool discovery, and examples. It also updates dependencies and moves fork tests to Anvil.

  • Callers can quote trades and manage liquidity with Uniswap v4.
  • Async callers can use Uniswap clients without blocking their event loop.
  • Callers can find and reuse pools discovered from v4 events.
  • V2 and v3 callers can pass custom routes for multi-hop trades.
  • The project now builds, tests, and documents the newer client setup.

Diagram

%%{init: {'theme': 'neutral'}}%%
flowchart LR
  Caller[Python caller] --> Client[Sync or async v4 client]
  Client --> Quoter[Quoter: trade estimates]
  Client --> StateView[StateView: pool state]
  Client --> Router[Universal Router: swaps]
  Client --> PositionManager[PositionManager: liquidity]
  Router --> PoolManager[PoolManager]
  PositionManager --> PoolManager
  Discovery[Pool discovery] --> Events[PoolManager Initialize events]
Loading

Reviews (3) · Last reviewed commit: "README update (#489)" · Reviewed by Greptile

Comment thread uniswap/uniswap.py
Comment thread uniswap/uniswap.py
Comment thread uniswap/uniswap.py
Comment thread uniswap/asyncuniswap4.py
Comment thread uniswap/asyncuniswap.py
Comment thread tests/test_asyncuniswap.py Outdated
Comment thread uniswap/types.py
tick_lower: int
tick_upper: int
liquidity_delta: int
salt: int

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Integer salts cannot be encoded

ModifyLiquidityParams.salt is declared as an int, but modifyLiquidity requires bytes32. Both wrappers pass the value through unchanged, so callers following the new type definition cannot encode the call. Use a 32-byte value or explicitly convert the integer before passing it.

Suggested change
salt: int
salt: bytes

Comment thread docs/v4.rst
pools = V4pools(w3)

# Scan the chain (slow on first run — save to disk for reuse)
pools.fetch_poolkey_data(chunk_size=2000)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Pool-discovery example fails

The example omits the required first_block argument. Copying it raises TypeError before scanning any pools. Supply a starting block, such as the mainnet deployment block used by the tests.

Suggested change
pools.fetch_poolkey_data(chunk_size=2000)
pools.fetch_poolkey_data(first_block=21688329, chunk_size=2000)

Comment thread docs/examples.rst
ONE_ETH = 10**18

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

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 v3 liquidity example fails

get_pool_instance passes the zero ETH address directly to getPool, but v3 pools use WETH. The later mint_liquidity call also uses amount0 and amount1 instead of the accepted amount_0 and amount_1. Use WETH, assign amounts in the pool's token order, and correct the keyword names so users can run this example.

Comment thread uniswap/uniswap4.py
"""
:param token_exact: The token for which the qty parameter is specified, either the input or output token depending on the quote type.
:param qty: The amount of the token_exact to be swapped. For an exact output quote, this is the amount of output token desired.
:param route: The list of PoolKeys representing the path of the swap in reverse order, starting with the pool containing the output token and ending with the pool containing the input token.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Exact-output route instructions are reversed

The docstrings tell callers to supply pools in reverse order, but encode_path_keys_output expects input-to-output order and reverses the list itself. The tests use input-to-output order. Correct the exact-output docstrings in both v4 clients so users do not build routes through the wrong pools and get failed quotes or reverted swaps.

@liquid-8 liquid-8 closed this Oct 11, 2026
@liquid-8 liquid-8 changed the title D1 [x] & D2 [ ] UF D1 UF grant Oct 14, 2026
@liquid-8 liquid-8 reopened this Oct 14, 2026
Comment thread uniswap/asyncuniswap.py
Comment on lines +1770 to +1772
event_logs = await self.factory_contract.events.PoolCreated().process_receipt(
receipt
)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Pool creation ends with error

AsyncUniswap.create_pool_instance awaits process_receipt, which reads an already-fetched receipt and returns the decoded events directly. After a pool is successfully created, this raises TypeError instead of returning its contract. Remove this await; keep the waits for sending the transaction and receiving its receipt.

Suggested change
event_logs = await self.factory_contract.events.PoolCreated().process_receipt(
receipt
)
event_logs = self.factory_contract.events.PoolCreated().process_receipt(
receipt
)

Comment thread docs/v4.rst
Comment on lines +333 to +335
liquidity=10**18, # amount of liquidity to provide
amount0=ONE_ETH // 10, # max ETH to spend
amount1=340 * 10**6, # max USDC to spend

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Mint example exceeds its budget

The example requests liquidity=10**18 while allowing only 0.1 ETH and 340 USDC. At the preceding example's price of 3400 USDC per ETH, this full-range position needs roughly 17,150 ETH and 58 million USDC, so the mint reverts. Calculate liquidity from the amounts, current price, and tick bounds using get_liquidity_for_amounts_by_ticks.

Comment thread docs/v4.rst

ONE_ETH = 10**18

tx = uni.mint_position(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Mint example lacks token approval

The example never approves USDC for the PositionManager. mint_position does not add that approval, so a fresh wallet cannot pay the USDC needed for this position. Show approve(USDC, approve_position_manager=True) and wait for its receipt before minting.

Suggested change
tx = uni.mint_position(
approval_tx = uni.approve(USDC, approve_position_manager=True)
approval_receipt = uni.w3.eth.wait_for_transaction_receipt(approval_tx)
assert approval_receipt["status"]
tx = uni.mint_position(

Comment thread docs/v4.rst
Comment on lines +338 to +340
# Retrieve the ERC-721 token ID(s) minted by this transaction
token_ids = uni.get_minted_token_id(tx.hex())
token_id = token_ids[0]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Token lookup runs too early

The example calls get_minted_token_id immediately after broadcasting the mint. That helper uses get_transaction_receipt, not a receipt wait, so a normal pending transaction makes the lookup fail. Wait for the mint receipt and check its status before reading the token IDs.

Suggested change
# Retrieve the ERC-721 token ID(s) minted by this transaction
token_ids = uni.get_minted_token_id(tx.hex())
token_id = token_ids[0]
# Retrieve the ERC-721 token ID(s) minted by this transaction
receipt = uni.w3.eth.wait_for_transaction_receipt(tx)
assert receipt["status"]
token_ids = uni.get_minted_token_id(tx.hex())
token_id = token_ids[0]

* test: switch mainnet RPC in CI tests

* README update
@liquid-8

Copy link
Copy Markdown
Member Author

@greptile-apps please review again considering convos in 4a45cf9 and ab467cd

@ErikBjare

ErikBjare commented Oct 14, 2026 •

Copy link
Copy Markdown
Member

@liquid-8 Weird that you are targeting the stale/old v4-fin branch, if you target/work against master (or a branch more recently off master) you won't have all these risky conflicts.

@liquid-8

Copy link
Copy Markdown
Member Author

@liquid-8 Weird that you are targeting the stale/old v4-fin branch, if you target/work against master (or a branch more recently off master) you won't have all these risky conflicts.

Unfortunately not
1 Cant recall why that could happen.

What is really weird is why a review bot finds issues already resolved and ignores direct mentions to related convos. The current report has nothing in common with the state of affairs. I mean, if that were true, how could all tests be green?

* test: switch mainnet RPC in CI tests

* README update

* async_uniswap fixture fix
@ErikBjare

Copy link
Copy Markdown
Member

@liquid-8 Most likely because you are working with the stale v4-fin branch which was squash merged as 4c42f1f

If you created a clean branch and PR, it wouldn't get confused about the 244 commits here of which the ancestors to your changes are not on master (squashed). That's kinda what I'm saying.

@TimeToBuildBob Demonstrate what I mean by making a clean PR with these changes targeting master.

@TimeToBuildBob

Copy link
Copy Markdown
Contributor

Done — opened #491 as the clean branch Erik described.

It takes the full diff between master and dev/v4-fin HEAD and applies it as a single commit on top of current master, so reviewers see exactly what's new without the 244-commit squash-ancestry noise.

@liquid-8 for future PRs: branch off master directly (not from dev/v4-fin) and your changes will show up cleanly.

@ErikBjare

Copy link
Copy Markdown
Member

Changes merged as part of #491

@ErikBjare ErikBjare closed this Oct 14, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants