Inheritance Assignment

The Destroyable contract:

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

contract Destroyable is Ownable {

  function destroy() public onlyOwner {
    address payable receiver = msg.sender;
    selfdestruct(receiver);
  }
}

The Bank contract:

pragma solidity 0.7.5;

import "./Ownable.sol";
import "./Destructible.sol";

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

pragma solidity 0.5.12;

// Building a base (ownable) contract

contract Destroyable{
address payable creator = msg.sender;

    //adding a modifier
modifier onlyOwner(){
    require(creator == msg.sender);
    _;  // If true continue function
}



function destroyContract() public payable onlyOwner {
    selfdestruct(creator);
}

}

1 Like
pragma solidity 0.7.5;

contract Ownable {
    // normally would be in separate file kept here fore easy copy past into forum
     address payable owner;
     
     modifier onlyOwner {
        
        require(msg.sender == owner, "function restricted to owner");
        _; // run the function
    }
    
    constructor(){
        owner=msg.sender;
    }
    
}

contract Destroyable is Ownable {
    // normally would be in separate file kept here fore easy copy past into forum
    
    event contractDestroyed();
    
    function close() public onlyOwner { //onlyOwner is custom modifier
    emit contractDestroyed();
    selfdestruct(owner);  // `owner` is the owners address
    }
    
}

contract Bank is Ownable, Destroyable{
    
    mapping (address => uint) balance;
   
    
    event depositDone(uint amount, address indexed depositedTo);
    event amountTransfered(uint amount, address indexed transferedFrom, address indexed transferedTo);
    
    
    
    function deposit() public payable returns (uint){

        balance[msg.sender] += msg.value;
        emit depositDone(msg.value, msg.sender);
        return balance[msg.sender];
    }
    
    function withdraw(uint amount) public returns (uint){
        require (amount <= balance[msg.sender], "insufficient balance");
        
        balance[msg.sender] -= amount;
        msg.sender.transfer(amount);
        return balance[msg.sender];
    }
    
    function getBalance() public view returns(uint){
        return balance[msg.sender];
        
    }
    
    function transfer(address recipient, uint amount) public{
        
        // check balance
        require(balance[msg.sender] >= amount, "Balance insufficient");
        require(msg.sender != recipient, "Transfer to self not allowed");
        
        uint previousSenderBalance = balance[msg.sender];
        
        _transfer(msg.sender, recipient, amount);

        assert(balance[msg.sender] == previousSenderBalance - amount);
        // event logs and further checks
        emit amountTransfered(amount, msg.sender, recipient);
    }
    
    function _transfer(address from, address to, uint amount) private {
                
        balance[from] -= amount;
        balance[to] += amount;
        
    }
}
1 Like
pragma solidity 0.7.5;

contract Ownable {
    // normally would be in separate file kept here fore easy copy past into forum
     address payable owner;
     
     modifier onlyOwner {
        
        require(msg.sender == owner, "function restricted to owner");
        _; // run the function
    }
    
    constructor(){
        owner=msg.sender;
    }
    
}

contract Destroyable is Ownable {
    // normally would be in separate file kept here fore easy copy past into forum
    
    event contractDestroyed();
    
    function close() public onlyOwner { //onlyOwner is custom modifier
    emit contractDestroyed();
    selfdestruct(owner);  // `owner` is the owners address
    }
    
}

contract Bank is Ownable, Destroyable{
    
    mapping (address => uint) balance;
   
    
    event depositDone(uint amount, address indexed depositedTo);
    event amountTransfered(uint amount, address indexed transferedFrom, address indexed transferedTo);
    
    
    
    function deposit() public payable returns (uint){

        balance[msg.sender] += msg.value;
        emit depositDone(msg.value, msg.sender);
        return balance[msg.sender];
    }
    
    function withdraw(uint amount) public returns (uint){
        require (amount <= balance[msg.sender], "insufficient balance");
        
        balance[msg.sender] -= amount;
        msg.sender.transfer(amount);
        return balance[msg.sender];
    }
    
    function getBalance() public view returns(uint){
        return balance[msg.sender];
        
    }
    
    function transfer(address recipient, uint amount) public{
        
        // check balance
        require(balance[msg.sender] >= amount, "Balance insufficient");
        require(msg.sender != recipient, "Transfer to self not allowed");
        
        uint previousSenderBalance = balance[msg.sender];
        
        _transfer(msg.sender, recipient, amount);

        assert(balance[msg.sender] == previousSenderBalance - amount);
        // event logs and further checks
        emit amountTransfered(amount, msg.sender, recipient);
    }
    
    function _transfer(address from, address to, uint amount) private {
                
        balance[from] -= amount;
        balance[to] += amount;
        
    }
}
1 Like
  1. Open a new file

image

  1. In the helloworld contract:

