Inheritance & External Contracts - Discussion

The problem came from this function, when adding a transaction to the government contract, you are also sending funds to it (value: 1 ether)

    function transfer(address recipient, uint amount) public payable {
        require(balance[msg.sender] >= amount, "Balance not sufficient.");
        require(msg.sender != recipient, "You can't transfer money to yourself.");
        
        uint previousSenderBalance = balance[msg.sender];
        
        _transfer(msg.sender, recipient, amount);
        
        governmentTxReport.addTransaction{value: 1 ether}(msg.sender, recipient, amount);
        
        assert(balance[msg.sender] == previousSenderBalance - amount);
    }
    

This line exactly governmentTxReport.addTransaction{value: 1 ether}(msg.sender, recipient, amount);

Thats why when depositing 2 ethers, transfering them to another account, 1 ether goes to the government contract (hard coded) and the other will go to the balance of the account.

Carlos Z

Thank you for taking a look at the issue. I’ll try to figure out how to make the transfer work better then. Just a clarifying question though:
I’m still confused why the getBalance function for the Bank.sol no longer returns the correct balance after the transaction. I thought that getBalance simply added up the sum of all the accounts on the smart contract and gave a total. After I perform a transfer, and 1 ETH goes to Government.sol, the getBalance function for Bank.sol says that there are only 2 ETH total left in the Bank.sol contract, but after individually checking the two addresses I used for the test, there are clearly still 3 ETH total, 1 in one account, and 2 in another. Just wondering how this is possible and what numbers the getBalance function is using to arrive at its total.
Thanks again for your assistance :slight_smile:

1 Like

Hi. Not sure why, but I am getting this error. Could someone tell me what they think is going on here?

Screen Shot 2021-08-05 at 9.29.17 PM

2 Likes

Can anyone tell me what might be wrong with these 2 line? They are both throwing errors in the Bank Contract for me…

assert(balance[msg.sender] == previousSenderBalance – amount);

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

1 Like

The problem come from the way you manage the funds, when doing a transfer, it will discount the amount from the balance[msg.sender], but the contract will pay 1 ether from its funds to governmentTxReport.addTransaction, instead of discounting it from msg.sender. Thats why, contract balance have less ethers than what the balance mapping shows on each account.

Carlos Z

Hey @alexhupe, @Bitborn, hope you guys are ok.

Please share your code in the following way so i can check why those error are being triggered :face_with_monocle:

Carlos Z

Oh ok, got it, thank you for the clarification!

  1. What is the base contract?

The base contract is the child contract’s inherited contract (in code, child_con is base_con)

  1. Which functions are available for derived contracts?

Public and internal functions

  1. What is hierarchical inheritance?

Inheritance where one parent contract has many different child contracts

1 Like
  1. What is the base contract?
    The parent contract, that is inherited by the child contract, is known as the base contract.

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

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

Hey, thanks for your help @thecil! I ended up figuring it out on my own, thankfully.

1 Like

Hi all,
I was doing the second inheritance assignment and I had an error that i do not understand
If anyone could explain me what i did wrong I would be greatful.
I pass the my code from my Bank.sol, ownAble.sol and destroyable.sol here.

Bank.sol:
// SPDX-License-Identifier: MIT
pragma solidity 0.7.5;

import “./ownAble.sol”;
import “./destroyable.sol”;
contract PlikiPliki is ownAble, destroyable {

mapping(address=>uint) balance;

event depositDone(uint amount, address indexed depositedTo);
event transferMade(address from, address to, uint amounTransered);


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 returns(uint){
    //require(amount <= balance[msg.sender]);
    msg.sender.transfer(amount);
    //balance[msg.sender] -= amount;
    return balance[msg.sender];
}

function transfer(address recipient, uint amount) public{
    //some important checks
    require(msg.sender != recipient);
    require(balance[msg.sender] >= amount);
    
    uint balanceBeforeTransfer = balance[msg.sender];
    _transfer(msg.sender, recipient, amount);
    
    //some other contract logic;
    assert(balanceBeforeTransfer == balance[msg.sender] + amount);
    emit transferMade(msg.sender, recipient, amount);
}

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

}
ownAble.sol:
// SPDX-License-Identifier: MIT
pragma solidity 0.7.5;

contract ownAble {

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

constructor(){
    owner = msg.sender;
}

}

destroyAble.sol:
// SPDX-License-Identifier: MIT
import “./ownAble.sol”;
pragma solidity >0.6.0;
contract Storage is ownAble {
function close() public {
selfdestruct(owner);
}
}

What is the base contract?

Inheritance defines multiple parent-child relationships between different contracts. The base contract is the one that is inherited (the contract that inherits is called the child contract).

Which functions are available for derived contracts?

All public and internal scoped functions and state variables are available to derived contracts

What is hierarchical inheritance?

