HYPE Price: $33.58 (+9.53%)
 

Overview

HYPE Balance

HyperEVM LogoHyperEVM LogoHyperEVM Logo0 HYPE

HYPE Value

$0.00

More Info

Private Name Tags

Multichain Info

No addresses found
Transaction Hash
Block
From
To

There are no matching entries

Please try again later

View more zero value Internal Transactions in Advanced View mode

Advanced mode:
Cross-Chain Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
ControlFacet

Compiler Version
v0.8.28+commit.7893614a

Optimization Enabled:
Yes with 20000 runs

Other Settings:
cancun EvmVersion
// SPDX-License-Identifier: MIT
pragma solidity =0.8.28;

import "@loans/storages/BaseStorage.sol";
import "@loans/storages/LoanStorage.sol";
import "@loans/libraries/LibValidator.sol";
import "@loans/libraries/LibDiamond.sol";
import "./IControlFacet.sol";
import "../AccessControl.sol";

/**
 * @dev Implementation of control operations for the multi-source loan protocol.
 *
 * This contract provides administrative functions for managing protocol parameters,
 * role-based access control, contract addresses, and fee structures. It follows
 * the Diamond Standard (EIP-2535) pattern as a facet.
 *
 * The contract implements a two-tier access control system:
 * - Contract Owner: Has ultimate control and can perform any operation
 * - Admin Role: Can perform most administrative operations except ownership transfer
 *
 * Protocol fee updates follow a notice period pattern to ensure transparency
 * and give users time to react to fee changes.
 *
 * NOTE: This contract is designed to be used as a Diamond facet and should not
 * be deployed standalone.
 */
