Inheritance Assignment

Hi @ppoluha,

Your destruct function header throws a compiler error. Can you resolve it?

Apart from that, your Destructible contract is looking good, but it relies on you having made an additional change in Ownable. So can we see that contract as well?

We also need to see what modifications you’ve made to the start of your Bank.sol file, and Bank contract header, for the inheritance, because that’s the contract we are actually deploying, using, and then destroying, and which, therefore, needs to inherit both the contract ownership and contract destruction functionality. Once completed successfully, you should be able to deploy Bank, perform some transactions, then destroy the Bank contract, transferring any remaining ether balance to the caller of the selfdestruct function (here, the contract owner).

Let us know if you have any questions :slightly_smiling_face:

Hey Juan,

Glad you found the feedback helpful.

Very good question!

address payable receiver = msg.sender;
selfdestruct(receiver);

The use of the additional local variable receiver is not actually necessary. It was done like this to break down what is happening into more easier-to-understand steps (although this can obviously confuse some students more than it helps!) However, it does highlight that the address passed to selfdestruct() needs to be a payable address. Have a look at this post where you can read more about the use of this receiver variable. It is only marked payable because if we assign a payable address (e.g. msg.sender before v0.8) to a variable and don’t define the variable as payable, then it will be assigned and stored as a non-payable address.

I hope that makes sense — just let me know if you have any more questions :slight_smile:

Hi @ybernaerts,

If you post your complete code (Bank, Destroyable and Ownable) I’ll take a look to see what the problem is.

Good solution @Filip_Rucka :ok_hand:

Aren’t you doing the new course using v.0.7.5?

Can we also see what modifications you’ve made to the start of your derived contract file, and contract header, for the inheritance?

Hi @filip i have some challenge on a project. Please how can i know amount of gas spent on a address on chain per day

Hi and thanks for your reply @jon_m!

Here’s the complete example. I made it possible to call selfdestruct from outside the contract although Filip wanted it to only be available from derived contracts as I didn’t want to create one more function in the Bank contract in order to call self destruct.

pragma solidity 0.7.5;

contract Ownable {
    address payable owner;
    
    constructor() {
        owner = msg.sender;
    }
    
    modifier onlyOwner {
        require(msg.sender == owner);
        _;
    }
}

contract Destructible is Ownable {
   function destruct() public onlyOwner { 
      selfdestruct(owner);
   }
}

contract Bank is Destructible {
    
    mapping(address => uint) balances;

    event depositDone(address indexed depositedFrom, uint amount);
    event withdrawalDone(address indexed withdrawnTo, uint amount);

    function deposit() public payable returns (uint) {
        balances[msg.sender] += msg.value;
        emit depositDone(msg.sender, msg.value);
        return balances[msg.sender];
    }
    
    function withdraw(uint amount) public returns (uint) {
        require(balances[msg.sender] >= amount, "Not enough funds for withdrawal!");
        uint originalAmount = balances[msg.sender];
        msg.sender.transfer(amount);
        balances[msg.sender] -= amount;
        assert(balances[msg.sender] + amount == originalAmount);
        emit withdrawalDone(msg.sender, amount);
        return balances[msg.sender];
    }
    
    function getBalance() public view returns (uint) {
        return balances[msg.sender];
    }
}
1 Like

// Destroyable Contract in destroyable.sol

import “./ownable.sol”;

contract Destroyable is Ownable {
function close() public onlyOwner {
selfdestruct(payable(owner));
}
}

// Main Contract

import “./ownable.sol”;
import “./destroyable.sol”;

