Skip to content

feat: added estimate_price_impact helper and warnings in docs #199

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Nov 11, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
30 changes: 19 additions & 11 deletions docs/getting-started.rst
Original file line number Diff line number Diff line change
Expand Up @@ -76,14 +76,14 @@ Quoting prices

.. note::

These methods assume a certain route for the swap to take, which may not be the optimal route. See :issue:`69` for details.
These methods assume a certain route for the swap to take, which may not be the optimal route. See :issue:`93` for details.

There are two functions to retrieve the price for a given pair, one for specifying how much you get given a certain amount of the input token, and another for specifying how much you need to pay to receive a certain amount of the output token.

:func:`~uniswap.Uniswap.get_price_input`
````````````````````````````````````````

Returns the cost of the given number of input tokens, priced in the output token.
Returns the amount of output tokens you get for a given amount of input tokens.

.. code:: python

Expand Down Expand Up @@ -120,26 +120,34 @@ Making trades

The same route assumptions and need for handling decimals apply here as those mentioned in the previous section.

.. warning::

Always check the expected price before executing a trade. It's important that you're using a pool with adequate liquidity, or else you may suffer significant losses! (see :issue:`198`)

Use the Uniswap version with the most liquidity for your route, and if using v3, make sure you set the ``fee`` parameter to use the best pool.