contract ControlFacet is IControlFacet, AccessControl {
    /**
     * @dev Minimum duration for liquidation auctions.
     *
     * Set to 3 days to ensure sufficient time for competitive bidding
     * while preventing indefinite auction periods.
     */
    uint48 public constant MIN_AUCTION_DURATION = 3 days;

    /**
     * @dev Maximum duration for liquidation auctions.
     *
     * Set to 7 days to balance auction competitiveness with timely
     * resolution of defaulted loans.
     */
    uint48 public constant MAX_AUCTION_DURATION = 7 days;


    /**
     * @dev Thrown when attempting to set protocol fee before notice period expires.
     * @param _pendingProtocolFeeSetTime The timestamp when the fee can be activated
     */
    error TooEarlyError(uint256 _pendingProtocolFeeSetTime);

    /**
     * @dev Thrown when attempting to whitelist a contract that's already whitelisted.
     */
    error AlreadyWhitelistedContract();

    /**
     * @dev Thrown when attempting to remove a contract that's not whitelisted.
     */
    error NotWhitelistedContract();

    /**
     * @dev Thrown when attempting to set protocol fee before notice period expires.
     */
    error TooSoonError();

    /**
     * @dev Thrown when auction duration is outside acceptable bounds.
     */
    error InvalidDurationError();

    /**
     * @dev Modifier that allows access to either contract owner or admin role holders.
     *
     * This provides flexibility in access control while maintaining security.
     * Used for critical operations that should be restricted to trusted entities.
     */
    modifier onlyContractOwnerOrAdminRole() {
        _checkOnlyContractOwnerOrAdmin();
        _;
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner_`).
     *
     * This is a critical operation that should only be performed by the current owner.
     * The new owner will have ultimate control over the protocol.
     *
     * Requirements:
     * - Can only be called by the current contract owner
     * - `newOwner_` must not be the zero address
     *
     * @param newOwner_ The address of the new owner
     */
    function transferOwnership(address newOwner_) external virtual override {
        LibDiamond.enforceIsContractOwner();
        LibValidator.checkNotZero(newOwner_);
        LibDiamond.setContractOwner(newOwner_);
    }

    /**
     * @dev Grants `role_` to `account_`.
     *
     * Internal function without access restriction. Access control is handled
     * by the modifier which allows both contract owner and admin role holders
     * to grant roles.
     *
     * Requirements:
     * - The caller must have contract ownership or admin role
     * - Emits a {RoleGranted} event
     *
     * @param role_ The role identifier to grant
     * @param account_ The address to receive the role
     */
    function grantRole(bytes32 role_, address account_) external virtual override onlyContractOwnerOrAdminRole {
        AccessControlStorage.layout().hasRole[account_][role_] = true;
        emit RoleGranted(role_, account_, msg.sender);
    }

    /**
     * @dev Revokes `role_` from `account_`.
     *
     * Internal function without access restriction. Access control is handled
     * by the modifier which allows both contract owner and admin role holders
     * to revoke roles.
     *
     * Requirements:
     * - The caller must have contract ownership or admin role
     * - Emits a {RoleRevoked} event
     *
     * @param role_ The role identifier to revoke
     * @param account_ The address to lose the role
     */
    function revokeRole(bytes32 role_, address account_) external virtual override onlyContractOwnerOrAdminRole {
        AccessControlStorage.layout().hasRole[account_][role_] = false;
        emit RoleRevoked(role_, account_, msg.sender);
    }

    /**
     * @dev Updates the liquidation contract address.
     *
     * The liquidation contract handles the auction and settlement process
     * for defaulted loans. This is a critical component that must implement
     * the required liquidation interface.
     *
     * Requirements:
     * - The caller must have the DEFAULT_ADMIN_ROLE
     * - `loanLiquidator_` must not be the zero address
     *
     * Emits:
     * - {LiquidationContractUpdated} event
     *
     * @param loanLiquidator_ The new liquidation contract address
     */
    function updateLiquidationContract(address loanLiquidator_)
        external
        virtual
        override
        onlyRole(LibAccessControl.DEFAULT_ADMIN_ROLE)
    {
        LibValidator.checkNotZero(loanLiquidator_);
        BaseStorage.layout().loanLiquidator = loanLiquidator_;
        emit LiquidationContractUpdated(loanLiquidator_);
    }

    /**
     * @dev Sets the flash action contract address.
     *
     * The flash action contract enables atomic operations across multiple
     * lending protocols within a single transaction. This can be set to
     * zero address to disable flash loan functionality.
     *
     * Requirements:
     * - The caller must have the DEFAULT_ADMIN_ROLE
     *
     * Emits:
     * - {FlashActionContractUpdated} event
     *
     * @param newFlashActionContract_ The new flash action contract address (can be zero)
     */
    function setFlashActionContract(address newFlashActionContract_)
        external
        virtual
        override
        onlyRole(LibAccessControl.DEFAULT_ADMIN_ROLE)
    {
        BaseStorage.layout().flashActionContract = newFlashActionContract_;
        emit FlashActionContractUpdated(newFlashActionContract_);
    }

    /**
     * @dev Updates the liquidation auction duration.
     *
     * This sets how long liquidation auctions will run before automatically
     * settling. The duration must be within predefined bounds to ensure
     * proper auction dynamics.
     *
     * Requirements:
     * - The caller must have the DEFAULT_ADMIN_ROLE
     * - Duration must be between MIN_AUCTION_DURATION and MAX_AUCTION_DURATION
     *
     * Emits:
     * - {LiquidationAuctionDurationUpdated} event
     *
     * @param liquidationAuctionDuration_ The new auction duration in seconds
     */
    function updateLiquidationAuctionDuration(uint48 liquidationAuctionDuration_)
        external
        virtual
        override
        onlyRole(LibAccessControl.DEFAULT_ADMIN_ROLE)
    {
        require(
            liquidationAuctionDuration_ >= MIN_AUCTION_DURATION && liquidationAuctionDuration_ <= MAX_AUCTION_DURATION,
            InvalidDurationError()
        );
        BaseStorage.layout().liquidationAuctionDuration = liquidationAuctionDuration_;
        emit LiquidationAuctionDurationUpdated(liquidationAuctionDuration_);
    }

    /**
     * @dev Sets the minimum lock period for new loans.
     *
     * During the lock period, loans cannot be refinanced or modified,
     * providing stability and predictability for lenders. This applies
     * to all new loans created after the change.
     *
     * Requirements:
     * - The caller must have the DEFAULT_ADMIN_ROLE
     *
     * Emits:
     * - {MinLockPeriodUpdated} event
     *
     * @param minLockPeriod_ The new minimum lock period in BPS
     */
    function setMinLockPeriod(uint256 minLockPeriod_)
        external
        virtual
        override
        onlyRole(LibAccessControl.DEFAULT_ADMIN_ROLE)
    {
        LoanStorage.layout().minLockPeriod = minLockPeriod_;
        emit MinLockPeriodUpdated(minLockPeriod_);
    }

    /**
     * @dev Adds a contract to the callback whitelist.
     *
     * Whitelisted contracts can receive callbacks during loan operations,
     * enabling integration with external protocols. Only trusted contracts
     * should be whitelisted to prevent malicious behavior.
     *
     * Requirements:
     * - The caller must have the DEFAULT_ADMIN_ROLE
     * - `contract_` must not be the zero address
     * - `contract_` must not already be whitelisted
     *
     * Emits:
     * - {WhitelistedCallbackContractAdded} event
     *
     * @param contract_ The contract address to add to the whitelist
     */
    function addWhitelistedCallbackContract(address contract_)
        external
        virtual
        override
        onlyRole(LibAccessControl.DEFAULT_ADMIN_ROLE)
    {
        LibValidator.checkNotZero(contract_);
        require(!BaseStorage.layout().isWhitelistedCallbackContract[contract_], AlreadyWhitelistedContract());
        BaseStorage.layout().isWhitelistedCallbackContract[contract_] = true;
        emit WhitelistedCallbackContractAdded(contract_);
    }

    /**
     * @dev Removes a contract from the callback whitelist.
     *
     * This revokes the contract's ability to receive callbacks during
     * loan operations. Useful for removing compromised or deprecated
     * integration contracts.
     *
     * Requirements:
     * - The caller must have the DEFAULT_ADMIN_ROLE
     * - `contract_` must currently be whitelisted
     *
     * Emits:
     * - {WhitelistedCallbackContractRemoved} event
     *
     * @param contract_ The contract address to remove from the whitelist
     */
    function removeWhitelistedCallbackContract(address contract_)
        external
        virtual
        override
        onlyRole(LibAccessControl.DEFAULT_ADMIN_ROLE)
    {
        require(BaseStorage.layout().isWhitelistedCallbackContract[contract_], NotWhitelistedContract());
        BaseStorage.layout().isWhitelistedCallbackContract[contract_] = false;
        emit WhitelistedCallbackContractRemoved(contract_);
    }

    /**
     * @dev Updates the minimum APR improvement required for loan refinancing.
     *
     * This prevents frivolous refinancing attempts by requiring a meaningful
     * improvement in loan terms. The value is typically expressed in basis points.
     *
     * Requirements:
     * - The caller must have the DEFAULT_ADMIN_ROLE
     *
     * Emits:
     * - {MinAprImprovementUpdated} event
     *
     * @param minImprovementApr_ The new minimum APR improvement in basis points
     */
    function updateMinImprovementApr(uint256 minImprovementApr_)
        external
        virtual
        override
        onlyRole(LibAccessControl.DEFAULT_ADMIN_ROLE)
    {
        LoanStorage.layout().minImprovementApr = minImprovementApr_;
        emit MinAprImprovementUpdated(minImprovementApr_);
    }

    /**
     * @dev Stages a new protocol fee configuration for future activation.
     *
     * The new fee structure enters a notice period before becoming active,
     * allowing users time to understand and react to fee changes. This
     * implements a transparent fee update mechanism.
     *
     * Requirements:
     * - The caller must have the DEFAULT_ADMIN_ROLE
     * - Fee recipient must not be the zero address
     *
     * Emits:
     * - {ProtocolFeePendingUpdate} event
     *
     * NOTE: The fee becomes active only after calling `setProtocolFee`
     * once the notice period has elapsed.
     *
     * @param protocolFee_ The new protocol fee configuration to stage
     */
    function updateProtocolFee(ProtocolFee calldata protocolFee_)
        external
        virtual
        override
        onlyRole(LibAccessControl.DEFAULT_ADMIN_ROLE)
    {
        LibValidator.checkNotZero(protocolFee_.recipient);

        BaseStorage.Layout storage $ = BaseStorage.layout();
        $.pendingProtocolFee = protocolFee_;
        $.pendingProtocolFeeSetTime = block.timestamp;

        emit ProtocolFeePendingUpdate(protocolFee_);
    }

    /**
     * @dev Activates a previously staged protocol fee.
     *
     * This function can only be called after the required notice period
     * has elapsed since the fee was staged via `updateProtocolFee`.
     * Once activated, the new fee structure applies to all future operations.
     *
     * Requirements:
     * - A fee update must be pending
     * - Can be called by anyone once conditions are met
     *
     * Emits:
     * - {ProtocolFeeUpdated} event with the newly active fee structure
     *
     * NOTE: This function clears the pending fee state after activation.
     */
    function setProtocolFee() external virtual override {
        require(block.timestamp >= BaseStorage.layout().pendingProtocolFeeSetTime, TooSoonError());
        BaseStorage.Layout storage $ = BaseStorage.layout();

        ProtocolFee memory newProtocolFee = $.pendingProtocolFee;
        $.protocolFee = newProtocolFee;

        delete $.pendingProtocolFee;

        $.pendingProtocolFeeSetTime = type(uint256).max;

        emit ProtocolFeeUpdated(newProtocolFee);
    }

    /**
     * @dev Internal function to check if caller has contract ownership or admin role.
     *
     * This function implements the dual access control logic where either
     * the contract owner or holders of the DEFAULT_ADMIN_ROLE can perform
     * certain operations.
     *
     * The function first checks for admin role (cheaper check) and falls back
     * to owner check if the role check fails.
     */
    function _checkOnlyContractOwnerOrAdmin() internal view {
        if (!LibAccessControl.hasRole(LibAccessControl.DEFAULT_ADMIN_ROLE, msg.sender)) {
            LibDiamond.enforceIsContractOwner();
        }
    }
}

File 2 of 12 : BaseStorage.sol
// SPDX-License-Identifier: MIT
pragma solidity =0.8.28;

/**
 * @dev Protocol fee configuration structure.
 *
 * Defines the fee structure for protocol operations, including the recipient
 * address and the fee fraction. Used for both active and pending fee configurations.
 */
struct ProtocolFee {
    /**
     * @dev Address that will receive the protocol fees.
     *
     * Must not be the zero address when setting active fees.
     */
    address recipient;
    /**
     * @dev Fee fraction expressed in basis points.
     *
     * For example, 100 = 1%, 10000 = 100%. The maximum value
     * should be validated by the implementing contract.
     */
    uint256 fraction;
}

/**
 * @dev Storage layout for base protocol configuration and contracts.
 *
 * This library implements the Diamond Storage pattern to store core protocol
 * configuration in a specific storage slot, avoiding storage collisions
 * when used in a Diamond proxy architecture.
 *
 * The storage contains addresses of key protocol contracts, fee configurations,
 * and operational parameters that are shared across different facets.
 *
 * Storage Location: Deterministically calculated using keccak256 hash to ensure
 * consistency across deployments and avoid collisions with other storage layouts.
 */
library BaseStorage {
    /**
     * @dev Storage slot for the base storage layout.
     *
     * Calculated as: keccak256(abi.encode(uint256(keccak256("bae.lending.storage.Base")) - 1)) & ~bytes32(uint256(0xff))
     * This ensures a pseudo-random storage slot that avoids collisions with
     * standard storage layouts and other Diamond storage patterns.
     */
    bytes32 private constant BaseLoanStorageLocation =
        0x014188aa47349e14521c6215ea0fc8aaca8692b6e279bfc01a7282e69c9d2000;

    /**
     * @dev Base storage layout containing core protocol configuration.
     *
     * This struct contains all the essential addresses and parameters needed
     * for protocol operation across different facets.
     */
    struct Layout {
        /**
         * @dev Address of the currency manager contract.
         *
         * Manages whitelist and validation of ERC20 tokens that can be used
         * as principal currencies in loans.
         */
        address currencyManager;
        /**
         * @dev Address of the collection manager contract.
         *
         * Manages whitelist and validation of NFT collections that can be used
         * as collateral in loans.
         */
        address collectionManager;
        /**
         * @dev Address of the loan liquidator contract.
         *
         * Handles the liquidation process for defaulted loans, including
         * auction management and collateral disposal.
         */
        address loanLiquidator;
        /**
         * @dev Address of the loan manager registry contract.
         *
         * Registry of approved loan manager contracts that can interact
         * with the protocol on behalf of users.
         */
        address loanManagerRegistry;
        /**
         * @dev Address of the fee discount manager contract.
         *
         * Manages fee discounts for qualifying users or specific conditions.
         * May be zero address if fee discounts are not implemented.
         */
        address feeDiscountManager;
        /**
         * @dev Address of the delegate registry contract.
         *
         * Manages delegation relationships for governance and operational
         * permissions within the protocol.
         */
        address delegateRegistry;
        /**
         * @dev Address of the flash action contract.
         *
         * Enables atomic operations and flash loans across multiple protocols.
         * May be zero address if flash functionality is disabled.
         */
        address flashActionContract;
        /**
         * @dev Current active protocol fee configuration.
         *
         * Defines the fee structure currently in effect for protocol operations.
         */
        ProtocolFee protocolFee;
        /**
         * @dev Pending protocol fee configuration awaiting activation.
         *
         * New fee structure that has been proposed but is still in the notice period.
         */
        ProtocolFee pendingProtocolFee;
        /**
         * @dev Timestamp when the pending protocol fee was set.
         *
         * Used to enforce the notice period before fee changes can take effect.
         * Set to type(uint256).max when no fee change is pending.
         */
        uint256 pendingProtocolFeeSetTime;
        /**
         * @dev Duration for liquidation auctions in seconds.
         *
         * Determines how long liquidation auctions remain open for bidding
         * before automatic settlement occurs.
         */
        uint48 liquidationAuctionDuration;
        /**
         * @dev Mapping of contracts whitelisted to receive callbacks.
         *
         * Whitelisted contracts can receive notifications during loan operations,
         * enabling complex integrations and automated responses.
         */
        mapping(address => bool) isWhitelistedCallbackContract;
    }

    /**
     * @dev Returns the storage pointer for the base storage layout.
     *
     * Uses inline assembly to return a storage pointer to the predetermined
     * storage slot, following the Diamond Storage pattern.
     *
     * @return $ Storage pointer to the base storage layout
     */
    function layout() internal pure returns (Layout storage $) {
        assembly {
            $.slot := BaseLoanStorageLocation
        }
    }
}

File 3 of 12 : LoanStorage.sol
// SPDX-License-Identifier: MIT
pragma solidity =0.8.28;

/**
 * @dev Storage layout for loan-specific data and operational parameters.
 *
 * This library implements the Diamond Storage pattern to store loan-related
 * data in a specific storage slot, separate from base protocol configuration.
 *
 * The storage contains loan tracking data, offer management, capacity tracking,
 * and operational parameters specific to loan functionality.
 *
 * Storage Location: Uses a different deterministically calculated slot from
 * BaseStorage to ensure proper separation of concerns.
 */
library LoanStorage {
    /**
     * @dev Storage slot for the loan storage layout.
     *
     * Calculated as: keccak256(abi.encode(uint256(keccak256("bae.lending.storage.Loan")) - 1)) & ~bytes32(uint256(0xff))
     * This ensures a pseudo-random storage slot that avoids collisions with
     * other storage layouts in the Diamond architecture.
     */
    bytes32 private constant BaseLoanStorageLocation =
        0x847582c39cc3b2c67c7a5fe5a43704b4d7ff45ccf56777815a28a282cadb5800;

    /**
     * @dev Loan storage layout containing all loan-related data.
     *
     * This struct organizes loan data, offer tracking, capacity management,
     * and cancellation status in a coherent storage structure.
     */
    struct Layout {
        /**
         * @dev Total number of loans issued by the protocol.
         *
         * Monotonically increasing counter used for generating unique loan IDs
         * and tracking protocol usage statistics.
         */
        uint256 totalLoansIssued;
        /**
         * @dev Maximum number of tranches allowed per loan.
         *
         * Tranches enable complex loan structures with multiple lenders having
         * different terms, priorities, and risk profiles within a single loan.
         */
        uint256 maxTranches;
        /**
         * @dev Minimum lock period for new loans in seconds.
         *
         * During the lock period, loans cannot be refinanced or modified,
         * providing stability and predictability for lenders.
         */
        uint256 minLockPeriod;
        /**
         * @dev Minimum APR improvement required for loan refinancing.
         *
         * Expressed in basis points to prevent frivolous refinancing attempts
         * by requiring meaningful improvement in loan terms.
         */
        uint256 minImprovementApr;
        /**
         * @dev Mapping from loan ID to loan data hash.
         *
         * Stores the hash of loan parameters for verification and integrity checks.
         * The hash serves as a commitment to the loan terms and enables detection
         * of any unauthorized modifications.
         */
        mapping(uint256 loanId => bytes32 loanHash) loans;
        /**
         * @dev Mapping of used capacity for lender offers.
         *
         * Tracks how much of each lender's offer has been utilized across all loans.
         * Used to enforce offer capacity limits and calculate remaining availability.
         *
         * Structure: lender address => offer ID => used amount
         */
        mapping(address user => mapping(uint256 offerId => uint256 used)) used;
        /**
         * @dev Mapping of used capacity per borrower for lender offers.
         *
         * Enables per-borrower capacity limits on offers, allowing lenders to
         * diversify risk by limiting exposure to individual borrowers.
         *
         * Structure: lender address => borrower address => offer ID => used amount
         */
        mapping(address user => mapping(address borrower => mapping(uint256 offerId => uint256 used))) usedBorrower;
        /**
         * @dev Mapping of minimum offer ID for each user's lending offers.
         *
         * Used for gas-efficient iteration over active offers and cleanup of
         * expired offers. Offers with IDs below this value may be inactive.
         */
        mapping(address user => uint256 minOfferId) minOfferId;
        /**
         * @dev Mapping of minimum borrow offer ID for each user.
         *
         * Used for efficient management of borrow requests and cleanup of
         * expired or fulfilled borrow offers.
         */
        mapping(address user => uint256 minOfferId) minBorrowOfferId;
        /**
         * @dev Mapping of cancelled renegotiation offers.
         *
         * Tracks which renegotiation offers have been cancelled by their creators.
         * Renegotiation offers allow modification of existing loan terms.
         *
         * Structure: user address => renegotiation ID => is cancelled
         */
        mapping(address user => mapping(uint256 renegotiationIf => bool notActive)) isRenegotiationOfferCancelled;
        /**
         * @dev Mapping of cancelled borrow offers.
         *
         * Tracks which borrow offers have been cancelled by borrowers before
         * being matched with lenders.
         *
         * Structure: borrower address => offer ID => is cancelled
         */
        mapping(address user => mapping(uint256 offerId => bool notActive)) isBorrowOfferCancelled;
        /**
         * @dev Mapping of cancelled lending offers.
         *
         * Tracks which lending offers have been cancelled by lenders before
         * being accepted by borrowers.
         *
         * Structure: lender address => offer ID => is cancelled
         */
        mapping(address user => mapping(uint256 offerId => bool notActive)) isOfferCancelled;
        /**
         * @dev Mapping of lenders attached to borrower offers.
         *
         * When a borrower creates an offer that gets matched with a specific lender,
         * this mapping tracks that relationship for future reference and validation.
         *
         * Structure: borrower address => offer ID => attached lender address
         */
        mapping(address borrower => mapping(uint256 offerId => address)) borrowerOfferAttachedLender;
    }

    /**
     * @dev Returns the storage pointer for the loan storage layout.
     *
     * Uses inline assembly to return a storage pointer to the predetermined
     * storage slot, following the Diamond Storage pattern.
     *
     * @return $ Storage pointer to the loan storage layout
     */
    function layout() internal pure returns (Layout storage $) {
        assembly {
            $.slot := BaseLoanStorageLocation
        }
    }
}

// SPDX-License-Identifier: MIT
pragma solidity =0.8.28;

/**
 * @dev Library for common input validation operations.
 *
 * Provides reusable validation functions to ensure data integrity
 * and prevent common errors like zero address assignments.
 */
library LibValidator {
    /**
     * @dev Thrown when an address parameter is the zero address.
     */
    error AddressZero();

    /**
     * @dev Validates that an address is not the zero address.
     *
     * @param target_ The address to validate
     */
    function checkNotZero(address target_) internal pure {
        require(target_ != address(0), AddressZero());
    }
}

// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity >=0.8.18;

/**
 * \
 * Author: Nick Mudge <[email protected]> (https://twitter.com/mudgen)
 * EIP-2535 Diamonds: https://eips.ethereum.org/EIPS/eip-2535
 * /*****************************************************************************
 */
import { IDiamondCut } from "@loans/facets/DiamondCut/IDiamondCut.sol";
import { IDiamondLoupe } from "@loans/facets/DiamondLoup/IDiamondLoupe.sol";

library LibDiamond {
    bytes32 public constant DIAMOND_STORAGE_POSITION = keccak256("diamond.standard.diamond.storage");

    struct FacetAddressAndSelectorPosition {
        address facetAddress;
        uint16 selectorPosition;
    }

    struct DiamondStorage {
        // function selector => facet address and selector position in selectors array
        mapping(bytes4 => FacetAddressAndSelectorPosition) facetAddressAndSelectorPosition;
        bytes4[] selectors;
        mapping(bytes4 => bool) supportedInterfaces;
        // owner of the contract
        address contractOwner;
    }

    function diamondStorage() internal pure returns (DiamondStorage storage ds) {
        bytes32 position = DIAMOND_STORAGE_POSITION;
        assembly {
            ds.slot := position
        }
    }

    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    function setContractOwner(address _newOwner) internal {
        DiamondStorage storage ds = diamondStorage();
        address previousOwner = ds.contractOwner;
        ds.contractOwner = _newOwner;
        emit OwnershipTransferred(previousOwner, _newOwner);
    }

    function contractOwner() internal view returns (address contractOwner_) {
        contractOwner_ = diamondStorage().contractOwner;
    }

    function enforceIsOwnerOrContract() internal view {
        require(
            msg.sender == diamondStorage().contractOwner || msg.sender == address(this),
            "LibDiamond: Must be contract or owner"
        );
    }

    function enforceIsContractOwner() internal view {
        require(msg.sender == diamondStorage().contractOwner, "LibDiamond: Must be contract owner");
    }

    event DiamondCut(IDiamondCut.FacetCut[] _diamondCut, address _init, bytes _calldata);

    // Internal function version of diamondCut
    function diamondCut(IDiamondCut.FacetCut[] memory _diamondCut, address _init, bytes memory _calldata) internal {
        for (uint256 facetIndex; facetIndex < _diamondCut.length; facetIndex++) {
            IDiamondCut.FacetCutAction action = _diamondCut[facetIndex].action;
            if (action == IDiamondCut.FacetCutAction.Add) {
                addFunctions(_diamondCut[facetIndex].facetAddress, _diamondCut[facetIndex].functionSelectors);
            } else if (action == IDiamondCut.FacetCutAction.Replace) {
                replaceFunctions(_diamondCut[facetIndex].facetAddress, _diamondCut[facetIndex].functionSelectors);
            } else if (action == IDiamondCut.FacetCutAction.Remove) {
                removeFunctions(_diamondCut[facetIndex].facetAddress, _diamondCut[facetIndex].functionSelectors);
            } else {
                revert("LibDiamondCut: Incorrect FacetCutAction");
            }
        }
        emit DiamondCut(_diamondCut, _init, _calldata);
        initializeDiamondCut(_init, _calldata);
    }

    function addFunctions(address _facetAddress, bytes4[] memory _functionSelectors) internal {
        require(_functionSelectors.length > 0, "LibDiamondCut: No selectors in facet to cut");
        DiamondStorage storage ds = diamondStorage();
        uint16 selectorCount = uint16(ds.selectors.length);
        require(_facetAddress != address(0), "LibDiamondCut: Add facet can't be address(0)");
        enforceHasContractCode(_facetAddress, "LibDiamondCut: Add facet has no code");
        for (uint256 selectorIndex; selectorIndex < _functionSelectors.length; selectorIndex++) {
            bytes4 selector = _functionSelectors[selectorIndex];
            address oldFacetAddress = ds.facetAddressAndSelectorPosition[selector].facetAddress;
            require(oldFacetAddress == address(0), "LibDiamondCut: Can't add function that already exists");
            ds.facetAddressAndSelectorPosition[selector] = FacetAddressAndSelectorPosition(_facetAddress, selectorCount);
            ds.selectors.push(selector);
            selectorCount++;
        }
    }

    function replaceFunctions(address _facetAddress, bytes4[] memory _functionSelectors) internal {
        require(_functionSelectors.length > 0, "LibDiamondCut: No selectors in facet to cut");
        DiamondStorage storage ds = diamondStorage();
        require(_facetAddress != address(0), "LibDiamondCut: Replace facet can't be address(0)");
        enforceHasContractCode(_facetAddress, "LibDiamondCut: Replace facet has no code");
        for (uint256 selectorIndex; selectorIndex < _functionSelectors.length; selectorIndex++) {
            bytes4 selector = _functionSelectors[selectorIndex];
            address oldFacetAddress = ds.facetAddressAndSelectorPosition[selector].facetAddress;
            // can't replace immutable functions -- functions defined directly in the diamond
            require(oldFacetAddress != address(this), "LibDiamondCut: Can't replace immutable function");
            require(oldFacetAddress != _facetAddress, "LibDiamondCut: Can't replace function with same function");
            require(oldFacetAddress != address(0), "LibDiamondCut: Can't replace function that doesn't exist");
            // replace old facet address
            ds.facetAddressAndSelectorPosition[selector].facetAddress = _facetAddress;
        }
    }

    function removeFunctions(address _facetAddress, bytes4[] memory _functionSelectors) internal {
        require(_functionSelectors.length > 0, "LibDiamondCut: No selectors in facet to cut");
        DiamondStorage storage ds = diamondStorage();
        uint256 selectorCount = ds.selectors.length;
        require(_facetAddress == address(0), "LibDiamondCut: Remove facet address must be address(0)");
        for (uint256 selectorIndex; selectorIndex < _functionSelectors.length; selectorIndex++) {
            bytes4 selector = _functionSelectors[selectorIndex];
            FacetAddressAndSelectorPosition memory oldFacetAddressAndSelectorPosition =
                ds.facetAddressAndSelectorPosition[selector];
            require(
                oldFacetAddressAndSelectorPosition.facetAddress != address(0),
                "LibDiamondCut: Can't remove function that doesn't exist"
            );
            // can't remove immutable functions -- functions defined directly in the diamond
            require(
                oldFacetAddressAndSelectorPosition.facetAddress != address(this),
                "LibDiamondCut: Can't remove immutable function."
            );
            // replace selector with last selector
            selectorCount--;
            if (oldFacetAddressAndSelectorPosition.selectorPosition != selectorCount) {
                bytes4 lastSelector = ds.selectors[selectorCount];
                ds.selectors[oldFacetAddressAndSelectorPosition.selectorPosition] = lastSelector;
                ds.facetAddressAndSelectorPosition[lastSelector].selectorPosition =
                    oldFacetAddressAndSelectorPosition.selectorPosition;
            }
            // delete last selector
            ds.selectors.pop();
            delete ds.facetAddressAndSelectorPosition[selector];
        }
    }

    function initializeDiamondCut(address _init, bytes memory _calldata) internal {
        if (_init == address(0)) {
            require(_calldata.length == 0, "LibDiamondCut: _init is address(0) but_calldata is not empty");
        } else {
            require(_calldata.length > 0, "LibDiamondCut: _calldata is empty but _init is not address(0)");
            if (_init != address(this)) {
                enforceHasContractCode(_init, "LibDiamondCut: _init address has no code");
            }
            (bool success, bytes memory error) = _init.delegatecall(_calldata);
            if (!success) {
                if (error.length > 0) {
                    // bubble up the error
                    revert(string(error));
                } else {
                    revert("LibDiamondCut: _init function reverted");
                }
            }
        }
    }

    function enforceHasContractCode(address _contract, string memory _errorMessage) internal view {
        uint256 contractSize;
        assembly {
            contractSize := extcodesize(_contract)
        }
        require(contractSize > 0, _errorMessage);
    }
}

// SPDX-License-Identifier: MIT
pragma solidity =0.8.28;

import "./IControlEvents.sol";

/**
 * @dev Interface for control operations in the multi-source loan protocol.
 *
 * This interface provides administrative functions for managing protocol
 * parameters, role-based access control, contract addresses, and fee structures.
 *
 * All functions in this interface require appropriate administrative privileges
 * and may have additional validation requirements.
 *
 * The interface extends IControlEvents to ensure all control operations
 * can emit the appropriate events for transparency and monitoring.
 */
interface IControlFacet is IControlEvents {
    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner_`).
     *
     * Requirements:
     * - Can only be called by the current owner
     * - `newOwner_` must not be the zero address
     *
     * @param newOwner_ The address of the new owner
     */
    function transferOwnership(address newOwner_) external;

    /**
     * @dev Grants `role_` to `account_`.
     *
     * If `account_` had not been already granted `role_`, emits a {RoleGranted} event.
     *
     * Requirements:
     * - The caller must have the admin role for the role being granted
     * - `account_` must not be the zero address
     *
     * @param role_ The role identifier to grant
     * @param account_ The address to receive the role
     */
    function grantRole(bytes32 role_, address account_) external;

    /**
     * @dev Revokes `role_` from `account_`.
     *
     * If `account_` had been granted `role_`, emits a {RoleRevoked} event.
     *
     * Requirements:
     * - The caller must have the admin role for the role being revoked
     * - `account_` must currently have the role
     *
     * @param role_ The role identifier to revoke
     * @param account_ The address to lose the role
     */
    function revokeRole(bytes32 role_, address account_) external;

    /**
     * @dev Updates the liquidation contract address.
     *
     * Requirements:
     * - The caller must have the appropriate admin role
     * - `loanLiquidator_` must not be the zero address
     * - `loanLiquidator_` must implement the required liquidation interface
     *
     * @param loanLiquidator_ The new liquidation contract address
     */
    function updateLiquidationContract(address loanLiquidator_) external;

    /**
     * @dev Sets the flash action contract address.
     *
     * The flash action contract enables atomic operations across multiple
     * lending protocols within a single transaction.
     *
     * Requirements:
     * - The caller must have the appropriate admin role
     * - `newFlashActionContract_` can be the zero address to disable flash actions
     *
     * @param newFlashActionContract_ The new flash action contract address
     */
    function setFlashActionContract(address newFlashActionContract_) external;

    /**
     * @dev Updates the liquidation auction duration.
     *
     * This sets how long liquidation auctions will run before automatically
     * settling at the current highest bid.
     *
     * Requirements:
     * - The caller must have the appropriate admin role
     * - `liquidationAuctionDuration_` must be within reasonable bounds
     *
     * @param liquidationAuctionDuration_ The new auction duration in seconds
     */
    function updateLiquidationAuctionDuration(uint48 liquidationAuctionDuration_) external;

    /**
     * @dev Sets the minimum lock period for new loans.
     *
     * During the lock period, loans cannot be refinanced or modified,
     * providing stability for lenders.
     *
     * Requirements:
     * - The caller must have the appropriate admin role
     * - `minLockPeriod_` must be greater than zero
     *
     * @param minLockPeriod_ The new minimum lock period in BPS
     */
    function setMinLockPeriod(uint256 minLockPeriod_) external;

    /**
     * @dev Updates the minimum APR improvement required for loan refinancing.
     *
     * This prevents frivolous refinancing attempts and ensures meaningful
     * improvements for borrowers.
     *
     * Requirements:
     * - The caller must have the appropriate admin role
     * - `minImprovementApr_` must be expressed in basis points
     *
     * @param minImprovementApr_ The new minimum APR improvement in basis points
     */
    function updateMinImprovementApr(uint256 minImprovementApr_) external;

    /**
     * @dev Adds a contract to the callback whitelist.
     *
     * Whitelisted contracts can receive callbacks during loan operations,
     * enabling integration with external protocols.
     *
     * Requirements:
     * - The caller must have the appropriate admin role
     * - `contract_` must not be the zero address
     * - `contract_` must not already be whitelisted
     *
     * @param contract_ The contract address to add to the whitelist
     */
    function addWhitelistedCallbackContract(address contract_) external;

    /**
     * @dev Removes a contract from the callback whitelist.
     *
     * Requirements:
     * - The caller must have the appropriate admin role
     * - `contract_` must currently be whitelisted
     *
     * @param contract_ The contract address to remove from the whitelist
     */
    function removeWhitelistedCallbackContract(address contract_) external;

    /**
     * @dev Stages a new protocol fee configuration for future activation.
     *
     * The new fee structure enters a notice period before becoming active,
     * allowing users to react to fee changes.
     *
     * Requirements:
     * - The caller must have the appropriate admin role
     * - Fee parameters must be within acceptable ranges
     * - Notice period must be respected between fee updates
     *
     * @param protocolFee_ The new protocol fee configuration to stage
     */
    function updateProtocolFee(ProtocolFee calldata protocolFee_) external;

    /**
     * @dev Activates a previously staged protocol fee.
     *
     * This function can only be called after the required notice period
     * has elapsed since the fee was staged via `updateProtocolFee`.
     *
     * Requirements:
     * - The caller must have the appropriate admin role
     * - A fee update must be pending
     * - The notice period must have elapsed
     *
     * Emits:
     * - {ProtocolFeeUpdated} event with the newly active fee structure
     */
    function setProtocolFee() external;
}

