馃 Motivation
Contracts3.X doesn't support Native Meta-Transaction support. It's not compatible with any of the meta-transaction out there in the market.
馃摑 Details
As contract 3.X uses v0.6.6 standard of solidity, And function _msgSender in Context contract is virtual so it can only be overridden in parent contract which inherits the ERC20 standard. That means, the existing solutions for meta transaction are not compatible anymore. To give some context, Meta-Transaction relayers uses _msgSender, For instance Gas station network uses this implementation.
function _msgSender() internal view returns (address payable) {
if (msg.sender == address(this)) {
bytes20 userAddress;
uint256 dataLength = msg.data.length;
assembly {
calldatacopy(0x0, sub(dataLength, 40), sub(dataLength, 20))
userAddress := mload(0x0)
}
return address(uint160(userAddress));
} else {
return msg.sender;
}
}
I propose that we should include this change in Context contract itself or make changes so _msgSender() can be overridden by the other contracts too.
Thank you for reaching out @sanchaymittal.
I wasn't able to understand the problem that you point out.
Context._msgSender was specifically built for the GSN. The inheritance changes in Solidity 0.6 made it a bit more cumbersome to use, but everything should work. GSNRecipient defines the override for _msgSender.
Unfortunately in Solidity 0.6 inheriting from GSNRecipient will likely result in a contract that doesn't compile because the compiler doesn't know if it should use Context._msgSender or GSNRecipient._msgSender, but this is fixed by adding the following lines to your contract:
function _msgSender() internal view override(Context, GSNRecipient) returns (address payable) {
return super._msgSender();
}
function _msgData() internal view override(Context, GSNRecipient) returns (bytes memory) {
return super._msgData();
}
By using super we specify that we want to use the "most specific" implementation of _msgData according to the Solidity linearization, and that will be GSNRecipient's.
We definitely should have specifically this bit of code in the docs, but I couldn't find it. cc @nventuro
We have notes on the required overrides for GSN in the release notes for v3: https://github.com/OpenZeppelin/openzeppelin-contracts/releases/tag/v3.0.0
Thanks a lot guys!!! @frangio @abcoathup.
Got it resolved...
pragma solidity "0.6.6";
import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@opengsn/gsn/contracts/BaseRelayRecipient.sol";
contract TestToken is ERC20, BaseRelayRecipient {
constructor()
ERC20("Test Token", "TST")
public
{
uint256 value = 10**10 * (10**18);
_mint(_msgSender(), value);
}
function _msgSender() internal view override(Context, BaseRelayRecipient) returns (address payable) {
return BaseRelayRecipient._msgSender();
}
}
Awesome!
Most helpful comment
Thank you for reaching out @sanchaymittal.
I wasn't able to understand the problem that you point out.
Context._msgSenderwas specifically built for the GSN. The inheritance changes in Solidity 0.6 made it a bit more cumbersome to use, but everything should work.GSNRecipientdefines the override for_msgSender.Unfortunately in Solidity 0.6 inheriting from
GSNRecipientwill likely result in a contract that doesn't compile because the compiler doesn't know if it should useContext._msgSenderorGSNRecipient._msgSender, but this is fixed by adding the following lines to your contract:By using
superwe specify that we want to use the "most specific" implementation of_msgDataaccording to the Solidity linearization, and that will beGSNRecipient's.We definitely should have specifically this bit of code in the docs, but I couldn't find it. cc @nventuro