RodrigoR
RodrigoR

Reputation: 21

Getting the address of a contract by another one after inheritance

I am new to Solidity and I've come up with this issue. I want to develop a contract called senderContract {} that can receive ether from any address and then automatically transfer these funds to another contract called receiverContract {}. In this second contract, you will find two functions, the first one (manualTransfer()) is working correctly and allows to introduce manually the contract contract address to send the ether. But the second one (autoTransfer()) is not working.

I've discovered that the constructor() in the first contract changes the value of the variable recipient once the second contract es deployed. How is it possible that a variable in a constructor changes from its initialized value? Is the contructor not supposed to be executed just once?

Is there any reason for this action not being possible or am I just not writing the correct code? I leave the code here:

pragma solidity >= 0.7.0 < 0.9.0;


 contract receiverContract {

    event Log(uint);
    address public recipient;

    constructor () {
        recipient = address(this);
    } 

    fallback () external payable {
        emit Log(gasleft());
    } 

    receive () external payable {}

    function getThisAddress() public view returns(address) {
        return address(this);
    }

    function getBalance() public view returns (uint) {
        return address(this).balance;
    }

}



contract senderContract is receiverContract {

    function manualTransfer (address payable _to) public payable {
        _to.transfer(msg.value);
    }

    function autoTransfer () public payable {
        payable(recipient).transfer(msg.value);
    }

}

Thank you in advance!

Upvotes: 0

Views: 1664

Answers (2)

Seb_le_Bordelais
Seb_le_Bordelais

Reputation: 11

This seems to work well, using the super functionality (look at the first line of the second contract); on remix, recipent and _recipient are the same. Basically, using "super." in inherited contracts applies what's after one level up, see https://docs.soliditylang.org/en/v0.8.14/contracts.html?highlight=super :

pragma solidity >= 0.7.0 < 0.9.0;
contract receiverContract {

    event Log(uint);
    address public recipient;

    constructor () {
        recipient = address(this);
    } 

    fallback () external payable {
        emit Log(gasleft());
    } 

    receive () external payable {}

    function getThisAddress() public view returns(address) {
        return address(this);
    }

    function getBalance() public view returns (uint) {
        return address(this).balance;
    }

}



contract senderContract is receiverContract {

    address _recipient=super.getThisAddress();

// please see https://docs.soliditylang.org/en/v0.8.14/contracts.html?highlight=super 
//to understand how "super" works

    function manualTransfer (address payable _to) public payable {
        _to.transfer(msg.value);
    }

    function autoTransfer () public payable {
        payable(_recipient).transfer(msg.value);
    }

}

Upvotes: 1

Petr Hejda
Petr Hejda

Reputation: 43591

constructor () {
    recipient = address(this);
}

Constructor is in fact executed just once - during the contract deployment. However, the value of address(this) (the address of this contract) is different each time you deploy the contract. Which results in the value of recipient also being different each time.

The address of newly deployed contract is, by default, determined from the deployer address and nonce of the deploying transaction. First transaction has nonce 0, second transaction has nonce 1, etc. So when you send a first transaction deploying a contract from the deployer address, it results in the contract address 0x123. But a second transaction deploying a contract (any contract, even the same one) from the deployer address results in the contract address 0x456.


If you want the deployed contract address to be always the same (mind that you need to destruct the previously deployed contract before redeploying it), you can use the create2 opcode (the non-default option). See this answer for more info.

Upvotes: 0

Related Questions