# After the fix: are we safe now?

As you might remember from the previous labs, delegatecall is a tricky method that should be handled carefully.

Also you might have noticed that we use "library" to describe the walletLibrary contract, since it's not a solidity library. The solidity library should be stateless, while to enable delegation the walletLibrary has state variables.

The second thing is that the library is providing functions that are potentially harmful when executed on the libary itself. For example, the kill function:

// SPDX-License-Identifier: BSD-4-Clause
pragma solidity ^0.8.11;

contract PartTwoWalletLibrary {
    address public walletLibAddr;
    address payable public owner;
    address public initOwner;


    function initWallet(address payable _owner) external {
        owner = _owner;
    }

    function changeOwner(address payable _new_owner) external {
        require(msg.sender == owner, "You are not the owner");
        owner = _new_owner;
    }

    receive() external payable {}

    function withdraw(uint256 amount) external payable returns (bool) {
        require(msg.sender == owner, "You are not the owner");
        return owner.send(amount);
    }

    
    function kill(address _to) external {
        require(msg.sender == owner, "You are not the owner");
        selfdestruct(payable(_to));
    }

    function getBalance() external view returns (uint256) {
        return address(this).balance;
    }

    function completed(address player) external view returns (bool) {
        return owner == player;
    }
}

contract PartTwoWallet {
    address public walletLibAddr;
    address payable public owner;
    address public initOwner;

    constructor() {
        initOwner = msg.sender;
        walletLibAddr = address(new PartTwoWalletLibrary());

        (bool success /* bytes memory returnedData */, ) = walletLibAddr
            .delegatecall(
                abi.encodeCall(PartTwoWalletLibrary.initWallet, payable(msg.sender)) // new in solidity 0.8.11
            );
        require(success, "initWallet() failed");
    }

    // fallback function gets called if no other function matches call
    fallback() external payable {
        (bool success /* bytes memory returnedData */, ) = walletLibAddr
            .delegatecall(msg.data);
        require(success, "[delegatecall] failed");
    }

    function completed(address player) external view returns (bool) {
        PartTwoWalletLibrary _walletLibrary = PartTwoWalletLibrary(payable(walletLibAddr));
        return _walletLibrary.completed(player);
    }
}

To beat this level, claim ownership of the walletLibrary contract!

What happened in reality was that after claiming the ownership of the "library", the hacker immediately called kill to self-destruct the "library", rendering all the existing wallets using this "library" dead since they could no longer make any delegatecall.