image

1 Like

contract Destroyable {
address public owner;

constructor () {
    owner = msg.sender;
}

modifier onlyOwner {
    require (msg.sender == owner, "Can only be called by contract owner.");
    _;
}

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

}

1 Like

Hey @gkassaras, hope you are well.

Although that is the correct way to create a Destruct contract function, problem is that anyone could trigger it, because you have not specify any restricted permission for it (modifier).

Even when the funds WILL be sent to the owner of the contract, thanks to your constructor, anyone still can trigger it, is not limited to only the contract owner. (also, this contract does not manage any kind of funds)

If you have any more questions, please let us know so we can help you! :slight_smile:

Carlos Z.

1 Like

Hi @LiewJunXian,

Your code is correct, but if you pass owner as the argument to selfdestruct() instead of msg.sender , then you also need to either make an additional modification to contract Ownable, or add some additional code to contract Destroyable.

Do you know what this is, and why?

Also, have a look at this post — it explains how you can streamline the inheritance by having HelloWorld just inherit Destroyable. I think you’ll find it interesting :slight_smile:

Please don’t post screen shots of your assignment solutions. We can’t copy and paste the code from a screen shot into a text editor, which means we can’t test it if we need to. You should copy and paste your code into the forum text editor and format it using the </> icon in the menu at the top of the text editor. This will wrap your code in 2 sets of 3 back ticks, like this:
```
My code needs formatting
```
Then when your post is displayed, your code will be appear formatted, like this:

My code is now formatted