// SPDX-License-Identifier: MIT
pragma solidity =0.8.28;

import "@loans/libraries/LibAccessControl.sol";

/**
 * @title AccessControl
 * @author BAE Lending Protocol
 * @notice Abstract contract providing role-based access control functionality
 * @dev Implements OpenZeppelin-style access control patterns with Diamond proxy compatibility.
 *      Provides modifiers and internal functions for role-based authorization.
 *
 *      This contract is designed to be inherited by Diamond facets that need role-based
 *      access control. It uses the LibAccessControl library for actual role checking
 *      to maintain compatibility with Diamond storage patterns.
 */
abstract contract AccessControl {
    /**
     * @notice Thrown when an account lacks the required role for an operation
     * @dev This error should be caught and handled appropriately by calling contracts
     * @param account The address that attempted the unauthorized action
     * @param neededRole The role identifier that was required for the operation
     */
    error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);

    /**
     * @notice Modifier that restricts function access to accounts with a specific role
     * @dev Reverts with AccessControlUnauthorizedAccount if the caller lacks the required role
     * @param role_ The role identifier required to execute the function
     *
     * Usage:
     * ```solidity
     * function adminFunction() external onlyRole(DEFAULT_ADMIN_ROLE) {
     *     // Function implementation
     * }
     * ```
     */
    modifier onlyRole(bytes32 role_) {
        _checkRole(role_);
        _;
    }

    /**
     * @notice Internal function to check if msg.sender has the required role
     * @dev This is a convenience function that checks the role for the current message sender.
     *      Can be overridden in derived contracts to customize authorization logic.
     * @param role_ The role identifier to check against msg.sender
     *
     * @custom:throws AccessControlUnauthorizedAccount if msg.sender lacks the required role
     */
    function _checkRole(bytes32 role_) internal view virtual {
        _checkRole(role_, msg.sender);
    }

    /**
     * @notice Internal function to check if a specific account has the required role
     * @dev Core authorization function that performs the actual role verification.
     *      Uses LibAccessControl.hasRole() to query the Diamond storage.
     *      Can be overridden in derived contracts for custom authorization logic.
     *
     * @param role_ The role identifier to check
     * @param account The address to verify role membership for
     *
     * @custom:throws AccessControlUnauthorizedAccount if the account lacks the required role
     */
    function _checkRole(bytes32 role_, address account) internal view virtual {
        require(LibAccessControl.hasRole(role_, account), AccessControlUnauthorizedAccount(account, role_));
    }
}

// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity =0.8.28;

interface IDiamondCut {
    // Add=0, Replace=1, Remove=2
    enum FacetCutAction {
        Add,
        Replace,
        Remove
    }

    struct FacetCut {
        address facetAddress;
        FacetCutAction action;
        bytes4[] functionSelectors;
    }

    /// @notice Add/replace/remove any number of functions and optionally execute
    ///         a function with delegatecall
    /// @param _diamondCut Contains the facet addresses and function selectors
    /// @param _init The address of the contract or facet to execute _calldata
    /// @param _calldata A function call, including function selector and arguments
    ///                  _calldata is executed with delegatecall on _init
    function diamondCut(FacetCut[] calldata _diamondCut, address _init, bytes calldata _calldata) external;

    event DiamondCut(FacetCut[] _diamondCut, address _init, bytes _calldata);
}

// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity =0.8.28;

interface IDiamondLoupe {
    struct Facet {
        address facetAddress;
        bytes4[] functionSelectors;
    }

    /// @notice Gets all facet addresses and their four byte function selectors.
    /// @return facets_ Facet
    function facets() external view returns (Facet[] memory facets_);

    /// @notice Gets all the function selectors supported by a specific facet.
    /// @param _facet The facet address.
    /// @return facetFunctionSelectors_
    function facetFunctionSelectors(address _facet) external view returns (bytes4[] memory facetFunctionSelectors_);