contract myBank is Ownable, Destroyable {

1 Like

Ownable contract

pragma solidity 0.7.5;

contract Ownable{

  address payable owner; /* declaring the owner variable as a payable address type so it can receive funds*/

  modifier onlyOwner {
      require(msg.sender == owner); 
      _;  
  }

  constructor(){
      owner = msg.sender; 
  }

}

Destroyable contract:

pragma solidity 0.7.5;

import "./Ownable.sol";

contract Destroyable is Ownable{

function destroy() public onlyOwner {
    selfdestruct(owner); // sends funds to owner's address, contract's data is cleared freeing up space in the Ethereum blockchain
}

}

Bank Contract


pragma solidity 0.7.5;

import "./Destroyable.sol";

contract Bank is Destroyable{.....}

Seems to be working…

1 Like

Great solution @ppoluha :ok_hand:

Giving your destruct() function public visibility is exactly what is required. This means that it will be inherited by Bank, and can be called from an external service. In order for the contract owner to be able to call destruct() and trigger selfdestruct() it needs to be available externally, because the contract owner (distinct from the contract itself) has an external address. If we gave destruct() internal visibility, then it could only be called from within the Bank contract, and as you say, that would require an additional public function, which we don’t want, as that would result in code duplication — one of key things inheritance should help us avoid.

Unlike state variables, there is no default visibility with functions, and so we must define this in all function headers. State variables, on the other hand have internal visibility by default (when no visibility is explicitly defined).

Well done for making sure your owner address is payable , so that selfdestruct() is called with a payable address and, therefore, any remaining ether in the contract is paid/transferred to the owner when selfdestruct() is triggered.

Your implementation of a multi-level inheritance structure is also the best approach, because it is more streamlined. Bank only needs to explicitly inherit Destroyable, because it will implicitly inherit Ownable via Destroyable.

Best practice would usually be to place each contract in a separate file and import each base contract into the file of its derived contract using an import statement. This keeps our code as modular as possible.

Let me know if you have any questions.

1 Like

Nice solution @yllee9127 :ok_hand:

We can also streamline the inheritance structure by having Bank explicitly inherit Destroyable only, because it will inherit Ownable implicitly via Destroyable. This will give you a multi-level inheritance structure.

You’re making great progress! Just let us know if you have any questions :slight_smile:

An excellent solution @Jazmin :star_struck:

Your comments are also accurate, and show that you have a good understanding of some of the finer points. And your implementation of a multi-level inheritance structure is also the best approach, because it is more streamlined: Bank only needs to explicitly inherit Destroyable, because it will implicitly inherit Ownable via Destroyable.

You’re making great progress :muscle:

1 Like

Hi @chim4us,

Good question, but would you mind posting it as a new topic? This is the Inheritance Assignment discussion topic and so it isn’t in the right place. Just go to the forum homepage, click on the grey New Topic button (top right below your photo) and select an appropriate Category (probably Ethereum). That’s also the best way to ensure your question reaches the most number of people, and so you’re more likely to get a quicker response.

Thanks :slight_smile:

Thanks, I will start the class over! I have read the thread again, and I think it will be to my advantage.

1 Like

I made Destroyable.sol:

pragma solidity 0.7.5;

import "./Ownable.sol";

contract Destroyable is Ownable {
    function Destroy() public onlyOwner {
        selfdestruct(msg.sender);
    } 
}

I then imported it into Bank.sol:

pragma solidity 0.7.5;

import "./Ownable.sol";
import "./Destroyable.sol";

contract Bank is Ownable, Destroyable {
    //...
}

I am curious with both contracts importing Ownable.sol when they are compiled together into a single contract, what happens? I would expect that the compiler prevents code duplication.

1 Like

Thank you! That makes perfect sense. I do have one more question, regarding a line of code in the Bank contract, right after the function _transfer is called:

govermentInstance.addTransaction(msg.sender, recipient, amount);

I think I haven’t seen that in the previous lectures and would like to understand everything haha :smile: :grinning:

1 Like

Ownable contract file:



pragma solidity 0.7.5;

contract Ownable {
    
    modifier onlyOwner {
        require(msg.sender == owner);
        _; //it runs the function
    }
    
    constructor(){
        owner = msg.sender;
    }
    
    address public owner;
}

Destroyable contract file:

pragma solidity 0.7.5;

import "./ownable.sol";

contract Destroyable is Ownable{
    
    function destroyContract() public onlyOwner{
        selfdestruct(0x5B38Da6a701c568545dCfcB03FcB875f56beddC4);
// or I can use msg.sender instead of address?
    }
    
    
}

Bank contract file:

pragma solidity 0.7.5;

import "./destroyable.sol";


contract Bank is Destroyable {....
..............................
}
1 Like

ownable.sol:
pragma solidity 0.7.5;

contract Ownable {
address payable owner;

modifier onlyOwner(){
    require(msg.sender == owner);
    _;
}

constructor() {
    owner = msg.sender;
}

}
destroyable.sol:
pragma solidity 0.7.5;

import “./ownable.sol”;

contract Destroyable is Ownable {
function close() public onlyOwner {
selfdestruct(owner);
}
}

1 Like
import"./Ownable.sol";

contract Ownable {
    address owner;
    
    modifier onlyOwner {
        require (msg.sender == owner);
    _; // run the function
    }    
    contructor(){
        owner = msg.sender;
    }
contract Bank is destroyable{         
    function selfdestruct() public onlyOwner { //onlyOwner is custom modifier
  selfdestruct(owner);  // `owner` is the owners address
}
}
pragma solidity 0.7.5;

import "./Ownable.sol";

contract Destroyable is Ownable {

    function destroy() public onlyOwner {
    selfdestruct(msg.sender);
    }

}
1 Like

Nice solution @dustwise :ok_hand:

Haven’t you tried compiling and then deploying your solution in Remix to find out? Your question is a very good one, but you should now be getting to a stage where you have enough knowledge and confidence to be able to start testing, experimenting and investigating these sorts of things for yourself. You can then check your findings, and any preliminary conclusions you have been able to draw from them, by posting them here in the forum, and we’ll get back to you.

Each contract is actually compiled separately, but the compiler will highlight any issues with how the inheritance structure has been coded. Do your contracts compile with or without any errors or warnings?

In terms of deployment, we only need to deploy the Bank contract because the contract ownership and contract destruction functionalities in the other contracts are inherited and available in Bank.

You should also consider whether there is an alternative inheritance structure you could use to avoid the code duplication that you have quite rightly identified.

In fact, you will find that we can streamline the inheritance structure by having Bank explicitly inherit Destroyable only, because it will inherit Ownable implicitly via Destroyable. This will give you a multi-level inheritance structure, and will avoid some code duplication.

You’re making great progress! Just let me know if you have any further questions :slight_smile: