Nice solution @Jackthelad 
Just a couple of observations …
(1) You don’t need to include the require() statement in the terminate() function …
… because this exact same require statement is already within the inherited onlyOwner modifier, which has also been correctly applied to terminate(). So you are currently applying this same condition twice to the same function.
(2) This may just be a result of you mixing up different versions you’ve tried …
Implementing a multi-level inheritance structure is the best approach, because it is more streamlined. Bank only needs to explicitly inherit Destroyable, because it will implicitly inherit Ownable via Destroyable. However …
-
you have named the file containing your Destroyable contract Terminate.sol
, but you’re importing Destroyable.sol
which doesn’t exist in the code you’ve posted;
-
if Bank only inherits Destroyable, you don’t need to import Ownable.sol
as well.
You can use either, as long as it is passed to selfdestruct() as a payable address type. This is so that the contract’s remaining ether balance can be transferred to that address when the contract is destroyed. To receive ether an address must be payable. Some of the alternative ways to code this are:
(1) Use msg.sender
(as you have done) to reference the contract owner’s address, because this is the only address that it can ever represent in your terminate() function, as a result of the onlyOwner modifier restricting who can call this function in the first place. Prior to Solidity v.0.8, msg.sender
is payable
by default, and so that’s why you haven’t needed to explicitly convert it in your solution (this course is based on v0.7.5).
However, from v.0.8, msg.sender
is non-payable by default, and so whenever you are using v.0.8 and need to use msg.sender
as a payable address, this requires an explicit conversion e.g.
selfdestruct(payable(msg.sender));
(2) Use owner
to reference the contract owner’s address. To be able to do this, you also need to do either of the following:
-
Declare the owner
state variable in Ownable with a payable address type, instead of with the default, non-payable address type;
-
If you only need the contract owner’s address to be payable for the purposes of executing selfdestruct(), you can leave the owner
state variable as non-payable, and explicitly convert the address to payable locally, within the function where you actually need to use it as payable. You can even do this directly within the selfdestruct() function call itself, as follows:
function terminate() public onlyOwner {
selfdestruct(payable(owner));
}
Let me know if anything is unclear, or if you have any further questions 