Inheritance & External Contracts - Discussion

Hey there!

I have a problem. After i implemented the goverment contract i cant deploy my Bank contract anymore…

pragma solidity 0.7.5;

import"./Ownable.sol";
import"./Selfdestruct.sol";

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

contract Firstcontract is Ownable, Destroyable{

GovermentInterface govermentInstance = GovermentInterface(0x56f0F6A99FE5e78e533C6dC8C71C8572cE2c5621);

mapping(address=>uint)balance;



event depositDone( uint amount, address depositTo);
event coinsTransfered (address sentTo, uint amount, address sentFrom);



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);
    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, "dont send 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 );
    
    emit coinsTransfered(recipient, amount, msg.sender);
    
    
}

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

}

What is the error that is showed to you?

The common error here is the address of the government contract, which change everytime you deploy that contract, so be careful with it :nerd_face:

Carlos Z

1 Like

Perhaps future star ships will run with Ethereum smart contracts managing their selfdestruct functions … multisig style:

https://youtu.be/lqe-mr_zBdg

ya know, i’m enjoying learning about Solidity … but some of my learning through certain confusions about how the code works would be greatly accelerated if only there were something like console.log() built into solidity.

Why didn’t they include something like that?

And how about this as an alternative? Anyone use this?

https://medium.com/nomic-labs-blog/better-solidity-debugging-console-log-is-finally-here-fc66c54f2c4a

1 Like

I haven’t used it but it looks interesting @gaio … once you’ve completed the 201 course that follows this one, you should then have enough knowledge to be able to incorporate this tool into your smart contract development and experiment with it. Then you can let us know how useful you’ve found it :slight_smile:

Hey @Leonard_Gohlke,

Did you manage to get this working?

As @thecil said…

If you’re still having difficulties, then have a look at this post.

1 Like

hey @jon_m,
No i considerd his point already.
But as soon as i deleted the “Import ./destroyable” contract it started working.

Any way, Thank you guys!

1 Like
  1. What is the base contract?
    A base contract is parent contract .
  2. Which functions are available for derived contracts?
    derived contracts can use any functions in their parent contract.
  3. What is hierarchical inheritance?
    derived contracts can inherite from a base contract or multiple contracts .

is only one function allowed in one interface?

1 Like

If you call a function in contract A, which calls a function in Contract B, what will msg.sender be in Contract B’s function?

Can anyone help explain this?

1 Like

Hey @Leonard_Gohlke,

Glad you got it working!

That’s strange, though, because you should be able to keep your previous inheritance structure (Ownable => Destroyable => Bank), so that the selfdestruct functionality is still available when Bank is deployed. Adding the Government Interface and the external function call shouldn’t affect that.

Hi @chen,

No, you can include as many function definitions as you want. The restrictions for functions in an interface are:

  • They must only be definitions without any implementation i.e. no function body.
  • They must have external visibility.

Hi @chen,

It depends whether Contract B is inherited by Contract A, or is an external contract …

If the function in Contract B is inherited by Contract A, then, when the derived contract is deployed (contract A), msg.sender will reference the same external calling address in both …

  1. the initial function called externally in Contract A ; and
  2. the function in the inherited Contract B called internally from the initial function in Contract A.

If, however, you are referring to our example of the Bank Contract, where calling its transfer() function then calls the external Government contract’s addTransaction() function, then …

(1) Within the transfer() function body, msg.sender will reference the address that is calling transfer(). So the msg.sender argument in the external function call …

governmentInstance.addTransaction(msg.sender, recipient, amount);

… references the address that has called the Bank’s transfer() function.

BUT

(2) Within the Government contract’s addTransaction() function, msg.sender would reference the deployed Bank contract’s address, because this is the address that is calling the function. You can test this out by adding some extra code to your Government contract e.g …

struct Transaction {
    address bank;  /* ADDED to record which Bank contract the transaction
                      relates to (this way our Government contract can log
                      transactions performed in multiple Bank contracts) */
    address from;
    address to;
    uint amount;
    uint txId;
}

function addTransaction(address _from, address _to, uint _amount) external payable {
    transactionLog.push(Transaction(
        msg.sender,  // ADDED to reference the calling contract's address
        _from, _to, _amount, transactionLog.length
    ));
}

function getTransaction(uint _txId) external view returns(address bank, address from, address to, uint amount) {
    return (
        transactionLog[_txId].bank,  // ADDED to also retrieve this data from the transaction log
        transactionLog[_txId].from, transactionLog[_txId].to, transactionLog[_txId].amount
    );
}

Let me know if anything is unclear, or if you have any further questions.

Hi @chen,

Q1 :ok_hand:

No… not all functions in the parent contract are inherited. Those with public or internal visibility are inherited, but private and external functions are not available for derived contracts.

No …
Hierarchical inheritance is the term for a specific type of inheritance structure, where the same, single base/parent contract is inherited by more than one (i.e. multiple) derived/child contracts.
The opposite, where more than one base contract is inherited by the same derived contract, is termed multiple inheritance.

Let me know if anything is unclear, or if you have any questions :slight_smile:

{value: 1 ether}

this 1 ether is sent from which contract to which contract?

