Inheritance Assignment

Hello guys, here’s my solution to this assignment!

pragma solidity 0.7.5;

contract Ownable {

    address owner;

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

    constructor() {
        owner = msg.sender;
    }

}
---------------------------------

pragma solidity 0.7.5;

import "./ownable.sol";

contract Destroyable is Ownable {

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

}

pragma solidity 0.7.5;


import "./destroyable.sol";


contract Bank is Destroyable {


1 Like

Check here: https://docs.soliditylang.org/en/v0.8.13/types.html#address

Carlos Z

2 Likes

At first i imported Bank.sol for the Destroyable. After deploying the contract Destroyable.sol i also can use the functions of Bank.sol. Thats where i found out that this should not be accessable, so i changed my code.

pragma solidity 0.7.5;

contract Ownable{

address owner;

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

  constructor(){
        owner = msg.sender;
    }

}
pragma solidity 0.7.5;

import "./Ownable.sol";

contract Destroyable is Ownable{

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

}
}
pragma solidity 0.7.5;

import "./Destroyable.sol";

contract Bank is Destroyable{
1 Like

Same as some other solutions above, but here goes…

// SPDX-License-Identifier: MIT License;
pragma solidity ^0.7.5;

contract Ownable {
    address payable owner;

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

    constructor() {
        owner = msg.sender;
    }
}
// SPDX-License-Identifier: MIT License;
pragma solidity ^0.7.5;

import "./Ownable.sol";

contract Destroyable is Ownable{

    function close() public onlyOwner {
        selfdestruct(owner);
    }
}
// SPDX-License-Identifier: MIT License;
pragma solidity 0.7.5;

import "./Destroyable.sol";

contract Bank is Destroyable {
    mapping(address => uint) balance;
// body of contract
}
2 Likes
pragma solidity ^0.7.5;

import "./Destroyable.sol";

contract Bank is Destroyable {
    mapping(address => uint) balance;
pragma solidity ^0.7.5;

import "./Ownable.sol";

contract Destroyable  is Ownable {
    function kill() public {
        selfdestruct(owner);
    }
}
pragma solidity ^0.7.5;

contract Ownable {
    address payable public owner;

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

2 Likes

So I think I have not understood this even though I did some extra reading.

I think I should go back and review the previous videos and listen for the clues in respect of the address payable being the receiver. :thinking:

1 Like
pragma solidity 0.8.7;

contract Ownable {
    address payable public owner;

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

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

}
pragma solidity 0.8.7;

import "./Ownable.sol";

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

import "./Destroyable.sol";

contract Bank is Destroyable {
    
    mapping(address => uint) balance;
 ...
}
2 Likes

owner contract:

pragma solidity 0.7.5;
contract ownable{

    address payable public owner;

    constructor(){
        owner = msg.sender;

    }

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

}

Destroy contract:

pragma solidity 0.7.5;
import "./owner.sol";
contract destroyable is ownable{

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

}

Bank contract:

pragma solidity 0.7.5;

import "./transferSite.sol";

contract Bank is destroyable{

    mapping(address => uint) balance;

    event depositDone(uint amount, address to);

    // function to deposit funds
    function deposit() public payable returns(uint){
        balance[msg.sender] += msg.value;
        emit depositDone(msg.value, msg.sender);
        return balance[msg.sender];
    }

    function withdraw(address receiver, uint amount) public payable returns(uint){
        require(balance[msg.sender]>=amount, "not enough funds");
        require(receiver != msg.sender, "do not send money to yourself");
        uint oldBalance = balance[msg.sender];
        _transfer(receiver, amount);
        msg.sender.transfer(amount);
        assert(oldBalance-amount == balance[msg.sender]);
    }

    function _transfer(address receiver, uint amount) private {
        balance[msg.sender] -= amount;
        balance[receiver] += amount;
    }

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

}
2 Likes
Destroyable.sol
pragma solidity 0.7.5;

import "./Ownable.sol";

contract Destroyable is Ownable {

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

}
Ownable.sol
pragma solidity 0.7.5;

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

    constructor(){
        owner = msg.sender;
    }
}
bank.sol
pragma solidity 0.7.5;

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

contract Bank is Ownable, Destroyable {```
2 Likes

Ownable Contract

// SPDX-License-Identifier: UNLICENCED
pragma solidity 0.7.5;

contract Ownable {
    address owner;

    modifier onlyOwner {
        require(msg.sender == owner, "Only owner!");
        _;
    }

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

Destroyable Contract

// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.7.5;

import "./ownable.sol";

contract Destroyable is Ownable {

    function destroyMe() public onlyOwner {
        address payable sendTo = payable(owner);
        selfdestruct(sendTo);
    }
}

Bank contract

// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.7.5;

import "./ownable.sol";
import "./destroyable.sol";

contract Bank is Ownable, Destroyable{

    mapping (address => uint256) balances;

    function deposite() public payable {
        balances[msg.sender] += msg.value;
    }

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

    function close() public onlyOwner {
        destroyMe();
    }
}
2 Likes
pragma solidity 0.8.13;

abstract contract Ownable {
 
    address payable owner;

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

    modifier onlyOwner {
        require (msg.sender == owner, "User does not have permission for this operation.");
        _;
    }

}
pragma solidity 0.8.13;

import "./Ownable.sol";

contract Destroyable is Ownable {

    /**
     * Destroy this contract, sending any remaining funds to the owner.
     */
    function destroy() public onlyOwner {
        selfdestruct(owner);
    }

}
...
contract Bank is Destroyable {
...
2 Likes

The source code is using Solidity version 0.7.5 to comply with the version associated with the course even though the current version is higher (0.8.14). As instructed, below are my files of the source code for the assignment from base contract to inherited contracts:

  1. Ownable.sol
pragma solidity 0.7.5;

contract Ownable {

    address payable internal owner;

    modifier onlyOwner {
        require(msg.sender == owner, "Must be the owner of the contract to execute.");
        _; // run the function
    }

    constructor() {
        owner = msg.sender;
    }
}
  1. Destroyable.sol
pragma solidity 0.7.5;

import "./ownable.sol";

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

import "./destroyable.sol";

contract Bank is Destroyable {

    mapping(address => uint) balance;
    
    event depositDone(uint amount, address indexed depositedTo);

    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 onlyOwner returns (uint) {
        require(balance[msg.sender] >= amount, "Cannot send more than your 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 {
        require(balance[msg.sender] >= amount, "Balance not sufficient.");
        require(msg.sender != recipient, "Don't transfer money to yourself.");

        uint previousSenderBalance = balance[msg.sender];
    }
}
2 Likes

any form of criticism is highly appreciated :raised_hands:

ownable.sol

// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.7.5;

contract Ownable {

    address payable public owner;

    constructor(){
        owner= msg.sender;
    }

    modifier onlyOwner {
        require(msg.sender == owner, "restricted access for only owner");
        _;
    }

}

destroyable.sol

// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.7.5;

import "./ownable.sol";

contract Destroyable is Ownable {

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

}

banks.sol

// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.7.5;

import "./ownable.sol";
import "./destroyable.sol";

contract Bank is Destroyable {

    mapping (address => uint) balance;

    event depositComplete(uint amount, address indexed depositedTo);
    event withdrawCompleted(uint amount, address indexed withdrawnTo);


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

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

    function withdraw(uint amount) public returns(uint){
        require(balance[msg.sender] >= amount, "Balance not sufficient");
        msg.sender.transfer(amount);
        balance[msg.sender] -= amount;
        emit withdrawCompleted(amount, msg.sender);
        return balance[msg.sender];
    }

}
2 Likes

I do have a question @filip regarding the solution code

the Inheritance I have used is :point_down:

contact Destroyable is Ownable {...} => contact Bank is destroyable {...}

in contrast to solution code :point_down:

contact Destroyable is Ownable {...} => contact Bank is destroyable,Ownable {...}

Is there any issue to be concerned about when using a linear multi level inheritance rather than a multiple inheritance in this situation ?

2 Likes

Ownable.sol

pragma solidity 0.7.5;

contract Ownable {

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

Destroyable.sol

pragma solidity 0.7.5;

import "./Ownable.sol";

contract Destroyable is Ownable {

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

Destroyable.sol

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

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

Ownable.sol

pragma solidity 0.7.5;

contract Ownable {

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

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

Bank.sol

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

contract Bank is Destroyable {...
1 Like

Ownable.sol

pragma solidity 0.7.5;

contract Ownable {
    address payable public owner;

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

    constructor(){
        owner = msg.sender;
    }

}

Destroyable.sol

pragma solidity 0.7.5;

import "./Ownable.sol";

contract Destroyable is Ownable {

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

}

Bank.sol

pragma solidity 0.7.5;

import "./Ownable.sol";

import "./Destroyable.sol";

contract Bank is Ownable, Destroyable {
1 Like

Ownable.sol:

pragma solidity 0.7.5;

contract Ownable {
    address internal owner;

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

    constructor(){
        owner = msg.sender;
    }

}

Destroyable.sol:

pragma solidity 0.7.5;

import "./Ownable.sol";

contract Destroyable is Ownable {

    function destroy () public onlyOwner {
        selfdestruct(0x5B38Da6a701c568545dCfcB03FcB875f56beddC4);
    }

}

helloworld.sol (Bank):

pragma solidity 0.7.5;

import "Destroyable.sol";

contract Bank is Destroyable {

    mapping(address => uint) balance;

    event depositDone(uint amount, address indexed depositedTo);

    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 payable returns (uint){
        require(balance[msg.sender] >=amount, "Balance not sufficient");
        uint previousReceiverBalance = balance[msg.sender];
        balance[msg.sender] -= amount;
        assert(balance[msg.sender] == previousReceiverBalance - 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 {
        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);
    }

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

}

Seems to work as intended for the practice, but the only additional thing I saw with this is that if any other addresses deposited ether into the contract and then with the owner address select the destroy (selfdestruct) function, it would move all of the funds to the owner address, but then the other addresses would lose that ether.

In theory, say you have the “Owner” and someone from the public named “Bob”. If “Bob” deposited ether into the contract and the “Owner” destroyed it, wouldn’t that mean “Bob” lost his ether?

1 Like

Ownable.sol

Noticed that Ownable.sol in the assignment folder does not have pragma version at the top.

  1. Is the pragma version declaration not required here?

  2. Is this Ownable.sol contract considered an Abstract contract?

pragma solidity 0.7.5; // is this required?

contract Ownable {

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

}

Destroyable.sol

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

contract Destroyable is Ownable {

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

Bank.sol

Noticed that the Bank.sol reference in assignment folder;

  1. in the withdraw function, one line was missing to update balance after withdraw.

  2. in the withdraw function header, onlyOwner is used in the assignment’s bank.sol template; as a result users other than owner who deposit are not able to withdraw.

  3. there is a govermentInstance thing in the transfer function which I don’t know what it is, and was breaking the contract, so commented out to run the contract.

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

contract Bank is Ownable, Destroyable {

...

    function withdraw(uint amount) public onlyOwner returns (uint){ // onlyOwner should be removed so other depositors can withdraw their deposits
        require(balance[msg.sender] >= amount);
        balance[msg.sender] -= amount; // update balance after withdraw
        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);
        
        // govermentInstance.addTransaction(msg.sender, recipient, amount);
        
        assert(balance[msg.sender] == previousSenderBalance - amount);
    }

    ...
}

2 Likes
  1. It is required if you want to compile
  2. Abstract contract contains one function with out implementation, therefore no

About bank.sol

  1. Updating balance after transfer you mean? Yes balance is updated before execution of transfer to avoid re-entrancy.
  2. Only the owner can use withdraw function yes
  3. Been a while since I took the course but I think that was for external contracts so that they can interact with the smart contract (in this course´s example context it was a government agency´s contract which would be able to communicate with your smart contract)
2 Likes