contract Destroyable is Ownable{
function close() public onlyOwner { //onlyOwner is custom modifier
selfdestruct(msg.sender); // `owner` is the owners address
}
}
contract Destroyable is Ownable{
function close() public onlyOwner { //onlyOwner is custom modifier
selfdestruct(msg.sender); // `owner` is the owners address
}
}
I decided to instead add the destroy function to the Owner class as I believe it be best practice to always have the option to destroy the contract for whatever reason, therefore it will not be possible to forget to include it.
event contractDestroyed(address destroyer);
function destroy() public _onlyOwner {
emit contractDestroyed(msg.sender);
selfdestruct(msg.sender);
}
In HelloWorld.sol contract, just first lines
pragma solidity 0.5.12;
import './Destroyable.sol';
contract HelloWorld1 is Destroyable {
In Destroyable.sol contract
pragma solidity ^0.5.1;
import "./Ownable.sol";
contract Destroyable is Ownable {
function destroy() public onlyOwner { //onlyOwner is custom modifier
selfdestruct(owner);
}
}
In Ownable.sol contract
pragma solidity ^0.5.1;
contract Ownable{
address payable public owner;
constructor() public{
owner = msg.sender;
}
modifier onlyOwner(){
require(msg.sender==owner, 'You are not the owner');
_;
}
}
Note: in Ownable.sol, payable option is added since selfdestruct(),
sends the remaining balance of the contract to owner.
HelloWorld.sol:
import "./Ownable.sol";
import "./Destroyable.sol";
pragma solidity 0.5.12;
contract HelloWorld is Ownable, Destroyable {
Ownable.sol:
pragma solidity 0.5.12;
contract Ownable{
address payable public owner;
constructor() public{
owner = msg.sender;
}
modifier onlyOwner(){
require(msg.sender == owner);
_;
}
Destroyable.sol:
import "./Ownable.sol";
pragma solidity 0.5.12;
contract Destroyable is Ownable {
function destroy() public onlyOwner {
selfdestruct(owner);
}
}
pragma solidity 0.5.12;
import â./Ownable.solâ;
contract Destroyable is Ownable {
function destroy() public onlyOwner {
selfdestruct(address(uint160(owner)));
}
}
contract Destroy {
address payable private ownerAddress;
constructor () public {
ownerAddress = msg.sender;
}
modifier isOwner() {
require (msg.sender == ownerAddress);
_;
}
function close() public isOwner {
selfdestruct(ownerAddress);
}
}
then import into base contract and call close. Can also derive âOwnerâ functions from owner contract if applicable.
In Helloworld.sol:
import â./Ownable.solâ;
import â./Tearable.solâ;
pragma solidity 0.5.12;
contract Structobject is Ownable, Tearable{âŚ}
In Tearable.sol:
import â./Ownable.solâ;
pragma solidity 0.5.12;
contract Tearable is Ownable{
function tearContract() public onlyOwner {
selfdestruct(address(uint160(owner)));
}
}
import â./Ownable.solâ;
pragma solidity 0.5.12;
contract Destroyable is Ownable {
function close() public onlyOwner {
address payable deadOwner = address(uint160(owner));
selfdestruct(deadOwner);
}
}
pragma solidity 0.5.12;
contract Destroyable{
address public owner;
modifier onlyOwner(){
require(msg.sender == owner);
_; //Continue execution
function close() public onlyOwner{
selfdestruct(owner);
}
}
import "./Ownable.sol";
pragma solidity 0.5.12;
contract Destroyable is Ownable{
function destroyContract() public onlyOwner{
selfdestruct(msg.sender);
}
}
Also added this to HelloWorld:
import "./Ownable.sol";
import "./Destroyable.sol";
pragma solidity 0.5.12;
contract HelloWorld is Ownable , Destroyable{
....
Why do we want to do the payable part?
address payable receiver = msg.sender;
and not just :
selfdestruct(msg.sender);
@elterremoto
Thanks for reaching out!
payable
keyword is necessary to enable an address receive ETH.
Hence, once the address can receive or send ETH, we can call selfdestruct(msg.sender)
to transfer all ETH from the contract.
A brief info about selfdestruct()
:
Selfdestructs in Ethereum are an operation (an OPCODE actually) at the EVM level, independent of what language or client you are using.
For example, calling selfdestruct(address)
sends all of the contractâs current balance to address
.
This is useful when you are finished with a contract, because it costs far less gas than just sending the balance with address.send(this.balance)
.
In fact, the SELFDESTRUCT opcode uses negative gas because the operation frees up space on the blockchain by clearing all of the contractâs data.
This negative gas deducts from the total gas cost of the transaction, so if youâre doing some clean-up operations first, SELFDESTRUCT can reduce your gas costs.
Here it is, for some reason it isnât letting me add spaces in the reply.
import â./Ownable.solâ;
pragma solidity 0.5.12;
contract Destroyable is Ownable
{
function destroy(address) public onlyOwner
{
selfdestruct(msg.sender);
}
}
Hi @elterremoto,
Youâve asked a good question, and I just wanted to add to the reply @Taha has already sent you.
Thatâs correct, but the selfdestruct function sends the contractâs ETH balance to the ownerâs address, and, as Taha says, it must be a payable address to enable that to happen.
However, by default, msg.sender
is already a payable address, and so this is why we donât actually need the additional line of code:
address payable receiver = msg.sender;
and why we can just use:
selfdestruct(msg.sender);
Maybe this is what was confusing you. The reason why Filip includes the additional step in the video is discussed and explained in this post. However, the conclusion is that it isnât necessary.
I hope this clarifies things further for you
Hi @LTL
This is correct, except that your destroy function doesnât need an address parameter. By default, msg.sender
is always accessible within a function body, and it references the address which invokes the function as a payable address.
By the way, what amendments did you have to make to contract HelloWorld in terms of its inheritance?
If you mean spaces within your code, you may solve this by formatting your code before posting it here in the forum. Click on the </> icon in the menu at the top of this forumâs text editor. This will give you 2 sets of 3 back ticks.
```
input your code here
```
If you now input your code between these, you will end up with it nicely formatted. You should always format the code you post, as it is then much clearer and easier to read, and easier for someone else to copy and paste into a text editor for review and execution. It also makes it easier for you to organise your code with the correct spacing and indentation etc. and to spot any errors or copy-and-paste slips. By formatting it in this way, your code should end up looking something like this:
import "./Ownable.sol";
pragma solidity 0.5.12;
contract Destroyable is Ownable {
function destroy() public onlyOwner {
selfdestruct(msg.sender);
}
}
Inheriting Destroyable
from Ownable
--> Only allowing to destroy what you own and balance will be paid to owner.
contract Destroyable is Ownable {
function destroyContract() public onlyOwner {
selfdestruct(address(uint160(owner)));
}
}
Inheriting from Destroyable
, HelloWorld
will get Ownable
functionality as well as the destroyContract
function.
contract HelloWorld is Destroyable{
// no other changes for destroyable functionality
}
@filip
Question on your solution: The msg.sender
is the owner, but it is only implied by onlyOwner
doing its job flawlessly. It should work and I do not see how to âhackâ to steal funds, but just in case would it not be a notch safer to use owner
in Ownable
as receiver instead? Or does it open up other weakness? (Yes, I still have the Ethereum Security course ahead of me )
function destroy() public onlyOwner {
address payable receiver = owner;
selfdestruct(receiver);
}
I created a file called Destroyable.sol which contains this:
import "./Ownable.sol";
pragma solidity 0.5.12;
contract Destroyable is Ownable {
function close() public onlyOwner {
selfdestruct(msg.sender);
}
}
And the top of HelloWorld.sol now looks like this:
import "./Ownable.sol";
import "./Destroyable.sol";
pragma solidity 0.5.12;
contract HelloWorld is Ownable, Destroyable{
After posting that I realized that this is enough:
import "./Destroyable.sol";
pragma solidity 0.5.12;
contract HelloWorld is Destroyable{
as Destroyable already inherits Ownable.
It is anyway good to keep code short, but would it also save gas?
import â./Ownable.solâ;
pragma solidity 0.5.12;
contract Destroyable is Ownable{
function close() public onlyOwner {
selfdestruct(msg.sender);
}
}
import â./Ownable.solâ;
import â./Destroyable.solâ;
pragma solidity 0.5.12;
contract HelloWorld is Ownable, Destroyable{