Inheritance Assignment

Cleared up thanks. Below should just be the correct answer, should anyone find it useful.

In order to solve the problem we have to somehow let the contract be accessed by onlyOwner and we have to make the address where funds are being withdrawn to, somehow payable. In the solution below, the first characteristic is derived from inheritance, while for making variable payable there are multiple options:
Option #1 - we make the address payable by using msg.sender

contract Ownable {
    
    address public owner;

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

    constructor(){
        owner = msg.sender;
    }
}

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

Option #2.1 - we make the owner variable payable by hand

contract Ownable {
    
    address payable public owner;

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

    constructor(){
        owner = msg.sender;
    }
}

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

Option #2.2 - we can also leave the state variable owner as non-payable and instead making it payable only locally within the Destroyable function, like below.

address public owner;
...
function destroyContract() public onlyOwner {
    selfdestruct(payable(owner));
}

1 Like

Ownable file:

pragma solidity 0.7.5;
contract Ownable{

 address owner;

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

}

constructor(){

  owner = msg.sender;

}
}

Destroyable file:
import “./Ownable.sol”;
pragma solidity 0.7.5;
contract Destroyable is Ownable{

  function close() public OnlyOwner { //onlyOwner is custom modifier
     selfdestruct(msg.sender);  // msg.sender is the owners address by the father contract Ownable

}
}

Bank file:
import “./Ownable.sol”;
import “./Destroyable.sol”;
pragma solidity 0.7.5;
contract bank is Ownable, Destroyable{
}

1 Like

Thanks Jon, this is very useful info! :+1:
So selfdestruct() is more of a last-resort kill switch. And we should design contracts keeping in mind that they will exist forever on the chain.

Cheers,
Matt

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

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

Cool it works!

**Ownable.sol**

pragma solidity 0.7.5;

contract Ownable {
    address payable public owner;

    modifier onlyOwner {
        require(msg.sender == owner);
        _;  // run function
    }
    
    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

Ownable.sol

contract Ownable {
    address payable owner;

    constructor(){
        owner = msg.sender;
    }
    
    modifier onlyOwner{
        require(msg.sender == owner);  
        _;
    }
    
    function getOwner() public view returns (address){
        return owner;
    }
}

Destroyable.sol

import "./Ownable.sol";

contract Destroyable is Ownable{
    
    function close() public onlyOwner { //onlyOwner is custom modifier
        selfdestruct(owner);  // `owner` is the owners address
    }
}
1 Like

Nice solution @Nelson1 :ok_hand:

We can also streamline the inheritance by having Bank just inherit Destroyable, because it will then indirectly inherit Ownable via Destroyable. This will give you a multi-level inheritance structure. There would also no longer be any need to import Ownable.sol into Bank.sol (just Destroyable.sol).

Nice solution @jiadong_han :ok_hand:

We can also streamline the inheritance by having Bank just inherit Destroyable, because it will then indirectly inherit Ownable via Destroyable. This will give you a multi-level inheritance structure. There would also no longer be any need to import Ownable.sol into Bank.sol (just Destroyable.sol).

Exactly right.

The data relating to transactions which have already been executed and validated using the smart contract will remain immutable and stored permanently on the blockchain. We should design our smart contracts based on the premise that once they are deployed they can’t be modified. This means building them with a rigorous attention to security and only deploying them after thorough testing. The smart contracts themselves run on the EVM, which isn’t actually the same as the Ethereum blockchain. This is an important distiction to understand. The blockchain itself is where all the data is stored.

Believing that a smart contract will exist and run forever on the EVM is almost certainly unrealistic, as future developments in technology will eventually render a smart contract, which by it’s very nature can’t be modified or updated, either inefficient or obsolete, or increasingly at risk from ever more sophisticated attacks.

One way to manage the risk of a smart contract eventually being compromised or becoming obsolete, and to limit the potential financial loss that this could lead to, is to include the selfdestruct functionality.

1 Like

Hi @Conor_Neary,

You’ve nearly got it, but because you’ve called selfdestruct with owner as the argument, you need to make it a payable address. You should have got a compiler error as result of this.

Have a read of this post which explains the issue and the various ways to resolve it.

Also, what modifications did you make to the Bank contract header for the inheritance?

Excellent coding @MindFrac :muscle:

What modifications did you also make to the Bank contract header for the inheritance?

1 Like

Nice solution @herbz :ok_hand:

Don’t forget to add  pragma solidity 0.7.5;  at the top of each file. Your contract won’t deploy without it.

Also, what modifications did you make to the Bank contract header for the inheritance?

I had to change it to inherit from Destroyable:

import "./Destroyable.sol";

contract Bank is Destroyable { // code goes here }
1 Like

contract Ownable{
address payable owner;

modifier onlyOwner{
    require(owner == msg.sender,"Your not the owner");
    _;
}
constructor(){
    owner = msg.sender;
}

function close() public onlyOwner payable{ //onlyOwner is custom modifier
    selfdestruct(owner);  // `owner` is the owners address
}

}

1 Like

Nice solution @chim4us :ok_hand:

You can also make your code more modular by separating out the “destroy contract” functionality into a separate contract. You can then structure everything using multi-level inheritance:
Bank inherits Destructable,
Destructable inherits Ownable.
(Bank therefore inherits Ownable indirectly via Destructable, because Destructable already inherits Ownable).

You don’t need to make your close() function payable. A function only needs to be payable if it is receiving ether. The owner address passed as the argument to selfdestruct() does need to be a payable address because it will receive the contract’s ether balance when the contract self-destructs. You have already done this effectively with the line:

Can we also see how you’ve coded the start of your Bank contract to include the inheritance?

Let us know if anything is unclear, or if you have any questions :slight_smile:

1 Like

Thanks so muc @jon_m

1 Like

The main file would be:

pragma solidity 0.7.5;

import "./ownable.sol";

contract Destroyable is OWNABLE{
    
    function self_destruct() public onlyOwner{
        selfdestruct(msg.sender);
    }
}

Which calls the file ownable.sol that contains:


pragma solidity 0.7.5;

import "./ownable.sol";

contract Destroyable is OWNABLE{
    
    function self_destruct() public onlyOwner{
        selfdestruct(msg.sender);
    }
}

Further contracts inheriting from Destroyable have the functionality of getting removed from the ETH blockchain.

1 Like

Hi Filip,

I have just one question.
When we self destruct using the line selfdestruct(msg.sender)
is it destroying the wallet? Isn’t msg.sender the wallet address? and if it is destroying the wallet is the contract part of the wallet or separate?

1 Like

Hi @jaykch

msg.sender is the owner address so it transfers the ether to the person address.
contract has it own address it is called internal address.

Happy learning, :grinning:
Abel

Hi,

I don’t think you understood my query haha. I am confused about the msg.sender self destruct line, wouldn’t selfdestruct(msg.sender) destroy the public key usid to create the contract instead of the contract itself.

1 Like