2

I recently noticed that msg.sender isn't always the original caller's address (see here). It's the address of the current call. So if foo() calls bar(), then msg.sender in bar() will be the address of the contract containing foo().

My questions are:

1

msg.data, msg.sender, msg.sig, and msg.value will depend on the current call.

tx.origin is the original sender of the transaction (EOA = Externally Owned Account).

Note that the msg.* variables are only changed if you have

 this.fn()

or

 someOtherContractRef.fn()

Internal calls within the contract (without this.) will not change msg.* variables.

2

Adding to @ivicaa's and @Lauri's answer.

What's the best way to get the original sender's address?

tx.origin is a security concern and not recommended. Relying on it also ensures that contracts cannot be clients of your contract since a contract can never be the tx.origin. This limitation seriously constrains your dapp since it includes multi-signature wallet contracts and since there are usually desirable use-cases where the "user" could be another contract.

It's not a simple issue. This thread may shed some light on the considerations: https://github.com/ethereum/solidity/issues/683

  1. tx.origin is almost never useful. This is the most subjective point, but I have yet to come across a use of tx.origin that seemed legitimate to me. I welcome counter-examples, but I've written dozens or hundreds of smart contracts without needing it, and I have never heard of anyone else needing it either.

Instead, pass the msg.sender into functions that are concerned with the transaction signer. This implies that the called contract trusts the sending contract to tell the truth. The called contract should not naively listen to anything, but rather trust only whitelisted contracts that form part of your system.

function somethingOnBehalfOfSomeoneElse(address user) public onlyTrustedContracts {...

Hope it helps.

2
  • That's very helpful. How about doing stuff like: modifier onlyOwner() { require(msg.sender == owner || tx.origin == owner, "Sender is not the owner."); _; } ? Could that be a problem too? Jan 28 '19 at 16:25
  • 1
    My understanding is tx.origin can be overwritten by a determined adversary so I've learned to just disregard it and carry on as though it doesn't exist. I would call the example function with otherContact.somethingOnBehalfOfSomeoneElse(msg.sender) so my contract relies exclusively on values I believe are trustworthy. Jan 28 '19 at 17:00
1

All of the msg constants depend on the currenct scope (contract). Their value remains the same in the same contract (even in different functions) but if you call another contract the values change accordingly.

You can see them here in action:

pragma solidity ^0.5.0;
contract A {

    event Data(bytes a);
    event Sig(bytes4 a);
    event Val(uint a);

    function a() public payable {
        emit Data(msg.data);
        emit Sig(msg.sig);
        emit Val(msg.value);
        b();
        B b = new B();
        b.c();

    }

    function b() public payable {
        emit Data(msg.data);
        emit Sig(msg.sig);
        emit Val(msg.value);
    }
}

contract B {
    event Data(bytes a);
    event Sig(bytes4 a);
    event Val(uint a);

    function c() public payable {
        emit Data(msg.data);
        emit Sig(msg.sig);
        emit Val(msg.value);
    }
}

As for the original sender, you can simply use tx.origin. Note that this is very rarely used as using it may ruin functionality of some proxy contracts etc.

1
  • Thanks your answer is very good too but I accepted the other because it gave some details about the use of this. Jan 24 '19 at 19:06

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.