Metatransaction EIP-712 compliant reverted on Tether USDT Polygon contract

49 views Asked by At

I have a problem with the execution of a metatransaction EIP-712 compliant, I show you the backend code with ethers.js and the link of the contract on mainnet :slight_smile:

Contract : https://polygonscan.com/address/0xc2132d05d31c914a87c6611c10748aeb04b58e8f

Code :

    
const ethers = require("ethers");

/**************************** SETUP ****************************/

const provider = new ethers.providers.JsonRpcProvider("RPC URL");

// Tether USDT address
const address = "0xc2132d05d31c914a87c6611c10748aeb04b58e8f";

const abi = [
  {
    inputs: [
      { internalType: "address", name: "spender", type: "address" },
      { internalType: "uint256", name: "amount", type: "uint256" },
    ],
    name: "approve",
    outputs: [{ internalType: "bool", name: "", type: "bool" }],
    stateMutability: "nonpayable",
    type: "function",
  },
];

const signer = new ethers.Wallet("Approve Sender Priv Key", provider);

const contract = new ethers.Contract(address, abi, signer);

async function getSignature() {
  // Create transaction data
  const transaction = await contract.populateTransaction.approve(
    "Approve Receiver",
    "Amount"
  );

  // Get signer nonce
  const nonce = await contract.getNonce(signer.address);

  // Get Polygon Mainnet Chain ID
  const salt = ethers.utils.hexZeroPad(ethers.utils.hexValue(137 ?? 0), 32);

  // Create domain object
  const domain = {
    name: "UChildERC20Proxy",
    version: "1",
    verifyingContract: transaction.to,
    salt: salt,
  };

  // Create object according to MetaTransaction struct
  const types = {
    MetaTransaction: [
      {
        name: "nonce",
        type: "uint256",
      },
      {
        name: "from",
        type: "address",
      },
      {
        name: "functionSignature",
        type: "bytes",
      },
    ],
  };

  // Create message to be signed
  const message = {
    nonce: nonce,
    from: signer.address,
    functionSignature: transaction.data ?? "",
  };

  // Sign message
  const signature = await signer._signTypedData(domain, types, message);

  console.log(signature);

  // Retrieve v, r, s from previous signature
  const split = ethers.utils.splitSignature(signature);

  console.log(split);

  // Check address retrieved from the previous data
  const recoveredAddress = ethers.utils.verifyTypedData(
    domain,
    types,
    message,
    signature
  );

  console.log(recoveredAddress);
}

getSignature();

I have followed the EIP-712 and NativeMetaTransaction flux to populate the inputs of the executeMetaTransaction function, which is:

    
    function executeMetaTransaction(
        address userAddress,
        bytes memory functionSignature,
        bytes32 sigR,
        bytes32 sigS,
        uint8 sigV
    ) public payable returns (bytes memory) {
        MetaTransaction memory metaTx = MetaTransaction({
            nonce: nonces[userAddress],
            from: userAddress,
            functionSignature: functionSignature
        });

        require(
            verify(userAddress, metaTx, sigR, sigS, sigV),
            "Signer and signature do not match"
        );

        // increase nonce for user (to avoid re-use)
        nonces[userAddress] = nonces[userAddress].add(1);

        emit MetaTransactionExecuted(
            userAddress,
            msg.sender,
            functionSignature
        );

        // Append userAddress and relayer address at the end to extract it from calling context
        (bool success, bytes memory returnData) = address(this).call(
            abi.encodePacked(functionSignature, userAddress)
        );
        require(success, "Function call not successful");

        return returnData;
    }    function executeMetaTransaction(
        address userAddress,
        bytes memory functionSignature,
        bytes32 sigR,
        bytes32 sigS,
        uint8 sigV
    ) public payable returns (bytes memory) {
        MetaTransaction memory metaTx = MetaTransaction({
            nonce: nonces[userAddress],
            from: userAddress,
            functionSignature: functionSignature
        });

        require(
            verify(userAddress, metaTx, sigR, sigS, sigV),
            "Signer and signature do not match"
        );

        // increase nonce for user (to avoid re-use)
        nonces[userAddress] = nonces[userAddress].add(1);

        emit MetaTransactionExecuted(
            userAddress,
            msg.sender,
            functionSignature
        );

        // Append userAddress and relayer address at the end to extract it from calling context
        (bool success, bytes memory returnData) = address(this).call(
            abi.encodePacked(functionSignature, userAddress)
        );
        require(success, "Function call not successful");

        return returnData;
    }

When I go on the WriteProxy tab of the contract, I set all the inputs in this way:

userAddress (address) : address who approves and needs the metatransaction to be paid by the relayer (the approve sender) functionSignature (bytes) : function signature got from the backend script (signature) sigR (bytes32), sigS (bytes32), sigV (uint8) : values got from the backend script (split)

Then I connect another wallet with funds but on Metamask says the transaction will revert, I don't know why because I think everything is fine...

Thanks to everyone who will help me :)

0

There are 0 answers