Inheritance & External Contracts - Discussion

Hey guys, I have a problem here and I’ve spent hours stairing at the code and can’t for the life of me figure out what’s causing the issue.

For some reason the transfer() function has stopped working and I don’t understand why because it used to work just fine. I can deposit Eth, I can withdraw Eth, but I cannot transfer it. Every time I try I receive an error and the tx is reverted. Anybody know why?

pragma solidity 0.7.5;

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

interface GovernmentInterface {
    function addTransaction(address _from, address _to, uint _amount) external;
}

contract Bank is Ownable, Destroyable {
    
    GovernmentInterface GovernmentAddress = GovernmentInterface(0xf8e81D47203A594245E36C48e151709F0C19fBe8);
    
//mapping(keyType => valueType)name;
  mapping(address => uint     )balance;

  event depositDone(uint amount, address indexed depositedTo);
  event amountTransferred(address sentFrom, address sentTo, uint amount);
  

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

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

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

function transfer(address recipient, uint amount) public {
    emit amountTransferred(msg.sender, recipient, amount);
    require(balance[msg.sender] >= amount, "Insufficient funds");
    require(msg.sender != recipient, "Funds sent to self");
    
    uint previousSenderBalance = balance[msg.sender];
    
    _transfer(msg.sender, recipient, amount);
    
    GovernmentAddress.addTransaction(msg.sender, recipient, amount);
    
    assert(balance[msg.sender] == previousSenderBalance - amount);
}

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

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

}

Hey @Emmerich

It fails due to a require statement that does not pass successfully.
Can you provide the steps to reproduce the issue?

Cheers,
Dani

Hey Dani,

Thanks again for taking the time.

You know what the problem was? It was the location of the GovernmentInterface. Every time a redeployed that contract the contract address would change, which then in turn didn’t correspond with the address I had specified in the instantiation, which ultimately was the cause for the transfer to fail :slight_smile:

But now I have another question now: whenever I transfer funds to another address, the balance of the sender decreases correspondingly, but the overall balance of the contract does not. Shouldn’t the balance of the contract also decrease with the same amount as the transfer? Or am I missing something here?

Regards
Emmerich

1 Like

Hi @Emmerich

But now I have another question now: whenever I transfer funds to another address, the balance of the sender decreases correspondingly, but the overall balance of the contract does not.

If you are talking about ERC20 transfer, then you need to query balanceOf() your contract address.
The function you have now just returns the amount of Ether in your contract, not the ERC20 balance:

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

Regards,
Dani

Hi @dan-i, I’m having trouble with the transfer() function on my Bank Contract, it tells me that it should be payable, but I tried doing that and it still doesn’t work. Everything’s fine from deposit, withdraw, and getbalance of my account but I cannot do transfer(). This prevents it from being logged into the transactionLog of the Government contract. Any ideas why?

Bank Contract

pragma solidity 0.7.5;

import "./Ownable.sol";
// import "./Destroyable.sol"; - add Destroyable to contract (after Ownable) if this is implemented

interface GovernmentInterface{
    function addTransaction(address _from, address _to, uint _amount) external payable;
}

contract Bank is Ownable{
    
    GovernmentInterface governmentInstance = GovernmentInterface(0xAb8483F64d9C6d1EcF9b849Ae677dD3315835cb2);
 
    mapping(address => uint) balance;
    
    event depositDone(uint amount, address indexed depositedTo);

    event transferDetails(address indexed depositedFrom, address indexed depositedToAddress, uint 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 withdraw(uint amount) public onlyOwner returns (uint){
        require(amount <= balance[msg.sender]);
        msg.sender.transfer(amount);
        return balance[msg.sender];
    }
    
    function transfer(address recipient, uint amount) public{
        require(balance[msg.sender] >= amount, "Insufficient funds");
        require(msg.sender != recipient, "Don't send money to yourself");
        
        uint previousSenderBalance = balance[msg.sender];
        
        _transfer(msg.sender, recipient, amount);
        
        // 1 gwei = 10^9 wei
        // 1 ether = 10^18 wei
     
        governmentInstance.addTransaction{value: 1 ether}(msg.sender, recipient, amount);
        
        // governmentInstance.addTransaction(msg.sender, recipient, amount);
        
        emit transferDetails(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;
    }
}

Government Contract

pragma solidity 0.7.5;

contract Government {
// struct is object in JavaScript
    struct Transaction {
        address from;
        address to;
        uint amount;
        uint txId;
    }
    
    Transaction[] transactionLog;
// external function will not allow government to "addTransaction", only other contracts can use function "addTransaction"   
    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);
    }
}

Many Thanks!!

Hi @CryptoXyz

I deployed your contract and works for me.
Screenshot 2021-03-31 at 09.02.56

Make sure to use the right address in GovernmentInterface (if you deploy a new Government contract that address changes), also make sure to deposit enough ether as you hard coded:

governmentInstance.addTransaction{value: 1 ether}(msg.sender, recipient, amount);

Happy coding,
Dani

2 Likes

Thank you so much! @dan-i

2 Likes
  1. What is the base contract?
    The base contract is a parent contract.

  2. Which functions are available for derived contracts?
    All public and internal scope functions and state variables

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

1 Like

I had exact same issue, spent like 2 hours trying to fix it :rofl: :joy:
It looks that wrong government address makes error that function should be payable. not sure if I would come up with the error being wrong government address if weren’t for you, but for future ref, if I would want it to solve it myself, Is there explanation why?

Hi @Kamil37

Errors are not always accurate.
In this case you should go step by step though your code and debug it.

Happy learning,
Dani

1 Like

hey I’ve had alot of trouble getting my contracts to compile. I don’t understand the error message.

Screen Shot 2021-04-06 at 10.31.51 AM

2 Likes

Hey @HanaYezi, hope you are well.

Your struct name is transaction, you just have to rename your array to transaction[] transactionLog; for example. (the array data type should have the same name as the struct)

Carlos Z

1 Like

Hello, can anyone help out what’s wrong here?

interface Financial {
    function addTransaction (address _from, address _to, uint _amount) external; 
    
}
contract bank is Ownable {
    
    
    FinancialInterface FinancialInstance = FinancialInterface(0xf8e81D47203A594245E36C48e151709F0C19fBe8);
    
error message is saying (identifier not found or unique) but as you can see below, it is declared in my 'Financial' contract and interface is integrated into the main contract.


pragma solidity 0.7.5;

contract Financial {
    
    struct Transaction {
        address from;
        address to;
        uint amount;
        uint txId;
        
    }
    
    Transaction[] transactionLog;
    
    function addTransaction (address _from, address _to, uint _amount)external {
        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);
    }
}

Edit: code edited for clarity (dani)

Thanks

Hey @NetworkP

Please read this faq that will guide you to correctly post code in the forum: FAQ - How to post code in the forum

You called your interface Financial therefore your interface declaration has to use the same name.
Something like this should work:

interface FinancialInterface {
    function addTransaction (address _from, address _to, uint _amount) external; 
    
}
contract bank  {
    
    
    FinancialInterface  financial = FinancialInterface(0xf8e81D47203A594245E36C48e151709F0C19fBe8);
}


pragma solidity 0.7.6;

contract Financials {
    

Cheers,
Dani

1 Like

School boy error. Good old debugging for you!! always staring you in the face lol…Thanks alot. Much appreciated

1 Like
  1. What is the base contract?

It is a parent contract which is inherited by a child contract, and it itself inheriting from another parent contract.

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

  2. What is hierarchical inheritance?
    It is a (number >1) of contracts which inherits from the same derived class.

1 Like

What is the base contract?

  • The parent contract from which the child (derived contract) inherits.

Which functions are available for derived contracts?

  • Public and Internal functions and state variables

What is hierarchical inheritance?

  • A structure where multiple derived contracts inherit from a single base contract.

Polymorphism Question:

  • Based on my reading it seems like the purpose of polymorphism is to define as general a ‘template’ function as possible and then modify that function elsewhere as needed to minimize the need to rewrite code.

Is this accurate? Are there any benefits of polymorphism beyond this?

1 Like

Hello,
I wonder what happens when you send Eth from your contract to an external contract during the execution of one of your functions, but then one of the assert() or require()'s fail during the rest of your function execution. Does the Eth arrive at the external contract or will this transfer be undone? The same with when you call the function of an external contract, does this external functioncall go through when an assert() or require() within your function fails after making the function call?

Hey @Florian_P

If a contract does not pass a require statement, then the whole transaction is reverted therefore funds will not be sent to the receiver contract/user.

Cheers,
Dani

  1. What is the base contract?
    A base contract is a parent contract where other contracts inherit from.

  2. Which functions are available for derived contracts?
    All the functions within the derived contract as well as all public and external functions of the parent contract.

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

1 Like