1
abstract contract ContextMixin {
    function msgSender()
        internal
        view
        returns (address payable sender)
    {
        if (msg.sender == address(this)) {
            bytes memory array = msg.data;
            uint256 index = msg.data.length;
            assembly {
                // Load the 32 bytes word from memory with the address on the lower 20 bytes, and mask those.
                sender := and(
                    mload(add(array, index)),
                    0xffffffffffffffffffffffffffffffffffffffff
                )
            }
        } else {
            sender = payable(msg.sender);
        }
        return sender;
    }
}

Is this a OpenSea specific thing or in general?

3
  • Think it's just a wrapper for msg.sender. OpenZeppelin has one for its Context smart contracts as well. From what I understand, it's useful in cases where you want msg.sender in some cases, but want some other address in others.
    – Sloth Man
    Sep 24 at 21:37
  • @SlothMan I understand this exists so that OpenSea code can call my code and pretend to be me, I want to understand if this is a common standard?
    – Sid Datta
    Sep 24 at 22:32
  • Common standard as in common practice? Then yes, I think it is. Context smart contracts with wrapper functions for msg.sender is often used. It provides an alternative to calling tx.origin, which is generally accepted to be a bad idea.
    – Sloth Man
    Sep 25 at 3:22
1

I think it's supposed to be used for meta-transactions. You can find similar examples that OpenZeppelin implemented that was also designed to be used this way.

To support native meta transaction, OpenSea inherits NativeMetaTransaction contract that execute another function on itself (on behalf of the user with a signature), which will make the msg.sender its own address (address(this)).

(Read this if you don't understand why msg.sender can be the contract address itself: How can msg.sender == address(this)? )

In OpenSea's case, the meta transaction is executed by the function executeMetaTransaction here, which put the user's address as the first argument. So the _msgSender() function is basically just saying, if this is a meta transaction, use the original signer's (user) address as the message sender, which can be found by parsing msg.data

This is how they can support some gas-less transactions, where you just need to sign a signature and the opensea proxy will pay gas for you, while the contract will just works as you're interacting with it directly, without introducing additional roles in the contracts.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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