Hi @Davelopa,
This is a very well-presented solution which works and meets all of the main assignment objectives
Your implementation of 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.
A few comments …
(1) As the constructor initialises the _owner
state variable in Ownable, it is better to place it in Ownable as well.
By placing all of the code and functionality related to contract ownership within a single, separate contract (Ownable), you will improve the modularity of your code (one important reason for using inheritance) and will keep your code more organised.
It will also reduce any potential code duplication in the event that Ownable is re-used and inherited by other derived contracts, because the constructor won’t then have to be repeated in each derived contract for Ownable to work as it should. Reducing code duplication and increasing code re-usability are other important reasons for using inheritance.
(2) Your selfdestructed
event is certainly a good idea but, after calling close() and destroying the contract, if you check the transaction receipt you will notice that the event data you intended to emit hasn’t been logged. You are right that an emit statement should be placed after the code associated with the event itself, in order to minimise the risk of the event being emitted erroneously. However, in this case, if your emit statement is placed after the call to selfdestruct(), it will never be reached, because the contract will have been destroyed, and its code removed from the blockchain, once selfdestruct() has executed.
You could fix this by placing the emit statement before the selfdestruct() function call, but I don’t think this is wise, because we would be emitting the event before the actual event itself (contract destruction) has occurred. On the other hand, if selfdestruct() failed, then the function would revert, including the emitted event, but I would still be reluctant to place the emit statement first, for the reasons I’ve mentioned above in terms of reducing risk.
The reason why I say that emitting an event is a good idea (at least in theory) is because of a serious drawback of using the selfdestruct() function, the potential repercussions of which need to be fully understood before choosing to implement it. As you may, or may not, already have realised, after selfdestruct() has been executed, successful calls can still be made to the destroyed contract’s functions! As a result of this, if a smart contract deployed on the mainnet is ever destroyed, all users need to be notified and informed that they must not send any more funds to that contract address. If a user doesn’t know that the contract has been destroyed, and goes ahead and sends funds to it (e.g. by calling the deposit function), then those funds will be lost. You can see this for yourself by calling deposit() with an ether value. Remix will notify you that the transaction has been successful, and you will see the ether amount has been deducted from the external address balance. But if you add a function that gets the ether contract balance and call that (not the getBalance function), you will see that the contract has a zero balance!
It’s worth bearing in mind that emitting an event doesn’t necessarily mean that users will see that infomation, and so doesn’t actually prevent them from subsequently calling the destroyed contract’s functions, incurring a gas cost, and losing any ether sent. There would still need to be some form of communication to all users informing them of the contract’s destruction, and what the consequences and implications of this are in terms of what they must and mustn’t do from now on.
This is obviously hardly an ideal situation! In practice, other types of security mechanisms, such as pausable or proxy contracts, are implemented to deal with these kinds of emergency situations. But this is out of the scope of this introductory course. You will learn about more advanced security techniques and practices if you go on to take the Ethereum Smart Contract Security Course.
Let me know if you have any questions