uniswap_v2.fees

Documentation for eth_defi.uniswap_v2.fees Python module.

Uniswap v2 token price, fee and price impact calculations.

Mostly lifted from Uniswap-v2-py MIT licensed by Asynctomatic.

A short example how to get started:

import os

from web3 import Web3

from eth_defi.provider.multi_provider import create_multi_provider_web3
from eth_defi.uniswap_v2.deployment import fetch_deployment
from eth_defi.uniswap_v2.fees import estimate_buy_price
from eth_defi.uniswap_v2.pair import fetch_pair_details

# Default to Ankr free JSON-RPC endpoint if one not given
# https://eth.public-rpc.com/
web3 = create_multi_provider_web3(os.environ.get("JSON_RPC_ETHEREUM", "https://eth.public-rpc.com"))

assert web3.eth.chain_id == 1, f"We are not on Ethereum mainnet, got {web3.eth.chain_id}"

uniswap_v2 = fetch_deployment(
    web3=web3,
    factory_address="0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f",
    router_address="0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D",
    init_code_hash="0x96e8ac4277198ff8b6f785478aa9a39f403cb768dd02cbee326c3e7da348845f",
)

# Uniswap v2's USDC-WETH needs to be reserved to WETH-USDC in human logic
# https://tradingstrategy.ai/trading-view/ethereum/uniswap-v2/eth-usdc
pair = fetch_pair_details(web3, "0xb4e16d0168e52d35cacd2c6185b44281ec28c9dc", reverse_token_order=True)
print(f"Uniswap v2 pool is {pair.contract.address}, https://tradingstrategy.ai/trading-view/ethereum/uniswap-v2/eth-usdc")
print("Base token is", pair.get_base_token())
print("Quote token is", pair.get_quote_token())

raw_price = estimate_buy_price(
    uniswap_v2,
    base_token=pair.get_base_token().contract,
    quote_token=pair.get_quote_token().contract,
    quantity=1 * 10**18,  # 1 WETH = 1000000000000000000 wei
)

# Convert raw USDC Solidity amount -> human USDC
human_price = pair.get_quote_token().convert_to_decimals(raw_price)

print(f"Price is {human_price} ETH/USD")

Functions

estimate_buy_price(uniswap, base_token, ...)

Estimate how much we are going to need to pay when doing buy.

estimate_buy_price_decimals(uniswap, ...[, ...])

Estimate how much we are going to need to pay when doing buy.

estimate_buy_quantity(uniswap, base_token, ...)

Estimate how many tokens we are going to receive when doing a buy.

estimate_buy_received_amount_raw(uniswap, ...)

Estimate how much we receive for a certain cash amount.

estimate_sell_price(uniswap, base_token, ...)

Estimate how much we are going to get paid when doing a sell.

estimate_sell_price_decimals(uniswap, ...[, ...])

Estimate how much we are going to get paid when doing a sell.

estimate_sell_received_amount_raw(uniswap, ...)

Estimate how much cash we receive for a certain quantity of tokens sold.

Classes

UniswapV2FeeCalculator

A helper class to estimate Uniswap fees.

Exceptions

exception BadReserves

Bases: Exception

__init__(*args, **kwargs)
__new__(**kwargs)
add_note()

Exception.add_note(note) – add a note to the exception

with_traceback()

Exception.with_traceback(tb) – set self.__traceback__ to tb and return self.

class UniswapV2FeeCalculator

Bases: object

A helper class to estimate Uniswap fees.

__init__(uniswap_v2)
Parameters

uniswap_v2 (eth_defi.uniswap_v2.deployment.UniswapV2Deployment) –

get_reserves(token_a, token_b)

Gets the reserves of token_0 and token_1 used to price trades and distribute liquidity as well as the timestamp of the last block during which an interaction occurred for the pair.

Parameters
Returns

  • reserve_0 - Amount of token_0 in the contract.

  • reserve_1 - Amount of token_1 in the contract.

  • liquidity - Unix timestamp of the block containing the last pair interaction.