    /// @notice Get all the facet addresses used by a diamond.
    /// @return facetAddresses_
    function facetAddresses() external view returns (address[] memory facetAddresses_);

    /// @notice Gets the facet that supports the given selector.
    /// @dev If facet is not found return address(0).
    /// @param _functionSelector The function selector.
    /// @return facetAddress_ The facet address.
    function facetAddress(bytes4 _functionSelector) external view returns (address facetAddress_);
}

File 10 of 12 : IControlEvents.sol
// SPDX-License-Identifier: MIT
pragma solidity =0.8.28;

import { ProtocolFee } from "@loans/storages/BaseStorage.sol";

/**
 * @dev Interface for control-related events in the multi-source loan protocol.
 *
 * This interface defines all events that are emitted by control operations
 * such as role management, contract updates, and protocol parameter changes.
 *
 * Events follow the standard pattern of including indexed parameters for
 * efficient filtering and non-indexed parameters for additional context.
 */
interface IControlEvents {
    /**
     * @dev Emitted when `account` is granted `role`.
     *
     * `sender` is the account that originated the contract call. This account bears the admin role (for the granted role).
     * Expected in cases where the role was granted using the internal {AccessControl-_grantRole}.
     *
     * @param role The role identifier that was granted
     * @param account The address that received the role
     * @param sender The address that granted the role (must have admin privileges)
     */
    event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);

    /**
     * @dev Emitted when `account` is revoked `role`.
     *
     * `sender` is the account that originated the contract call:
     *   - if using `revokeRole`, it is the admin role bearer
     *   - if using `renounceRole`, it is the role bearer (i.e. `account`)
     *
     * @param role The role identifier that was revoked
     * @param account The address that lost the role
     * @param sender The address that revoked the role
     */
    event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);

    /**
     * @dev Emitted when the minimum bid for liquidations is updated.
     *
     * @param newMinBid The new minimum bid amount required for liquidation auctions
     */
    event MinBidLiquidationUpdated(uint256 newMinBid);

    /**
     * @dev Emitted when the liquidation contract address is updated.
     *
     * @param liquidator The new liquidation contract address
     */
    event LiquidationContractUpdated(address liquidator);

    /**
     * @dev Emitted when the minimum APR improvement requirement is updated.
     *
     * @param _minimum The new minimum APR improvement required for loan refinancing
     */
    event MinAprImprovementUpdated(uint256 _minimum);

    /**
     * @dev Emitted when a contract is added to the callback whitelist.
     *
     * @param contractAdded The address of the contract added to the whitelist
     */
    event WhitelistedCallbackContractAdded(address contractAdded);

    /**
     * @dev Emitted when a contract is removed from the callback whitelist.
     *
     * @param contractRemoved The address of the contract removed from the whitelist
     */
    event WhitelistedCallbackContractRemoved(address contractRemoved);

    /**
     * @dev Emitted when `protocolFee` is updated and becomes effective.
     *
     * This event is fired when the new protocol fee structure takes effect
     * after the required notice period has elapsed.
     *
     * @param fee The newly activated protocol fee configuration
     */
    event ProtocolFeeUpdated(ProtocolFee fee);

    /**
     * @dev Emitted when a new fee is staged and enters the notice period.
     *
     * The staged fee will become active after call Set Protocol Fee
     * expires, providing users time to react to fee changes.
     *
     * @param fee The fee configuration that will become active after the notice period
     */
    event ProtocolFeePendingUpdate(ProtocolFee fee);

    /**
     * @dev Emitted when the liquidation auction duration is updated.
     *
     * @param newDuration The new duration for liquidation auctions in seconds
     */
    event LiquidationAuctionDurationUpdated(uint256 newDuration);

    /**
     * @dev Emitted when the flash action contract address is updated.
     *
     * @param newFlashActionContract The new flash action contract address
     */
    event FlashActionContractUpdated(address newFlashActionContract);

    /**
     * @dev Emitted when the minimum lock period for loans is updated.
     *
     * @param minLockPeriod The new minimum lock period in BPS
     */
    event MinLockPeriodUpdated(uint256 minLockPeriod);
}

