Inheritance Assignment

Hey Micky,

This is looking much better :ok_hand:
You have made sure your owner address in Ownable is payable, which is what it needs to be so that when selfdestruct() is called it is called with a payable address: it needs to be payable so that any remaining ether in the contract can be paid/transferred to the owner.

But your Bank contract still doesn’t have access to Destroyable. I mentioned this before:

Your Bank contract as it is will compile and deploy successfully, but you won’t be able to call selfdestruct(), which was the whole point of this inheritance assignment :wink:
Once you’ve compiled and deployed your contracts, you need to test that they successfully perform all of the different transactions that they are meant to. Try deploying your Bank contract as it is and see if you can destroy it…

contract Ownable{

address payable owner;

modifier onlyOwner
{
require(msg.sender == owner);
_; //run the function

}

constructor()
{
owner = msg.sender ;
}

function close() internal onlyOwner //onlyOwner is custom modifier
{
selfdestruct(owner); // ‘owner’ is the owners address
}

}

pragma solidity 0.7.5;

import “./Ownable.sol”;

contract Call_Destruction is Ownable
{

function terminate() public onlyOwner
{
close();
}

}

1 Like

contract Ownable {

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

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

}

pragma solidity 0.7.5;

import “Ownable”;

contract Destroy is Ownable{

function destroy () public onlyOwner {
selfdestruct(owner);

}

}

pragma solidity 0.7.5;

import "./Ownable.sol";

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

In the bank contract

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

contract Bank is Ownable, Destroyable{
1 Like

Hi @Bhushan_Pawar,

Your Ownable contract and close() function are well coded :+1:
The deployed contract is successfully destroyed when terminate() is called because you have added the correct code so that Call_Destruction inherits the functionality of Ownable, including the close() function which contains selfdestruct()

However, because close() is available to the derived contract via inheritance, there is no need to also write a function (terminate) in the derived contract to be able to call close() once the derived contract has been deployed. By changing the visibility of close() from internal to public, if you remove terminate(), you will see that close() is still available to call from Remix. This highlights an important advantage of inheritance: it helps to avoid code duplication, while maintaining modularity.

I think this also explains why you were getting a bit confused when describing how inheritance works in the previous Reading assignment.

Now, once we’ve removed the function terminate() from your derived contract, you will see that, as it is at moment, there is actually no need to have this contract in the first place, because it doesn’t contain any true functionality of its own. There is also no need to destroy a contract that doesn’t store any data or perform any other useful operations.

The aim of this assignment is for our Bank contract (or similar, if you’ve been developing your own variation) to inherit the selfdestruct() and Ownable functionality, so that we can:

  • destroy a contract which has already performed some transactions and stored some data in its contract state (otherwise you can’t actually see if the destruction was successful or not); and
  • demonstrate a key feature of selfdestruct() : the transfer of the ether balance remaining in the contract being destroyed, to the caller of the selfdestruct function (here, the contract owner).

You can also develop the inheritance structure one stage further, in order to keep the contract ownership and contract destruction functionality separate — each within its own contract e.g. Ownable and Destroyable. You would then need to decide how to change your exisiting code for this inheritance structure, because you would now have three contracts instead of just two.

Let us know if anything is unclear, or if you have any questions about how to implement any of the above :slight_smile:

Hi @Andrewg,

You should be getting a compiler error for this line:

The address passed as an argument to the selfdestruct function must be payable because this is the address that any ether remaining in the contract will be transferred to on destruction. Do you know how to make this address payable? There are a couple of alternatives.

Do you know how to compile your code to check for any errors? If not, let us know, so we can help you :slight_smile:

To complete each coding assignment, and before moving on to the next lesson, you need to make sure (i) your code compiles without any errors (ii) your contract (in this case the child contract Bank) deploys successfully; and (iii) your deployed contract is able to perform all of the necessary transactions i.e. it does what you expect it to. If it doesn’t do all of these things, then you can have a look at other students’ solutions, and the feedback and suggestions they’ve received, posted in these assignment discussion topics. This is where you can also post any questions you have about the assignment, and ask for help.

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

Nice solution @CMar10 :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.

This should be throwing a compiler error: the file name is missing .sol … but I’m sure this is just a copy-and-paste slip :wink:

Hi @PhilD99 ,

Can we see your other two contracts which are also part of this inheritance structure?

Your Destroy contract is looking good, but it relies on you having made an additional change in Ownable. That’s why we need to see it as part of your solution. If your Destroy contract, as posted here, is throwing a compiling error, then that means you need to make the necessary adjustment either in Ownable or in Destroy itself: there are two alternatives.

I’m not sure if this is just a slip, but this line of code will also give you a compiler error: the file name is missing .sol .  The name of the inherited contract goes in the derived contract header; but you need to put the file path, where the inherited contract is located, between the quotes after import .

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.

Let us know if you have any questions :slightly_smiling_face:

Thanks jon_m

Code is here - I changed the destroy contract slightly and it now works. I had forgotten to add the file extension .sol after “Ownable”.

Contract Ownable:

pragma solidity 0.7.5;

contract Ownable{
address public owner;
modifier onlyOwner{

   require (msg.sender == owner);
   _;

}

constructor (){
owner = msg.sender;
}

}

Contract Destroy:

pragma solidity 0.7.5;

import “Ownable.sol”;

contract Destroy is Ownable{

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

}

}

