Inheritance & External Contracts - Discussion

Thanks Jon. All good now. I appreciate your help :love_you_gesture:

1 Like

Thanks for the thorough explanation Jon. This was really helpful. There is just one other thing i am hoping you can answer regarding the transferFrom function… Supposing I approve someone to spend my funds. That person can then use the transferFrom to send my funds to whomever he wants correct?

So in the transferFrom header… the “from” address is the person i have approved to spend my funds? And the “to”/msg.sender" is where he is sending the funds i have given him the approval to spend? Or do i have something mixed up here?

Hi @Bitborn,

I’ve tried to find a post of yours with your full Bank contract, but it doesn’t seem like you ever posted it… is that right? I wanted to see it because you mention a transferFrom() function header, and this doesn’t appear in the Bank contract used in the course videos/assignments.

Anyway, I’ll assume you mean the _transfer() helper function which is called from within the transfer() function…

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

This is a private function, and so can’t be called from outside the Bank contract. When the public transfer() function is called, the _transfer() function is then called from within the transfer() function in this line of code …

_transfer(msg.sender, recipient, amount);

As you can see, the msg.sender argument is passed to the _transfer() function as the address from parameter.

So, no … it’s the caller of the public transfer() function…

function transfer(address recipient, uint amount) public { ... }

The caller of this function is the address which executes the internal transfer, which is effectively a reallocation of part, or all, of their own share of the total amount of ether held in the contract (recorded as their individual balance mapped to their address in the mapping) to another address of their choosing. No ether leaves the contract: the reallocated share is added to the other address’s individual balance (also mapped to their address in the mapping). This reallocation is performed in the _transfer() helper function.

The recipient argument is passed to the _transfer() function as the address to parameter. The msg.sender argument is passed to the _transfer() function as the address from parameter.

msg.sender / from
is transferring part, or all, of their own share of the total amount of ether held in the contract
TO
recipient / to

The Bank contract used in the course/assignments doesn’t allow an address to approve another address to perform any transactions on its behalf. Our use of msg.sender in the code ensures that…

  1. The caller of the deposit() function can only transfer ether from their external address balance to the contract, where it is recorded in the mapping as their own share of the total contract balance:   balance[msg.sender] += msg.value

  2. The caller of the withdraw() function can only transfer ether out of the contract to their own external address balance:   msg.sender.transfer(amount)
    … and that this reduction in the total contract ether balance can only be recorded as a reduction in that same caller’s own share of the total contract balance:   balance[msg.sender] -= amount

  3. The caller of the transfer() function can only reallocate part, or all, of their own share of the total amount of ether held in the contract:
    balance[from] -= amount
    from is msg.sender passed to _transfer() helper function from public transfer() function
    … so that ownership of this share of the total contract ether balance (expressed as an amount) is transferred to an address of their choosing (input as the recipient argument):
    balance[to] += amount
    to is recipient passed to _transfer() helper function from public transfer() function

I hope that helps to clarify things some more. But if I’ve misunderstood what you mean by the transferFrom() function, then post your full Bank contract code and I’ll take another look. Let me know if anything I’ve explained is unclear, or if you have any further questions :slight_smile:

Did you resolve this in the end?

You may find the errors are the following (but these may just be copy-and-paste mistakes in your post, and not errors in your code in Remix) …

(1)

The units of ether must be written in lower case letters i.e.

1 ether
1 gwei
1 wei

(2)

Your operator here is a dash, and not a minus sign. A dash is longer, and will throw a compiler error.

previousSenderBalance – amount // dash => incorrect syntax
previousSenderBalance - amount // minus sign => correct subtraction operator

If you look carefully you can just see the difference.


If these were just errors in your post, then post a full copy of your Bank contract, appropriately formatted as explained here, so that I can compile it myself and identify the issues.

Hi Filip,
In the Value calls tutorial. you have mentioned {value: 1 ether}. Please tell me why it is written 1 ether. can we write 2 ether, etc., and what does this value signify? Shouldn’t it be written as {value: amount ether} the amount that we want to transfer?
Thanks and regards.

1 Like

Hi @astro1,

Great questions!