Return type

tuple[int]

get_amount_out(amount_in, path, *, fee=30, slippage=0)

Get how much token we are going to receive.

Parameters
  • amount_in (int) – Amount of input asset.

  • path (list[eth_typing.evm.HexAddress]) – List of token addresses how to route the trade

  • fee (int) – Trading fee express in bps, default = 30 bps (0.3%)

  • slippage (float) – Slippage express in bps

Returns

Return type

int

get_amount_in(amount_out, path, *, fee=30, slippage=0)

Get how much token we are going to spend.

Parameters
  • amount_out (int) – Amount of output asset.

  • path (list[eth_typing.evm.HexAddress]) – List of token addresses how to route the trade

  • fee (int) – Trading fee express in bps, default = 30 bps (0.3%)

  • slippage (float) – Slippage express in bps

Returns

Return type

int

static get_amount_in_from_reserves(amount_out, reserve_in, reserve_out, *, fee=30)

Returns the minimum input asset amount required to buy the given output asset amount (accounting for fees) given reserves.

Parameters
  • amount_out (int) – Amount of output asset.

  • reserve_in (int) – Reserve of input asset in the pair contract.

  • reserve_out (int) – Reserve of output asset in the pair contract.

  • fee (int) – Trading fee express in bps, default = 30 bps (0.3%)

Returns

Required amount of input asset.

Return type

int

static get_amount_out_from_reserves(amount_in, reserve_in, reserve_out, *, fee=30)

Given an input asset amount, returns the maximum output amount of the other asset (accounting for fees) given reserves.

Parameters
  • amount_in (int) – Amount of input asset.

  • reserve_in (int) – Reserve of input asset in the pair contract.

  • reserve_out (int) – Reserve of output asset in the pair contract.

  • fee (int) – Trading fee express in bps, default = 30 bps (0.3%)

Returns

Maximum amount of output asset.

Return type

int

estimate_buy_quantity(uniswap, base_token, quote_token, quantity, *, fee=30, slippage=0)

Estimate how many tokens we are going to receive when doing a buy.

Good for doing a price impact calculations.

Calls the on-chain contract to get the current liquidity and estimates the the price based on it.

Example:

# Estimate how much ETH we will receive for 500 USDC.
# In this case the pool ETH price is $1700 so this should be below ~1/4 of ETH
amount_eth = estimate_buy_quantity(
    uniswap_v2,
    weth,
    usdc,
    500 * 10**18,
)
assert amount_eth / 1e18 == pytest.approx(0.28488156127668085)
Parameters
  • quantity (int) – How much of the quote token we have to use

  • uniswap (eth_defi.uniswap_v2.deployment.UniswapV2Deployment) – Uniswap v2 deployment

  • base_token (web3.contract.contract.Contract) – Base token of the trading pair

  • quote_token (web3.contract.contract.Contract) – Quote token of the trading pair

  • fee (int) – Trading fee express in bps, default = 30 bps (0.3%)

  • slippage (float) – Slippage express in bps

Returns

Expected base token to receive

Return type

int

estimate_buy_price(uniswap, base_token, quote_token, quantity, *, fee=30, slippage=0, intermediate_token=None)

Estimate how much we are going to need to pay when doing buy.

Calls the on-chain contract to get the current liquidity and estimates the the price based on it.

Example for Ethereum mainnet Uniswap:

import os

from web3 import Web3

from eth_defi.provider.multi_provider import create_multi_provider_web3
from eth_defi.uniswap_v2.deployment import fetch_deployment
from eth_defi.uniswap_v2.fees import estimate_buy_price
from eth_defi.uniswap_v2.pair import fetch_pair_details

# Default to Ankr free JSON-RPC endpoint if one not given
# https://eth.public-rpc.com/
web3 = create_multi_provider_web3(os.environ.get("JSON_RPC_ETHEREUM", "https://eth.public-rpc.com"))