1 Like

Help, does not compile. Have worked on this for three days looking for examples of code. What I settled on was a simple lease agreement. Here’s the code. The error message is on line 23, the deposit function. The message states ParserError: expected type name function deposit(1ether) public payable costs(1 ether) {
}

Any help?

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

contract leaseAgreement is Ownable{
    
uint public balance;

    modifier costs (uint cost){
        require(msg.value >= cost);
        _;
    }
    
    mapping (address => Person) private people;
    address[] private creators;
    
    event rentPaid(string name, bool rentPaid);
    event RentContractDestroyed(string name, bool destroyed);
    
    function deposit(1 ether) public payable costs(1 ether) {
        address Owner = msg.sender;
     if (msg.sender == creator) {
        balance += msg.value;
     
        }
        emit rentPaid(deposit memory dpositMade); 
    }
    
     function withdrawAll() public onlyOwner returns(uint){
         uint toTransfer = balance;
         balance = 0;
         msg.sender.transfer(balance);
         return toTransfer; 
    
    function balance() returns() {
        
    }
    function close() public onlyOwner returns(){
        selfdestruct(owner)
        msg.sender.transfer(balance);
        return toTransfer;
        
    }
    
}```

Hi Jon,

Thanks for such clear insight of code. I am going through your recommendations & I will come up with queries if I don’t understand something.Just forgive me in case if I ask childish questions.

1 Like

Do you have best copy of the code for the above assignment? It will help me understand in much better way.

1 Like

Hello everyone ! good morning, afternoon or evening wherever you are.
According to what is asked in the assignment this is what I came up with but there is something a little bit confusing to me. Why does it have to be ownable if the address in the function is msg.sender anyway?

pragma solidity 0.7.5;

contract Destroyable {

address owner;

constructor(){
    owner = msg.sender;
}

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

function close() public onlyOwner{
    address payable _owner = msg.sender;
    selfdestruct(_owner);
}

}

1 Like

Hi Jon,

I have observed the solution & realised where i made the mistake :slight_smile:

1 Like

Bank.sol

pragma solidity 0.7.5;

// SPDX-License-Identifier: UNLICENSED

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

contract Bank is Ownable, Destroyable {
    
    mapping(address => uint) balance;

    
    modifier costs(uint price) {
        require(msg.value >= price);
        _;
    }
    
    modifier enoughBalance (uint amount) {
    require(balance[msg.sender]>= amount, "Not enough funds");
    _; //Run the function
    }
    
    event depositDone(uint amount, address depositedTo);
    

    
    function withdraw(uint amount) public onlyOwner {
        require(balance[msg.sender] >= amount);
        msg.sender.transfer(amount);
        balance[msg.sender] -= amount;
    }
    
    function deposit() public payable returns (uint) {
        balance[msg.sender] += msg.value;
        emit depositDone(msg.value, msg.sender);
        return balance[msg.sender];
    }
    function getBalance () public view returns (uint) {
        return balance[msg.sender];
    }
    function transfer (address recipient, uint amount) public {
        require(balance[msg.sender] >= amount);
        require(msg.sender != recipient);
        
        uint previousSenderBalance = balance[msg.sender];
        
        _transfer(msg.sender, recipient, amount);
        
        assert(balance[msg.sender] == previousSenderBalance - amount);
    }
    function _transfer (address from, address to, uint amount) private {
        balance[from] -= amount;
        balance[to] += amount;
    }
}

Ownable.sol

pragma solidity 0.7.5;

// SPDX-License-Identifier: UNLICENSED


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

Destroyable.sol

pragma solidity 0.7.5;

// SPDX-License-Identifier: UNLICENSED

import "./Ownable.sol";

contract Destroyable is Ownable {

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

}
1 Like
pragma solidity 0.7.5;

import ".ownable.sol";

contract Destroyable is ownable{
    
    
    function DestroyContact() public {
        selfdestruct(owner);
    }
}

Destroyable inherits from Ownable and Bank/HelloWorld inherits from Destroyable

//Ownable.sol code here

pragma solidity 0.7.5;

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

//Destroyable.sol code here

pragma solidity 0.7.5;

import "./Ownable.sol";

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

//Hello World.sol code here

pragma solidity 0.7.5;

import "./Ownable.sol";

contract Bank is Destroyable {...}
    
1 Like

Hi @PhilD99,

Ownable and Destroy looking good :ok_hand:

That’s because the aim of this assignment is for our Bank contract to inherit the selfdestruct() and Ownable functionality, so that both are available when we just deploy Bank i.e. we 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 :slight_smile:

Hi @Bhushan_Pawar,

Just got to your messages… that’s great if you’ve already worked out the modifications you needed to make, yourself :+1:
You’ll also find lots of help, ideas and suggestions in other student solutions and feedback here in this discussion topic.

Just let us know if anything is still unclear, or if you have any further questions :slight_smile:

1 Like