Understanding msg.value and msg.sender in Solidity
📖 Scenario: You are creating a simple smart contract for a crowdfunding campaign on the Ethereum blockchain. People can send money to support the project, and the contract keeps track of who sent money and how much.
🎯 Goal: Build a smart contract that records the sender's address and the amount of Ether sent using msg.sender and msg.value. Then display the total amount collected and the last sender's address.
📋 What You'll Learn
Create a public variable lastSender to store the address of the last person who sent Ether
Create a public variable totalCollected to store the total amount of Ether collected
Write a receive function to accept Ether and update lastSender and totalCollected
Write a function getSummary that returns lastSender and totalCollected
💡 Why This Matters
🌍 Real World
Smart contracts on Ethereum use <code>msg.sender</code> and <code>msg.value</code> to handle payments and identify users.
💼 Career
Understanding these variables is essential for blockchain developers building decentralized applications that handle money.
Progress0 / 4 steps
1
Set up the contract and variables
Create a contract called CrowdFund. Inside it, declare a public address variable called lastSender and a public unsigned integer variable called totalCollected.
Blockchain / Solidity
Hint
Use address public lastSender; and uint public totalCollected; inside the contract.
2
Add the receive function to accept Ether
Add a receive function that is external and payable. Inside it, set lastSender to msg.sender and add msg.value to totalCollected.
Blockchain / Solidity
Hint
The receive function must be external payable. Use msg.sender and msg.value inside it.
3
Create a function to get the summary
Write a public view function called getSummary that returns the lastSender address and the totalCollected amount.
Blockchain / Solidity
Hint
Use function getSummary() public view returns (address, uint) and return the two variables.
4
Test the contract output
Write a comment showing the expected output of calling getSummary() after someone sends 1 Ether from address 0x123.... The output should show lastSender as 0x123... and totalCollected as 1000000000000000000 (1 Ether in wei).
Blockchain / Solidity
Hint
Remember 1 Ether = 10^18 wei. Show the address and total in a comment.
Practice
(1/5)
1. What does msg.sender represent in a smart contract?
easy
A. The amount of ether sent with the transaction
B. The address of the account that called the contract
C. The balance of the contract
D. The gas price of the transaction
Solution
Step 1: Understand the role of msg.sender
msg.sender always holds the address of the account or contract that called the current function.
Step 2: Differentiate from msg.value
msg.value holds the amount of ether sent, not the caller's address.
Final Answer:
The address of the account that called the contract -> Option B
Quick Check:
msg.sender = caller address [OK]
Hint: Remember: sender is who calls, value is what is sent [OK]
Common Mistakes:
Confusing msg.sender with msg.value
Thinking msg.sender is contract balance
Assuming msg.sender is always a user (it can be a contract)
2. Which of the following is the correct way to check if the caller sent at least 1 ether in Solidity?
easy
A. if (msg.value >= 1 ether) {}
B. if (msg.value == msg.sender) {}
C. if (msg.sender >= 1 ether) {}
D. if (msg.sender == 1 ether) {}
Solution
Step 1: Identify the variable holding sent ether amount
msg.value stores the amount of ether sent with the call.
Step 2: Use comparison to check minimum ether sent
Checking if msg.value >= 1 ether correctly tests if at least 1 ether was sent.
Final Answer:
if (msg.value >= 1 ether) {} -> Option A
Quick Check:
Check ether amount with msg.value [OK]
Hint: Use msg.value to check ether sent, not msg.sender [OK]
Common Mistakes:
Using msg.sender to compare ether amounts
Using equality instead of >= for minimum check
Mixing up msg.sender and msg.value in conditions
3. What will be the output of this Solidity function when called by address 0xABC with 2 ether sent?
function pay() public payable returns (address, uint) {
return (msg.sender, msg.value);
}
medium
A. (0xABC, 0)
B. (msg.sender, msg.value)
C. (address(0), 2 ether)
D. (0xABC, 2 ether)
Solution
Step 1: Understand msg.sender and msg.value in the function
msg.sender is the caller's address (0xABC), and msg.value is the ether sent (2 ether).
Step 2: Return values match caller and sent ether
The function returns these two values exactly as (0xABC, 2 ether).
Final Answer:
(0xABC, 2 ether) -> Option D
Quick Check:
Caller and sent ether returned correctly [OK]
Hint: Returned values match caller address and sent ether [OK]
Common Mistakes:
Assuming msg.value is zero if not explicitly set
Confusing msg.sender with zero address
Expecting variable names instead of actual values
4. Identify the error in this Solidity function that tries to check if the caller sent ether:
function deposit() public {
require(msg.value > 0, "Send some ether");
}
medium
A. Missing payable keyword in function declaration
B. Incorrect use of require syntax
C. msg.value cannot be compared with > 0
D. Function should return a value
Solution
Step 1: Check function declaration for payable
To receive ether and access msg.value, the function must be marked payable.
Step 2: Identify missing payable keyword
The function lacks payable, so msg.value will always be zero and cause errors.
Final Answer:
Missing payable keyword in function declaration -> Option A
Quick Check:
Functions receiving ether must be payable [OK]
Hint: Add payable to receive ether and use msg.value [OK]
Common Mistakes:
Forgetting payable keyword
Thinking require syntax is wrong
Expecting function to return value unnecessarily
5. You want to write a Solidity function that only accepts payments from a specific address and requires at least 0.5 ether sent. Which code snippet correctly enforces both conditions?
hard
A. function pay() public payable {
require(msg.sender != 0x123 && msg.value > 0.5 ether);
}
B. function pay() public {
require(msg.sender == 0x123);
require(msg.value >= 0.5 ether);
}
C. function pay() public payable {
require(msg.sender == 0x123 && msg.value >= 0.5 ether, "Unauthorized or insufficient funds");
}
D. function pay() public payable {
if (msg.sender == 0x123 || msg.value >= 0.5 ether) {}
}
Solution
Step 1: Ensure function is payable to accept ether
Only options A, C, and D have payable, needed to receive ether.
Step 2: Check conditions for sender and ether amount
function pay() public payable {
require(msg.sender == 0x123 && msg.value >= 0.5 ether, "Unauthorized or insufficient funds");
} uses require with AND (&&) to enforce both sender address and minimum ether sent.
Step 3: Evaluate other options for correctness
function pay() public {
require(msg.sender == 0x123);
require(msg.value >= 0.5 ether);
} lacks payable, so msg.value is always zero. function pay() public payable {
if (msg.sender == 0x123 || msg.value >= 0.5 ether) {}
} uses OR (||), allowing either condition alone. function pay() public payable {
require(msg.sender != 0x123 && msg.value > 0.5 ether);
} uses != which rejects the correct sender.
Final Answer:
function pay() public payable {
require(msg.sender == 0x123 && msg.value >= 0.5 ether, "Unauthorized or insufficient funds");
} -> Option C
Quick Check:
Use payable and require with AND for both checks [OK]
Hint: Use payable and require with && to check sender and value [OK]
Common Mistakes:
Forgetting payable keyword
Using OR instead of AND for conditions
Checking msg.sender with != instead of ==
Not combining conditions in one require
Recommended
Ready to prove it?
Pass the test and this pattern moves unknownstrongwhile earning +1 Grip toward your certificate.