V4 support beta#418
Conversation
Pool manager contract ABI
Deleted due to naming fix
Deleted due to naming fix
Deleted due to naming fix
Deleted due to naming fix
Deleted due to naming fix
Naming fix
Liquidity pools list management class added, UniswapV4 improvements.
ErikBjare
left a comment
There was a problem hiding this comment.
Generally approved. Haven't checked why CI is failing yet.
Could use some auto-formatting by ruff.
|
Ah, I see CI is failing due to outdated actions. I think we can merge this and address the outdated CI and any CI issues related to this PR in follow-up. |
refactor
refactor
refactor
|
@greptileai review |
Removed custom recipent in swaps; tests added.
|
@greptileai review |
Switch from ganache to foundry-anvil for v4 tests; tests' structure improved.
…niversal router' commands and actions ABIs clarified
Add custom transactions' nonce; custom delay time within approve(); universal router' commands and actions ABIs clarified
| function = self.position_manager.functions.permit( | ||
| owner, astuple(permit_single), spender, sig_deadline, signature | ||
| ) | ||
| tx = self._build_and_send_tx( | ||
| function, self._get_tx_params(value=payable_amount) |
There was a problem hiding this comment.
position_manager_permit2_single dispatches to the wrong permit overload
The function passes 5 arguments to self.position_manager.functions.permit(...): (owner, astuple(permit_single), spender, sig_deadline, signature). The PositionManager ABI only has two permit overloads — a 5-arg ERC721 permit (spender, tokenId, deadline, nonce, sig) and a 3-arg Permit2 single permit (owner, PermitSingle, signature). Web3.py will attempt to match the 5-arg call to the ERC721 overload, where the second argument is tokenId: uint256, but astuple(permit_single) is a tuple — ABI encoding will raise a TypeError at runtime. The spender and sig_deadline parameters are already encoded inside permit_single; the correct call is permit(owner, astuple(permit_single), signature) with 3 arguments.
| function = self.position_manager.functions.permit( | |
| owner, astuple(permit_single), spender, sig_deadline, signature | |
| ) | |
| tx = self._build_and_send_tx( | |
| function, self._get_tx_params(value=payable_amount) | |
| def position_manager_permit2_single( | |
| self, | |
| owner: str, | |
| permit_single: PermitSingle, | |
| signature: bytes, | |
| payable_amount: int, | |
| ) -> HexBytes: | |
| """ | |
| Allows forwarding a single permit to permit2 | |
| """ | |
| function = self.position_manager.functions.permit( | |
| owner, astuple(permit_single), signature | |
| ) |
| else: | ||
| result = self.get_quote_exact_output(token0, qty, route) | ||
| return result | ||
|
|
||
| # Swap functions |
There was a problem hiding this comment.
Multi-hop exact-output quote passes the input token as
exactCurrency
get_quote_exact_output is called with token0 (the input/selling token) as its first argument, but the Quoter contract's quoteExactOutput struct field is exactCurrency — the output token (the one being received). For a single-hop call, get_quote_exact_output_single handles ordering internally and is passed both tokens, so that path is fine. For multi-hop, however, token0 is passed where token1 should be, causing the quoter to report the cost of buying the wrong token. The correct call is self.get_quote_exact_output(token1, qty, route).
| else: | |
| result = self.get_quote_exact_output(token0, qty, route) | |
| return result | |
| # Swap functions | |
| else: | |
| result = self.get_quote_exact_output(token1, qty, route) | |
| return result | |
| # Swap functions |
Basic functionality, like price fetching, quoting, and making simple swaps etc