Skip to content

Slippage limit does not seem to hold, or price impact is incorrect #338

Open

Description

@sitwano

Describe the bug
As title. I set the slippage to 0.05%, however looking at arbiscan I get a slippage that is up to 2%. For example, here is my recent swap: 0x26d30e23fab9edea1b16e324fa1364377b51b29026b21866619b6f32c93fc06e.
I suspected it was the slippage that was the problem, since the price impact function showed me 0.11%. Unless maybe the price impact was calculated incorrectly... not sure.

I use a loop to keep retying the swap (up to 10 times) if it fails. I get "execution reverted: Too little received" error 5-6 times before the 7th try was successful.

SWAP DETAILS on arbiscan:
1,380.729352 USDC
to
0.715545115632159099 ETH (1343.72 estimated value at time of swap)

Net loss from swap: 2.17%

To Reproduce
Not really sure how to reproduce this... I guess swap USDC for ETH on arbitrum with a 0.05% slippage and see what happens during times of high price movement.

Expected behavior
The max slippage limit should hold, so if the amount is exceeded, the transaction should revert.

Activity

  1. changed the title [-]Slippage limit does not seem to hold[/-] [+]Slippage limit does not seem to hold, or price impact is incorrect[/+] on Jun 24, 2023
  2. ErikBjare commented on Jun 24, 2023

    @ErikBjare
    Member

    Thanks for reporting this and including a tx!

    I'm a bit baffled by this. Could you share the exact code for the relevant calls?

    Trying to think of a way to write a test for this. Probably doable within our current testing framework, but would be easier if we had finished implemented creating LP positions for V3.

  3. liquid-8 commented on Jun 26, 2023

    @liquid-8
    Member

    As far as I can see, it is neither a slippage nor price impact correctness issue. Let's take a look. I got the price impact for a liq pool. Now I'm going to swap tokens, so I'm calling a price fetching function to receive params for swap. Generally speaking, people could make some actions inter price-impact and price-fetching calls. In this case, the pool's liquidity state would be altered; hence my swap would make a different impact. This situation could occur on rare occasions on the main net. However, it has a much higher probability in L2 rollups due to their blocks producing time, which is significantly shorter. Likely, it's worth considering performing call batches while controlling if all calls are executed within the same block.

    Still would like to see the exact code too.

  4. sitwano commented on Jul 6, 2023

    @sitwano
    Author

    Hi thank you very much for the response. The code i used is quite simple. Sorry, I can't seem to get the formatting right for the code below. As you can see, all I am trying to do is recalculate the maximum amount i can lose (impact + slippage + gas fee) and then try the swap. If swap fails, then I just repeat until successful.

    `
    def buy_safety_check(my_uniswap, quantity):

    original, actual, minimum , impact = get_usdc_eth_rate(my_uniswap, quantity)

    max_price_diff = original- minimum

    if(original > 0):
        max_price_diff_perc = 100* max_price_diff/original
        
        my_gas_fee = get_gas_estimate(my_uniswap, eth, usdc)
    
        if((max_price_diff_perc >= 0.15) | (my_gas_fee > MAX_GAS_FEE)):
            return False, max_price_diff_perc, my_gas_fee
        else:
            return True, max_price_diff_perc, my_gas_fee
    else:
        return False, max_price_diff_perc, my_gas_fee
    

    while(attempt < MAX_SWAP_ATTEMPTS):

            try:
    
                safety_check, max_impact, gas_fee_estimate = buy_safety_check(my_uniswap, token_max_quantity)
    
                if(safety_check == True):    
                    tx = my_uniswap.make_trade(usdc, swap_token, token_max_quantity_usdc, fee = default_swap_fee, slippage = default_slippage)
                    my_tx = str(tx.hex())
                    print("SWAP SUCCESSFUL: " + my_tx)
                    return token_max_quantity_usdc/10**6, True, my_tx, max_impact, gas_fee_estimate
                else:
                    msg = "Retrying buy order: bad exchange rate. Impact:" + str(max_impact) +"%"
                    print(msg)
                    sleep(60)
            
            except Exception as e:
                attempt = attempt + 1
                print(e)
                print("SWAP ERROR. RETRY...")
                sleep(10)`
    
  5. liquid-8 commented on Jul 28, 2023

    @liquid-8
    Member

    Sorry for the delay. From what I see, it's ok. The code should work as intended if get_usdc_eth_rate() is implemented correctly. I must note that both slippage and impact implementation are fine, as I use the same logic in production with zero issues, at least at L1 networks. Still tend to believe you were trapped in something like I described earlier. I'll try to wrap my head around it; however, I can't promise a quick solution.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions