Ethereum: Issue with tx.origin and msg.sender in Foundry testing
As part of my ongoing research on smart contracts, I was working on a test case of an Ethernaut Level 4 (phone) contract using Foundry. However, I encountered an unexpected issue that required troubleshooting.
Issue:
During testing, I noticed that the “tx.origin” and “msg.sender” fields in my contract were not behaving as expected. In particular, these fields seemed to return different values than I expected.
Issue:
After reviewing the contract code and understanding how it interacts with the blockchain, I realized there were two main issues:
tx.origin: Thetx.originfield contains the address of the account that initiated the transaction (i.e., the sender). However, when using the Foundry test framework, this value is not always accurate.
msg.sender: Themsg.senderfield contains the address of the account that called the contract function (i.e. the recipient). This value may differ from thetx.originvalue, especially if the transaction was sent via a different account.
Solution:
To solve this problem, I made some changes to the test code:
- Use 
senderinstead oforigin: In the Foundry test framework,
senderseems to be the correct attribute when accessing the sender of a transaction. 
- Use 
contractAddressas a fallback: Iftx.originandmsg.senderare still different, I can fall back to the contract address (contractAddress) as an alternative. 
Here is an updated code snippet demonstrating these changes:
const { Ether } = require("Ether");
// Test case for phone contract
async function testTelephone() {
// Initialize contract and account
const phoneContract = new Ether.Contract(
"
ABI phoneContract,
ethers.Wallet.fromPrivateKey(
"YOUR_PRIVATE_KEY", // Replace it with your private key
)
);
// Create a transaction object
Constants tx = {
from: ethers.Wallet.fromPrivateKey("YOUR_PRIVATE_KEY"),
to: phoneContract.address, // The correct address for this contract
value: ethers.utils.parseEther("1"), // Set the transaction value
gasPrice: 20n, // Set gas price (optional)
gasLimit: 2000, // Set maximum gas limit
data: "0x", // Set the transaction data (in this case it is empty)
};
// Commit transaction
const result = await phoneContract.sendTransaction(tx);
console.log(result);
}
// Run the test function
testPhone();
Conclusion:
With these changes, I was able to resolve the issue with tx.origin and msg.sender in my phone contract test case. Now that the values are accurate, I can move on to further testing and analysis.
If you encounter similar issues or have any questions about this solution, feel free to ask!