A hierarchical inheritance is when a single contract acts as a base contract (parent) of many derived contracts.

1 Like

pragma solidity 0.7.5;

contract Ownable {
address owner;

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

constructor(){
    owner = msg.sender;
}

}

pragma solidity 0.7.5;
import “./Ownable.sol”;

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

pragma solidity 0.7.5;

import “./Ownable.sol”;
import “./Destroyable.sol”;

contract Bank20 is Ownable, Destroyable{

mapping(address => uint) balance;

event depositDone(uint amount, address indexed depositTo);

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

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(balance[msg.sender] >= amount);
msg.sender.transfer(amount);
return balance[msg.sender];
}

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

What’s not working here is the getBalance() function.
I can deposit and withdraw. When I deposit the getBalance() function is updating the deposit. When I withdraw the getBalance() function is not updating. The getContractBalance however is updating after deposit and withdraw. i only realized that now (not during the withDraw assignment…) and couldn’t figure out why that is. Can you help? thank you.

1 Like

Bank Contract

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

contract Bank is Ownable, Destroyable {
...
}

Ownable Contract

contract Ownable {
    // adding public to a state variable will automatically create a function that will allow you to access the variable
    address payable public owner;
    
    modifier onlyOwner {
        require(msg.sender == owner);
        _; //run the function
    }
    
    constructor() {
        owner = msg.sender;
    }
}

Destroyable Contract

contract Destroyable is Ownable {
    function close() public onlyOwner { 
        selfdestruct(owner); 
    }
}
1 Like

I’m getting following error when trying to transfer an amount.
edit: Error has been fixed. I had the wallet address that deployed the contract set at GovernmentInterface instead of the contract address itself.

transact to Bank.transfer errored: VM error: revert.

revert
The transaction has been reverted to the initial state.
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.
creation of Bank pending…

Here is my code:

pragma solidity 0.7.5;

import “./Ownable.sol”;
import “./SelfDestruct.sol”;

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

contract Bank is Ownable, SelfDestruct {

GovernmentInterface GovernmentInstance = GovernmentInterface(0x5B38Da6a701c568545dCfcB03FcB875f56beddC4);

mapping(address => uint) balance;

event depositDone(uint amount, address indexed depostiedTo);
event amountTransfered(uint amount, address indexed transferedTo, address indexed transferedFrom);

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, “The amount you tried to withdraw is bigger than your balance”);
uint previousSenderBalance = balance[msg.sender];
balance[msg.sender] -= amount;
msg.sender.transfer(amount);
assert(balance[msg.sender] == previousSenderBalance - 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);

GovernmentInstance.addTransaction(msg.sender, recipient, amount);
emit amountTransfered(amount, recipient, msg.sender);
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;
}

}

pragma solidity 0.7.5;

contract Government {

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

}
}

1 Like

In the video of Value calls Filip talks about the value of wei, gwei and ether. In Remix there is also an option to add finney. What’s the value of this?

1 Like

Basically it refers to this: (ether denominations)
image

Carlos Z

1 Like

Hmm. I am getting this error as well. Here is my code:

pragma solidity 0.7.5;
 
 import "./Ownable.sol";
 
 
 interface GovernmentInterface{
     function addTransaction(address _from, address _to, uint _amount) external;
 }
 
 contract Bank is Ownable{
     
    GovernmentInterface governmentInsatance = GovernmentInterface(0xCA35b7d915458EF540aDe6068dFe2F44E8fa733c);
     
    mapping(address => uint) balance;
    
    
    
    event depositDone(uint amount, address depositedTo);
    event amountTransfered(uint amount, address trasferedFrom, address trasferedTo);
    
   
    
   
    
    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 not sufficent!" );
        msg.sender.transfer(amount);
        balance[msg.sender] -= amount;
        return balance[msg.sender];
    }
     
     function getBalance() public view returns (uint){
         return balance[msg.sender];
     }
     
     function transfer(address recipeint, uint amount) public {
         require(balance[msg.sender] >= amount, "Balance not sufficent!" );
         require(msg.sender != recipeint);
         
         uint previousSenderBalance = balance[msg.sender];
         
         _transfer(msg.sender, recipeint, amount);
         
         governmentInsatance.addTransaction(msg.sender, recipeint, 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;
     }
     
 }


pragma solidity 0.7.5;


contract Government{
    
    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);
        
    }
    
}
pragma solidity 0.7.5;


 
 contract  Ownable   {
     address public owner;
     
      modifier onlyOwner{
        require(msg.sender == owner);
        _; //Run the function 
    }
     
     constructor(){
        owner = msg.sender;
    }
 }

image

That might be a require condition that is triggered but does not contain a revert message, you should check the transfer function.

Carlos Z

1 Like

hiii what is the use of value as we are having amount as argument already .what is the difference between two?