5

I read about who is msg.sender when calling a contract from a contract, but who is msg.sender when calling a contract from a contract that calls another contract and so on and so forth?

3
  • 3
    Possible duplicate of Who is msg.sender when calling a contract from a contract
    – Ismael
    Jul 21, 2019 at 4:57
  • @Ismael it's not a duplicate, I specifically mentioned that I'd already checked that question. Jul 21, 2019 at 17:58
  • Contracts are not aware of the call context, they cannot know if they have more than one ancestor in the call chain (they can check tx.origin != msg.sender). You have codecall and delegatecall that change msg.sender but otherwise they do not affect the call context.
    – Ismael
    Jul 23, 2019 at 14:30

2 Answers 2

5

Let's take this snippet, which you can deploy for yourself on Remix:

pragma solidity 0.5.10;

contract A {

    event LogMsgSender(address who);

    function callMe() public {
        emit LogMsgSender(msg.sender);
    }
}

contract B {

    function callMe(address a) public {
        A(a).callMe();
    }
}

contract C {

    function callMe(address a, address b) public {
        B(b).callMe(a);
    }
}

contract D {

    function callMe(address a, address b, address c) public {
        C(c).callMe(a, b);
    }
}

Calling each method, we get the following results:

  • A.callMe() logs the actual transaction sender.
  • B.callMe(a) logs B's address.
  • C.callMe(a, b) also logs B's address.
  • D.callMe(a, b, c) also log's B's address.

Thus, no matter how deep the nested call chain, msg.sender is always the address of the last but one contract.

3

It's the innermost, or nearest/most recent caller.

Referring to your example:

From A's perspective, it is the txn sender, B, or any other contract that called it (entirely possible). In practice, it may be to A's advantage to check that the caller is B and only B.

From B's perspective, it is the txn sender, C, or any other contract that called it. In practice, it may be to B's advantage to check that the caller is C.

From D's perspective, it is the txn sender or a contract that called it.

If D is meant to be the entry-point, than A, B and C should have knowledge of the contracts that are intended to call and reject requests from untrusted contracts - unless it is okay for random users and contracts to manipulate the system from any starting point which is seldom the case.

Consider

require(msg.sender = address(c), "You are not C. I don't know you.  Goodbye.");

Hope it helps.

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.