:func:`~uniswap.Uniswap.make_trade`
```````````````````````````````````

.. code:: python

# Make a trade where the input qty being known parameters
uniswap.make_trade(eth, bat, 1*10**18) # sell 1 ETH for however many BAT
uniswap.make_trade(bat, eth, 1*10**18) # sell 1 BAT for however many ETH
uniswap.make_trade(bat, dai, 1*10**18) # sell 1 BAT for however many DAI
uniswap.make_trade(eth, bat, 1*10**18, "0x123...") # sell 1 ETH for however many BAT, and send the BAT to the provided address
# Make a trade by specifying the quantity of the input token you wish to sell
uniswap.make_trade(eth, bat, 1*10**18) # sell 1 ETH for BAT
uniswap.make_trade(bat, eth, 1*10**18) # sell 1 BAT for ETH
uniswap.make_trade(bat, dai, 1*10**18) # sell 1 BAT for DAI
uniswap.make_trade(eth, bat, 1*10**18, "0x123...") # sell 1 ETH for BAT, and send the BAT to the provided address
uniswap.make_trade(dai, usdc, 1*10**18, fee=500) # sell 1 DAI for USDC using the 0.05% fee pool (v3 only)

:func:`~uniswap.Uniswap.make_trade_output`
``````````````````````````````````````````

.. code:: python

# Make a trade where the output qty is known, based on the input parameters
uniswap.make_trade_output(eth, bat, 1*10**18) # buy however many ETH for 1 BAT
uniswap.make_trade_output(bat, eth, 1*10**18) # buy however many BAT for 1 ETH
uniswap.make_trade_output(bat, dai, 1*10**18, "0x123...") # buy however many BAT for 1 DAI, and send the BAT to the provided address
# Make a trade by specifying the quantity of the output token you wish to buy
uniswap.make_trade_output(eth, bat, 1*10**18) # buy ETH for 1 BAT
uniswap.make_trade_output(bat, eth, 1*10**18) # buy BAT for 1 ETH
uniswap.make_trade_output(bat, dai, 1*10**18, "0x123...") # buy BAT for 1 DAI, and send the BAT to the provided address
uniswap.make_trade_output(dai, usdc, 1*10**8, fee=500) # buy USDC for 1 DAI using the 0.05% fee pool (v3 only)


Pool Methods (v1 only)
Expand Down
63 changes: 63 additions & 0 deletions examples/price_impact.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
from typing import List

from web3 import Web3

from uniswap import Uniswap
from uniswap.types import AddressLike

eth = Web3.toChecksumAddress("0x0000000000000000000000000000000000000000")
weth = Web3.toChecksumAddress("0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2")
usdt = Web3.toChecksumAddress("0xdac17f958d2ee523a2206206994597c13d831ec7")
vxv = Web3.toChecksumAddress("0x7d29a64504629172a429e64183d6673b9dacbfce")


def _perc(f: float) -> str:
return f"{round(f * 100, 3)}%"


def usdt_to_vxv_v2():
"""
Checks impact for a pool with very little liquidity.

This particular route caused a $14k loss for one user: https://github.com/uniswap-python/uniswap-python/discussions/198
"""
uniswap = Uniswap(address=None, private_key=None, version=2)

route: List[AddressLike] = [usdt, weth, vxv]

# Compare the results with the output of:
# https://app.uniswap.org/#/swap?use=v2&inputCurrency=0xdac17f958d2ee523a2206206994597c13d831ec7&outputCurrency=0x7d29a64504629172a429e64183d6673b9dacbfce
qty = 10 * 10 ** 8

# price = uniswap.get_price_input(usdt, vxv, qty, route=route) / 10 ** 18
# print(price)

impact = uniswap.estimate_price_impact(usdt, vxv, qty, route=route)
# NOTE: Not sure why this differs from the quote in the UI?
# Getting -27% in the UI for 10 USDT, but this returns >95%
# The slippage for v3 (in example below) returns correct results.
print(f"Impact for buying VXV on v2 with {qty / 10**8} USDT: {_perc(impact)}")

qty = 13900 * 10 ** 8
impact = uniswap.estimate_price_impact(usdt, vxv, qty, route=route)
print(f"Impact for buying VXV on v2 with {qty / 10**8} USDT: {_perc(impact)}")


def eth_to_vxv_v3():
"""Checks price impact for a pool with liquidity."""
uniswap = Uniswap(address=None, private_key=None, version=3)

# Compare the results with the output of:
# https://app.uniswap.org/#/swap?use=v3&inputCurrency=ETH&outputCurrency=0x7d29a64504629172a429e64183d6673b9dacbfce
qty = 1 * 10 ** 18
impact = uniswap.estimate_price_impact(eth, vxv, qty, fee=10000)
print(f"Impact for buying VXV on v3 with {qty / 10**18} ETH: {_perc(impact)}")

qty = 100 * 10 ** 18
impact = uniswap.estimate_price_impact(eth, vxv, qty, fee=10000)
print(f"Impact for buying VXV on v3 with {qty / 10**18} ETH: {_perc(impact)}")


if __name__ == "__main__":
usdt_to_vxv_v2()
eth_to_vxv_v3()
30 changes: 29 additions & 1 deletion uniswap/uniswap.py
Original file line number Diff line number Diff line change
Expand Up @@ -1172,7 +1172,7 @@ def _calculate_max_output_token(

# ------ Helpers ------------------------------------------------------------

def get_token(self, address: AddressLike, abi_name:str="erc20") -> ERC20Token:
def get_token(self, address: AddressLike, abi_name: str = "erc20") -> ERC20Token:
"""
Retrieves metadata from the ERC20 contract of a given token, like its name, symbol, and decimals.
"""
Expand Down Expand Up @@ -1209,6 +1209,34 @@ def get_weth_address(self) -> ChecksumAddress:
address = self.router.functions.WETH9().call()
return address

def estimate_price_impact(
self,
token_in: AddressLike,
token_out: AddressLike,
amount_in: int,
fee: int = None,
route: Optional[List[AddressLike]] = None,
) -> float:
"""
Returns the estimated price impact as a positive float (0.01 = 1%).

NOTE: Work-in-progress.

See ``examples/price_impact.py`` for an example which uses this.
"""
amount_small = 10 ** 2
cost_small = self.get_price_input(
token_in, token_out, amount_small, fee=fee, route=route
)
cost_amount = self.get_price_input(
token_in, token_out, amount_in, fee=fee, route=route
)

price_small = cost_small / amount_small
price_amount = cost_amount / amount_in

return (price_small - price_amount) / price_small

# ------ Exchange ------------------------------------------------------------------
@supports([1, 2])
def get_fee_maker(self) -> float:
Expand Down
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy