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 :)