contract xxx {

address payable private owner;
uint256 number;
constructor() {
owner = msg.sender;
}
function store(uint256 num) public {
number = num;
}
function retrieve() public view returns (uint256){
return number;
}

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

Hey @gkassaras,

Are you going to modifiy your solution for the feedback @thecil gave you?

The argument you’ve passed to the selfdestruct function (owner) is the address any remaining funds in the contract will be transferred to when it is destroyed. As @thecil mentions…

The idea of the assignment is for the Bank contract (or your similar version) to inherit this contract, so that when the Bank contract is deployed it inherits its functionality, including the selfdestruct function. As the Bank contract handles ether, passing the owner address to selfdestruct() then becomes relevant, because now there will potentially be a remaining ether balance to transfer.

That’s OK to include the functionality of contract Ownable and contract Destroyable (introduced in the video lectures) within one single base contract, but you can make your code more modular by separating both types of functionality (contract ownership | contract destruction) into 2 separate contracts and then use multi-level inheritance as your overall structure.

Whatever inheritance structure you decide to use, we would still like to see how you have coded the inheritance — at the moment, this isn’t clear from the code you’ve posted.

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

2 Likes

I made some modifications on the code for the inheritance (made the code more clear), added some design security using private functions and please see @jon_m e code below and comment:

For the Ownable.sol contract:

//Seperate the owner from the initial contract
// SPDX-License-Identifier: MIT
pragma solidity 0.7.5;

contract Ownable {


    address payable public   owner;

    constructor(){
        
        owner = msg.sender; // Adding owner to the initilizer
        
    }

    
    modifier onlyOwner { // Add modifier for the owner 
        require(msg.sender == owner);
        _;
    }
    
}

For the BankOfEth contract:

// SPDX-License-Identifier: MIT
pragma solidity 0.7.5;
// Simple bank code examaple

import "./Ownable.sol";

contract BankofEth is Ownable {

    mapping (address => uint) private balances;
    

    //////////////////////////////////////////////////////////////////////////////////
    // Adding events for logging and interacting better with dapps
    ///////////////////////////////////////////////////////////////////////////////////
    
    event logDepositMade(address indexed comeFromAddress, uint indexed amount); // Logging deposit made
    
    event logWithdrawMade(uint indexed amount); // Logging withdrawal made
    
    //////////////////////////////////////////////////////////////////////////////////
    // Private functions
    ///////////////////////////////////////////////////////////////////////////////////
    
    function _withdraw(uint _withdrawAmount) private {
        // Check enough balance available, otherwise just return balance
        require(_withdrawAmount <= balances[msg.sender]);
        balances[msg.sender] -= _withdrawAmount;
        msg.sender.transfer(_withdrawAmount);
        
    }
    
    function _destroyContract() private { 
        selfdestruct(owner); 
    }
    //////////////////////////////////////////////////////////////////////////////////
    // Public functions
    ///////////////////////////////////////////////////////////////////////////////////
    
    function getBalance() public view returns (uint) {
        return balances[msg.sender];
    }


    function deposit() public payable returns (uint) {
        balances[msg.sender] += msg.value;
        emit logDepositMade(msg.sender, msg.value);
        return balances[msg.sender];
    }

    function depositsBalance() public  onlyOwner returns (uint) {
        emit logWithdrawMade(address(this).balance);
        return address(this).balance;
    }

    function withdraw(uint withdrawAmount) public returns (uint remainingBal) {
        _withdraw(withdrawAmount);
        return balances[msg.sender];
    }
    
    function destroyContract() public onlyOwner {
        _destroyContract();
    }


}

These are the warning:

inh1

Also the code can be found in my github page here

…

1 Like

Here is my attempted solution – although I’m getting an error currently:

pragma solidity 0.7.5;

contract Destroyable {

address owner;

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

constructor() {
    owner = msg.sender;
}

function close() onlyOwner public payable{ //onlyOwner is custom modifier
   // selfdestruct(owner);  // `owner` is the owners address
   selfdestruct(msg.sender); // This works -- I had it as it is in the line above earlier and got error
}

}

1 Like

Here’s my solution:

import "./ownable.sol";

contract Destroyable is Ownable {
    
    function destroy() public onlyOwner {
        selfdestruct(owner);
    }
    
}
1 Like
pragma solidity 0.7.5;

contract Destructable {
    
    address public owner;
    
    modifier onlyOwner {
        require(msg.sender == owner);
        _;
    }
    
    constructor(){
        owner = msg.sender;
    }
    
    function close() public onlyOwner {
         selfdestruct(msg.sender);
    }
}
1 Like

Destroyable.sol Contract

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

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

helloworld.sol Contract

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

contract Bank is Ownable, Destroyable {

Ownable.sol Contract

contract Ownable {
     
     address owner;
     
     modifier  onlyOwner {
        require(msg.sender == owner);
        _; // run the function
    }
    
    constructor() {
        owner = msg.sender;
    }
}
1 Like
pragma solidity 0.7.5;
import "./destroyable.sol";

contract Bank is Destroyable {
    function deposit() public payable returns (string memory)  {
        balance[msg.sender] += msg.value;
        emit depositDone(msg.value, msg.sender);
        return kill(msg.sender);
    }
contract Destroyable {
    

    function kill(address payable owner) public payable  returns (string memory){
        require(msg.sender == owner);
        selfdestruct(owner);
    }
}
1 Like

This was the most frustrating thing ever. I see that my contract isnt payble apparently however i dont know the syntax to appease this program.

Destroyable.sol

pragma solidity ^0.7.5;

import ā€œ./Ownable.solā€;

contract Destroyable is Ownable{

function selfdestruct() public onlyOwner {
selfdestruct();

}

}

Ownable.sol

pragma solidity ^0.7.5;

contract Ownable {
address internal owner;

modifier onlyOwner {
    require(msg.sender == owner, "Tsk Tsk Tsk not your funds");
    _; //run the function
}


constructor(){
    owner = msg.sender;
} 

}

Bank.sol

pragma solidity ^0.7.5;

import ā€œ./Ownable.solā€;
import ā€œ./Destroyable.solā€;

contract Bank is Ownable, Destroyable{

mapping(address => uint) balance;

event depositDone(uint amount, address indexed depositedTo);
//events cannot be same name as function.
    
function deposit() payable public returns (uint) {
    balance[msg.sender] += msg.value;
    
    emit depositDone(msg.value, msg.sender);
    //emit is named same as event.
    return balance[msg.sender];
}

function getBalance() public view returns (uint){
    return balance[msg.sender];
}

function withdraw(uint amount) public onlyOwner returns (uint){
    //msg.sender is an address
    require(balance[msg.sender] >= amount);
    balance[msg.sender] -= amount;
    msg.sender.transfer(amount);
    return balance[msg.sender];

}

function transfer(address recipient, uint amount) public { 
    require(balance[msg.sender] >= amount, "Balance not sufficient");
    require(msg.sender != recipient, "Don't transfer money to yourself");
    
    uint previousSenderBalance = balance[msg.sender];
     _transfer(msg.sender, recipient, amount);
    
    assert(balance[msg.sender] == previousSenderBalance - amount);
    //event Logs and further checks
}

function _transfer(address from, address to, uint amount) private {
    balance[from] -= amount;
    balance[to] += amount;
}

}

Im having an issue with compiler , helloworld wont compile for browser , I’ve ask for help but have not heard a response. I cannot continue at a practical level, please advise. Thank you.

J.F

1 Like

pragma solidity 0.7.5;

contract Destructible
{
address payable owner;

constructor()
{
    owner = msg.sender;
}

function Destroy() public
{
    require(msg.sender == owner);
    selfdestruct(owner);
}

}

1 Like

Hey @DUUKA_SMASH, hope you are great

You Destroyable contract is not complete, the selfdestruct function requires an argument to work with, which is most of the time the owner of the contract address.

Overall your contracts looks great.

If you have any more questions, please let us know so we can help you! :slight_smile:

Carlos Z.