Developers need to understand the difference between and in Solidity. These two global variables often need clarification with each other despite their fundamental differences. While they may appear similar at first glance, and represent distinct addresses in the context of a transaction. tx.origin msg.sender tx.origin msg.sender In this blog post, we will delve deeper into the meanings of each of these variables. What Is ? tx.origin In Solidity, identifies the original sender of a transaction. It points to the external account initiating the transaction and remains constant throughout subsequent smart contract interactions (full call chain). tx.origin When a transaction is initiated through the MetaMask wallet, the address of the user's MetaMask wallet is stored in . This address remains the same, even if the transaction passes through multiple contracts. The consistency of this address is essential for tracing the initial sender of the transaction. tx.origin What Is ? msg.sender In smart contract development, identifies the sender of the current call. This variable is dynamic and can change throughout the transaction process. msg.sender When a transaction moves through several smart contracts, the value changes to indicate the most recent contract address in the call chain. For example, if Contract A calls Contract B, then the value within Contract B will be recognized as Contract A. msg.sender msg.sender Coding It Up To demonstrate how the and change between smart contract calls, we will create an smart contract that references the contract. tx.origin msg.sender EntryContract UnderlyingContract Let's add a function that prints each address. printTxOriginAndMsgSender Here, we have the smart contract: Entry contract EntryContract { IUnderlyingContract private underlyingContract; constructor(IUnderlyingContract _underlyingContract) { underlyingContract = _underlyingContract; } function printTxOriginAndMsgSender() public view { console.log("tx.origin", tx.origin); console.log("msg.sender", msg.sender); } function callUnderlyingContract() external { underlyingContract.printTxOriginAndMsgSender(); } } Now, let's define the and its interface: UnderlyingContract interface IUnderlyingContract { function printTxOriginAndMsgSender() external ; } contract UnderlyingContract is IUnderlyingContract { function printTxOriginAndMsgSender() external view { console.log("tx.origin", tx.origin); console.log("msg.sender", msg.sender); } } To execute the test, we must first deploy the , and use its address when deploying the . UnderlyingContract EntryContract When we call the function of the contract, we see that both addresses are the same. printTxOriginAndMsgSender EntryContract Let's call the function on the contract. We can see that and are different now. is the original caller's address and is the smart contract’s address. callUnderlyingContract EntryContract tx.origin msg.sender tx.origin msg.sender EntryContract TL;DR In Solidity, and are two variables that serve different but crucial purposes. always refers to the address that initially initiated the transaction and remains constant throughout the transaction chain. tx.origin msg.sender tx.origin On the other hand, represents the sender of the current message or contract interaction and changes with each call. msg.sender It is crucial to be cautious when using as it may not always represent the initial caller of the transaction. msg.sender Links Demo code Solidity documentation: Special Variables and Functions Solidity documentation: Block and Transaction Properties Unraveling Solidity Mysteries: Demystifying tx.origin and msg.sender