Spent way too long trying to figure this out. I have a contract that mocks "plain no flashloan" arbitrage, it has this test function

    function test(
        IRouter02 _target,
        address[] memory _path,
        uint256 _qtyIn,
        uint256 _qtyOut
    ) external onlyOwner {
            block.timestamp + 60

The goal is to supply it with a path, and make it swap back into the original token. If the path is "A -> B -> A", then we start with token A and end with token A.

However, executing this, always returns the INSUFFICINET_INPUT_AMOUNT even when the _qtyOut is set zero.

Using getAmountsOut, I can see that the correct values are returned.

This same function works just fine if I do not include the cycle, i.e. "A -> B" works

  • it also works just fine if the last token is not the first token. i.e. A -> B -> C works too. Hmm, and now A -> B -> C -> A worked... (with zero qtyOut amount)
    – Naz
    Jun 21, 2021 at 0:29

1 Answer 1


I've also encountered this issue and realized that when you swap A->B->A, the amount of token A in the pair automatically transfers back to the same pair. This causes the sync function (after the successful completion of the first swap) to synchronize the balance of token A entirely. Therefore, in the second swap (B->A), the amount of token A, which should be considered as amountIn, has already been synchronized in the previous step (resulting in amountIn being calculated as 0). This leads to the "INSUFFICIENT_INPUT_AMOUNT" error.

To avoid this error, we need to separate the recipient address for tokenOut in the first swap from the recipient address for tokenIn in the subsequent swap (i guess).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.