assert web3.eth.chain_id == 1, f"We are not on Ethereum mainnet, got {web3.eth.chain_id}"

uniswap_v2 = fetch_deployment(
    web3=web3,
    factory_address="0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f",
    router_address="0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D",
    init_code_hash="0x96e8ac4277198ff8b6f785478aa9a39f403cb768dd02cbee326c3e7da348845f",
)

# Uniswap v2's USDC-WETH needs to be reserved to WETH-USDC in human logic
# https://tradingstrategy.ai/trading-view/ethereum/uniswap-v2/eth-usdc
pair = fetch_pair_details(web3, "0xb4e16d0168e52d35cacd2c6185b44281ec28c9dc", reverse_token_order=True)
print(f"Uniswap v2 pool is {pair.contract.address}, https://tradingstrategy.ai/trading-view/ethereum/uniswap-v2/eth-usdc")
print("Base token is", pair.get_base_token())
print("Quote token is", pair.get_quote_token())

raw_price = estimate_buy_price(
    uniswap_v2,
    base_token=pair.get_base_token().contract,
    quote_token=pair.get_quote_token().contract,
    quantity=1 * 10**18,  # 1 WETH = 1000000000000000000 wei
)

# Convert raw USDC Solidity amount -> human USDC
human_price = pair.get_quote_token().convert_to_decimals(raw_price)

print(f"Price is {human_price} ETH/USD")

Example for unit testing:

# Estimate how much ETH we will receive for 500 USDC.
# In this case the pool ETH price is $1700 so this should be below ~1/4 of ETH
amount_eth = estimate_buy_price(
    uniswap_v2,
    weth,
    usdc,
    1 * 10**18,
)
assert amount_eth / 1e18 == pytest.approx(0.28488156127668085)
Parameters
  • uniswap (eth_defi.uniswap_v2.deployment.UniswapV2Deployment) – Uniswap v2 deployment

  • base_token (web3.contract.contract.Contract) – Base token of the trading pair

  • quote_token (web3.contract.contract.Contract) – Quote token of the trading pair

  • quantity (int) – How much of the base token we want to buy

  • fee (int) – Trading fee express in bps, default = 30 bps (0.3%)

  • slippage (float) – Slippage express in bps

  • intermediate_token (Optional[web3.contract.contract.Contract]) –

Returns

Expected base token to receive

Return type

int

estimate_sell_price(uniswap, base_token, quote_token, quantity, *, fee=30, slippage=0, intermediate_token=None)

Estimate how much we are going to get paid when doing a sell.

Calls the on-chain contract to get the current liquidity and estimates the the price based on it.

Note

The price of an asset depends on how much you are selling it. More you sell, more there will be price impact.

To get a price of an asset, ask for quantity 1 of it:

# Create the trading pair and add iint(10_000 * amounts[-1] // (10_000 - slippage))nitial liquidity for price 1700 USDC/ETH
deploy_trading_pair(
    web3,
    deployer,
    uniswap_v2,
    weth,
    usdc,
    1_000 * 10**18,  # 1000 ETH liquidity
    1_700_000 * 10**6,  # 1.7M USDC liquidity
)

# Estimate the price of selling 1 ETH
usdc_per_eth = estimate_sell_price(
    uniswap_v2,
    weth,
    usdc,
    1 * 10**18,  # 1 ETH
)
price_as_usd = usdc_per_eth / 1e6
assert price_as_usd == pytest.approx(1693.2118677678354)
Parameters
  • quantity (int) – How much of the base token we want to sell

  • uniswap (eth_defi.uniswap_v2.deployment.UniswapV2Deployment) – Uniswap v2 deployment

  • base_token (web3.contract.contract.Contract) – Base token of the trading pair

  • quote_token (web3.contract.contract.Contract) – Quote token of the trading pair

  • fee (int) – Trading fee express in bps, default = 30 bps (0.3%)

  • slippage (float) – Slippage express in bps

  • intermediate_token (Optional[web3.contract.contract.Contract]) –

Returns

Expected quote token amount to receive

Return type

int

estimate_buy_price_decimals(uniswap, base_token_address, quote_token_address, quantity, *, fee=30, slippage=0, intermediate_token_address=None)

Estimate how much we are going to need to pay when doing buy.

Much like estimate_buy_price() with the differences of - Tokens are passed as address instead of contract instance - We use base token quantity units instead of cash - We use decimals instead of raw token amounts

Example:

# Create the trading pair and add initial liquidity
deploy_trading_pair(
    web3,
    deployer,
    uniswap_v2,
    weth,
    usdc,
    1_000 * 10**18,  # 1000 ETH liquidity
    1_700_000 * 10**18,  # 1.7M USDC liquidity
)

# Estimate the price of buying 1 ETH
usdc_per_eth = estimate_buy_price_decimals(
    uniswap_v2,
    weth.address,
    usdc.address,
    Decimal(1.0),
)
assert usdc_per_eth == pytest.approx(Decimal(1706.82216820632059904))
Parameters
Returns

Expected quote token amount to receive

Raises

TokenDetailError – If we have an issue with ERC-20 contracts

Return type

decimal.Decimal

estimate_sell_price_decimals(uniswap, base_token_address, quote_token_address, quantity, *, fee=30, slippage=0, intermediate_token_address=None)

Estimate how much we are going to get paid when doing a sell.

Much like estimate_sell_price() but in/out is expressed as python Decimal units. Furthermore, no ERC-20 token contract needed ABI, but it is loaded by the function.

Parameters
Returns

Expected quote token amount to receive in quota tokens (decimal converted).

Raises

TokenDetailError – If we have an issue with ERC-20 contracts

Return type

decimal.Decimal

estimate_buy_received_amount_raw(uniswap, base_token_address, quote_token_address, quantity_raw, *, fee=30, slippage=0, intermediate_token_address=None)

Estimate how much we receive for a certain cash amount.

Example:

# Create the trading pair and add initial liquidity
deploy_trading_pair(
    web3,
    deployer,
    uniswap_v2,
    weth,
    usdc,
    1_000 * 10**18,  # 1000 ETH liquidity
    1_700_000 * 10**18,  # 1.7M USDC liquidity
)

# Estimate the price of buying 1650 USDC worth of ETH
eth_received = estimate_buy_received_amount_raw(
    uniswap_v2,
    weth.address,
    usdc.address,
    1650 * 10**18,
)

assert eth_received / (10**18) == pytest.approx(0.9667409780905836)

# Calculate price of ETH as $ for our purchase
price = (1650 * 10**18) / eth_received
assert price == pytest.approx(Decimal(1706.7653460381143))
Parameters
Returns

Expected quote token amount to receive

Raises

TokenDetailError – If we have an issue with ERC-20 contracts

Return type

int

estimate_sell_received_amount_raw(uniswap, base_token_address, quote_token_address, quantity_raw, *, fee=30, slippage=0, intermediate_token_address=None)

Estimate how much cash we receive for a certain quantity of tokens sold.

Example:

deploy_trading_pair(
    web3,
    deployer,
    uniswap_v2,
    weth,
    usdc,
    1_000 * 10**18,  # 1000 ETH liquidity
    1_700_000 * 10**18,  # 1.7M USDC liquidity
)

# Sell 50 ETH
usdc_received = estimate_sell_received_amount_raw(
    uniswap_v2,
    weth.address,
    usdc.address,
    50 * 10**18,
)

usdc_received_decimals = usdc_received / 10**18
assert usdc_received_decimals == pytest.approx(80721.05538886508)

# Calculate price of ETH as $ for our purchase
price = usdc_received / (50 * 10**18)
assert price == pytest.approx(Decimal(1614.4211077773016))
Parameters
Returns

Expected quote token amount to receive

Raises

TokenDetailError – If we have an issue with ERC-20 contracts

Return type

int