tradingstrategy-ai/web3-ethereum-defi

Read token tax from a token

miohtama opened this issue · 1 comments

Some tokens with ponzinomis have a token tax. This is especially popular on wild west blockchains like BNB Chain and PancakeSwap.

Token tax is used to

  • Create deflanatory tokens
  • Create malicious honey pots for trading bots ("buy only") - effectively a very high tokex tax like 90% on sell

An example trading pair and token with token tax is ELEPHANT-BUSD.

  • Buy has 10% tax
  • Sell has 10% tax

image

honeypot.is is an independent service to check the token tax. It does this by (likely) running Ganache mainnet fork and simulates the transactions. There is no API to ask this information.

Step 1: Read the token tax with Python

To figure out the amount of different token taxes (buy, sell, transfer) one needs to run a simulated transaction in Ganache.

Here is a pseudo-Python code to do it:

from eth_account.signers.local import LocalAccount
from eth_typing import HexAddress
from web3 import Web3

from eth_defi.uniswap_v2.deployment import UniswapV2Deployment
from tradeexecutor.utils import dataclass


@dataclass
class TokenTaxInfo:
    """Different token taxes we figured out."""

    #: Token in the question
    base_token: HexAddress

    #: Which token we traded against it
    quote_token: HexAddress

    #: How much % we lost of the token on buy
    buy_tax: float

    #: How much % we lose the token when we transfer between addresses
    transfer_tax:float

    #: How much % we lose the token when we sold it
    sell_tax: float


def estimate_token_taxes(
        uniswap: UniswapV2Deployment,
        base_token: HexAddress,
        quote_token: HexAddress,
        buy_account: LocalAccount,
        sell_account: LocalAccount
    ) -> TokenTaxInfo:
    """Estimates different token taxes for a token by running Ganache simulations for it.

    :param uniswap:
        Uniswap deployment on a Ganache mainnet fork.
        Set up prior calling this function.
        See `ganache.py` and `test_ganache.py` for more details.

    :param base_token:
        The token of which tax properties we are figuring out.

    :param quote_token:
        Address of the quote token used for the trading pair. E.g. `BUDS`, `WBNB`
        Based on this information we can derive Uniswap trading pair address.

    :param buy_account:
        The account that does initial buy to measure the buy tax.
        This account must be loaded with gas money (ETH/BNB) and `quote_token`
        for a purchase.

    :param sell_account:
        The account that receives the token transfer and does the sell to measure the sell tax.
        This account must be loaded with gas money for the sell.

    :return:
        ToxTaxInfo tells us what we figure out about taxes.
        This can be later recorded to a database.
    """

    web3: Web3 = uniswap.web3

    # Figure out base_token/quote_token trading pair
    # Buy base_token with buy_account
    # Measure the loss as "buy tax"
    # Transfer tokens to sell_account
    # Measure the loss as "transfer tax"
    # Sell tokens
    # Measure the loss as "sell tax"

The TokenTaxInfo info can be then stored in a database or similar, like SQL, JSON file repo and so on.
It can be later retrieved when you want to trade tokens.

Step 2: Making taxed tokens easily tradeable with Python

Create a buy/sell_with_tax(token_tax_info: TokenTaxInfo, max_slippage) function that considers slippage and token tax and correctly handles trading these kinds of tokens.

  • Normally buying ELELPHANT-BUSD would revert
  • Normally selling a token tax token would fail with execution reverted: TransferHelper: TRANSFER_FROM_FAILED because there is a mismatch between allowance() and swap amount

Create four test based on BSC mainnet fork using the existing Ganache fixtures

  • Naive buy of ELEPHANT fails
  • Taxed buy of ELEPHANT success, we can calculate the taxed amount after the buy (update analyse_trade to return this value)
  • Naive sell of ELEPHANT fails
  • Taxed sell of ELEPHANT success, we can calculate the taxed amount after the sell
  • Comment how this can be also considered in three-way trade (BUSD-BNB-ELEPHANT)

I added a new manual script:

https://github.com/tradingstrategy-ai/web3-ethereum-defi/blob/master/scripts/fetch-bnb-chain-pairs.py (git master, you might need to do git rebase to your branch)

It fetches all BNB Chain trading pairs. Because the resulting JSON file is 20 MB, I decided not to commit it.

  • Can you check if you can regenerate /tmp/bnb-chain-trading-pairs.json with this script?
  • Instructions are at the start of the script
  • If you can get the trading pairs downloaded, then the next step would be to create a new script in scripts/ folder that will try to get tax of all of the tokens (or most of the tokens) in the list.

This will do "data" test. It is likely that we start to see some errors or Ganache failure. But it is a good attempt how far we get to the list.

  • The results can be saved in JSON, or similar, but not strictly necessary, as we can have this data to go directly to SQL database and then publish on Trading Strategy API, so we or others do not need to run the token tax fetcher in the future. It's only needed if new tokens are added.