// SPDX-License-Identifier: MIT
pragma solidity =0.8.28;

import "@loans/storages/AccessControlStorage.sol";

/**
 * @title LibAccessControl
 * @author BAE Lending Protocol
 * @notice Library providing core access control functionality for role-based permissions
 * @dev Implements role-based access control patterns compatible with OpenZeppelin's AccessControl
 *      but optimized for Diamond proxy storage patterns. Provides internal functions for role checking.
 */
library LibAccessControl {
    /// @notice The default admin role identifier, represented as bytes32(0)
    /// @dev This role has special privileges and can grant/revoke other roles
    bytes32 internal constant DEFAULT_ADMIN_ROLE = 0x00;

    /**
     * @notice Checks if an account has been granted a specific role
     * @dev Queries the Diamond storage to determine role membership
     * @param role_ The role identifier to check (keccak256 hash)
     * @param account_ The address to check for role membership
     * @return hasRole True if the account has the specified role, false otherwise
     */
    function hasRole(bytes32 role_, address account_) internal view returns (bool) {
        AccessControlStorage.Layout storage $ = AccessControlStorage.layout();
        return $.hasRole[account_][role_];
    }
}

File 12 of 12 : AccessControlStorage.sol
// SPDX-License-Identifier: MIT
pragma solidity =0.8.28;

/**
 * @title AccessControlStorage
 * @author BAE Lending Protocol
 * @notice Provides storage layout for role-based access control in a Diamond proxy pattern
 * @dev This library implements ERC-2535 Diamond storage pattern to avoid storage collisions
 *      in a multi-facet proxy system. Uses a deterministic storage slot based on a unique namespace.
 */
library AccessControlStorage {
    /// @dev Storage slot location calculated as:
    /// keccak256(abi.encode(uint256(keccak256("bae.lending.storage.AccessControl")) - 1)) & ~bytes32(uint256(0xff))
    /// This ensures the storage slot is deterministic and collision-resistant in Diamond proxy
    bytes32 private constant BaseLoanStorageLocation =
        0xfbd26770be56a82eb749ee8a16f2d01dbfcdba8e3efdf2a04de27a0b60aed200;

    /**
     * @notice Storage layout for access control data
     * @dev Contains mappings for role assignments using nested mapping pattern
     */
    struct Layout {
        /// @notice Mapping from account address to role hash to boolean indicating role possession
        /// @dev Structure: hasRole[account][roleHash] = true/false
        mapping(address => mapping(bytes32 => bool)) hasRole;
    }

    /**
     * @notice Returns a storage pointer to the AccessControl storage layout
     * @dev Uses inline assembly to return a storage reference at the predetermined slot
     * @return $ Storage pointer to the Layout struct
     */
    function layout() internal pure returns (Layout storage $) {
        assembly {
            $.slot := BaseLoanStorageLocation
        }
    }
}

Settings
{
  "remappings": [
    "@/=src/",
    "@delegate-registry/=dependencies/delegate-registry-2.0/src/",
    "@openzeppelin/contracts/=dependencies/@openzeppelin-contracts-5.3.0/",
    "@openzeppelin/contracts-upgradeable/=dependencies/@openzeppelin-contracts-upgradeable-5.3.0/",
    "@forge-std/=dependencies/forge-std-1.9.7/src/",
    "@loans/=src/loans/",
    "@test/=test/",
    "@openzeppelin-contracts-5.3.0/=dependencies/@openzeppelin-contracts-5.3.0/",
    "@openzeppelin-contracts-upgradeable-5.3.0/=dependencies/@openzeppelin-contracts-upgradeable-5.3.0/",
    "delegate-registry-2.0/=dependencies/delegate-registry-2.0/src/",
    "ds-test/=dependencies/delegate-registry-2.0/lib/forge-std/lib/ds-test/src/",
    "forge-std-1.9.7/=dependencies/forge-std-1.9.7/src/",
    "forge-std/=dependencies/delegate-registry-2.0/lib/forge-std/src/",
    "murky/=dependencies/delegate-registry-2.0/lib/murky/src/",
    "openzeppelin/=dependencies/delegate-registry-2.0/lib/openzeppelin-contracts/contracts/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 20000
  },
  "metadata": {
    "useLiteralContent": false,
    "bytecodeHash": "none",
    "appendCBOR": true
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "evmVersion": "cancun",
  "viaIR": true
}

Contract Security Audit

Contract ABI

API
[{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"neededRole","type":"bytes32"}],"name":"AccessControlUnauthorizedAccount","type":"error"},{"inputs":[],"name":"AddressZero","type":"error"},{"inputs":[],"name":"AlreadyWhitelistedContract","type":"error"},{"inputs":[],"name":"InvalidDurationError","type":"error"},{"inputs":[],"name":"NotWhitelistedContract","type":"error"},{"inputs":[{"internalType":"uint256","name":"_pendingProtocolFeeSetTime","type":"uint256"}],"name":"TooEarlyError","type":"error"},{"inputs":[],"name":"TooSoonError","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"newFlashActionContract","type":"address"}],"name":"FlashActionContractUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"newDuration","type":"uint256"}],"name":"LiquidationAuctionDurationUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"liquidator","type":"address"}],"name":"LiquidationContractUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_minimum","type":"uint256"}],"name":"MinAprImprovementUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"newMinBid","type":"uint256"}],"name":"MinBidLiquidationUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"minLockPeriod","type":"uint256"}],"name":"MinLockPeriodUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"components":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"fraction","type":"uint256"}],"indexed":false,"internalType":"struct ProtocolFee","name":"fee","type":"tuple"}],"name":"ProtocolFeePendingUpdate","type":"event"},{"anonymous":false,"inputs":[{"components":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"fraction","type":"uint256"}],"indexed":false,"internalType":"struct ProtocolFee","name":"fee","type":"tuple"}],"name":"ProtocolFeeUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"contractAdded","type":"address"}],"name":"WhitelistedCallbackContractAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"contractRemoved","type":"address"}],"name":"WhitelistedCallbackContractRemoved","type":"event"},{"inputs":[],"name":"MAX_AUCTION_DURATION","outputs":[{"internalType":"uint48","name":"","type":"uint48"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_AUCTION_DURATION","outputs":[{"internalType":"uint48","name":"","type":"uint48"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"contract_","type":"address"}],"name":"addWhitelistedCallbackContract","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role_","type":"bytes32"},{"internalType":"address","name":"account_","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"contract_","type":"address"}],"name":"removeWhitelistedCallbackContract","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role_","type":"bytes32"},{"internalType":"address","name":"account_","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newFlashActionContract_","type":"address"}],"name":"setFlashActionContract","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"minLockPeriod_","type":"uint256"}],"name":"setMinLockPeriod","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"setProtocolFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner_","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint48","name":"liquidationAuctionDuration_","type":"uint48"}],"name":"updateLiquidationAuctionDuration","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"loanLiquidator_","type":"address"}],"name":"updateLiquidationContract","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"minImprovementApr_","type":"uint256"}],"name":"updateMinImprovementApr","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"fraction","type":"uint256"}],"internalType":"struct ProtocolFee","name":"protocolFee_","type":"tuple"}],"name":"updateProtocolFee","outputs":[],"stateMutability":"nonpayable","type":"function"}]

