import "./ownable.sol"
contract destroyable is ownable {
function SelfDestruct() public OnlyOwner {
selfdestruct(owner);
}
}
Thanks Jon, yes, this makes sense. I will try to revise this exercise or maybe just do what was intended with the bank contract but it is very good feedback. I appreciate it.
Ownable.sol code //Parent of Destroyable.sol
pragma solidity 0.7.5;
contract Ownable {
address public owner;
modifier onlyOwner {
require(msg.sender == owner);
_;
}
constructor(){
owner = msg.sender;
}
}
Destroyable.sol code //Parent of Bank.sol
pragma solidity 0.7.5;
import "./Ownable.sol"; // an important code to access Ownable.sol
contract Destroyable is Ownable { // an important code to access Ownable.sol
function destroy() public onlyOwner {
selfdestruct(msg.sender);
}
}
Bank.sol code //inherits both Ownable.sol and Destroyable.sol
pragma solidity 0.7.5;
import "./Destroyable.sol"; // an important code to access both Ownable.sol and Destroyable.sol
contract Bank is Destroyable { // an important code to access both Ownable.sol and Destroyable.sol
...
}
Short explanation of my answer:
This inheritance assignment is an example of a multi-level inheritance wherein Ownable.sol is the parent of Destroyable.sol and Destroyable.sol is the parent of Bank.sol. By virtue of multi-level inheritance, Bank.sol can access both Ownable and Destroyable contract.
P.S. You can check the diagram above made by @evasilev to understand further.
This is a good diagram man!
I believe the solution could be,
pragma solidity 0.7.5;
import â./Ownable.solâ;
contract Destroyable is Ownable {
function close() public onlyOwner {
selfdestruct(owner);
}
}
Where Ownable.sol includes the code from the bank code example,
contract Ownable {
address public owner;
modifier onlyOwner{
require(msg.sender == owner);
_; //needed, it means run the function
}
constructor(){
owner = msg.sender;
}
}
Assuming that all the contracts located in the same folder, the code might be like that:
pragma solidity 0.7.5;
contract Ownable{
address payable owner;
constructor(){owner = msg.sender;}
modifier onlyOwner{require (msg.sender==owner);_;}
}
pragma solidity 0.7.5;
import "./Ownable.sol";
contract Destroyable is Ownable{
function close() public onlyOwner {
// I should have specified the owner parameter:
// address payable owner = msg.sender;
selfdestruct(owner);}
}
pragma solidity 0.7.5;
import "./Destroyable.sol";
contract HelloWorld is Destroyable{....}
Hi @makinitnow,
The onlyOwner modifier (inherited from Ownable) restricts who can call a function (with onlyOwner in the header) to the owner of the contract. In our example, the owner of the contract is set using the constructor (also inherited from Ownable) to the address which initially deploys the contract. By placing the onlyOwner restriction on the selfdestruct function (inherited from Destroyable) only the contract owner (its deployer) can destroy it. This isnât an unusual feature to find in smart contracts, because if we wanted to include the option for the contract to be destroyed (for risk management reasons, for example) then it makes sense that the ability to initiate this would be restricted to just one authorised individual or group of individuals.
pragma solidity 0.7.5;
import â./Ownableâ;
contract Destroyable is Ownable{
function close () public Ownable{
selfdestruct(owner);
}
}
just as quick question, lets say we wanted to use the functionality in the parent destroyable contract within the child bank contract, how would we do that? the modifier onlyOwner is inherited from Ownable and used in the function headers. But how would we trigger the function in destroyable? would we create a public function in Bank that has the onlyOwner modifier and uses a function instance of Destroy(). Can you give an example please?
Or is the destroy function available for the owner to click/invoke once the contract is deployed therefore unnecessary to reference it in Bank?
Hi @Bdos87
In order to access the close function(or selfdestruct) from bank contract, Back contract has to inherits to destroyable contract. it will be like this Back contract -> Destroyable contract -> Ownable contract and other way we can just created the close function inside the Bank contract we dont need to inherits the destroyable function, Because selfdestruct is available to any contract is build-in function.
Happy learning
Abel
Destroyable.sol:
pragma solidity 0.7.5;
import "./Ownable.sol";
contract Destroyable is Ownable {
function close() public onlyOwner {
selfdestruct(msg.sender);
}
}```
Also, in Bank.sol make sure it inherits from Destroyable, i.e:
contract Bank is Destroyable { ...
Ownable.sol:
pragma solidity 0.7.5;
contract Ownable {
address payable public owner;
modifier onlyOwner {
require(msg.sender == owner);
_;
}
constructor(){
owner = msg.sender;
}
}
Destroyable.sol:
pragma solidity 0.7.5;
import "./Ownable.sol";
contract Destroyable is Ownable{
// delete the deployed contract
function close() public onlyOwner {
selfdestruct(owner);
}
}
selfDestrucr.sol
pragma solidity 0.7.5;
import "./ownable.sol";
contract Destroyable is Ownable {
function close() public onlyOwner { //onlyOwner is custom modifier
selfdestruct(msg.sender); // `owner` is the owners address
}
}
and in Helloworld.sol
import "./selfDestruct.sol";
contract BankOfNico is Ownable, Destroyable
pragma solidity 0.7.5;
import âOwnable.solâ;
contract Destroyable is Ownable {
function removeContract() public onlyOwner {
selfdestruct(msg.sender);
}
}
/* to use
import âDestroyable.solâ;
contract HelloWorld is Destroyable{
}
*/
Here is an example of Destroyable base contract that allows the Bank contract to be destroyed, provided the caller is the owner.
It seems to work but I am a bit confused because Remix allows me to call âdestroyâ more than once. The second call does not fail but has a transaction cost of zero.
pragma solidity 0.7.5;
contract Destroyable{
address payable owner;
constructor(){
owner = msg.sender;
}
function destroy() public {
require( msg.sender == owner, "Only the owner can destroy this contract");
selfdestruct(owner);
}
}
contract Bank is Destroyable{
mapping(address => uint) balance;
event depositDone(uint amount, address indexed depositedTo);
modifier onlyOwner {
require(msg.sender == owner);
_;
}
function deposit() public payable returns(uint) {
balance[msg.sender] += msg.value;
emit depositDone(msg.value, msg.sender);
return balance[msg.sender];
}
function withdraw(uint amount) public returns (uint){
require(balance[msg.sender] >= amount, "balance not sufficient");
msg.sender.transfer(amount);
balance[msg.sender] -= amount;
return balance[msg.sender];
}
function getBalance() public view returns (uint){
return balance[msg.sender];
}
}
This is my solution to the problem. I changed the main smart contract to âis Destroyableâ. I noticed that I got an error at the input of selfdestruct(owner)⌠I thought the variable owner is accessible, since it is public, but I noticed from the way others solved this, that I have to put msg.sender. Could you explain why is this? Since Iâve made the Destroyable contract âis Ownableâ, shouldnât it by rule of inheritance know what the variable âownerâ is? Thank you very much, for the answer.
contract Ownable {
address public owner;
modifier onlyOwner {
require(msg.sender == owner);
_;
}
constructor(){
owner = msg.sender;
}
}
contract Destroyable is Ownable {
function destroyContract() public onlyOwner {
selfdestruct(owner);
}
}
Hi @codinginlondon,
Good question! Your contract does work, but you are correct that even after the contract has been destroyed, the destroy function can still be called. In fact any of the other functions can also still be called, and gas will be consumed. However, the smart contract is inoperable and even though the functions can still be invoked they wonât have any effect (other than consuming gas). But the fact that users are not made aware that the smart contract has been destroyed, and can still make function calls that consume gas, is obviously a disadvantage with using selfdestruct. This is why selfdestruct is only meant to be invoked in extreme circumstances e.g. to retrieve funds held in the contract in the event of an attack, as a form of damage limitation. One way in which this disadvantage with selfdestruct() can be avoided is by adding code that will divert control of the contract in the event of selfdestruct being invoked.
One way in which your contract can be improved is to move the onlyOwner modifier from the derived contract to the parent contract. That way it can be used to restrict access to selfdestruct() in the parent contract, while still being available via inheritance in the derived contract, if needed. This avoids code duplication and the need to repeat the same require statement in both the modifier and the destroy function.
Also, have a look at this post which explains an important security modification that should be made to the order of the statements within your withdraw function body.
Hi @ZigaP,
Good question! You are correct that as the state variable owner has public visibility it is inherited and accessible in the derived contract Destroyable. However the reason you are getting the error is not because of this.
The address argument passed to selfdestruct() is where the contractâs ETH balance is transferred to on destruction (so these funds arenât lost). Because this address is used to receive a payment, it needs to be a payable address.
Addresses can be stored in variables as either payable, or non-payable. Unless we specifically mark them as payable, then they are non-payable by default. However, when msg.sender
is used directly as a value (and not first assigned to a variable), it is treated as a payable address by default in Solidity, so thatâs why âselfdestruct(msg.sender)
â works without having to add anything further or make any additional modifications. If you do the same with owner
the compiler will give you an error, because you currently have it defined as a non-payable address in contract Ownable:
address public owner;
You can still use owner
but you will need to also define it as a payable address by explicity adding the payable keyword:
address payable public owner;
If you make this modification to the owner state variable definition in Ownable, then selfdestruct(owner);
will work.
Another alternative is to leave the owner state variable definition as non-payable, and convert it to a payable address directly within the selfdestruct function call in contract Destroyable:
selfdestruct(payable(owner));
I hope that makes sense now, but do let us know if you have any further questions
I got it to work!..
3 files, 1 The contract to be destroy, 2 The Ownable, 3 The Destroyable
- Code for the Contract to be DestroyedâŚ
pragma solidity 0.7.5;
import â./Ownable.solâ;
import â./Destroyable.solâ;
contract Bank is Ownable, Destroyable {
mapping(address => uint) Balance;
function addBalance(uint _ToAdd) public onlyowner returns(uint){âŚ}
}
-
Ownable fileâŚ
pragma solidity 0.7.5;
contract Ownable {
address owner;
modifier onlyowner {
require(msg.sender == owner, âonly owner can run this functionâŚâ);
_;
}
//We use constructor to initialize variablesâŚ
constructor(){
owner = msg.sender;
}
} -
The Destroyable contractâŚ
pragma solidity 0.7.5;
import â./Ownable.solâ;
contract Destroyable is Ownable {
function close() public onlyowner{
selfdestruct(msg.sender)
}
}