Skip to content

Commit e65778b

Browse files
committed
Added multi-hop quotes support
1 parent 01f1814 commit e65778b

File tree

2 files changed

+118
-23
lines changed

2 files changed

+118
-23
lines changed

uniswap/types.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,15 @@ class PoolKey:
1616
hooks: str
1717

1818

19+
@dataclass
20+
class PathKey:
21+
intermediate_currency: str
22+
fee: int
23+
tick_spacing: int
24+
hooks: str
25+
hook_data: bytes
26+
27+
1928
@dataclass
2029
class PermitDetails:
2130
token: str

uniswap/uniswap4.py

Lines changed: 109 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
from .types import (
3737
AddressLike,
3838
ModifyLiquidityParams,
39+
PathKey,
3940
PermitBatch,
4041
PermitSingle,
4142
PoolKey,
@@ -1370,29 +1371,6 @@ def get_token_token_spot_price(
13701371
spot_price = 1 / spot_price
13711372
return spot_price
13721373

1373-
def get_quote_exact_input_single(
1374-
self,
1375-
token0: str,
1376-
token1: str,
1377-
qty: int,
1378-
fee: int = 500,
1379-
tick_spacing: int = 10,
1380-
hooks: str = ZERO_HOOK,
1381-
hook_data: bytes = bytes(),
1382-
) -> int:
1383-
"""Quote for token to token single hop trades with an exact input."""
1384-
if token0 < token1:
1385-
zero_for_one = True
1386-
else:
1387-
zero_for_one = False
1388-
(token0, token1) = (token1, token0)
1389-
pool_key = (token0, token1, fee, tick_spacing, hooks)
1390-
# [0]=The output quote [1]=estimated gas units used for the swap
1391-
quote_amount: int = self.quoter.functions.quoteExactInputSingle(
1392-
(pool_key, zero_for_one, qty, hook_data)
1393-
).call()[0]
1394-
return quote_amount
1395-
13961374
def get_pool_id(self, pool: PoolKey) -> HexBytes:
13971375
pool_data = eth_abi.abi.encode(
13981376
types=["address", "address", "uint24", "int24", "address"],
@@ -1494,6 +1472,95 @@ def estimate_price_impact(
14941472
price_impact_real: float = price_impact_with_fees - fee_realised_percentage
14951473
return price_impact_real
14961474

1475+
def encode_path_keys_input(
1476+
self,
1477+
path: List[PoolKey],
1478+
currency_in: str,
1479+
) -> List[PathKey]:
1480+
"""
1481+
Encodes a list of PoolKeys into the format expected by the quoter for multi-hop ExactInput quotes.
1482+
"""
1483+
encoded_path: List[PathKey] = []
1484+
for pool_key in path:
1485+
currency_out: str = (
1486+
pool_key.currency1
1487+
if currency_in.lower() == pool_key.currency0.lower()
1488+
else pool_key.currency0
1489+
)
1490+
path_key: PathKey = PathKey(
1491+
currency_out, pool_key.fee, pool_key.tick_spacing, pool_key.hooks, b""
1492+
)
1493+
encoded_path.append(path_key)
1494+
currency_in = currency_out
1495+
return encoded_path
1496+
1497+
def encode_path_keys_output(
1498+
self,
1499+
path: List[PoolKey],
1500+
currency_out: str,
1501+
) -> List[PathKey]:
1502+
"""
1503+
Encodes a list of PoolKeys into the format expected by the quoter for multi-hop ExactOutput quotes.
1504+
"""
1505+
encoded_path: List[PathKey] = []
1506+
for pool_key in reversed(path):
1507+
currency_in: str = (
1508+
pool_key.currency1
1509+
if currency_out.lower() == pool_key.currency0.lower()
1510+
else pool_key.currency0
1511+
)
1512+
path_key: PathKey = PathKey(
1513+
currency_in, pool_key.fee, pool_key.tick_spacing, pool_key.hooks, b""
1514+
)
1515+
encoded_path.insert(0, path_key)
1516+
currency_out = currency_in
1517+
return encoded_path
1518+
1519+
# Quoter methods
1520+
# Read methods
1521+
def get_quote_exact_input_single(
1522+
self,
1523+
token0: str,
1524+
token1: str,
1525+
qty: int,
1526+
fee: int = 500,
1527+
tick_spacing: int = 10,
1528+
hooks: str = ZERO_HOOK,
1529+
hook_data: bytes = bytes(),
1530+
) -> int:
1531+
"""Quote for token to token single hop trades with an exact input."""
1532+
if token0 < token1:
1533+
zero_for_one = True
1534+
else:
1535+
zero_for_one = False
1536+
(token0, token1) = (token1, token0)
1537+
pool_key = (token0, token1, fee, tick_spacing, hooks)
1538+
# [0]=The output quote [1]=estimated gas units used for the swap
1539+
quote_amount: int = self.quoter.functions.quoteExactInputSingle(
1540+
(pool_key, zero_for_one, qty, hook_data)
1541+
).call()[0]
1542+
return quote_amount
1543+
1544+
def get_quote_exact_input(
1545+
self,
1546+
token0: str,
1547+
token1: str,
1548+
qty: int,
1549+
path: List[PoolKey],
1550+
) -> int:
1551+
"""Quote for token to token multi-hop trades with an exact input."""
1552+
# [0]=The output quote [1]=estimated gas units used for the swap
1553+
encoded_path = self.encode_path_keys_input(path, token0)
1554+
1555+
quote_amount: int = self.quoter.functions.quoteExactInput(
1556+
(
1557+
token0,
1558+
encoded_path,
1559+
qty,
1560+
)
1561+
).call()[0]
1562+
return quote_amount
1563+
14971564
def get_quote_exact_output_single(
14981565
self,
14991566
token0: str,
@@ -1524,6 +1591,25 @@ def get_quote_exact_output_single(
15241591
).call()[0]
15251592
return quote_amount
15261593

1594+
def get_quote_exact_output(
1595+
self,
1596+
token0: str,
1597+
token1: str,
1598+
qty: int,
1599+
path: List[PoolKey],
1600+
) -> int:
1601+
"""Quote for token to token multi-hop trades with an exact output."""
1602+
1603+
encoded_path = self.encode_path_keys_output(path, token1)
1604+
quote_amount: int = self.quoter.functions.quoteExactOutput(
1605+
(
1606+
token1,
1607+
encoded_path,
1608+
qty,
1609+
)
1610+
).call()[0]
1611+
return quote_amount
1612+
15271613
# Swap functions
15281614
def _token_to_token_swap_input(
15291615
self,

0 commit comments

Comments
 (0)