1

I don't understand how people can debug transactions when there are no error details shown.

Here is a recent transaction I submitted to Polygon:

enter image description here

As you can see, it doesn't in any way indicate what error has occured. All it says is that the transaction was reverted, with no additional context.

How can I dig into this transaction and get more details?

I tried using the Remix Debugger as well, but I'm getting this error:

enter image description here

Before submitting this transaction, I was warned that it was likely to fail. As you can see, this warning gives no information either:

enter image description here

As you can see the data field holds a garbage value rather than error codes.

Any help would be much appreciated.

Here is the ABI if it's useful/necessary for debugging:

[
    {
        "inputs": [
            {
                "internalType": "contract IERC20",
                "name": "inputToken",
                "type": "address"
            },
            {
                "internalType": "contract IERC20",
                "name": "outputToken",
                "type": "address"
            },
            {
                "internalType": "uint256",
                "name": "targetPriceNumerator",
                "type": "uint256"
            },
            {
                "internalType": "uint256",
                "name": "targetPriceDenominator",
                "type": "uint256"
            },
            {
                "internalType": "uint256",
                "name": "minimumExecution",
                "type": "uint256"
            }
        ],
        "stateMutability": "nonpayable",
        "type": "constructor"
    },
    {
        "inputs": [],
        "name": "execute",
        "outputs": [],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [
            {
                "internalType": "uint256",
                "name": "amount",
                "type": "uint256"
            }
        ],
        "name": "failsafe_withdraw_input",
        "outputs": [],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [
            {
                "internalType": "uint256",
                "name": "amount",
                "type": "uint256"
            }
        ],
        "name": "failsafe_withdraw_output",
        "outputs": [],
        "stateMutability": "nonpayable",
        "type": "function"
    }
]

Edit: Function code:


    function execute() public {
        require(block.number - _lastExecutionBlockNumber >= 41400, "Can only be executed every 23 hours.");
        _lastExecutionBlockNumber = block.number;
        
        (uint112 reserve0, uint112 reserve1,) = _pair.getReserves();
        uint inputReserve = _inputIndex == 0 ? reserve0 : reserve1;
        uint outputReserve = _outputIndex == 0 ? reserve0 : reserve1;
        uint inputAmount = (_sqrt((_targetPriceNumerator * inputReserve * outputReserve) / _targetPriceDenominator) * _targetPriceDenominator) / _targetPriceNumerator - inputReserve;
        
        require(_inputToken.balanceOf(address(this)) >= inputAmount, "Insufficient funds.");
        require(inputAmount >= _minimumExecution, "Less than minimum execution.");
        _inputToken.approve(address(_router), inputAmount);
        address[] memory path = new address[](2);
        path[0] = address(_inputToken);
        path[1] = address(_outputToken);
        uint outputAmount = _router.swapExactTokensForTokens(inputAmount, 0 /* safe because of inputAmount calculation */, path, address(this), block.timestamp)[1];

        _inputToken.approve(address(_router), 2 ** 256 - 1);
        _outputToken.approve(address(_router), outputAmount);
        uint outputTokenAmount = outputAmount;
        uint inputTokenAmount = (outputTokenAmount * inputReserve) / outputReserve;
        _router.addLiquidity(address(_inputToken), address(_outputToken), inputTokenAmount, outputTokenAmount, inputTokenAmount, outputTokenAmount, _owner, block.timestamp);
    }

5
  • 1
    Can you add the function code for the call you were trying to execute? Sep 9 at 0:44
  • @AaronKlich I've done that. Without the function code, shouldn't I still be able to figure out the error? The reason why it was reverted? Sep 9 at 9:16
  • The thing is , solidity's runtime errors arent precise , if the blockchain encounters a problem executing a function it reverts with no explanation unless you read the error with a require command. without a require command the revertion most of the times has no explanation. however with my experiences when youre warned about an error before executing a function, its 99% of the times due to an error you made within the function code that is only noticeable during runtime, that is why i asked for your code Sep 10 at 0:20
  • @AaronKlich Ok I wasn't aware of that. Can you see anything wrong with my code? Is there some way of debugging the transaction by simulating re-running it in a way that shows the error message? Sep 10 at 9:34
  • @AaronKlich Normally I would test this transaction locally with something like truffle, but I figure that wouldn't work out too well since I'm integrating with QuickSwap and I want to test the live version. Sep 10 at 9:40
0

From the transaction trace it did a single externall call and reverted.

  "type": "CALL",
  "from": "0xa3bab7a95ed40c2a62c7a1ac4ef2043f8b7a1cb6",
  "to": "0x51bc0f8a859fc64c69df3e8802dd6ed2709904a7",
  "value": "0x0",
  "gas": "0x2d7478",
  "gasUsed": "0x13dc5",
  "input": "0x61461954",
  "output": "0x4e487b710000000000000000000000000000000000000000000000000000000000000011",
  "error": "execution reverted",
  "time": "127.9954ms",
  "calls": [
    {
      "type": "STATICCALL",
      "from": "0x51bc0f8a859fc64c69df3e8802dd6ed2709904a7",
      "to": "0xcb33a1f36adb14fa90c983e9edee99961e20f426",
      "gas": "0x2c5d89",
      "gasUsed": "0x9c8",
      "input": "0x0902f1ac",
      "output": "0x000000000000000000000000000000000000000000000004339e9e4050da71e50000000000000000000000000000000000000000000040820b96f69ecf45e79500000000000000000000000000000000000000000000000000000000611e9cfe"
    }
  ]

From the source code the first external call is _pair.getReserves() and the second is _inputToken.balanceOf(), so somewhere between those is the error. Probably it is in inputAmount computation.

function execute() public {
    require(block.number - _lastExecutionBlockNumber >= 41400, "Can only be executed every 23 hours.");
    _lastExecutionBlockNumber = block.number;
    
    (uint112 reserve0, uint112 reserve1,) = _pair.getReserves();
    uint inputReserve = _inputIndex == 0 ? reserve0 : reserve1;
    uint outputReserve = _outputIndex == 0 ? reserve0 : reserve1;
    uint inputAmount = (_sqrt((_targetPriceNumerator * inputReserve * outputReserve) / _targetPriceDenominator) * _targetPriceDenominator) / _targetPriceNumerator - inputReserve;
    
    require(_inputToken.balanceOf(address(this)) >= inputAmount, "Insufficient funds.");
    require(inputAmount >= _minimumExecution, "Less than minimum execution.");
    _inputToken.approve(address(_router), inputAmount);
1
  • Thanks I'll take a look. That is a nice way of narrowing down where the error came from. Sep 10 at 18:31

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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