import "./Ownable.sol";
pragma solidity 0.5.12;
contract Destroyable is Ownable{
function destroy() public onlyOwner {
selfdestruct(msg.sender);
}
}
import "./Ownable.sol";
import "./Destroyable.sol";
pragma solidity 0.5.12; //quelle version utiliser
contract HelloWorld is Ownable, Destroyable{
...
}
Why can`t I use owner instead of msg.sender? I had to peak a little!
import â./Ownable.solâ;
pragma solidity 0.5.12;
contract Destroyable is Ownable{
function close() public onlyOwner{
selfdestruct(msg.sender);
}
}
import "./Ownable.sol";
pragma solidity 0.5.12;
contract Destroyable is Ownable {
function destroycontract() public onlyOwner {
selfdestruct(msg.sender);
}
}
import â./Ownable.solâ;
pragma solidity 0.5.12;
contract Destroyble is Ownable {
function destroy() public onlyOwner{
selfdestruct (msg.sender);
}
}
// No change to Ownable.sol
// New file Destroyable.sol containing new parent contract
pragma solidity 0.5.12;
contract Destroyable {
function transferAndDestroy() internal {
selfdestruct(msg.sender); // see note below
}
}
// Additions to child contract
import "./Ownable.sol";
import "./Destroyable.sol";
pragma solidity 0.5.12;
contract HelloWorld is Ownable, Destroyable {
// Rest of contract remains the same, except for following additional function
function close() public onlyOwner {
transferAndDestroy();
}
}
Note âââ msg.sender
âused instead ofâowner
This simplifies the code. Ifâselfdestruct(owner)
âwere used instead, we would also need to modify the following:
-
â
Destroyable
âinherits fromâOwnable
-
Change the state variableâ
owner
âinâOwnable
âfrom a non-payable address type to a payable address type, by adding the keywordâpayable
: âaddress payable public owner;
Having now watched the solution video, Iâve learnt that it isnât necessary to include another function in the child contract to call the inherited function (fromâcontract Destroyable
)âfrom an external service such as Remix, as long as the inherited function is defined withâpublic
â(instead ofâinternal
)âvisibility, and is also restricted toâonlyOwner
, within the parent contract itself. This also requires the function to gain access to theâonlyOwner
âmodifier by importingâOwnable.sol
âintoâDestroyable.sol
and making the following modification so that âcontract Destroyable
â inherits âcontract Ownable
contract Destroyable is Ownable { ... }
As a result of the following comment from @ivga80, Iâve also learnt that if âcontract Destroyable
â inherits âcontract Ownable
â, then we can remove the code from âcontract HelloWorld
â that explicity inherits âcontract Ownable
â. This is becauseâHelloWorld
âalready inherits fromâDestroyable
,âand so now indirectly inheritsâOwnable
âviaâDestroyable
.
But the solution video left me with one question:
Why is it necessary to assignâmsg.sender
â(the ownerâs address) to a local variable (receiver
) with a payable-address type, and then passâreceiver
âtoâselfdestruct()
âas its parameter? Canât this be made more concise and simpler by just passingâmsg.sender
âdirectly?
ââi.e â selfdestruct(msg.sender);
Having looked at some of the other solutions posted, I can see that the more concise âselfdestruct(msg.sender);
âhas been widely used. I then found that this point has already been raised and answered in some posts from @Guy and @filip at the beginning of this topic. Iâll link to the discussion here via some quotes, in case others have the same question, but wouldnât otherwise see the relevant posts:
I think the points made in these posts are really helpful
The problem is thatâowner
âhas already been defined in âcontract Ownable
â as a non-payable address type. So, if you used it instead, you would also need to do something like one of the following:
- Change the actual definition of the state variableâ
owner
âin âcontract Ownable
â from a non-payable address type to a payable address type, by adding the keywordâpayable
âi.e.âaddress payable public owner;
â â or
- Convert the inherited state variableâ
owner
â(from a non-payable address type to a payable address type) within âcontract Destroyable
â e.g.
or
function close() public onlyOwner {
address payable receiver = address(uint160(owner));
selfdestruct(receiver);
}
Thank you for the help!
Iâm confused by this. How can we use a non-payable address as a parameter of âselfdestruct()
âif, like @pedromndias also says, the compiler throws an error suggesting the address should be payable?
Do you maybe mean that we could convert a non-payable address into a payable one, locally, just for the purposes ofâselfdestruct()
â?âe.g.
Also, when would you want to send ETH to a contract which isnât supposed to receive it?
It depends on your compiler version
pragma solidity 0.4.18;
contract suce{
function suce() payable{
}
function sucide() public {
address receiver = 0x56f8b4cC2402Fa214a2C2406AD1DEf48f84408Ac;
selfdestruct(receiver);
}
}
To âpentestâ them, by sending funds you ll be able to change the balance of the contract and sometime you are not allow to.
https://ethernaut.openzeppelin.com/level/0x24d661beb31b85a7d775272d7841f80e662c283b
If you can access a contract which is the owner of an other contract (an erc20) you will be able to mint token for example.
I use this trick to mint dai on a custom forked main net
Changes in HelloWorld contract:
import "./Ownable.sol";
import "./Destroyable.sol";
pragma solidity 0.5.12;
contract Inheritance is Ownable, Destroyable {
New Destroyable Contract:
import "./Ownable.sol";
pragma solidity 0.5.12;
contract Destroyable is Ownable {
function close() public onlyOwner {
selfdestruct(owner);
}
}
Small change in Ownable:
address payable public owner;
There are three contracts.
- the HelloWorld contract, child of Ownable conract and of Destroyable contract:
import "./destroyable.sol";
import "./ownable.sol";
pragma solidity 0.5.12;
contract HelloWorld is Ownable, Destroyable{
- the Destroyable contract, child of Ownable contract:
pragma solidity 0.5.12;
import "./ownable.sol";
contract Destroyable is Ownable {
function close() public onlyOwner {
selfdestruct(msg.sender);
}
}
- the Ownable parent contract:
pragma solidity 0.5.12;
contract Ownable {
address public owner;
modifier onlyOwner(){
require(msg.sender == owner);
_;
}
}
In this assignment there is a multi-level inheritance:
Contract A => Ownable
pragma solidity 0.5.12;
contract Ownable{
address payable public owner;
modifier onlyOwner(){
require (msg.sender == owner);
_;
}
constructor() public{
owner = msg.sender;
}
}
Contract B => Destroyable
import "./07Ownable.sol";
pragma solidity 0.5.12;
contract Destroyable is Ownable{
function close() public onlyOwner{ //onlyOwner is custom modifier
selfdestruct(owner); //owner is the owners address
}
}
Contract C => HelloWorld
import "./08Destroyable.sol";
pragma solidity 0.5.12;
contract HelloWorld is Destroyable{
struct Car{
string model;
uint year;
}
............
The new contract code is as follows:
import "./Ownable.sol";
pragma solidity 0.6.6;
contract Destroyable is Ownable{
function destroy() public onlyOwner { //onlyOwner is custom modifier
selfdestruct(owner); // `owner` is the owners address
}
}
And in the HelloWorld contract we just need to add the following to the contract header:
import "./Ownable.sol";
import "./Destroyable.sol";
pragma solidity 0.6.6;
contract HelloWorld is Ownable, Destroyable{
// All logic goes here
}
Oh and the owner address must be payable in order to get the funds back!!
@filip I got confused after watching your solution video. For testing if the contract was destroyed and the money sent back to the owner, I used the function âcreatePersonâ sending 1 ETH. After destroying the contract money was sent back but i could run the functions to see the values empty (as shown in the image below) but in your case you receive an error because contract is deleted. Does this mean that my contract is not deleted?
Hi @Maikimais
When a value doesnât exist in solidity it shows 0 or ââ or false, it depends on the type.
You are using a more modern version of remix than in the video, so itâs normal before remix was sending back an error
You will see in the detail of your transaction that the execution cost is 0.
Thanks for your reply gabba!
Thatâs what I thought, also while following the next video I had to modify some syntax because the one that Filip uses was deprecated. But wanted to be sure!
Thanks again! ^^
import "./Ownable.sol";
pragma solidity 0.5.12;
contract Destroyable is Ownable {
function close() public onlyOwner {
selfdestruct(address(uint160(owner))); //can also be msg.sender
}
}
Then you just inherit from Owner and Destroyable in the createPerson contract and you get access to the close() function once you deploy the contract.
It will send the balance from smart contract to the owner address and clear contract data.
Any full node storing just the current state no longer needs to store that code. Full archive nodes still store it for things like block explorers.
import â./Ownable.solâ
pragma solidity 0.5.12;
contract Destroyable is Ownable {
function close() public onlyOwner { //onlyOwner is custom modifier
selfdestruct( msg.sender);
}
}
import"./Ownable.sol";
pragma solidity 0.5.12;
contract Destroyable is Ownable {
function close() public onlyOwner {
selfdestruct(msg.sender);
}
}
// Import Destroyable in the HelloWorld contract