Inheritance & External Contracts - Discussion

Fkin legend with the government joke :smiley: Sadly exponentially more true today than 2 years ago.

What is the base contract?
The base contract is the contract we are extending a new contract from, its the parent contract.

Which functions are available for derived contracts?
All public and internal scoped functions.

What is hierarchical inheritance?
Is where a base contract serves as a parent contract for multiple contracts.

1 Like

Dear Filip and other friends of the academy,

I am doing the inheritance course.
I’ve made the bank contract (parent) and child contract (ownable), but when I try to deploy I can only pick ownable.sol while I have made two separate files of them.
Schermafbeelding 2022-02-28 om 16.46.38

Anyone know what’s wrong here?
All the code is as written by Filip in the courses and I was just able to deploy the bank contract before adding the ‘child’ ownable.

I am of course in the bank.sol contract when I try to deploy it.

Well today it all just works for some reason, didn’t change a thing, same browser and everything. :sweat_smile:
Back to the courses!

1 Like

Hi @DaanBoshoven,

Glad to hear you’ve managed to resolve the problem you were having, even though you’re not sure what the problem was in the first place! :sweat_smile:

I must admit, the fact that you say you haven’t changed anything is strange. Remix is known to misbehave sometimes, and when it does, closing everything down and exiting, and then reloading it again, can often resolve things, and this is maybe what has happened in your case.

Even if Bank.sol is open, it still might not appear in the contract field dropdown if it hasn’t compiled successfully: this could be due to errors in either Bank.sol itself or in any of its imported files and/or inherited contracts. But you can only deploy a contract if it has compiled without any errors; so the fact that you can now select it and deploy it without having made any changes, suggests that the issue you were having wasn’t the result of compilation errors.

Just to be clear: Bank should be the child contract (derived contract) which inherits Ownable (the parent, or base contract).

Looking forward to seeing your solution to the Inheritance assignment! If you have any more deployment issues, post your full code so I can copy-and-paste it into Remix and find out what the problem is.

By the way, don’t forget to also post your solutions to the earlier Events Assignment and Transfer Assignment …

Events Assignment https://studygroup.moralis.io/t/events-assignment/28040?u=jon_m
This is the assignment from the Events video lecture, which is near the end of the Additional Solidity Concepts section of the course.

Transfer Assignment https://studygroup.moralis.io/t/transfer-assignment/27368?u=jon_m
This is the assignment from the Payable Functions section of the course, where you have the task of completing the withdraw() function.

1 Like

Hey Jon, thanks for your reply!
Guess it was just a classic case of ‘computer says no’ :sweat_smile:.
It was all fine yesterday, been messing with the selfdestruct function, but at the end of the day it happened again.
Will try a different browser and see if that helps (currently using Chrome on MacOS).

I see I indeed forgot to post my solutions to the two assignments you mentioned.
Have done them both and written them down in my notebook (pen and paper, old skool :sunglasses:)
Will post the code on the forum as soon as I’m done messing with the selfdestruct function!

1 Like

I had the same problem. I saw it’s not happening to you anymore but in case you have it again, I solved it by saving the code (control “s”) of the contract I want to deploy and then it would switch to that file automatically

2 Likes

I am trying to deploy the government.sol file with the getBalance function that Filip talks about at the end of the video. This one:

getBalance function in government.sol
function getBalance() public view returns(uint){
        return address(this).balance;
    }

But when I deploy the government contract and just try the getTransaction function with index 0, I get an error and it throws revert saying:
Note: The called function should be payable if you send value and the value you send should be less than your current balance.
Debug the transaction to get more information.

This also happens if I deploy both the government.sol and the bank.sol contracts, send a transfer on the bank contract and then look for the Transaction in the transactionLog in government.sol

Complete government.sol code
pragma solidity 0.8.7;

contract Government {

    struct Transaction {
        address from;
        address to;
        uint amount;
        uint txId;
    }

    Transaction[] transactionLog;

    function addTransaction(address _from, address _to, uint _amount) external payable {
        transactionLog.push(Transaction(_from, _to, _amount, transactionLog.length));
    }

    function getTransaction(uint _index) public view returns(address, address, uint) {
        return(transactionLog[_index].from, transactionLog[_index].to, transactionLog[_index].amount);
    }

    function getBalance() public view returns(uint){
        return address(this).balance;
    }

}

Did someone have the same problem? Not sure what is missing or why I’m getting the error.

Thanks for sharing that “fix” @santiago :ok_hand:

I’ve never had this problem, so I guess it must be due to a bug that only affects certain browsers/operating systems etc.

In my Remix, if the wrong file is showing in the contract field, I can just select the one I actually want to deploy from the dropdown, but all of the files in the inheritance structure are always included in the dropdown. But it sounds like the Bank contract isn’t/wasn’t even appearing in the dropdown for you and @DaanBoshoven :grimacing:

Anyway, thanks for sharing your workaround, as that may well help others if they experience the same issue. These things can be very frustrating when they just seem to randomly happen to you!

