I'm new to solidity and trying to understand OpenZeppelin's Context contract. At the time of writing, the documentation says:

While these are generally available via msg.sender and msg.data, they should not be accessed in such a direct manner, since when dealing with meta-transactions the account sending and paying for execution may not be the actual sender (as far as an application is concerned).

This contract is only required for intermediate, library-like contracts.

I kind of understand at a high level that msg.sender can be different from the actual sender for a meta-transaction, but I do not understand how using Context's _msgSender() or _msgData() helps with that. Both functions are simply returning msg.sender and msg.data and they look no different from directly accessing msg.sender or msg.data.

OpenZeppelin's Ownable uses _msgSender() in its constructor and modifier onlyOwner() but I don't understand how that's different from hardcoding msg.sender.

A specific example where calling _msgSender() is different from msg.sender would be very helpful!

1 Answer 1


This question has been asked and answered on the OZ forum here : https://forum.openzeppelin.com/t/help-understanding-contract-context/10579.

The _msg.sender and _msg.data functions are in fact overridden in the OZ smart contract ERC2771Context which implements the EIP-2771 : Secure Protocol for Native Meta Transactions.

_msg.sender here allows a recipient contract to retrieve the original sender in the case of a meta-transaction sent by a trusted forwarder :

function _msgSender() internal view virtual override returns (address sender) {
    if (isTrustedForwarder(msg.sender)) {
        // The assembly code is more direct than the Solidity version using `abi.decode`.
        assembly {
            sender := shr(96, calldataload(sub(calldatasize(), 20)))
    } else {
        return super._msgSender();

From the EIP-2771 :

The Trusted Forwarder is responsible for calling the Recipient contract and MUST append the address of the Transaction Signer (20 bytes of data) to the end of the call data.


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.