3
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, 2021 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, 2021 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, 2021 at 3:22

1 Answer 1

3

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 from the NativeMetaTransaction contract that executes 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 work as you're interacting with it directly, without introducing additional roles in the contracts.

0

Your Answer

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

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