Hey @santiago,

If you only deploy your Government contract, and then call getTransaction() with any index value (including 0), but you do this before you have manually added any transaction data to the transactionLog array by calling addTransaction() with _to and _from addresses and an _amount … then you will get the error message you describe. This is a default error message, which usually isn’t helpful in pinpointing the actual error, which most probably isn’t anything to do with the function not being marked payable or the value exceeding the current balance. Instead, it looks like you’re getting this default error message because there is no Transaction struct instance in the array at that index position.

Having said that, however, the addTransaction() function only really has any meaning when called by an external function in another contract which is executing an actual transfer transaction of an amount between two addresses, and which supplies addTransaction() with these 3 pieces of data: sender’s address, recipient’s address, and transfer amount. So, getTransaction() in Government is only meant to be called after the Bank contract has performed at least one transfer transaction.

Have a look at this post, as this may well solve this issue, which is still giving you an error message even when you’ve called the transfer() function in Bank, which has then in turn called addTransaction() in Government. What could well be happening is what I describe in either (1) or (2), which are both caused by not changing the Government address assigned to your governmentInstance in Bank (which I explain at the beginning of this linked post).

Anyway, I hope that solves the problem. But if it doesn’t, post your full code (all contracts) and I’ll have a look to see if I can find what the problem is. I can’t immediately see any issues with your Government contract code, but debugging often requires reviewing, deploying and testing the full code.

1 Like

What is the base contract?
The base contract is known as the parent contract.
Which functions are available for derived contracts?
A derived contract can access all non private members including state variables and
internal methods.
What is hierarchical inheritance?
Hierarchical inheritance is similar to simple inheritance except a single contract acts as
a base contract for multiple derived contracts.

1 Like

I realize this is probably very wrong. This is completely new for me and I know I have a lot of work to do by myself to be fluent in solidity. Very Sorry if I butchered this.

pragma solidity >=0.7.5;
  
contract Ownable {
    address public _owner;

    constructor () internal {
        _owner = msg.sender;
    }

    /**
    * @dev Throws if called by any account other than the owner.
    */
    modifier onlyOwner() {
        require(isOwner(), "Ownable: caller is not the owner");
        _;
    }

    /**
    * @dev Returns true if the caller is the current owner.
    */
    function isOwner() public view returns (bool) {
        return (msg.sender == _owner);
    }
}
import "./Ownable.sol";
import "./Item.sol";

contract ItemManager is Ownable {

    //…

    function createItem(string memory _identifier, uint _priceInWei) public onlyOwner {
 //…
    }

    function triggerPayment(uint _index) public payable {
      //…
    }

    function triggerDelivery(uint _index) public onlyOwner {
        contract Storage {
 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); 
 }
}
        //…

Hi @kcoffey,

Q1 & Q3 :ok_hand:

Just to clarify …

… it’s single not simple inheritance. There is an error in the article, here. This type of inheritance is correctly termed single inheritance in all the other places it’s mentioned in the article.


Q2

You’re halfway there …

This is correct for state variables in the parent contract, because state variables have either public, internal, or private visibility, and it’s those that are either public or internal which can be accessed from within the derived contract.

But what do you mean by members? This is a programming term, but it seems to be used to mean different things by different people and in the context of different programming languages.

The only functions which aren’t inherited are those with private visibility. In other words, public, internal and external functions are all inherited.

However, only the parent contract functions with public or internal visibility are available to be called from within the derived contract. Functions with external visibility are only inherited to the extent that they will be available to call externally e.g. from Remix, a web3 client (such as the front-end interface of a dapp), or from an external (i.e. non-derived) contract.

This is correct, if by method you mean function. However, the important point to make for functions is what I’ve already mentioned above, that it’s the public and internal functions in the parent contract which are available to be called from within the derived contract.

All modifers and event declarations in the parent contract are also inherited and available for derived contracts.

Just let me know if anything is unclear, or if you have any questions.

when i deploy contract it says “creation of Helloworld pending…” any suggestions? missing code?

pragma solidity 0.7.5;

import “./Ownable.sol”;

contract Helloworld is ownable{

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);

    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];

   

    _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;

}

}

1 Like

can u share error msg

pragma solidity 0.7.5;

import “./ethBank4.sol”;
import “./ethBank2.sol”;

contract destroyable is ethBank4, ethBank2 {

function  close() public onlyOwner returns (uint){
    withdraw(balance[msg.sender]);
    return msg.sender.balance;
    selfdestruct(payable(owner));
    
}

}

Hi @Jason_Purcell,

Have you managed to resolve this now?

If your code has compiled successfully, then if when you try to deploy Bank it gets “stuck” on  creation of Helloworld pending...  but you never actually get the transaction receipt with the green tick confirming successful deployment, then you may just need to close Remix in your browser and then reopen it (perhaps also completely closing your browser and reopening that as well). Sometimes Remix just gets tired and sluggish, and needs fresh start :wink:

I’m assuming this contract you’ve posted is before you’ve actually done the Inheritance assignment, right? I’m only asking because you’ll need a third contract in your inheritance structure for the assignment solution… but I imagine you’re just posting this here because you got stuck with this issue before even starting the assignment …

Anyway, just let us know if you’re still experiencing any problems and need some more help.


By the way, you also need to remove the onlyOwner modifier from your withdraw() function header. Adding this means that only the contract owner will be able to withdraw funds while the Bank contract is deployed and operating normally. The contract allows multiple addresses to deposit funds (we are simulating a bank with bank account holders) and so, while the contract is still deployed, it only seems fair that all users should be able to withdraw their funds as well, don’t you think? :sweat_smile: Earlier on in the course, our withdraw() function header didn’t include the onlyOwner modifier, but it looks like you’ve missed out the assignment where we focus on this function in particular, so maybe you haven’t realised this. I think during the course we’ve been adding and removing onlyOwner from various functions to demonstrate different scenarios, and I think it might have ended up being left in the withdraw() function in the code for this later part of the course by mistake!

I think you may have also missed out the Events Assignment, because you are missing a Transfer event, and a corresponding emit statement, in your contract. This is the assignment from the Events video lecture, which is near the end of the Additional Solidity Concepts section of the course. I would encourage you to have a go and post your solution code for all the course assignments, because this is a good opportunity to practise, and to get some helpful feedback on your progress and some suggestions :slight_smile:

Hi @markzachary,

… and welcome to the forum! … I hope you’ve been enjoying the course! :slight_smile:

The solution you’ve posted inherits 2 other contracts, so can we see those as well, so that we can fully understand how it works and deploy and test it if necessary? Unless we can see the parent contracts, it’s also difficult to make comments or provide you with feedback with any degree of certainty.

Having said that, I assume that ethBank4 must be what we’ve been calling Ownable, and ethBank2 what we’ve been calling Bank, right?

Have you tried testing your contract? … If you have, and assuming I’m right in my assumptions about the parent contracts, you should have found a few problems that need solving…

(1)  The contract owner will never be able to destroy the contract, because the line of code with the selfdestruct method is unreachable. On compiling your code you should get an orange warning that notifies you about this. It’s unreachable, because a function will finish executing after a return statement.

Have you completed all of the other course assignments? If you haven’t, I would strongly suggest that you do, and that you post your solutions, because that will help you practice and become aware of these sorts of concepts. It will also give you a chance to get some useful feedback about your progress before moving on to more advanced topics.


(2) During testing, after several different transactions have been performed — involving the deposit, withdraw and transfer functions, and resulting in several users holding shares of the total contract address balance — you will notice that when the contract owner calls the destroy() function, they only receive their share of the remaining contract balance, and not all of the remaining funds. This is because the withdraw() function (which I assume is inherited) is being called with a withdrawal amount equivalent to the contract owner’s individual balance in the mapping, and not the total contract address balance.

In fact, you don’t even need this line of code …

As well as destroying the contract, selfdestruct also automatically transfers the remaining contract balance to the payable address argument it is called with (in our case, the contract owner’s address). This is all part of the pre-defined selfdestruct functionality, and is why there is no need to include an extra line of code to perform this transfer of funds.


(3) Before making any amendments for the above issues, the return statement is currently returning the contract owner’s total external address balance (showing in the Account field near the top of the Deploy & Run Transactions panel in Remix) after the withdrawal of their individual share of the total Ether held in the contract, but before the close transaction’s gas cost has also been deducted.

However, after making the necessary modifications for (1) and (2) above, even if this return statement is corrected to return the total remaining contract address balance, it should still be removed, because …

  • If it’s placed before selfdestruct, it will prevent selfdestruct from executing (as already discussed above);

  • If it’s placed after selfdestruct, the return statement itself cannot execute, because once selfdestruct has been executed, the contract will have been destroyed and its code removed from the blockchain, and so the return statement will actually no longer exist, anyway.


I would also suggest that the contract we were calling Bank should be the most derived contract in your inheritance structure, the contract that we actually deploy, and not Destroyable. Once you’ve corrected your close() function for the above issues, even though your exisiting inheritance structure will now produce the desired result when Destroyable is deployed, one important reason for using inheritance is to create re-usable modules of code. And by having Destroyable inherit Bank, we are considerably reducing the re-usability of Destroyable, because instead of other contracts just being able to implement its “off-the-shelf” contract destruction functionality, together with the contract ownership functionality which Destroyable also inherits from Ownable, these other contracts will also have to inherit all the additional “baggage” from Bank, most of which they probably won’t need.

So, see if you can also come up with an alternative inheritance structure, which increases overall modularity and re-usability.

Let me know if anything is unclear, if you need any further help adapting your solution, or if you have any questions :slight_smile:

2 questions on addresses… the owner address is the address that deploys the contract? how is the contract address generated?

1 Like