Inheritance & External Contracts - Discussion

Thank you very much for your help, Jon. I assumed I understood your remarks, but it seems that I didn’t and I don’t know why. I am sorry, but could you please help me again? I followed your steps and I still get the revert error. Please see below the steps I made.

  1. I changed the address for the GovernmentInterface with a new one, but didn’t deploy the Etherbank contract yet:
GovernmentInterface GovernmentInstance = GovernmentInterface(0x617F2E2fD72FD9D5503197092aC168c91465E7f2);
  1. I went into the Government contract and deployed it with the address 0x617F2E2fD72FD9D5503197092aC168c91465E7f2

  2. Now I deployed Etherbank contract with the address 0x5B38Da6a701c568545dCfcB03FcB875f56beddC4

  3. I deposited 2 ether with the address 0x5B38Da6a701c568545dCfcB03FcB875f56beddC4, got the ballance 2000000000000000000.

  4. Try to transfer 1000000000000000000 from the address 0x5B38Da6a701c568545dCfcB03FcB875f56beddC4 to address 0xAb8483F64d9C6d1EcF9b849Ae677dD3315835cb2.

  5. Got the error:

transact to Bank.transfer errored: VM error: 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.

Hey Cosmin,

You’ve got confused between external wallet addresses (user/deployer addresses) and contract addresses. The address that deploys the contract is not the same as the address the contract is then deployed at.


(1)

Do this first.
0x617…7f2 is the external address of the contract deployer.

(2) To get the contract address (the address it’s deployed at), go to the bottom of the Deploy & Run Transactions panel to the deployed contract, where it will say   GOVERNMENT AT   and then the address the Government contract is now deployed at. This is the address you need to copy and paste (use the icon to the right of the address) into your governmentInstance declaration in Bank …

To create an instance of the Government interface, we need to declare where the contract (on which the interface is based) is deployed at. Otherwise, an external function call can’t be made to it. At the moment, your Bank contract is trying to call a function on the deployer’s external address which doesn’t exist.


(3) Continue with your steps 3 and 4

(4) And your step 5 will now work, without throwing the error :raised_hands:

(5) You can now call getTransaction() in Government with a transaction ID of 0, and retrieve the transaction data from the transaction log in Government.


Just let me know if you still have problems getting this to work.

1 Like

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