I read in many places that selfdestruct can remove the contract bytecode on a blockchain and effectively nullifiy the functionalities on a contract at a given address, but I did some hands on tests and found out executing selfdestruct does nothing to a contract except moving the fund in that contract to a designated address. This happens in both a direct call and a delegatecall. See examples below. The contract bytecode length remains unchanged after calling selfdestruct. Wondering why this is the case and if I am missing or misunderstanding anything. Thanks.
contract Target {
address public target;
uint256 public val;
function doIt() external {
val = block.timestamp;
selfdestruct(payable(msg.sender));
}
function getTimestamp() external view returns (uint256) {
return block.timestamp;
}
}
contract TestSelfDestruct {
address public target;
uint256 public val;
constructor(address _target) {
target = _target;
}
function setVal(uint256 _val) external {
val = _val;
}
function getBalance() external view returns (uint256) {
return address(this).balance;
}
function doIt() external {
bytes memory data = abi.encodeWithSignature("doIt()");
(bool success, ) = target.delegatecall(data);
require(success);
}
}
Thanks for this. This is what I thought. But I did get different results running tests in Foundry. Could this be an issue on the foundry side? Appreciate any help on proof running the script below:
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;
import "forge-std/Test.sol";
contract SimpleStorageTest is Test {
SimpleStorage test;
function setUp() public {
test = new SimpleStorage();
test.store(100);
}
function testSelfDestruct() public {
assertEq(test.retrieve(), 100);
test.close();
test.store(110);
assertEq(test.retrieve(), 110);
}
}
contract SimpleStorage {
address private owner;
uint256 number;
constructor() {
owner = msg.sender;
}
function store(uint256 num) public {
number = num;
}
function retrieve() public view returns (uint256){
return number;
}
function close() public {
selfdestruct(payable(owner));
}
}