Inheritance Assignment

import "./Ownable.sol";
pragma solidity 0.5.12;


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


import "./Ownable.sol";
import "./Destroyable.sol";
pragma solidity 0.5.12; //quelle version utiliser

 
contract HelloWorld is Ownable, Destroyable{
    
    ...
}
1 Like

Why can`t I use owner instead of msg.sender? I had to peak a little!

import “./Ownable.sol”;
pragma solidity 0.5.12;

contract Destroyable is Ownable{

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

1 Like
import "./Ownable.sol";

pragma solidity 0.5.12;

contract Destroyable is Ownable {

  function destroycontract() public onlyOwner {
   selfdestruct(msg.sender);
  }
}
1 Like

import “./Ownable.sol”;
pragma solidity 0.5.12;

contract Destroyble is Ownable {

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

}

// No change to Ownable.sol
// New file Destroyable.sol containing new parent contract

pragma solidity 0.5.12;

contract Destroyable {
   function transferAndDestroy() internal {    
      selfdestruct(msg.sender);    // see note below
   }                             
}

// Additions to child contract

import "./Ownable.sol";
import "./Destroyable.sol";
pragma solidity 0.5.12;

contract HelloWorld is Ownable, Destroyable {
// Rest of contract remains the same, except for following additional function 
   function close() public onlyOwner {
      transferAndDestroy();
   }
}

Note  —  msg.sender used instead of owner
This simplifies the code. If selfdestruct(owner) were used instead, we would also need to modify the following:

  1.  Destroyable inherits from Ownable

  2. Change the state variable owner in Ownable from a non-payable address type to a payable address type, by adding the keyword payable :   address payable public owner;

1 Like

Having now watched the solution video, I’ve learnt that it isn’t necessary to include another function in the child contract to call the inherited function (from contract Destroyable) from an external service such as Remix, as long as the inherited function is defined with public (instead of internal) visibility, and is also restricted to onlyOwner, within the parent contract itself. This also requires the function to gain access to the onlyOwner modifier by importing Ownable.sol into Destroyable.sol and making the following modification so that  contract Destroyable  inherits  contract Ownable

contract Destroyable is Ownable { ... }

As a result of the following comment from @ivga80, I’ve also learnt that if  contract Destroyable  inherits  contract Ownable , then we can remove the code from  contract HelloWorld  that explicity inherits  contract Ownable . This is because HelloWorld already inherits from Destroyable , and so now indirectly inherits Ownable via Destroyable .

But the solution video left me with one question:
Why is it necessary to assign msg.sender (the owner’s address) to a local variable (receiver) with a payable-address type, and then pass receiver to selfdestruct() as its parameter? Can’t this be made more concise and simpler by just passing msg.sender directly?

  i.e   selfdestruct(msg.sender);

Having looked at some of the other solutions posted, I can see that the more concise  selfdestruct(msg.sender); has been widely used. I then found that this point has already been raised and answered in some posts from @Guy and @filip at the beginning of this topic. I’ll link to the discussion here via some quotes, in case others have the same question, but wouldn’t otherwise see the relevant posts:

I think the points made in these posts are really helpful :slightly_smiling_face:

2 Likes

The problem is that owner has already been defined in  contract Ownable  as a non-payable address type. So, if you used it instead, you would also need to do something like one of the following:

  1. Change the actual definition of the state variable owner in  contract Ownable  from a non-payable address type to a payable address type, by adding the keyword payable i.e. address payable public owner;

    or

  1. Convert the inherited state variable owner (from a non-payable address type to a payable address type) within  contract Destroyable  e.g.

or

      function close() public onlyOwner {
         address payable receiver = address(uint160(owner));
         selfdestruct(receiver); 
      }
2 Likes

Thank you for the help!

1 Like

I’m confused by this. How can we use a non-payable address as a parameter of  selfdestruct() if, like @pedromndias also says, the compiler throws an error suggesting the address should be payable?

Do you maybe mean that we could convert a non-payable address into a payable one, locally, just for the purposes of selfdestruct() ? e.g.

Also, when would you want to send ETH to a contract which isn’t supposed to receive it?

1 Like

It depends on your compiler version

pragma solidity 0.4.18;

contract suce{

    function suce() payable{        
    }

    function sucide() public {
         address receiver = 0x56f8b4cC2402Fa214a2C2406AD1DEf48f84408Ac;
         selfdestruct(receiver); 
    }
}

To “pentest” them, by sending funds you ll be able to change the balance of the contract and sometime you are not allow to.

https://ethernaut.openzeppelin.com/level/0x24d661beb31b85a7d775272d7841f80e662c283b

If you can access a contract which is the owner of an other contract (an erc20) you will be able to mint token for example.

I use this trick to mint dai on a custom forked main net

Changes in HelloWorld contract:

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

pragma solidity 0.5.12;

contract Inheritance is Ownable, Destroyable {

New Destroyable Contract:

import "./Ownable.sol";

pragma solidity 0.5.12;

contract Destroyable is Ownable {

    function close() public onlyOwner {
      selfdestruct(owner);
    }
}

Small change in Ownable:

address payable public owner;
1 Like

There are three contracts.

  1. the HelloWorld contract, child of Ownable conract and of Destroyable contract:
import "./destroyable.sol";
import "./ownable.sol";
pragma solidity 0.5.12;

contract HelloWorld is Ownable, Destroyable{

  1. the Destroyable contract, child of Ownable contract:
pragma solidity 0.5.12;

import "./ownable.sol";

contract Destroyable is Ownable {
    
    function close() public onlyOwner {
        selfdestruct(msg.sender);
    }
}
  1. the Ownable parent contract:
pragma solidity 0.5.12;


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

}
1 Like

In this assignment there is a multi-level inheritance:

Contract A => Ownable

pragma solidity 0.5.12;

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

Contract B => Destroyable

import "./07Ownable.sol";
pragma solidity 0.5.12;

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

Contract C => HelloWorld

import "./08Destroyable.sol";
pragma solidity 0.5.12;

contract HelloWorld is Destroyable{
    
    struct Car{
        string model;
        uint year;
    }
............
1 Like

The new contract code is as follows:

import "./Ownable.sol";

pragma solidity 0.6.6;

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

And in the HelloWorld contract we just need to add the following to the contract header:

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

pragma solidity 0.6.6;

contract HelloWorld is Ownable, Destroyable{ 

// All logic goes here

}

Oh and the owner address must be payable in order to get the funds back!!

1 Like

@filip I got confused after watching your solution video. For testing if the contract was destroyed and the money sent back to the owner, I used the function ‘createPerson’ sending 1 ETH. After destroying the contract money was sent back but i could run the functions to see the values empty (as shown in the image below) but in your case you receive an error because contract is deleted. Does this mean that my contract is not deleted?

Hi @Maikimais
When a value doesn’t exist in solidity it shows 0 or “” or false, it depends on the type.
You are using a more modern version of remix than in the video, so it’s normal before remix was sending back an error
You will see in the detail of your transaction that the execution cost is 0.

Thanks for your reply gabba!

That’s what I thought, also while following the next video I had to modify some syntax because the one that Filip uses was deprecated. But wanted to be sure!

Thanks again! ^^

1 Like
import "./Ownable.sol";
pragma solidity 0.5.12;

contract Destroyable is Ownable {
    
    function close() public onlyOwner {
        selfdestruct(address(uint160(owner)));    //can also be msg.sender
    }
}

Then you just inherit from Owner and Destroyable in the createPerson contract and you get access to the close() function once you deploy the contract.

It will send the balance from smart contract to the owner address and clear contract data.
Any full node storing just the current state no longer needs to store that code. Full archive nodes still store it for things like block explorers.

1 Like

import “./Ownable.sol”
pragma solidity 0.5.12;

contract Destroyable is Ownable {
function close() public onlyOwner { //onlyOwner is custom modifier
selfdestruct( msg.sender);
}

}

1 Like

import"./Ownable.sol";

pragma solidity 0.5.12;

contract Destroyable is Ownable {

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

// Import Destroyable in the HelloWorld contract

1 Like