From the Bank contract to the Government contract. It is deducted from the Bank contract ether balance, and added to the Government contract balance.
You can check this by adding the following function to each contract and then calling them. It retrieves a contract’s total ether balance.

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

I’m playing around with the Government contract but I’m not able to add the event log successfully,
Where should the “event” & “emit” string be added in the government Code.
Code below:

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

}

Hey @david.maluenda,

The idea isn’t to emit an event, but to call getTransaction() on the Government contract, after a transfer has been executed (i.e. the transfer function called) in Bank.

You need to call getTransaction() with the index of the transaction you want to view. So the first transfer made in Bank will be logged in the Government contract’s transaction log at index 0, the second transfer at index 1 etc.

For the external function call   governmentInstance.addTransaction()   to work you will have deployed both the Government contract and Bank, and so you’ll need to ensure that you’ve expanded the Government contract, as well as Bank, in the Deploy & Run Transactions panel in Remix, in order to be able to add the index argument for getTransaction and then click its blue button to retrieve the data from the transaction log.

Let me know if that makes sense, or if you have any further questions about how to get this working practically :slight_smile:

Hi @david.maluenda,

Following on from my previous post …

You should already have an event emitted for each transfer transaction in Bank. This should be emitted at the end of the transfer() function, after the transfer has been performed within Bank and the external Government function (addTransaction) has been executed successfully (adding the transfer data to the Government transaction log).

You could potentially add an additional event emitted by the Government contract as additional confirmation of the transaction data added to the transaction log array. But in terms of the transfer amount, and its sender and recipient addresses, this data is already contained in the event emitted by Bank. If the Government’s addTransaction() function failed to add the data to the transaction log, then the transfer() function in Bank would also fail to finish executing, and so its transfer event wouldn’t be emitted anyway. However, emitting the txId (the transaction’s index position in the array) could be useful in order to call the getTransaction() function and retrieve a specific transaction’s data afterwards. You could add an event declaration to the top of the Government contract, and the corresponding emit statement to the end of the addTransaction() function e.g.

pragma solidity 0.7.5;

contract Government {

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

   event GovTxLog(uint txId);  // ADD event declaration

   Transaction[] transactionLog;

   function addTransaction(address _from, address _to, uint _amount) external {
      /* Add a local variable to save transactionLog.length before it increases,
      to ensure the txId emitted in the event is the same index number */
      uint txId = transactionLog.length;  // ADD
      // Reference variable txId instead of expression transactionLog.length
      transactionLog.push(Transaction(_from, _to, _amount, txId));
      emit GovTxLog(txId);  // ADD emit statement
   }

   // etc.
}

Both events will now be emitted (one from each contract) when the transfer() function is executed. There is only one transaction, though, so both logged events will appear together in the logs of the same transaction receipt generated in the Remix console. However, the event data emitted from the external Government contract is not displayed in the same reader-friendly format as that emitted from Bank — although, if you know what you’re looking for, you can see that both events have been logged, as follows …

[
   {  //** Logged GovTxLog event data **//
      "from": "0x1bB...7B0b",  // Smart contract address (Government) 
      "data": "0x000...0001",  /* Emitted event argument(s) (except if indexed)
       txId => 1  (2nd tx logged in array) integer expressed as hexadecimal */
      "topics": ["0x964...aa26"]  /* 1st topic => Event Signature (hash of
       event name and its parameter types). Up to 3 more topics => one for
       each indexed argument (but there aren't any in this example) */
   },

   {  //** logged Transfer event data **//
      "from": "0xdda...482d",   // Smart contract address (Bank)
      "topic": "0xddf...b3ef",  // Event Signature
      "event": "Transfer",      // Event name
      "args": {  // Logged data, according to the defined event arguments
                 // Same data given twice (i) by index (ii) by argument name 
         "0": "0x5B3...ddC4",       // Sender's address
         "1": "0xAb8...5cb2",        // Recipient's address
         "2": "2000000000000000000",  // Amount transferred (always in wei)
         "from": "0x5B3...ddC4",       // Sender's address (repeated)
         "to": "0xAb8...5cb2",          // Recipient's address (repeated)
         "amount": "2000000000000000000" // Amount transferred (repeated)
      }
   }
]

Just let me know if you have any questions :slight_smile:

1 Like

Hello Peeps, need help from you guys!

When deploying my contract I get the following message:
image

Cant really see what the problem is, doing the exact same thing as Filip is doing in the video.

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 governmentInstance = GovernmentInterface(0x3643b7a9F6338115159a4D3a2cc678C99aD657aa);



mapping(address => uint)balance;



event depositDone(uint amount, address indexed depositTo);
event transferDone(address from, address to, uint amount);



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


function transfer(address recipient, uint amount) public {
    require(balance[msg.sender] >= amount, "Dont have enough money");
    require(msg.sender != recipient, "Dont send money to yourself");
    
    uint balanceBeforeSending = balance[msg.sender];
    
    _transfer(msg.sender, recipient, amount);
    
    governmentInstance.addTransaction(msg.sender, recipient, amount);
    
    assert(balance[msg.sender] == balanceBeforeSending - amount);
}


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

}