contract Punisher is Permissions, ILocker {

    /**
     * @dev Emitted when a slashing condition occurs.
     */
    event Slash(
        uint validatorId,
        uint amount
    );

    /**
     * @dev Emitted when a forgive condition occurs.
     */
    event Forgive(
        address wallet,
        uint amount
    );

    //        holder => tokens
    mapping (address => uint) private _locked;

    /**
     * @dev Executes slashing on a validator and its delegations by an `amount`
     * of tokens. Currently, SkaleDKG is the only service allowed to execute
     * slashing.
     *
     * Emits a Slash event.
     *
     * @param validatorId uint validator to be slashed
     * @param amount uint slashed amount
    */
    function slash(uint validatorId, uint amount) external allow("SkaleDKG") {
        ValidatorService validatorService = ValidatorService(contractManager.getContract("ValidatorService"));
        DelegationController delegationController = DelegationController(
            contractManager.getContract("DelegationController"));

        require(validatorService.validatorExists(validatorId), "Validator does not exist");

        delegationController.confiscate(validatorId, amount);

        emit Slash(validatorId, amount);
    }

    /**
     * @dev Allows the Owner to forgive a slashing condition.
     *
     * Emits a Forgive event.
     *
     * @param holder address of the slashed
     * @param amount uint amount to be forgiven
     */
    function forgive(address holder, uint amount) external onlyAdmin {
        DelegationController delegationController = DelegationController(
            contractManager.getContract("DelegationController"));

        require(!delegationController.hasUnprocessedSlashes(holder), "Not all slashes were calculated");

        if (amount > _locked[holder]) {
            delete _locked[holder];
        } else {
            _locked[holder] = _locked[holder].sub(amount);
        }

        emit Forgive(holder, amount);
    }

    /**
     * @dev See ILocker-getAndUpdateLockedAmount
     */
    function getAndUpdateLockedAmount(address wallet) external override returns (uint) {
        return _getAndUpdateLockedAmount(wallet);
    }

    /**
     * @dev See ILocker-getAndUpdateForbiddenForDelegationAmount
     */
    function getAndUpdateForbiddenForDelegationAmount(address wallet) external override returns (uint) {
        return _getAndUpdateLockedAmount(wallet);
    }

    function handleSlash(address holder, uint amount) external allow("DelegationController") {
        _locked[holder] = _locked[holder].add(amount);
    }

    function initialize(address contractManagerAddress) public override initializer {
        Permissions.initialize(contractManagerAddress);
    }

    // private

    function _getAndUpdateLockedAmount(address wallet) private returns (uint) {
        DelegationController delegationController = DelegationController(
            contractManager.getContract("DelegationController"));

        delegationController.processAllSlashes(wallet);
        return _locked[wallet];
    }

}
/**
 * @title Punisher
 * @dev This contract handles all slashing and forgiving operations.
 */
function _getAndUpdateLockedAmount(address wallet) private returns (uint) {
    DelegationController delegationController = DelegationController(
        contractManager.getContract("DelegationController"));

    delegationController.processAllSlashes(wallet);
    return _locked[wallet];
}

// private