I'd like to use multicall and metatransaction at the same time but seems like it's impossible.
is there any good solution ?
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/metatx/ERC2771Context.sol";
import "@openzeppelin/contracts/metatx/MinimalForwarder.sol";
import "@openzeppelin/contracts/utils/Multicall.sol";
contract Registry is ERC2771Context, Multicall {
event Registered(address indexed who, string name);
mapping(address => string) public names;
mapping(string => address) public owners;
constructor(
MinimalForwarder forwarder // Initialize trusted forwarder
) ERC2771Context(address(forwarder)) {}
function register(string memory name) public {
require(owners[name] == address(0), "Name taken");
address owner = _msgSender(); // Changed from msg.sender
owners[name] = owner;
names[owner] = name;
emit Registered(owner, name);
}
}
test
const { expect } = require("chai");
const { ethers } = require("hardhat");
const { signMetaTxRequest } = require("../../src/signer");
async function deploy(name, ...params) {
const Contract = await ethers.getContractFactory(name);
return await Contract.deploy(...params).then(f => f.deployed());
}
describe("contracts/Registry", function() {
beforeEach(async function() {
this.forwarder = await deploy('MinimalForwarder');
this.registry = await deploy("Registry", this.forwarder.address);
this.accounts = await ethers.getSigners();
});
it("registers names via a meta-tx", async function() {
const signer = this.accounts[2];
const relayer = this.accounts[3];
const forwarder = this.forwarder.connect(relayer);
const registry = this.registry;
const interface = new ethers.utils.Interface([
"function register(string memory name) public",
"function multicall(bytes[] calldata data) external",
])
const calls = [
interface.encodeFunctionData("register", ["defender"]),
interface.encodeFunctionData("register", ["multicall-example"])
]
const { request, signature } = await signMetaTxRequest(signer.provider, forwarder, {
from: signer.address,
to: registry.address,
data: registry.interface.encodeFunctionData('multicall', [calls]),
});
await forwarder.execute(request, signature).then(tx => tx.wait());
expect(await registry.owners('defender')).to.equal(signer.address);
expect(await registry.owners('multicall-example')).to.equal(signer.address);
});
});
error
1) contracts/Registry
registers names via a meta-tx:
AssertionError: expected '0x0000000000000000000000000000000000000000' to equal '0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC'
+ expected - actual
-0x0000000000000000000000000000000000000000
+0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC
at Context.<anonymous> (test/contracts/Registry.test.js:66:50)
at processTicksAndRejections (node:internal/process/task_queues:96:5)