Our particuar example code is based on a contractual relationship between a bank and the government. The idea is that the government needs to collect some kind of tax (or levy) on each banking transaction that is an internal bank transfer. To keep things simple in our example, the government is collecting a fixed amount of tax on each transfer. I would suggest an amount much smaller than 1 ether would be more appropriate, for example any value from 1 wei up to 1 gwei. This amount (which is the amount of tax paid by the Bank, and not the amount transferred from one bank account holder to another) will be automatically transferred from the Bank contract balance to the Government contract balance on each successfully executed transfer transaction. For record keeping purposes, the relevant data for each transfer is also sent from Bank to Government and stored in the government’s transaction log (an array).

Instead of as a tax, another way to interpret this transfer of value between the two contracts could be as payment, or fees, for some kind of record keeping service i.e. the Bank contract pays the Government contract for storing all of its transaction data.

However we interpret this payment from one contract to the other, it demonstrates (albeit in an overly simplistic way) how we can program automatic interactions between individual contracts for the purposes of both data and value transfer. Hopefully, this example shows the potential for these sorts of programmed interactions to be applied to many different use cases.


Yes …

In Solidity, unsigned integers representing Ether values are equivalent to uints of wei e.g.

{value: 1000000000000000000}

/* A value call of 1000000000000000000 Wei  =  1000000000 Gwei  =  1 Ether

However, Solidity syntax also includes the suffixes ether and gwei , which provide us with a useful shorthand. For example, the following 3 alternatives are all equivalent to value calls of 1 ether …

{value: 1000000000000000000}
{value: 1000000000 gwei}
{value: 1 ether}

The suffix wei is also available, but this would only seem to be worth using in situations where there could be a risk of confusion, because the following 2 alternatives are both equivalent to value calls of 0.05 gwei …

{value: 50000000 wei}
{value: 50000000}

Here is a link to the relevant section in the Solidity documentation:
https://docs.soliditylang.org/en/latest/units-and-global-variables.html#ether-units

I’ve already partly answered this, above. The Ether value we are transferring to the Government contract is a payment made by Bank to Government in respect of the transfer of funds between two individual users of the Bank contract. The transfer itself is an internal transfer within Bank, and the amount value sent to Government is part of the data which will be added to the Government transaction log as a record of the transfer for which Bank has made a payment (of tax, or a fee for a service).

In any case, the suffixes ether, gwei and wei can only be used after literal numbers. You could reference an unsigned integer stored in a variable, but without the suffix e.g.

uint tax;

function transfer(address recipient, uint amount) public {
   // additional code
   governmentInstance.addTransaction{value: tax}(msg.sender, recipient, amount);
   // additional code
}

Just one final point… If you haven’t already, you’ll find it really helpful to add the following function to both the Bank and Government contracts. It enables you to retrieve the total contract address balance for each contract before and after specific transactions. This is useful for testing and for understanding the movements of Ether at a contract level.

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

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

Thanks Jon! Makes sense and see the error now.

1 Like

Thanks for the explanation with all this as it really clarified the intentions of the transfer and _transfer functions. Tbh I accidentally posted my question about transferFrom here when it was in fact a lesson from Eth Smart Contract Programming 201, “TokenStandards”. My bad, I’ve been going back and forth, occasionally going over old material and confused what lesson i was on. In any case, i will post that in the appropriate lesson so not to confuse anyone here because its not part of the lesson here. Either way this was helpful, thanks.

1 Like

Hey @Bitborn,

Ahhhh … OK that makes sense now :sweat_smile:
Not to worry … it’s great that you’re re-visiting earlier material, as you can often get more out of it, and discover things you didn’t notice before, after having aquired more technical knowledge and gained more practical experience :muscle:

Anyway, I’m glad the extra explanations were helpful :slight_smile:

Hey filip, I’m a bit confused on how value calls work. I would appreciate it if you could type a brief explanation or send an article. :grinning:

Hi @Adrian1,

I would suggest looking at this post, which first gives a detailed explanation of what the transfer() function itself is actually doing (point 1), and then goes on to explain how the external value call works within the context of the transfer() function’s operations (point 2). I think looking at this wider picture first will help you to identify what it is you have been missing, or have misunderstood, and is causing your confusion.

Then have a look at this post, which repeats some of the information in the first post, but also goes into detail about the different ways we can code the actual ETH value being transferred from one contract to another — using unsigned integers with or without the suffixes ether, gwei or wei; or by referencing an unsigned-integer value stored in a variable. This could help clear up any confusion relating to this particular aspect of the value call.

You can then let me know if there is still something specific that you don’t understand, and I’ll help you out with that :slight_smile:

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.