Inheritance Assignment

Hi @jon_m,
Does this mean that if I pass owner instead of the msg.sender, I will destroy the owner not the subject I wanted to delete?

1 Like

Destroyable.sol:

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

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

Helloworld.sol

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


contract HelloWorld is Ownable, Destroyable {}
1 Like

Destroyable.sol contract:

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

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

Remix seemed to give some cautionary flag for the above suggesting the address “owner” was not a payable address and so I then converted it as Fillip had mentioned previously. This solved any warning remix was giving.

HelloWorld.sol contract:

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

contract HelloWorld is Ownable, Destroyable{
1 Like

Hi @Jun_0113

No… the address you pass into selfdestruct() as the argument won’t be destroyed. The selfdestruct function destroys the contract (in this case HelloWorld, as that’s the contract we’ve deployed and from where we are calling the inherited selfdestruct function). The address argument is where the contract’s ETH balance is transferred upon destruction (so these funds aren’t lost). Because this address is used to receive a payment, it needs to be a payable address.

Addresses can be stored in variables as either payable, or non-payable. Unless we specifically mark them as payable, then they are non-payable by default. When msg.sender is used directly as a value (and not first assigned to a variable), it is treated as a payable address by default in Solidity, so that’s why  selfdestruct(msg.sender)  works without having to add anything further or make any additional modifications. If you do the same with owner the compiler will give you an error, because it is defined as a non-payable address in contract Ownable:

address public owner;

You can still use owner but you will need to also define it as a payable address by explicity adding the payable keyword:

address payable public owner;

If you make this modification to the owner state variable definition in Ownable, then  selfdestruct(owner); will work.
Another alternative is to leave the owner state variable definition as non-payable, and convert it to a payable address directly within the selfdestruct function call in contract Destroyable:

selfdestruct(address(uint160(owner)));

I hope that makes things clearer. But just let us know if you have any further questions.

1 Like

My solution:

import "./Ownable.sol";

pragma solidity 0.5.12;

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

In Ownable contract I changed the owner variable to payable:

    address payable public owner;

And I added inheritance from Destroyable to HelloWorld:

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

pragma solidity 0.5.12;

contract HelloWrold is Ownable, Destroyable{
    //the rest of the code
}

I think it works.

1 Like

Hi @jon_m,
I think I understand! Thank you.

1 Like

function destroyContract() public onlyOwner {
//We have already required that only the owner can change this code so is msg.sender isn’t equal to owner it will throw an exception
selfdestruct(msg.sender);
}

My solution

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

contract Destroyable is Ownable {

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

I have a question @filip
Why I cant use owner instead of msg.sender ? It is definied in Ownable contract, so I thought that I can use, but it seams its not inherit from Ownable contract why ?

My Ownable contract here

pragma solidity 0.5.12;

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

Edit:

I found I need to cast it payble address

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

contract Destroyable is Ownable {

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

Is there any other solution ? can the owner be as payble on Ownable contract ? so casting is not needed ?

I have owner as internal in Ownable contract, but still cant use it in Destroyable contract

1 Like

You also can define your owner address as payable at the begining of your Ownable contract in order to avoir the conversion (address(uint160(owner))).

You can just use address payable public owner, then in your close function does not need the conversion.

Carlos Z

Destroyable.sol

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

contract Destroyable is Ownable {
    
    function selfDestruct() public onlyOwner {
        selfdestruct(address(uint160(owner)));
    }
}

HelloWorld.sol

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

contract HelloWorld is Ownable, Destroyable {
    // STATE VARIABLES
    uint private balance;
...
}
1 Like

I created a new contract called “Destroyable.sol”. In it I created the following code:

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

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

In the main file I added

import "./Destroyable.sol";

Also in the contract header I added the “Destroyable” child contract.

contract HelloWorld is Ownable, Destroyable{

I also had to update the Ownable.sol file to make the owner address payable. :slight_smile:

1 Like

Destroyable Contract

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

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

To be able to send funds from the contract to the owner, the address needed to be payable

address payable public owner;

Next the steps for the HelloWorld Contract

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

Deploy contract, create a person, then destroy this contract and send funds to owner.

image
After destroy ^ Funds are back to the owner > image

1 Like

Destroyable contract

image

HelloWorld contract

image

1 Like

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

contract Destroyable is Ownable{

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

}

1 Like

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

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

in HellowWorld
import “./Ownable.sol”;
import “./Destroyable.sol”;
pragma solidity 0.7.3;
contract HelloWorld is Ownable, Destroyable{

in Ownable.sol I needed to change owner to payable:
address payable owner;

2 Likes

Hey all, really enjoyed this assignment…

Here is what i have conjured up…

My Ownable Contract

pragma solidity 0.5.12;

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

Destroyable Contract

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

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

And my Hello World

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

contract HelloWorld is Ownable {

    struct Person {
      uint id;
      string name;
      uint age;
      uint height;
      bool senior;
    }

    event personCreated(string name, bool senior);
    event personDeleted(string name, bool senior, address deletedBy);

    uint public balance;

    modifier costs(uint cost){
        require(msg.value >= cost);
        _;
    }

    mapping (address => Person) private people;
    address[] private creators;

    function createPerson(string memory name, uint age, uint height) public payable costs(1 ether){
      require(age < 150, "Age needs to be below 150");
      require(msg.value >= 1 ether);
      balance += msg.value;

        //This creates a person
        Person memory newPerson;
        newPerson.name = name;
        newPerson.age = age;
        newPerson.height = height;

        if(age >= 65){
           newPerson.senior = true;
       }
       else{
           newPerson.senior = false;
       }

        insertPerson(newPerson);
        creators.push(msg.sender);

        assert(
            keccak256(
                abi.encodePacked(
                    people[msg.sender].name,
                    people[msg.sender].age,
                    people[msg.sender].height,
                    people[msg.sender].senior
                )
            )
            ==
            keccak256(
                abi.encodePacked(
                    newPerson.name,
                    newPerson.age,
                    newPerson.height,
                    newPerson.senior
                )
            )
        );
        emit personCreated(newPerson.name, newPerson.senior);
    }
    function insertPerson(Person memory newPerson) private {
        address creator = msg.sender;
        people[creator] = newPerson;
    }
    function getPerson() public view returns(string memory name, uint age, uint height, bool senior){
        address creator = msg.sender;
        return (people[creator].name, people[creator].age, people[creator].height, people[creator].senior);
    }
    function deletePerson(address creator) public onlyOwner {
      string memory name = people[creator].name;
      bool senior = people[creator].senior;

       delete people[creator];
       assert(people[creator].age == 0);
       emit personDeleted(name, senior, owner);
   }
   function getCreator(uint index) public view onlyOwner returns(address){
       return creators[index];
   }
   function withdrawAll() public onlyOwner returns(uint) {
       uint toTransfer = balance;
       balance = 0;
       msg.sender.transfer(toTransfer);
       return toTransfer;
   }

}
1 Like

Adding further to this brilliant task… I found when deploying my Hello World Contract that my “KILL” Function was not showing on it.

When i dived deeper to figure out what was missing my “Hello World” contract has Ownable Inherited to it and not Destroyable. This ment that “KILL” would not appear when deployed.

Other than that it feels good to actually now look at a problem and be able to work out what is wrong.

Thanks @thecil

By far the best course yet !!!

Rob.

1 Like

Here is my code for Destroyable contract:

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

contract Destroyable is Ownable{

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

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


function close() public onlyOwner { //onlyOwner is custom modifier

selfdestruct(0x5B38Da6a701c568545dCfcB03FcB875f56beddC4); // owner is the owners address
}

}

Soooo happy I solved this all by myself!! Getting better at this!! Not completely sure I should have the actual address in the contract as opposed to a variable holding the owners address, but I kept getting the error for the address being not payable and could not seem to figure out how to convert it, at least this code compiled.

1 Like

Youn have 2 options to fix the message of a payable address…

You also can define your owner address as payable at the begining of your Ownable contract in order to avoir the conversion (address(uint160(owner))) .

You can just use address payable public owner , then in your close function does not need the conversion.

Carlos Z

// Destroyable.sol:

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

contract Destroyable is Ownable{

/// destroy the contract by providing the owner address.
function killContract(address ownerAddress) public onlyOwner{
    require(msg.sender == ownerAddress);
    selfdestruct(msg.sender);
}

}

1 Like