60808060405234601557610f64908161001a8239f35b5f80fdfe60806040526004361015610011575f80fd5b5f3560e01c80632f2ff15d14610c6b57806336cb351b14610c005780633fb3517814610be35780634fd930ba14610a9a5780635122afb1146109555780636ccc9dde146108815780637320ca261461081657806373b99f10146105ac578063b97e527a146104a4578063c2f50a7a14610487578063d547741f146103ca578063da8d76b514610276578063db540a8a146101ab5763f2fde38b146100b3575f80fd5b346101a75760206003193601126101a7576100cc610d4e565b6100d4610e93565b6100dd81610e4e565b73ffffffffffffffffffffffffffffffffffffffff807fc8fcad8db84d3cc18b4c41d551ea0ee66dd599cde068d998e57d5e09332c131f5416911690817fffffffffffffffffffffffff00000000000000000000000000000000000000007fc8fcad8db84d3cc18b4c41d551ea0ee66dd599cde068d998e57d5e09332c131f5416177fc8fcad8db84d3cc18b4c41d551ea0ee66dd599cde068d998e57d5e09332c131f557f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e05f80a3005b5f80fd5b346101a75760206003193601126101a7577faed358a2bd4ca37fb72362cad5ae66b0b49a2a2031f9474a656e47b1f4afc419602073ffffffffffffffffffffffffffffffffffffffff6101fc610d4e565b610204610dde565b16807fffffffffffffffffffffffff00000000000000000000000000000000000000007f014188aa47349e14521c6215ea0fc8aaca8692b6e279bfc01a7282e69c9d20065416177f014188aa47349e14521c6215ea0fc8aaca8692b6e279bfc01a7282e69c9d200655604051908152a1005b346101a75760206003193601126101a75761028f610d4e565b610297610dde565b6102a081610e4e565b60ff6102e98273ffffffffffffffffffffffffffffffffffffffff165f527f014188aa47349e14521c6215ea0fc8aaca8692b6e279bfc01a7282e69c9d200d60205260405f2090565b54166103a25760208161035a7f6a6b10ec403319c89f7cc46cb63debaa4dd4b26822f357ca8f43e7a05059a69b9373ffffffffffffffffffffffffffffffffffffffff165f527f014188aa47349e14521c6215ea0fc8aaca8692b6e279bfc01a7282e69c9d200d60205260405f2090565b60017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0082541617905573ffffffffffffffffffffffffffffffffffffffff60405191168152a1005b7f9ad3410b000000000000000000000000000000000000000000000000000000005f5260045ffd5b346101a75760406003193601126101a75760043573ffffffffffffffffffffffffffffffffffffffff6103fb610d2b565b610403610d94565b16805f527ffbd26770be56a82eb749ee8a16f2d01dbfcdba8e3efdf2a04de27a0b60aed20060205260405f20825f5260205260405f207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00815416905533917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b5f80a4005b346101a7575f6003193601126101a75760206040516203f4808152f35b346101a75760206003193601126101a75760043565ffffffffffff81168091036101a7576104d0610dde565b6203f4808110158061059f575b15610577576020817f9b0306e96c09148e30f9acd9a1ebc2c7cb1bc0348adbf320530ead875f78292c927fffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000007f014188aa47349e14521c6215ea0fc8aaca8692b6e279bfc01a7282e69c9d200c5416177f014188aa47349e14521c6215ea0fc8aaca8692b6e279bfc01a7282e69c9d200c55604051908152a1005b7fa922f92c000000000000000000000000000000000000000000000000000000005f5260045ffd5b5062093a808111156104dd565b346101a7575f6003193601126101a7577f014188aa47349e14521c6215ea0fc8aaca8692b6e279bfc01a7282e69c9d200b5442106107ee576040516040810181811067ffffffffffffffff8211176107c1577fb3c1d38dbdc9199d0ce01f386d70e29014ed4af7af1d321ca6641a91f4b4dc0c91604091825273ffffffffffffffffffffffffffffffffffffffff7f014188aa47349e14521c6215ea0fc8aaca8692b6e279bfc01a7282e69c9d200954168082527f014188aa47349e14521c6215ea0fc8aaca8692b6e279bfc01a7282e69c9d200a5460208301918183527fffffffffffffffffffffffff00000000000000000000000000000000000000007f014188aa47349e14521c6215ea0fc8aaca8692b6e279bfc01a7282e69c9d20075416177f014188aa47349e14521c6215ea0fc8aaca8692b6e279bfc01a7282e69c9d2007557f014188aa47349e14521c6215ea0fc8aaca8692b6e279bfc01a7282e69c9d2008555f7f014188aa47349e14521c6215ea0fc8aaca8692b6e279bfc01a7282e69c9d2009555f7f014188aa47349e14521c6215ea0fc8aaca8692b6e279bfc01a7282e69c9d200a557fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f014188aa47349e14521c6215ea0fc8aaca8692b6e279bfc01a7282e69c9d200b5573ffffffffffffffffffffffffffffffffffffffff83519251168252516020820152a1005b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b7fa8a3a9dc000000000000000000000000000000000000000000000000000000005f5260045ffd5b346101a75760206003193601126101a7577fe818ff6972bf8970ca14a893539e57452588b197b76e6afe29c40a31b3363c616020600435610855610dde565b807f847582c39cc3b2c67c7a5fe5a43704b4d7ff45ccf56777815a28a282cadb580255604051908152a1005b346101a75760206003193601126101a7577f0656dc0fa3e59bca53331c14b87a4778ffac8c184915152fdd0f103838a4f378602073ffffffffffffffffffffffffffffffffffffffff6108d2610d4e565b6108da610dde565b6108e381610e4e565b16807fffffffffffffffffffffffff00000000000000000000000000000000000000007f014188aa47349e14521c6215ea0fc8aaca8692b6e279bfc01a7282e69c9d20025416177f014188aa47349e14521c6215ea0fc8aaca8692b6e279bfc01a7282e69c9d200255604051908152a1005b346101a75760406003193601126101a75761096e610dde565b61097e610979610d71565b610e4e565b73ffffffffffffffffffffffffffffffffffffffff61099b610d71565b167fffffffffffffffffffffffff00000000000000000000000000000000000000007f014188aa47349e14521c6215ea0fc8aaca8692b6e279bfc01a7282e69c9d20095416177f014188aa47349e14521c6215ea0fc8aaca8692b6e279bfc01a7282e69c9d2009557f160fef22fef07b45037a807beef2c89408a81168d1055cf34024c85396b882af6040602435807f014188aa47349e14521c6215ea0fc8aaca8692b6e279bfc01a7282e69c9d200a55427f014188aa47349e14521c6215ea0fc8aaca8692b6e279bfc01a7282e69c9d200b5581519073ffffffffffffffffffffffffffffffffffffffff610a8f610d4e565b1682526020820152a1005b346101a75760206003193601126101a757610ab3610d4e565b610abb610dde565b60ff610b048273ffffffffffffffffffffffffffffffffffffffff165f527f014188aa47349e14521c6215ea0fc8aaca8692b6e279bfc01a7282e69c9d200d60205260405f2090565b541615610bbb57602081610b767f924773930b2679ab8bf328330b211bedfb8f917551fd856f536bec008d17f9a69373ffffffffffffffffffffffffffffffffffffffff165f527f014188aa47349e14521c6215ea0fc8aaca8692b6e279bfc01a7282e69c9d200d60205260405f2090565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00815416905573ffffffffffffffffffffffffffffffffffffffff60405191168152a1005b7f178eb9d9000000000000000000000000000000000000000000000000000000005f5260045ffd5b346101a7575f6003193601126101a757602060405162093a808152f35b346101a75760206003193601126101a7577f257d95d6b6cd5a1a1e56bddff8487147cadd06fce4618b2197b174ccc96342016020600435610c3f610dde565b807f847582c39cc3b2c67c7a5fe5a43704b4d7ff45ccf56777815a28a282cadb580355604051908152a1005b346101a75760406003193601126101a75760043573ffffffffffffffffffffffffffffffffffffffff610c9c610d2b565b610ca4610d94565b16805f527ffbd26770be56a82eb749ee8a16f2d01dbfcdba8e3efdf2a04de27a0b60aed20060205260405f20825f5260205260405f2060017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0082541617905533917f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d5f80a4005b6024359073ffffffffffffffffffffffffffffffffffffffff821682036101a757565b6004359073ffffffffffffffffffffffffffffffffffffffff821682036101a757565b60043573ffffffffffffffffffffffffffffffffffffffff811681036101a75790565b335f527ffbd26770be56a82eb749ee8a16f2d01dbfcdba8e3efdf2a04de27a0b60aed20060205260405f205f805260205260ff60405f20541615610dd457565b610ddc610e93565b565b335f527ffbd26770be56a82eb749ee8a16f2d01dbfcdba8e3efdf2a04de27a0b60aed20060205260405f205f805260205260ff60405f20541615610e1e57565b7fe2517d3f000000000000000000000000000000000000000000000000000000005f52336004525f60245260445ffd5b73ffffffffffffffffffffffffffffffffffffffff1615610e6b57565b7f9fabe1c1000000000000000000000000000000000000000000000000000000005f5260045ffd5b73ffffffffffffffffffffffffffffffffffffffff7fc8fcad8db84d3cc18b4c41d551ea0ee66dd599cde068d998e57d5e09332c131f54163303610ed357565b60846040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f4c69624469616d6f6e643a204d75737420626520636f6e7472616374206f776e60448201527f65720000000000000000000000000000000000000000000000000000000000006064820152fdfea164736f6c634300081c000a

Deployed Bytecode

