Hi @Jimmyjim,
Your coding of the inheritance structure is good, but there are still several issues remainingâŚ
(1)
You now have the owner variable declared twice â once in Ownable and again in Destroy. This throws a compiler error, and if you look at the error message it will tell you what the problem is. This error makes it impossible to deploy the Bank contract. Did you not try to do this, and find that you couldnât?
The whole point of inheritance is that functions and state variables with either public or internal visibility in the base contract (Ownable) are available in the derived contract (Destroy). So you only need to declare the owner state variable once in Ownable, and as payable. It will be inherited if it has either public or internal visibility. State variables have internal visibility by default, which means they will have internal visibility if you donât explicity state the visibility.
(2)
Once you modify your code for section 1, your code will now compile, and you will be able to deploy Bank. But any address can now call your close() function and trigger selfdestruct(). This is obviously not very secure! And thatâs why the assignment instructions ask you to restrict access to this function, so that only the contract owner can trigger selfdestruct().
No⌠who can or canât call a function will be determined by any restrictions defined in require statements, either within the function body, or applied using a modifier. The purpose of Ownable is to:
- set and store the deployerâs address as the contract owner;
- define an onlyOwner modifier that restricts access (to any function it modifies) to the contract ownerâs address.
So you prevent anyone other than the contract owner from calling close() and triggering selfdestruct(), by applying the onlyOwner modifier to that function. All modifiers in a base contract are inherited by the derived contract, so the onlyOwner modifier in Ownable is available to apply to close() in Destroy.
As well as anyone being able to call close() and destroy the contract, the other problem you will have before making the modification discussed in this section, is that the remaining funds in the contract will not be transferred anywhere when the contract is destroyed, and will be lost. The reason for this is explained in section 3.
(3)
But after modifying your code for section 2, no one will now be able to call your close() function. This is because your constructor has disappeared from Ownable. It is the constructor that assigns the deployerâs address to the owner variable (and therefore sets the contract owner) when the Bank contract is deployed. This happens when Bank is deployed because Bank inherits Ownable.
No constructor means no contract owner address.
No contract owner address means the modifierâs require statement will always fail.
And if the modifierâs require statement always fails, itâs impossible for the close() function to execute and call selfdestruct().
The owner state variable not having an address assigned to it, is also the reason why the remaining funds in the contract were not sent anywhere, and were lost, when anyone could call the close() function.
Once youâve fixed all of these issues, you can check that everything is working as it should by deploying Bank, performing some transactions, then ensuring that only the contract owner address can call close() and destroy the Bank contract and, finally, that the remaining ether balance is transferred to the contract ownerâs external wallet address â you should see their ether balance increase by that amount.
No⌠because if you make close() internal, it will be inherited by Bank, but will only be accessible from within the Bank and the Destroy contracts, and not externally. This means that the contract owner will not be able to call close() to destroy the contract using their own external wallet address (the external address that deployed the Bank contract in the first place).
Let me know if anything is still unclear, and if you have any further questions 