Failed internal transaction on signed meta transaction using openzepplin relay and autotask

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
pragma abicoder v2;

import "@openzeppelin/contracts/metatx/ERC2771Context.sol";
import "@openzeppelin/contracts/metatx/MinimalForwarder.sol";
import "@uniswap/v3-periphery/contracts/interfaces/ISwapRouter.sol";
import "@uniswap/v3-periphery/contracts/libraries/TransferHelper.sol";

contract Registry is ERC2771Context {
event Registered(address indexed who, string name);

mapping(address => string) public names;
mapping(string => address) public owners;

ISwapRouter public immutable swapRouter;

//kovan addresses
address public constant DAI = 0x4F96Fe3b7A6Cf9725f59d353F723c1bDb64CA6Aa; // kovan
address public constant WETH9 = 0xd0A1E359811322d97991E03f863a0C30C2cF029C; // kovan

//ignore for now
address public constant USDC = 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48;

// For this example, we will set the pool fee to 0.3%.
uint24 public constant poolFee = 3000;

constructor(
    MinimalForwarder forwarder,
    ISwapRouter _swapRouter // Initialize trusted forwarder
) ERC2771Context(address(forwarder)) {
    swapRouter = _swapRouter;
}

function swapExactInputSingle(uint256 amountIn)
    internal
    returns (uint256 amountOut)
{
    // msg.sender must approve this contract

    // Transfer the specified amount of DAI to this contract.
    TransferHelper.safeTransferFrom(
        DAI,
        msg.sender,
        address(this),
        amountIn
    );

    // Approve the router to spend DAI.
    TransferHelper.safeApprove(DAI, address(swapRouter), amountIn);

    // Naively set amountOutMinimum to 0. In production, use an oracle or other data source to choose a safer value for amountOutMinimum.
    // We also set the sqrtPriceLimitx96 to be 0 to ensure we swap our exact input amount.
    ISwapRouter.ExactInputSingleParams memory params = ISwapRouter
        .ExactInputSingleParams({
            tokenIn: DAI,
            tokenOut: WETH9,
            fee: poolFee,
            recipient: msg.sender,
            deadline: block.timestamp,
            amountIn: amountIn,
            amountOutMinimum: 0,
            sqrtPriceLimitX96: 0
        });

    // The call to `exactInputSingle` executes the swap.
    amountOut = swapRouter.exactInputSingle(params);
}

function register(string memory name) external {
    
    require(owners[name] == address(0), "Name taken");
    address owner = _msgSender(); // Changed from msg.sender
    owners[name] = owner;
    names[owner] = name;
    swapExactInputSingle(10);
    emit Registered(owner, name);
}

}

SO I modified the contract https://github.com/OpenZeppelin/workshops/tree/master/01-defender-meta-txs to include token swapping using UniswapV3 as a normal transaction, this works well, the swap and registration works fine but when I send it as a meta transaction, execution fails,

on the autotask, the transaction is successfully relayed

AUTOTASK START
2022-06-29T09:52:26.457Z INFO Relaying {
value: 0,
gas: 1000000,
nonce: '8',
to: '0x80071477cf8845F6917359e5Ae2132A966522a0E',
from: '0x84E5B4cf1B91EC15dD34E097B403B07175f72d35',
data: '0xf2c298be0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000b5349474e45442054455354000000000000000000000000000000000000000000'
}
2022-06-29T09:52:31.389Z INFO Sent meta-tx: 0xcabf31a3c665e8e22825374cb2f36ea17b17a785f2982a1c8581c60ae7b4d535
END RequestId: 65010971-79dd-4525-a1f4-52b6a5d8a5a1
AUTOTASK COMPLETE.

but when I check the explorer, I get to see that it was reverted. here is the clone demo project -> https://github.com/Jeon316upzx/openZepDemo

Hey @Jeon316upzx

The way the gasLimit estimation works for a function execution when no fixed gasLimit is provided, is by doing a binary search using different gasLimit values until the top-level call is a success. In this case, the top-level call successfully succeded but the underlying call to Uniswap V3 is likely failing because it ran out of gas.

There's no easy way to accurately estimate the gasLimit needed for the underlying call, but I think you're providing a fixed gasLimit, so please just increase it to slightly more to whatever the normal Uniswap V3 swap call used in your previous successful examples without a meta transaction.

Hope this helps!

So I increased the gasLimit like this ->

and on the relay, I also increased the adjustment from 50000 to ->


I even tried the gasLimit of (30,000,000) but I still get this warning here ->
but when I increase the value from 0 to say 1 or 4, I don't get the warning

but the registered name doesn't show up on the list either,

Thanks for the details @Jeon316upzx

Sorry for rushing with the response, my first thought for these situations is the gasPrice because of the explanation I've given previously.

Seems like it's an internal revert reason but the contracts are not verified and is not clear on first sight.
Also I'm curious about the fact that increasing the value from 0 to 1 makes the underlying transaction pass but I don't see any successful internal transaction going via meta tx. Do you have any example?

I'm comparing two execute() calls

  1. Unsuccessful
  2. Successful

Is it maybe triggering the require(owners[name] == address(0), "Name taken");. Again, should be more clear if the contract is verified.

I hope this helps although there's not much insight. I'll stay tuned if there's any update and I'll let you know if I find more details