0x60806040526004361015610011575f80fd5b5f3560e01c80632f2ff15d14610c6b57806336cb351b14610c005780633fb3517814610be35780634fd930ba14610a9a5780635122afb1146109555780636ccc9dde146108815780637320ca261461081657806373b99f10146105ac578063b97e527a146104a4578063c2f50a7a14610487578063d547741f146103ca578063da8d76b514610276578063db540a8a146101ab5763f2fde38b146100b3575f80fd5b346101a75760206003193601126101a7576100cc610d4e565b6100d4610e93565b6100dd81610e4e565b73ffffffffffffffffffffffffffffffffffffffff807fc8fcad8db84d3cc18b4c41d551ea0ee66dd599cde068d998e57d5e09332c131f5416911690817fffffffffffffffffffffffff00000000000000000000000000000000000000007fc8fcad8db84d3cc18b4c41d551ea0ee66dd599cde068d998e57d5e09332c131f5416177fc8fcad8db84d3cc18b4c41d551ea0ee66dd599cde068d998e57d5e09332c131f557f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e05f80a3005b5f80fd5b346101a75760206003193601126101a7577faed358a2bd4ca37fb72362cad5ae66b0b49a2a2031f9474a656e47b1f4afc419602073ffffffffffffffffffffffffffffffffffffffff6101fc610d4e565b610204610dde565b16807fffffffffffffffffffffffff00000000000000000000000000000000000000007f014188aa47349e14521c6215ea0fc8aaca8692b6e279bfc01a7282e69c9d20065416177f014188aa47349e14521c6215ea0fc8aaca8692b6e279bfc01a7282e69c9d200655604051908152a1005b346101a75760206003193601126101a75761028f610d4e565b610297610dde565b6102a081610e4e565b60ff6102e98273ffffffffffffffffffffffffffffffffffffffff165f527f014188aa47349e14521c6215ea0fc8aaca8692b6e279bfc01a7282e69c9d200d60205260405f2090565b54166103a25760208161035a7f6a6b10ec403319c89f7cc46cb63debaa4dd4b26822f357ca8f43e7a05059a69b9373ffffffffffffffffffffffffffffffffffffffff165f527f014188aa47349e14521c6215ea0fc8aaca8692b6e279bfc01a7282e69c9d200d60205260405f2090565b60017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0082541617905573ffffffffffffffffffffffffffffffffffffffff60405191168152a1005b7f9ad3410b000000000000000000000000000000000000000000000000000000005f5260045ffd5b346101a75760406003193601126101a75760043573ffffffffffffffffffffffffffffffffffffffff6103fb610d2b565b610403610d94565b16805f527ffbd26770be56a82eb749ee8a16f2d01dbfcdba8e3efdf2a04de27a0b60aed20060205260405f20825f5260205260405f207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00815416905533917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b5f80a4005b346101a7575f6003193601126101a75760206040516203f4808152f35b346101a75760206003193601126101a75760043565ffffffffffff81168091036101a7576104d0610dde565b6203f4808110158061059f575b15610577576020817f9b0306e96c09148e30f9acd9a1ebc2c7cb1bc0348adbf320530ead875f78292c927fffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000007f014188aa47349e14521c6215ea0fc8aaca8692b6e279bfc01a7282e69c9d200c5416177f014188aa47349e14521c6215ea0fc8aaca8692b6e279bfc01a7282e69c9d200c55604051908152a1005b7fa922f92c000000000000000000000000000000000000000000000000000000005f5260045ffd5b5062093a808111156104dd565b346101a7575f6003193601126101a7577f014188aa47349e14521c6215ea0fc8aaca8692b6e279bfc01a7282e69c9d200b5442106107ee576040516040810181811067ffffffffffffffff8211176107c1577fb3c1d38dbdc9199d0ce01f386d70e29014ed4af7af1d321ca6641a91f4b4dc0c91604091825273ffffffffffffffffffffffffffffffffffffffff7f014188aa47349e14521c6215ea0fc8aaca8692b6e279bfc01a7282e69c9d200954168082527f014188aa47349e14521c6215ea0fc8aaca8692b6e279bfc01a7282e69c9d200a5460208301918183527fffffffffffffffffffffffff00000000000000000000000000000000000000007f014188aa47349e14521c6215ea0fc8aaca8692b6e279bfc01a7282e69c9d20075416177f014188aa47349e14521c6215ea0fc8aaca8692b6e279bfc01a7282e69c9d2007557f014188aa47349e14521c6215ea0fc8aaca8692b6e279bfc01a7282e69c9d2008555f7f014188aa47349e14521c6215ea0fc8aaca8692b6e279bfc01a7282e69c9d2009555f7f014188aa47349e14521c6215ea0fc8aaca8692b6e279bfc01a7282e69c9d200a557fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f014188aa47349e14521c6215ea0fc8aaca8692b6e279bfc01a7282e69c9d200b5573ffffffffffffffffffffffffffffffffffffffff83519251168252516020820152a1005b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b7fa8a3a9dc000000000000000000000000000000000000000000000000000000005f5260045ffd5b346101a75760206003193601126101a7577fe818ff6972bf8970ca14a893539e57452588b197b76e6afe29c40a31b3363c616020600435610855610dde565b807f847582c39cc3b2c67c7a5fe5a43704b4d7ff45ccf56777815a28a282cadb580255604051908152a1005b346101a75760206003193601126101a7577f0656dc0fa3e59bca53331c14b87a4778ffac8c184915152fdd0f103838a4f378602073ffffffffffffffffffffffffffffffffffffffff6108d2610d4e565b6108da610dde565b6108e381610e4e565b16807fffffffffffffffffffffffff00000000000000000000000000000000000000007f014188aa47349e14521c6215ea0fc8aaca8692b6e279bfc01a7282e69c9d20025416177f014188aa47349e14521c6215ea0fc8aaca8692b6e279bfc01a7282e69c9d200255604051908152a1005b346101a75760406003193601126101a75761096e610dde565b61097e610979610d71565b610e4e565b73ffffffffffffffffffffffffffffffffffffffff61099b610d71565b167fffffffffffffffffffffffff00000000000000000000000000000000000000007f014188aa47349e14521c6215ea0fc8aaca8692b6e279bfc01a7282e69c9d20095416177f014188aa47349e14521c6215ea0fc8aaca8692b6e279bfc01a7282e69c9d2009557f160fef22fef07b45037a807beef2c89408a81168d1055cf34024c85396b882af6040602435807f014188aa47349e14521c6215ea0fc8aaca8692b6e279bfc01a7282e69c9d200a55427f014188aa47349e14521c6215ea0fc8aaca8692b6e279bfc01a7282e69c9d200b5581519073ffffffffffffffffffffffffffffffffffffffff610a8f610d4e565b1682526020820152a1005b346101a75760206003193601126101a757610ab3610d4e565b610abb610dde565b60ff610b048273ffffffffffffffffffffffffffffffffffffffff165f527f014188aa47349e14521c6215ea0fc8aaca8692b6e279bfc01a7282e69c9d200d60205260405f2090565b541615610bbb57602081610b767f924773930b2679ab8bf328330b211bedfb8f917551fd856f536bec008d17f9a69373ffffffffffffffffffffffffffffffffffffffff165f527f014188aa47349e14521c6215ea0fc8aaca8692b6e279bfc01a7282e69c9d200d60205260405f2090565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00815416905573ffffffffffffffffffffffffffffffffffffffff60405191168152a1005b7f178eb9d9000000000000000000000000000000000000000000000000000000005f5260045ffd5b346101a7575f6003193601126101a757602060405162093a808152f35b346101a75760206003193601126101a7577f257d95d6b6cd5a1a1e56bddff8487147cadd06fce4618b2197b174ccc96342016020600435610c3f610dde565b807f847582c39cc3b2c67c7a5fe5a43704b4d7ff45ccf56777815a28a282cadb580355604051908152a1005b346101a75760406003193601126101a75760043573ffffffffffffffffffffffffffffffffffffffff610c9c610d2b565b610ca4610d94565b16805f527ffbd26770be56a82eb749ee8a16f2d01dbfcdba8e3efdf2a04de27a0b60aed20060205260405f20825f5260205260405f2060017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0082541617905533917f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d5f80a4005b6024359073ffffffffffffffffffffffffffffffffffffffff821682036101a757565b6004359073ffffffffffffffffffffffffffffffffffffffff821682036101a757565b60043573ffffffffffffffffffffffffffffffffffffffff811681036101a75790565b335f527ffbd26770be56a82eb749ee8a16f2d01dbfcdba8e3efdf2a04de27a0b60aed20060205260405f205f805260205260ff60405f20541615610dd457565b610ddc610e93565b565b335f527ffbd26770be56a82eb749ee8a16f2d01dbfcdba8e3efdf2a04de27a0b60aed20060205260405f205f805260205260ff60405f20541615610e1e57565b7fe2517d3f000000000000000000000000000000000000000000000000000000005f52336004525f60245260445ffd5b73ffffffffffffffffffffffffffffffffffffffff1615610e6b57565b7f9fabe1c1000000000000000000000000000000000000000000000000000000005f5260045ffd5b73ffffffffffffffffffffffffffffffffffffffff7fc8fcad8db84d3cc18b4c41d551ea0ee66dd599cde068d998e57d5e09332c131f54163303610ed357565b60846040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f4c69624469616d6f6e643a204d75737420626520636f6e7472616374206f776e60448201527f65720000000000000000000000000000000000000000000000000000000000006064820152fdfea164736f6c634300081c000a

Block Transaction Gas Used Reward
view all blocks ##produced##

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading
Loading...
Loading

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading

A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.