Inheritance & External Contracts - Discussion

Hi Micky,

I’ve cut the following Government contract from your post in the Inheritance Assignment topic, and pasted it here. I know they are all one project, but I just want to avoid code and discussion involving the external Government contract appearing in a thread related to an earlier part of the course, where external contract instances, external function calls, and interfaces haven’t been introduced yet.

My feedback on this particular contract is below your code.

pragma solidity 0.7.5;

contract Goverment {
    
    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 returns(address, address, uint) {
        return(transactionLog[_index].from, transactionLog[_index].to, transactionLog[_index].amount);
    }
      
}

Just a couple of other minor points to mention here:

  • You should be getting an orange warning in the compiler, indicating that you should restrict the getTransaction function to view. If a function doesn’t need to change the contract state, it’s always safer to restrict it to view (so it can read the contract state, but not change it). Similarly if a function doesn’t need to read or change the contract state, it’s safer to restrict it to pure.
  • Also in the getTransaction function, I would add names to the 2 address values returned, so that it’s clear which is the sender’s address and which is the recipient’s address.
1 Like

When running the government contract I get the following error:

call to Government.getTransaction errored: VM error: invalid opcode. invalid opcode The execution might have thrown. Debug the transaction to get more information.

When I debug I it points to the getTansaction line

function getTransaction(uint _index) public view returns(address, address, uint) {

I have reviewed the video a few times and have the exact same code. I am not certain how to fix this error.

  1. The base contracts is the contract that a child/ derived contract inherits.

  2. The functions defined in the parent contract.

  3. Hierarchal inheritance is where a parent class is inherited by multiple different child contracts.

1 Like

Hi @Michael_Gerst,

Q1 :ok_hand:

Q2

The functions in the parent contract with internal and public visibility are available for derived contracts, but not those with external or private visibility.

Q3 :ok_hand:

Yes… “…where a single parent contract is inherited by multiple different child contracts…”

1 Like

Hi @CMar10,

I assume you are trying to call getTransaction() from Remix, and not as an external function call from Bank, is that right? If I remember rightly, in the video only addTransaction() is included in the GovernmentInterface in Bank and then called externally from the Bank contract.

If that’s the case, then one reason why you would get this error, is because you are calling getTransaction before having added a transaction i.e. if the transactionLog array is still empty.

transactionLog may be empty either because (i) addTransaction() hasn’t been called from Remix, (ii) transfer() in Bank hasn’t been called yet, meaning that addTransaction hasn’t been called externally from within the transfer() function (which is the intended method of calling addTransaction and adding data to transactionLog). Or (iii) it could be due to an error related to the addTransaction function somewhere else in your Bank or Government code, meaning that calling addTransaction() itself fails.


** EDIT **
Before reading the rest of this post, jump to my next post, which I didn’t realise until afterwards is more likely to be the issue. But, if not, then come back to the rest of this post…


If your compiler is indicating an error with the line…

… then this could also be triggered by something in the function body, or even in the syntax at the end of your addTransaction function above. So, if the suggestions above (and below) don’t help solve the problem, we would need to see your full code (both the Government and the Bank contract) to be able to identify the issue for you.

Other things that may be causing a problem (although I doubt it, considering the error you have described above):

Thanks for the feedback.

1 Like

Hi again @CMar10,

I’ve just realised that there might be another problem that’s causing your error message, related to…

Your transactionLog may not be empty (meaning that you’ve successfully added transactions by making external function calls to addTransaction from Bank). But, you need to ensure that you call getTransaction with a valid array index — an array index that corresponds to an existing transaction within the transactionLog array:
e.g.
If you have added only 1 transaction, then only an input (_index) of 0 will successfully output transaction data. An input (_index) of >= 1  will result in the error message you say you got.
If you have added, say 3 transactions, then only an input (_index) of 0 , 1 or 2  will successfully output transaction data.   >= 3 will throw the error … etc.

I re-watched the video and figured out the issue. Since I had edited and re-deployed both the bank and the government contract a few times, I needed to update the address of the Government contract in the GovernmentInterface settings on the bank contract. This seemed to fix the issue.

1 Like
  1. What is the base contract?
    The parent contract or the contract that is derived from.

  2. Which functions are available for derived contracts?
    all the functions of the parent.

  3. What is hierarchical inheritance?
    a single contract acts as a base contract for multiple derived contracts.

1 Like

Hi @Bryan,

Q1 & 3 :ok_hand:

Not all functions in the parent contract.
Functions with public or internal visibility are available for derived contracts, but those with private or external visibility are not inherited.

Thank you! I will fix this.

1 Like
  1. What is the base contract?

The parent contract we are inheriting.

  1. Which functions are available for derived contracts?

Public and internal functions of a parent are available in child contracts.

  1. What is hierarchical inheritance?

When a contract is directly inherited by 2 or more child contracts.

1 Like
What is the base contract?
	A contract which is inherited
Which functions are available for derived contracts?
	public and internal functions
What is hierarchical inheritance?
	A single contract acts as a base contact for multiple derived contracts
1 Like

Hello, I can’t use the transfer function, when I use it, it’s will throw an error and revert the function!
the compiler note said: 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.

Could anyone help me fix it
please.

pragma solidity 0.8.3;

import “./bigbro.sol”;

interface companyinterface{
function addtransacion(address _from, address _to, uint _amount) external payable;
}

contract bank is bigbro{

companyinterface companyinstance = companyinterface(0xfC01E11F9eC3E3D3831C010227D84Fa3E65b2FFB);

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

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

function withdraw(uint amount) public returns(uint){
    require(balance[msg.sender] >= amount);
    balance[msg.sender] -= amount;
    payable(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(msg.sender != recipient);
    require(balance[msg.sender] >= amount);
    uint prevamount = balance[msg.sender];
    _transfer(msg.sender, recipient, amount);
    
    companyinstance.addtransacion{value: 1 gwei}(msg.sender,recipient,amount);
    
    
    assert(  balance[msg.sender] == (prevamount - amount));
}

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

}

Hi @Jab_kaiju

You should be deploying your Government contract (which I think you’ve renamed Company) before deploying Bank. If you redeploy Company at any stage, then it will have a different contract address, and so you also need to change the Company address assigned to your CompanyInstance in this line of your code in Bank:

If you have forgotten to replace the previous address of your external contract for the new one, then this will have caused the transaction to revert when you called the transfer function, and will have given you the error message you got. The problem is that the error message you got was just a default one, and so that’s why it wasn’t helpful in pinpointing the error. Your error wasn’t anything to do with the function not being marked payable, or the value exceeding the current balance.

This is easily done, and catches most of us out the first time we make that mistake :sweat_smile:

Adding an error message to your require() statements, is always a good idea, because if the revert is caused by one of them, the message you added will appear as part of the error message you get in the Remix console. If one of your own error messages doesn’t appear, you know that the transaction reverted because of something else.

So, if the cause of the revert isn’t forgetting to replace the external contract address, try adding error messages to your require statements, and see if the revert is caused by either of the two require statements in the transfer() function.

If after that, you still have a problem, then post a copy of your Company contract as well, because it’s also possible that the transfer is failing due to an error in that contract rather than in Bank.

Just one other thing… In Solidity, it’s standard practice to start function and variable names (including mappings and arrays) with a lower case letter. Whereas the convention is to start contract, interface, event and struct names with a capital letter (although your code does still work using a lower case letter for these) e.g.
contract Bank is BigBro {...}
interface CompanyInterface {...}
event Deposit(uint amount, address indexed depositedTo);
This makes our code clearer, more readable, and helps to avoid confusion.

1 Like
  1. What is the base contract?
    The base contract is also known as the parent contract that the ‘derived class’ or ‘child contract’ inherits from.

  2. Which functions are available for derived contracts?
    All public and internal labelled functions are available to derived contracts.

  3. What is hierarchical inheritance?
    Hierarchical inheritance is when the base contract has multiple derived contracts that inherit from it directly.

1 Like

What is the base contract?:
The parent contract that is inherited from.

Which functions are available for derived contracts?:
Public and internal functions.

What is hierarchical?:
When a single parent contract has multiple child contracts.

1 Like
  1. What is the base contract?
    The parent contract is also called the base contract.

  2. Which functions are available for derived contracts?
    Public and internal tagged functions.

  3. What is hierarchical inheritance?
    This is where a base contract acts as the inherited contract for multiple derived contracts.

1 Like

Nice answers @JasonM :ok_hand:

A single base contract, yes… and multiple derived contracts all inherit from that same base contract.

What is the base contract?
Multiple contracts are connected to the main base contract. => B is A, C is A
Which functions are available for derived contracts?
Public and internal tagged functions.

What is hierarchical inheritance?
When B is A, C is A and D is A,B,C

1 Like