SiloLens

Description:

Multi-signature wallet contract requiring multiple confirmations for transaction execution.

Blockchain: Ethereum

Source Code: View Code On The Blockchain

Solidity Source Code:

{{
  "language": "Solidity",
  "sources": {
    "silo-core/contracts/SiloLens.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.28;

// solhint-disable ordering

import {Strings} from "openzeppelin5/utils/Strings.sol";
import {IERC20} from "openzeppelin5/token/ERC20/IERC20.sol";
import {Utils} from "silo-foundry-utils/lib/Utils.sol";

import {ISiloLens, ISilo} from "./interfaces/ISiloLens.sol";
import {IShareToken} from "./interfaces/IShareToken.sol";
import {ISiloConfig} from "./interfaces/ISiloConfig.sol";
import {IPartialLiquidation} from "./interfaces/IPartialLiquidation.sol";
import {IInterestRateModel} from "./interfaces/IInterestRateModel.sol";

import {SiloLensLib} from "./lib/SiloLensLib.sol";
import {SiloStdLib} from "./lib/SiloStdLib.sol";
import {IPartialLiquidation} from "./interfaces/IPartialLiquidation.sol";
import {IDistributionManager} from "silo-core/contracts/incentives/interfaces/IDistributionManager.sol";


/// @title SiloLens is a helper contract for integrations and UI
contract SiloLens is ISiloLens {
    uint256 internal constant _PRECISION_DECIMALS = 1e18;

    /// @inheritdoc ISiloLens
    function isSolvent(ISilo _silo, address _borrower) external view returns (bool) {
        return _silo.isSolvent(_borrower);
    }

    /// @inheritdoc ISiloLens
    function liquidity(ISilo _silo) external view returns (uint256) {
        return _silo.getLiquidity();
    }

    /// @inheritdoc ISiloLens
    function getRawLiquidity(ISilo _silo) external view virtual returns (uint256 rawLiquidity) {
        rawLiquidity = SiloLensLib.getRawLiquidity(_silo);
    }

    /// @inheritdoc ISiloLens
    function getMaxLtv(ISilo _silo) external view virtual returns (uint256 maxLtv) {
        return SiloLensLib.getMaxLtv(_silo);
    }

    /// @inheritdoc ISiloLens
    function getLt(ISilo _silo) external view virtual returns (uint256 lt) {
        lt = SiloLensLib.getLt(_silo);
    }

    /// @inheritdoc ISiloLens
    function getUserLT(ISilo _silo, address _borrower) external view returns (uint256 userLT) {
        return SiloLensLib.getUserLt(_silo, _borrower);
    }

    function getUsersLT(Borrower[] calldata _borrowers) external view returns (uint256[] memory usersLTs) {
        usersLTs = new uint256[](_borrowers.length);

        for (uint256 i; i < _borrowers.length; i++) {
            Borrower memory borrower = _borrowers[i];
            usersLTs[i] = SiloLensLib.getUserLt(borrower.silo, borrower.wallet);
        }
    }

    function getUsersHealth(Borrower[] calldata _borrowers) external view returns (BorrowerHealth[] memory healths) {
        healths = new BorrowerHealth[](_borrowers.length);

        for (uint256 i; i < _borrowers.length; i++) {
            Borrower memory borrower = _borrowers[i];
            BorrowerHealth memory health = healths[i];

            (health.ltv, health.lt) = SiloLensLib.getLtvAndLt(borrower.silo, borrower.wallet);
        }
    }

    /// @inheritdoc ISiloLens
    function getUserLTV(ISilo _silo, address _borrower) external view returns (uint256 userLTV) {
        return SiloLensLib.getLtv(_silo, _borrower);
    }

    /// @inheritdoc ISiloLens
    function getLtv(ISilo _silo, address _borrower) external view virtual returns (uint256 ltv) {
        return SiloLensLib.getLtv(_silo, _borrower);
    }

    /// @inheritdoc ISiloLens
    function hasPosition(ISiloConfig _siloConfig, address _borrower) external view virtual returns (bool has) {
        has = SiloLensLib.hasPosition(_siloConfig, _borrower);
    }

    /// @inheritdoc ISiloLens
    function inDebt(ISiloConfig _siloConfig, address _borrower) external view returns (bool hasDebt) {
        hasDebt = SiloLensLib.inDebt(_siloConfig, _borrower);
    }

    /// @inheritdoc ISiloLens
    function calculateProfitableLiquidation(ISilo _silo, address _borrower) 
        external
        view
        returns (uint256 collateralToLiquidate, uint256 debtToCover)
    {
        (collateralToLiquidate, debtToCover) = SiloLensLib.calculateProfitableLiquidation(_silo, _borrower);
    }

    /// @inheritdoc ISiloLens
    function getFeesAndFeeReceivers(ISilo _silo)
        external
        view
        virtual
        returns (address daoFeeReceiver, address deployerFeeReceiver, uint256 daoFee, uint256 deployerFee)
    {
        (daoFeeReceiver, deployerFeeReceiver, daoFee, deployerFee,) = SiloStdLib.getFeesAndFeeReceiversWithAsset(_silo);
    }

    /// @inheritdoc ISiloLens
    function collateralBalanceOfUnderlying(ISilo _silo, address _borrower)
        external
        view
        virtual
        returns (uint256 borrowerCollateral)
    {
        return SiloLensLib.collateralBalanceOfUnderlying(_silo, _borrower);
    }

    /// @inheritdoc ISiloLens
    function debtBalanceOfUnderlying(ISilo _silo, address _borrower) external view virtual returns (uint256) {
        return _silo.maxRepay(_borrower);
    }

    /// @inheritdoc ISiloLens
    function maxLiquidation(ISilo _silo, IPartialLiquidation _hook, address _borrower)
        external
        view
        virtual
        returns (uint256 collateralToLiquidate, uint256 debtToRepay, bool sTokenRequired, bool fullLiquidation)
    {
        (collateralToLiquidate, debtToRepay, sTokenRequired) = _hook.maxLiquidation(_borrower);

        uint256 maxRepay = _silo.maxRepay(_borrower);
        fullLiquidation = maxRepay == debtToRepay;

        if (!sTokenRequired) return (collateralToLiquidate, debtToRepay, sTokenRequired, fullLiquidation);

        ISiloConfig siloConfig = _silo.config();

        (ISiloConfig.ConfigData memory collateralConfig,) = siloConfig.getConfigsForSolvency(_borrower);

        uint256 protectedShares = IERC20(collateralConfig.protectedShareToken).balanceOf(_borrower);

        if (protectedShares == 0) return (collateralToLiquidate, debtToRepay, sTokenRequired, fullLiquidation);

        uint256 protectedAssets = ISilo(collateralConfig.silo).convertToAssets(
            protectedShares,
            ISilo.AssetType.Protected
        );

        if (protectedAssets == 0) return (collateralToLiquidate, debtToRepay, sTokenRequired, fullLiquidation);

        uint256 availableLiquidity = ISilo(collateralConfig.silo).getLiquidity();

        sTokenRequired = availableLiquidity + protectedAssets < collateralToLiquidate;
    }

    /// @inheritdoc ISiloLens
    function totalDeposits(ISilo _silo) external view returns (uint256 totalDepositsAmount) {
        totalDepositsAmount = _silo.getTotalAssetsStorage(ISilo.AssetType.Collateral);
    }

    /// @inheritdoc ISiloLens
    function totalDepositsWithInterest(ISilo _silo) external view returns (uint256 amount) {
        amount = _silo.totalAssets();
    }

    function totalBorrowAmountWithInterest(ISilo _silo) external view returns (uint256 amount) {
        amount = _silo.getDebtAssets();
    }

    /// @inheritdoc ISiloLens
    function collateralOnlyDeposits(ISilo _silo) external view returns (uint256) {
        return _silo.getTotalAssetsStorage(ISilo.AssetType.Protected);
    }

    /// @inheritdoc ISiloLens
    function getDepositAmount(ISilo _silo, address _borrower)
        external
        view
        returns (uint256 borrowerDeposits)
    {
        borrowerDeposits = _silo.previewRedeem(_silo.balanceOf(_borrower));
    }

    /// @inheritdoc ISiloLens
    function totalBorrowAmount(ISilo _silo) external view returns (uint256) {
        return _silo.getTotalAssetsStorage(ISilo.AssetType.Debt);
    }

    /// @inheritdoc ISiloLens
    function totalBorrowShare(ISilo _silo) external view returns (uint256) {
        return SiloLensLib.totalBorrowShare(_silo);
    }

    /// @inheritdoc ISiloLens
    function getBorrowAmount(ISilo _silo, address _borrower)
        external
        view
        returns (uint256 maxRepay)
    {
        maxRepay = _silo.maxRepay(_borrower);
    }

    /// @inheritdoc ISiloLens
    function borrowShare(ISilo _silo, address _borrower) external view returns (uint256) {
        return SiloLensLib.borrowShare(_silo, _borrower);
    }

    /// @inheritdoc ISiloLens
    function protocolFees(ISilo _silo) external view returns (uint256 daoAndDeployerRevenue) {
        (daoAndDeployerRevenue,,,,) = _silo.getSiloStorage();
    }

    /// @inheritdoc ISiloLens
    function calculateCollateralValue(ISiloConfig _siloConfig, address _borrower)
        external
        view
        returns (uint256 collateralValue)
    {
        (collateralValue,) = SiloLensLib.calculateValues(_siloConfig, _borrower);
    }

    /// @inheritdoc ISiloLens
    function calculateBorrowValue(ISiloConfig _siloConfig, address _borrower)
        external
        view
        returns (uint256 borrowValue)
    {
        (, borrowValue) = SiloLensLib.calculateValues(_siloConfig, _borrower);
    }

    /// @inheritdoc ISiloLens
    function getUtilization(ISilo _silo) external view returns (uint256 utilization) {
        ISilo.UtilizationData memory data = _silo.utilizationData();

        if (data.collateralAssets != 0) {
            utilization = data.debtAssets * _PRECISION_DECIMALS / data.collateralAssets;
        }
    }

    /// @inheritdoc ISiloLens
    function getInterestRateModel(ISilo _silo) external view virtual returns (address irm) {
        return SiloLensLib.getInterestRateModel(_silo);
    }

    /// @inheritdoc ISiloLens
    function getBorrowAPR(ISilo _silo) external view virtual returns (uint256 borrowAPR) {
        return SiloLensLib.getBorrowAPR(_silo);
    }

    /// @inheritdoc ISiloLens
    function getDepositAPR(ISilo _silo) external view virtual returns (uint256 depositAPR) {
        return SiloLensLib.getDepositAPR(_silo);
    }

    /// @inheritdoc ISiloLens
    function getAPRs(ISilo[] calldata _silos) external view virtual returns (APR[] memory aprs) {
        aprs = new APR[](_silos.length);

        for (uint256 i; i < _silos.length; i++) {
            ISilo silo = _silos[i];

            aprs[i] = APR({
                borrowAPR: SiloLensLib.getBorrowAPR(silo),
                depositAPR: SiloLensLib.getDepositAPR(silo)
            });
        }
    }

    function getModel(ISilo _silo) public view returns (IInterestRateModel irm) {
        irm = IInterestRateModel(_silo.config().getConfig(address(_silo)).interestRateModel);
    }

    function getSiloIncentivesControllerProgramsNames(
        address _siloIncentivesController
    ) public view returns (string[] memory programsNames) {
        IDistributionManager distributionManager = IDistributionManager(_siloIncentivesController);
        string[] memory originalProgramsNames = distributionManager.getAllProgramsNames();

        programsNames = new string[](originalProgramsNames.length);

        for (uint256 i; i < originalProgramsNames.length; i++) {
            bytes memory originalProgramName = bytes(originalProgramsNames[i]);

            if (_isTokenAddress(originalProgramName)) {
                address token = address(bytes20(originalProgramName));
                programsNames[i] = Strings.toHexString(token);
            } else {
                programsNames[i] = originalProgramsNames[i];
            }
        }
    }

    function getOracleAddresses(ISilo _silo) external view returns (address solvencyOracle, address maxLtvOracle) {
        ISiloConfig.ConfigData memory config = _silo.config().getConfig(address(_silo));

        solvencyOracle = config.solvencyOracle;
        maxLtvOracle = config.maxLtvOracle;
    }

    function _isTokenAddress(bytes memory _name) private view returns (bool isToken) {
        if (_name.length != 20) return false;

        address token = address(bytes20(_name));

        if (Utils.getCodeAt(token).length == 0) return false;

        // Sanity check to be sure that it is a token
        try IERC20(token).balanceOf(address(this)) returns (uint256) {
            isToken = true;
        } catch {}
    }
}
"
    },
    "gitmodules/openzeppelin-contracts-5/contracts/utils/Strings.sol": {
      "content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Strings.sol)

pragma solidity ^0.8.20;

import {Math} from "./math/Math.sol";
import {SignedMath} from "./math/SignedMath.sol";

/**
 * @dev String operations.
 */
library Strings {
    bytes16 private constant HEX_DIGITS = "0123456789abcdef";
    uint8 private constant ADDRESS_LENGTH = 20;

    /**
     * @dev The `value` string doesn't fit in the specified `length`.
     */
    error StringsInsufficientHexLength(uint256 value, uint256 length);

    /**
     * @dev Converts a `uint256` to its ASCII `string` decimal representation.
     */
    function toString(uint256 value) internal pure returns (string memory) {
        unchecked {
            uint256 length = Math.log10(value) + 1;
            string memory buffer = new string(length);
            uint256 ptr;
            /// @solidity memory-safe-assembly
            assembly {
                ptr := add(buffer, add(32, length))
            }
            while (true) {
                ptr--;
                /// @solidity memory-safe-assembly
                assembly {
                    mstore8(ptr, byte(mod(value, 10), HEX_DIGITS))
                }
                value /= 10;
                if (value == 0) break;
            }
            return buffer;
        }
    }

    /**
     * @dev Converts a `int256` to its ASCII `string` decimal representation.
     */
    function toStringSigned(int256 value) internal pure returns (string memory) {
        return string.concat(value < 0 ? "-" : "", toString(SignedMath.abs(value)));
    }

    /**
     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
     */
    function toHexString(uint256 value) internal pure returns (string memory) {
        unchecked {
            return toHexString(value, Math.log256(value) + 1);
        }
    }

    /**
     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
     */
    function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
        uint256 localValue = value;
        bytes memory buffer = new bytes(2 * length + 2);
        buffer[0] = "0";
        buffer[1] = "x";
        for (uint256 i = 2 * length + 1; i > 1; --i) {
            buffer[i] = HEX_DIGITS[localValue & 0xf];
            localValue >>= 4;
        }
        if (localValue != 0) {
            revert StringsInsufficientHexLength(value, length);
        }
        return string(buffer);
    }

    /**
     * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal
     * representation.
     */
    function toHexString(address addr) internal pure returns (string memory) {
        return toHexString(uint256(uint160(addr)), ADDRESS_LENGTH);
    }

    /**
     * @dev Returns true if the two strings are equal.
     */
    function equal(string memory a, string memory b) internal pure returns (bool) {
        return bytes(a).length == bytes(b).length && keccak256(bytes(a)) == keccak256(bytes(b));
    }
}
"
    },
    "gitmodules/openzeppelin-contracts-5/contracts/token/ERC20/IERC20.sol": {
      "content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)

pragma solidity ^0.8.20;

/**
 * @dev Interface of the ERC-20 standard as defined in the ERC.
 */
interface IERC20 {
    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

    /**
     * @dev Emitted when the allowance of a `spender` for an `owner` is set by
     * a call to {approve}. `value` is the new allowance.
     */
    event Approval(address indexed owner, address indexed spender, uint256 value);

    /**
     * @dev Returns the value of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns the value of tokens owned by `account`.
     */
    function balanceOf(address account) external view returns (uint256);

    /**
     * @dev Moves a `value` amount of tokens from the caller's account to `to`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address to, uint256 value) external returns (bool);

    /**
     * @dev Returns the remaining number of tokens that `spender` will be
     * allowed to spend on behalf of `owner` through {transferFrom}. This is
     * zero by default.
     *
     * This value changes when {approve} or {transferFrom} are called.
     */
    function allowance(address owner, address spender) external view returns (uint256);

    /**
     * @dev Sets a `value` amount of tokens as the allowance of `spender` over the
     * caller's tokens.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * IMPORTANT: Beware that changing an allowance with this method brings the risk
     * that someone may use both the old and the new allowance by unfortunate
     * transaction ordering. One possible solution to mitigate this race
     * condition is to first reduce the spender's allowance to 0 and set the
     * desired value afterwards:
     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
     *
     * Emits an {Approval} event.
     */
    function approve(address spender, uint256 value) external returns (bool);

    /**
     * @dev Moves a `value` amount of tokens from `from` to `to` using the
     * allowance mechanism. `value` is then deducted from the caller's
     * allowance.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(address from, address to, uint256 value) external returns (bool);
}
"
    },
    "gitmodules/silo-foundry-utils/contracts/lib/Utils.sol": {
      "content": "// SPDX-License-Identifier: MIT
pragma solidity >=0.6.2 <0.9.0;

library Utils {
    // https://docs.soliditylang.org/en/latest/assembly.html#example
    function getCodeAt(address _addr) internal view returns (bytes memory oCode) {
        assembly {
            // retrieve the size of the code, this needs assembly
            let size := extcodesize(_addr)
            // allocate output byte array - this could also be done without assembly
            // by using o_code = new bytes(size)
            oCode := mload(0x40)
            // new "memory end" including padding
            mstore(0x40, add(oCode, and(add(add(size, 0x20), 0x1f), not(0x1f))))
            // store length in memory
            mstore(oCode, size)
            // actually retrieve the code, this needs assembly
            extcodecopy(_addr, add(oCode, 0x20), 0, size)
        }
    }

    // https://ethereum.stackexchange.com/questions/10932/how-to-convert-string-to-int
    function stringToUint(string memory s) internal pure returns (uint256) {
        bytes memory b = bytes(s);
        uint256 result = 0;
        for (uint256 i = 0; i < b.length; i++) {
            if (uint8(b[i]) >= 48 && uint8(b[i]) <= 57) {
                result = result * 10 + (uint256(uint8(b[i])) - 48);
            }
        }
        return result;
    }

    function encodeGetAddressCall(bytes4 _fnSig, uint256 _chainId, string memory _key)
        internal
        pure
        returns (bytes memory fnPayload)
    {
        assembly {
            function allocate(length) -> pos {
                pos := mload(0x40)
                mstore(0x40, add(pos, length))
            }

            let keyLength := mload(_key)

            fnPayload := mload(0x40)

            let p := allocate(0x20)

            let keySlots := mul(add(div(keyLength, 0x20), 0x01), 0x20)

            mstore(p, add(0x64, keySlots))

            p := allocate(0x04)
            mstore(p, _fnSig)

            p := allocate(0x20)
            mstore(p, _chainId)

            p := allocate(0x20)
            mstore(p, 0x40)

            p := allocate(0x20)
            mstore(p, keyLength)

            for { let i := 0 } lt(i, keyLength) { i := add(i, 0x20) } {
                p := allocate(0x20)
                mstore(p, mload(add(add(_key, 0x20), i)))
            }
        }
    }

    function encodeSingleSelectorCall(bytes4 _fnSig) internal pure returns (bytes memory fnPayload) {
        assembly {
            function allocate(length) -> pos {
                pos := mload(0x40)
                mstore(0x40, add(pos, length))
            }

            fnPayload := mload(0x40)

            let p := allocate(0x20)
            mstore(fnPayload, 0x04)

            p := allocate(0x04)
            mstore(p, _fnSig)
        }
    }

    // https://ethereum.stackexchange.com/questions/15350/how-to-convert-an-bytes-to-address-in-solidity
    function asciiBytesToAddress(bytes memory b) internal pure returns (address) {
        uint256 result = 0;
        for (uint256 i = 0; i < b.length; i++) {
            uint256 c = uint256(uint8(b[i]));
            if (c >= 48 && c <= 57) {
                result = result * 16 + (c - 48);
            }
            if (c >= 65 && c <= 90) {
                result = result * 16 + (c - 55);
            }
            if (c >= 97 && c <= 122) {
                result = result * 16 + (c - 87);
            }
        }
        return address(uint160(result));
    }
}
"
    },
    "silo-core/contracts/interfaces/ISiloLens.sol": {
      "content": "// SPDX-License-Identifier: MIT
pragma solidity >=0.5.0;

import {ISiloConfig} from "./ISiloConfig.sol";
import {ISilo} from "./ISilo.sol";
import {IInterestRateModel} from "./IInterestRateModel.sol";
import {IPartialLiquidation} from "./IPartialLiquidation.sol";

interface ISiloLens {
    struct Borrower {
        ISilo silo;
        address wallet;
    }

    struct BorrowerHealth {
        uint256 lt;
        uint256 ltv;
    }

    struct APR {
        uint256 depositAPR;
        uint256 borrowAPR;
    }

    error InvalidAsset();

    /// @dev calculates solvency
    /// @notice this is backwards compatible method, you can use `_silo.isSolvent(_borrower)` directly.
    /// @param _silo Silo address from which to read data
    /// @param _borrower wallet address
    /// @return true if solvent, false otherwise
    function isSolvent(ISilo _silo, address _borrower) external view returns (bool);

    /// @dev Amount of token that is available for borrowing.
    /// @notice this is backwards compatible method, you can use `_silo.getLiquidity()`
    /// @param _silo Silo address from which to read data
    /// @return Silo liquidity
    function liquidity(ISilo _silo) external view returns (uint256);

    /// @return liquidity based on contract state (without interest, fees)
    function getRawLiquidity(ISilo _silo) external view returns (uint256 liquidity);

    /// @notice Retrieves the maximum loan-to-value (LTV) ratio
    /// @param _silo Address of the silo
    /// @return maxLtv The maximum LTV ratio configured for the silo in 18 decimals points
    function getMaxLtv(ISilo _silo) external view returns (uint256 maxLtv);

    /// @notice Retrieves the LT value
    /// @param _silo Address of the silo
    /// @return lt The LT value in 18 decimals points
    function getLt(ISilo _silo) external view returns (uint256 lt);

    /// @notice Retrieves the LT for a specific borrower
    /// @param _silo Address of the silo
    /// @param _borrower Address of the borrower
    /// @return userLT The LT for the borrower in 18 decimals points, returns 0 if no debt
    function getUserLT(ISilo _silo, address _borrower) external view returns (uint256 userLT);

    /// @notice Retrieves the LT for a specific borrowers
    /// @param _borrowers list of borrowers with corresponding silo addresses
    /// @return usersLTs The LTs for the borrowers in 18 decimals points, returns 0 for users with no debt
    function getUsersLT(Borrower[] calldata _borrowers) external view returns (uint256[] memory usersLTs);

    /// @notice Retrieves the LT and LTV for a specific borrowers
    /// @param _borrowers list of borrowers with corresponding silo addresses
    /// @return healths The LTs and LTVs for the borrowers in 18 decimals points, returns 0 for users with no debt
    function getUsersHealth(Borrower[] calldata _borrowers) external view returns (BorrowerHealth[] memory healths);

    /// @notice Retrieves the loan-to-value (LTV) for a specific borrower
    /// @param _silo Address of the silo
    /// @param _borrower Address of the borrower
    /// @return userLTV The LTV for the borrower in 18 decimals points
    function getUserLTV(ISilo _silo, address _borrower) external view returns (uint256 userLTV);

    /// @notice Retrieves the loan-to-value (LTV) for a specific borrower
    /// @param _silo Address of the silo
    /// @param _borrower Address of the borrower
    /// @return ltv The LTV for the borrower in 18 decimals points
    function getLtv(ISilo _silo, address _borrower) external view returns (uint256 ltv);

    /// @notice Check if user has position (collateral, protected or debt)
    /// in any asset in a market (both silos are checked)
    /// @param _siloConfig Market address (silo config address)
    /// @param _borrower wallet address for which to read data
    /// @return TRUE if user has position in any asset
    function hasPosition(ISiloConfig _siloConfig, address _borrower) external view returns (bool);

    /// @notice Check if user is in debt
    /// @param _siloConfig Market address (silo config address)
    /// @param _borrower wallet address for which to read data
    /// @return TRUE if user borrowed any amount of any asset, otherwise FALSE
    function inDebt(ISiloConfig _siloConfig, address _borrower) external view returns (bool);

    /// @dev calculate profitable liquidation values, in case of bad debt, it will calculate max debt to cover
    /// based on available collateral. 
    /// Result returned by this method might not work for case, when full liquidation is required.
    function calculateProfitableLiquidation(ISilo _silo, address _borrower) 
        external
        view
        returns (uint256 collateralToLiquidate, uint256 debtToCover);

    /// @notice Retrieves the fee details in 18 decimals points and the addresses of the DAO and deployer fee receivers
    /// @param _silo Address of the silo
    /// @return daoFeeReceiver The address of the DAO fee receiver
    /// @return deployerFeeReceiver The address of the deployer fee receiver
    /// @return daoFee The total fee for the DAO in 18 decimals points
    /// @return deployerFee The total fee for the deployer in 18 decimals points
    function getFeesAndFeeReceivers(ISilo _silo)
        external
        view
        returns (address daoFeeReceiver, address deployerFeeReceiver, uint256 daoFee, uint256 deployerFee);

    /// @notice Get underlying balance of all deposits of silo asset of given user including "protected"
    /// deposits, with interest
    /// @param _silo Address of the silo
    /// @param _borrower wallet address for which to read data
    /// @return balance of underlying tokens for the given `_borrower`
    function collateralBalanceOfUnderlying(ISilo _silo, address _borrower)
        external
        view
        returns (uint256);

    /// @notice Get amount of debt of underlying token for given user
    /// @param _silo Silo address from which to read data
    /// @param _borrower wallet address for which to read data
    /// @return balance of underlying token owed
    function debtBalanceOfUnderlying(ISilo _silo, address _borrower) external view returns (uint256);

    /// @param _silo silo where borrower has debt
    /// @param _hook hook for silo with debt
    /// @param _borrower borrower address
    /// @return collateralToLiquidate underestimated amount of collateral liquidator will get
    /// @return debtToRepay debt amount needed to be repay to get `collateralToLiquidate`
    /// @return sTokenRequired TRUE, when liquidation with underlying asset is not possible because of not enough
    /// liquidity
    /// @return fullLiquidation TRUE if position has to be fully liquidated
    function maxLiquidation(ISilo _silo, IPartialLiquidation _hook, address _borrower)
        external
        view
        returns (uint256 collateralToLiquidate, uint256 debtToRepay, bool sTokenRequired, bool fullLiquidation);

    /// @notice Get amount of underlying asset that has been deposited to Silo
    /// @dev It reads directly from storage so interest generated between last update and now is not
    /// taken for account
    /// @param _silo Silo address from which to read data
    /// @return totalDeposits amount of all deposits made for given asset
    function totalDeposits(ISilo _silo) external view returns (uint256 totalDeposits);

    /// @notice returns total deposits with interest dynamically calculated at current block timestamp
    /// @return total deposits amount with interest
    function totalDepositsWithInterest(ISilo _silo) external view returns (uint256);

    /// @notice returns total borrow amount with interest dynamically calculated at current block timestamp
    /// @return _totalBorrowAmount total deposits amount with interest
    function totalBorrowAmountWithInterest(ISilo _silo)
        external
        view
        returns (uint256 _totalBorrowAmount);

    /// @notice Get amount of protected asset token that has been deposited to Silo
    /// @param _silo Silo address from which to read data
    /// @return amount of all "protected" deposits
    function collateralOnlyDeposits(ISilo _silo) external view returns (uint256);

    /// @notice Calculates current deposit (with interest) for user
    /// without protected deposits
    /// @param _silo Silo address from which to read data
    /// @param _borrower account for which calculation are done
    /// @return borrowerDeposits amount of asset _borrower posses
    function getDepositAmount(ISilo _silo, address _borrower)
        external
        view
        returns (uint256 borrowerDeposits);

    /// @notice Get amount of asset that has been borrowed
    /// @dev It reads directly from storage so interest generated between last update and now is not
    /// taken for account
    /// @param _silo Silo address from which to read data
    /// @return amount of asset that has been borrowed
    function totalBorrowAmount(ISilo _silo) external view returns (uint256);

    /// @notice Get totalSupply of debt token
    /// @dev Debt token represents a share in total debt of given asset
    /// @param _silo Silo address from which to read data
    /// @return totalSupply of debt token
    function totalBorrowShare(ISilo _silo) external view returns (uint256);

    /// @notice Calculates current borrow amount for user with interest
    /// @param _silo Silo address from which to read data
    /// @param _borrower account for which calculation are done
    /// @return total amount of asset user needs to repay at provided timestamp
    function getBorrowAmount(ISilo _silo, address _borrower)
        external
        view
        returns (uint256);

    /// @notice Get debt token balance of a user
    /// @dev Debt token represents a share in total debt of given asset.
    /// This method calls balanceOf(_borrower) on that token.
    /// @param _silo Silo address from which to read data
    /// @param _borrower wallet address for which to read data
    /// @return balance of debt token of given user
    function borrowShare(ISilo _silo, address _borrower) external view returns (uint256);

    /// @notice Get amount of fees earned by protocol to date
    /// @dev It reads directly from storage so interest generated between last update and now is not
    /// taken for account. In SiloLens v1 this was total (ever growing) amount, in this one is since last withdraw.
    /// @param _silo Silo address from which to read data
    /// @return amount of fees earned by protocol to date since last withdraw
    function protocolFees(ISilo _silo) external view returns (uint256);

    /// @notice Calculate value of collateral asset for user
    /// @dev It dynamically adds interest earned. Takes for account protected deposits as well.
    /// In v1 result is always in 18 decimals, here it depends on oracle setup.
    /// @param _siloConfig Market address (silo config address)
    /// @param _borrower account for which calculation are done
    /// @return value of collateral denominated in quote token, decimal depends on oracle setup.
    function calculateCollateralValue(ISiloConfig _siloConfig, address _borrower) external view returns (uint256);

    /// @notice Calculate value of borrowed asset by user
    /// @dev It dynamically adds interest earned to borrowed amount
    /// In v1 result is always in 18 decimals, here it depends on oracle setup.
    /// @param _siloConfig Market address (silo config address)
    /// @param _borrower account for which calculation are done
    /// @return value of debt denominated in quote token, decimal depends on oracle setup.
    function calculateBorrowValue(ISiloConfig _siloConfig, address _borrower) external view returns (uint256);

    /// @notice Calculates fraction between borrowed amount and the current liquidity of tokens for given asset
    /// denominated in percentage
    /// @dev [v1 NOT compatible] Utilization is calculated current values in storage so it does not take for account
    /// earned interest and ever-increasing total borrow amount. It assumes `Model.DP()` = 100%.
    /// @param _silo Silo address from which to read data
    /// @return utilization value
    function getUtilization(ISilo _silo) external view returns (uint256);

    /// @notice Retrieves the interest rate model
    /// @param _silo Address of the silo
    /// @return irm InterestRateModel contract address
    function getInterestRateModel(ISilo _silo) external view returns (address irm);

    /// @notice Calculates current borrow interest rate
    /// @param _silo Address of the silo
    /// @return borrowAPR The interest rate value in 18 decimals points. 10**18 is equal to 100% per year
    function getBorrowAPR(ISilo _silo) external view returns (uint256 borrowAPR);

    /// @notice Calculates current deposit interest rate.
    /// @param _silo Address of the silo
    /// @return depositAPR The interest rate value in 18 decimals points. 10**18 is equal to 100% per year.
    function getDepositAPR(ISilo _silo) external view returns (uint256 depositAPR);

    /// @notice Calculates current deposit and borrow interest rates (bulk method).
    /// @param _silos Addresses of the silos
    /// @return aprs The interest rate values in 18 decimals points. 10**18 is equal to 100% per year.
    function getAPRs(ISilo[] calldata _silos) external view returns (APR[] memory aprs);

    /// @dev gets interest rates model object
    /// @param _silo Silo address from which to read data
    /// @return IInterestRateModel interest rates model object
    function getModel(ISilo _silo) external view returns (IInterestRateModel);

    /// @notice Get names of all programs in Silo incentives controller
    /// @param _siloIncentivesController Address of the Silo incentives controller
    /// @return programsNames Names of all programs in Silo incentives controller
    function getSiloIncentivesControllerProgramsNames(
        address _siloIncentivesController
    ) external view returns (string[] memory programsNames);

    /// @notice Returns oracle addresses for silo
    function getOracleAddresses(ISilo _silo) external view returns (address solvencyOracle, address maxLtvOracle);
}
"
    },
    "silo-core/contracts/interfaces/IShareToken.sol": {
      "content": "// SPDX-License-Identifier: MIT
pragma solidity >=0.5.0;

import {IERC20Metadata} from "openzeppelin5/token/ERC20/extensions/IERC20Metadata.sol";

import {ISiloConfig} from "./ISiloConfig.sol";
import {ISilo} from "./ISilo.sol";

interface IShareToken is IERC20Metadata {
    struct HookSetup {
        /// @param this is the same as in siloConfig
        address hookReceiver;
        /// @param hooks bitmap
        uint24 hooksBefore;
        /// @param hooks bitmap
        uint24 hooksAfter;
        /// @param tokenType must be one of this hooks values: COLLATERAL_TOKEN, PROTECTED_TOKEN, DEBT_TOKEN
        uint24 tokenType;
    }

    struct ShareTokenStorage {
        /// @notice Silo address for which tokens was deployed
        ISilo silo;

        /// @dev cached silo config address
        ISiloConfig siloConfig;

        /// @notice Copy of hooks setup from SiloConfig for optimisation purposes
        HookSetup hookSetup;

        bool transferWithChecks;
    }

    /// @notice Emitted every time receiver is notified about token transfer
    /// @param notificationReceiver receiver address
    /// @param success false if TX reverted on `notificationReceiver` side, otherwise true
    event NotificationSent(address indexed notificationReceiver, bool success);

    error OnlySilo();
    error OnlySiloConfig();
    error OwnerIsZero();
    error RecipientIsZero();
    error AmountExceedsAllowance();
    error RecipientNotSolventAfterTransfer();
    error SenderNotSolventAfterTransfer();
    error ZeroTransfer();

    /// @notice method for SiloConfig to synchronize hooks
    /// @param _hooksBefore hooks bitmap to trigger hooks BEFORE action
    /// @param _hooksAfter hooks bitmap to trigger hooks AFTER action
    function synchronizeHooks(uint24 _hooksBefore, uint24 _hooksAfter) external;

    /// @notice Mint method for Silo to create debt
    /// @param _owner wallet for which to mint token
    /// @param _spender wallet that asks for mint
    /// @param _amount amount of token to be minted
    function mint(address _owner, address _spender, uint256 _amount) external;

    /// @notice Burn method for Silo to close debt
    /// @param _owner wallet for which to burn token
    /// @param _spender wallet that asks for burn
    /// @param _amount amount of token to be burned
    function burn(address _owner, address _spender, uint256 _amount) external;

    /// @notice TransferFrom method for liquidation
    /// @param _from wallet from which we transferring tokens
    /// @param _to wallet that will get tokens
    /// @param _amount amount of token to transfer
    function forwardTransferFromNoChecks(address _from, address _to, uint256 _amount) external;

    /// @dev Returns the amount of tokens owned by `account`.
    /// @param _account address for which to return data
    /// @return balance of the _account
    /// @return totalSupply total supply of the token
    function balanceOfAndTotalSupply(address _account) external view returns (uint256 balance, uint256 totalSupply);

    /// @notice Returns silo address for which token was deployed
    /// @return silo address
    function silo() external view returns (ISilo silo);

    function siloConfig() external view returns (ISiloConfig silo);

    /// @notice Returns hook setup
    function hookSetup() external view returns (HookSetup memory);

    /// @notice Returns hook receiver address
    function hookReceiver() external view returns (address);
}
"
    },
    "silo-core/contracts/interfaces/ISiloConfig.sol": {
      "content": "// SPDX-License-Identifier: MIT
pragma solidity >=0.5.0;

import {ISilo} from "./ISilo.sol";
import {ICrossReentrancyGuard} from "./ICrossReentrancyGuard.sol";

interface ISiloConfig is ICrossReentrancyGuard {
    struct InitData {
        /// @notice Can be address zero if deployer fees are not to be collected. If deployer address is zero then
        /// deployer fee must be zero as well. Deployer will be minted an NFT that gives the right to claim deployer
        /// fees. NFT can be transferred with the right to claim.
        address deployer;

        /// @notice Address of the hook receiver called on every before/after action on Silo. Hook contract also
        /// implements liquidation logic and veSilo gauge connection.
        address hookReceiver;

        /// @notice Deployer's fee in 18 decimals points. Deployer will earn this fee based on the interest earned
        /// by the Silo. Max deployer fee is set by the DAO. At deployment it is 15%.
        uint256 deployerFee;

        /// @notice DAO's fee in 18 decimals points. DAO will earn this fee based on the interest earned
        /// by the Silo. Acceptable fee range fee is set by the DAO. Default at deployment is 5% - 50%.
        uint256 daoFee;

        /// @notice Address of the first token
        address token0;

        /// @notice Address of the solvency oracle. Solvency oracle is used to calculate LTV when deciding if borrower
        /// is solvent or should be liquidated. Solvency oracle is optional and if not set price of 1 will be assumed.
        address solvencyOracle0;

        /// @notice Address of the maxLtv oracle. Max LTV oracle is used to calculate LTV when deciding if borrower
        /// can borrow given amount of assets. Max LTV oracle is optional and if not set it defaults to solvency
        /// oracle. If neither is set price of 1 will be assumed.
        address maxLtvOracle0;

        /// @notice Address of the interest rate model
        address interestRateModel0;

        /// @notice Maximum LTV for first token. maxLTV is in 18 decimals points and is used to determine, if borrower
        /// can borrow given amount of assets. MaxLtv is in 18 decimals points. MaxLtv must be lower or equal to LT.
        uint256 maxLtv0;

        /// @notice Liquidation threshold for first token. LT is used to calculate solvency. LT is in 18 decimals
        /// points. LT must not be lower than maxLTV.
        uint256 lt0;

        /// @notice minimal acceptable LTV after liquidation, in 18 decimals points
        uint256 liquidationTargetLtv0;

        /// @notice Liquidation fee for the first token in 18 decimals points. Liquidation fee is what liquidator earns
        /// for repaying insolvent loan.
        uint256 liquidationFee0;

        /// @notice Flashloan fee sets the cost of taking a flashloan in 18 decimals points
        uint256 flashloanFee0;

        /// @notice Indicates if a beforeQuote on oracle contract should be called before quoting price
        bool callBeforeQuote0;

        /// @notice Address of the second token
        address token1;

        /// @notice Address of the solvency oracle. Solvency oracle is used to calculate LTV when deciding if borrower
        /// is solvent or should be liquidated. Solvency oracle is optional and if not set price of 1 will be assumed.
        address solvencyOracle1;

        /// @notice Address of the maxLtv oracle. Max LTV oracle is used to calculate LTV when deciding if borrower
        /// can borrow given amount of assets. Max LTV oracle is optional and if not set it defaults to solvency
        /// oracle. If neither is set price of 1 will be assumed.
        address maxLtvOracle1;

        /// @notice Address of the interest rate model
        address interestRateModel1;

        /// @notice Maximum LTV for first token. maxLTV is in 18 decimals points and is used to determine,
        /// if borrower can borrow given amount of assets. maxLtv is in 18 decimals points
        uint256 maxLtv1;

        /// @notice Liquidation threshold for first token. LT is used to calculate solvency. LT is in 18 decimals points
        uint256 lt1;

        /// @notice minimal acceptable LTV after liquidation, in 18 decimals points
        uint256 liquidationTargetLtv1;

        /// @notice Liquidation fee is what liquidator earns for repaying insolvent loan.
        uint256 liquidationFee1;

        /// @notice Flashloan fee sets the cost of taking a flashloan in 18 decimals points
        uint256 flashloanFee1;

        /// @notice Indicates if a beforeQuote on oracle contract should be called before quoting price
        bool callBeforeQuote1;
    }

    struct ConfigData {
        uint256 daoFee;
        uint256 deployerFee;
        address silo;
        address token;
        address protectedShareToken;
        address collateralShareToken;
        address debtShareToken;
        address solvencyOracle;
        address maxLtvOracle;
        address interestRateModel;
        uint256 maxLtv;
        uint256 lt;
        uint256 liquidationTargetLtv;
        uint256 liquidationFee;
        uint256 flashloanFee;
        address hookReceiver;
        bool callBeforeQuote;
    }

    struct DepositConfig {
        address silo;
        address token;
        address collateralShareToken;
        address protectedShareToken;
        uint256 daoFee;
        uint256 deployerFee;
        address interestRateModel;
    }

    error OnlySilo();
    error OnlySiloOrTokenOrHookReceiver();
    error WrongSilo();
    error OnlyDebtShareToken();
    error DebtExistInOtherSilo();
    error FeeTooHigh();

    /// @dev It should be called on debt transfer (debt share token transfer).
    /// In the case if the`_recipient` doesn't have configured a collateral silo,
    /// it will be set to the collateral silo of the `_sender`.
    /// @param _sender sender address
    /// @param _recipient recipient address
    function onDebtTransfer(address _sender, address _recipient) external;

    /// @notice Set collateral silo.
    /// @dev Revert if msg.sender is not a SILO_0 or SILO_1.
    /// @dev Always set collateral silo the same as msg.sender.
    /// @param _borrower borrower address
    /// @return collateralSiloChanged TRUE if collateral silo changed
    function setThisSiloAsCollateralSilo(address _borrower) external returns (bool collateralSiloChanged);

    /// @notice Set collateral silo
    /// @dev Revert if msg.sender is not a SILO_0 or SILO_1.
    /// @dev Always set collateral silo opposite to the msg.sender.
    /// @param _borrower borrower address
    /// @return collateralSiloChanged TRUE if collateral silo changed
    function setOtherSiloAsCollateralSilo(address _borrower) external returns (bool collateralSiloChanged);

    /// @notice Accrue interest for the silo
    /// @param _silo silo for which accrue interest
    function accrueInterestForSilo(address _silo) external;

    /// @notice Accrue interest for both silos (SILO_0 and SILO_1 in a config)
    function accrueInterestForBothSilos() external;

    /// @notice Retrieves the collateral silo for a specific borrower.
    /// @dev As a user can deposit into `Silo0` and `Silo1`, this property specifies which Silo
    /// will be used as collateral for the debt. Later on, it will be used for max LTV and solvency checks.
    /// After being set, the collateral silo is never set to `address(0)` again but such getters as
    /// `getConfigsForSolvency`, `getConfigsForBorrow`, `getConfigsForWithdraw` will return empty
    /// collateral silo config if borrower doesn't have debt.
    ///
    /// In the SiloConfig collateral silo is set by the following functions:
    /// `onDebtTransfer` - only if the recipient doesn't have collateral silo set (inherits it from the sender)
    /// This function is called on debt share token transfer (debt transfer).
    /// `setThisSiloAsCollateralSilo` - sets the same silo as the one that calls the function.
    /// `setOtherSiloAsCollateralSilo` - sets the opposite silo as collateral from the one that calls the function.
    ///
    /// In the Silo collateral silo is set by the following functions:
    /// `borrow` - always sets opposite silo as collateral.
    /// If Silo0 borrows, then Silo1 will be collateral and vice versa.
    /// `borrowSameAsset` - always sets the same silo as collateral.
    /// `switchCollateralToThisSilo` - always sets the same silo as collateral.
    /// @param _borrower The address of the borrower for which the collateral silo is being retrieved
    /// @return collateralSilo The address of the collateral silo for the specified borrower
    function borrowerCollateralSilo(address _borrower) external view returns (address collateralSilo);

    /// @notice Retrieves the silo ID
    /// @dev Each silo is assigned a unique ID. ERC-721 token is minted with identical ID to deployer.
    /// An owner of that token receives the deployer fees.
    /// @return siloId The ID of the silo
    function SILO_ID() external view returns (uint256 siloId); // solhint-disable-line func-name-mixedcase

    /// @notice Retrieves the addresses of the two silos
    /// @return silo0 The address of the first silo
    /// @return silo1 The address of the second silo
    function getSilos() external view returns (address silo0, address silo1);

    /// @notice Retrieves the asset associated with a specific silo
    /// @dev This function reverts for incorrect silo address input
    /// @param _silo The address of the silo for which the associated asset is being retrieved
    /// @return asset The address of the asset associated with the specified silo
    function getAssetForSilo(address _silo) external view returns (address asset);

    /// @notice Verifies if the borrower has debt in other silo by checking the debt share token balance
    /// @param _thisSilo The address of the silo in respect of which the debt is checked
    /// @param _borrower The address of the borrower for which the debt is checked
    /// @return hasDebt true if the borrower has debt in other silo
    function hasDebtInOtherSilo(address _thisSilo, address _borrower) external view returns (bool hasDebt);

    /// @notice Retrieves the debt silo associated with a specific borrower
    /// @dev This function reverts if debt present in two silo (should not happen)
    /// @param _borrower The address of the borrower for which the debt silo is being retrieved
    function getDebtSilo(address _borrower) external view returns (address debtSilo);

    /// @notice Retrieves configuration data for both silos. First config is for the silo that is asking for configs.
    /// @param borrower borrower address for which debtConfig will be returned
    /// @return collateralConfig The configuration data for collateral silo (empty if there is no debt).
    /// @return debtConfig The configuration data for debt silo (empty if there is no debt).
    function getConfigsForSolvency(address borrower)
        external
        view
        returns (ConfigData memory collateralConfig, ConfigData memory debtConfig);

    /// @notice Retrieves configuration data for a specific silo
    /// @dev This function reverts for incorrect silo address input.
    /// @param _silo The address of the silo for which configuration data is being retrieved
    /// @return config The configuration data for the specified silo
    function getConfig(address _silo) external view returns (ConfigData memory config);

    /// @notice Retrieves configuration data for a specific silo for withdraw fn.
    /// @dev This function reverts for incorrect silo address input.
    /// @param _silo The address of the silo for which configuration data is being retrieved
    /// @return depositConfig The configuration data for the specified silo (always config for `_silo`)
    /// @return collateralConfig The configuration data for the collateral silo (empty if there is no debt)
    /// @return debtConfig The configuration data for the debt silo (empty if there is no debt)
    function getConfigsForWithdraw(address _silo, address _borrower) external view returns (
        DepositConfig memory depositConfig,
        ConfigData memory collateralConfig,
        ConfigData memory debtConfig
    );

    /// @notice Retrieves configuration data for a specific silo for borrow fn.
    /// @dev This function reverts for incorrect silo address input.
    /// @param _debtSilo The address of the silo for which configuration data is being retrieved
    /// @return collateralConfig The configuration data for the collateral silo (always other than `_debtSilo`)
    /// @return debtConfig The configuration data for the debt silo (always config for `_debtSilo`)
    function getConfigsForBorrow(address _debtSilo)
        external
        view
        returns (ConfigData memory collateralConfig, ConfigData memory debtConfig);

    /// @notice Retrieves fee-related information for a specific silo
    /// @dev This function reverts for incorrect silo address input
    /// @param _silo The address of the silo for which fee-related information is being retrieved.
    /// @return daoFee The DAO fee percentage in 18 decimals points.
    /// @return deployerFee The deployer fee percentage in 18 decimals points.
    /// @return flashloanFee The flashloan fee percentage in 18 decimals points.
    /// @return asset The address of the asset associated with the specified silo.
    function getFeesWithAsset(address _silo)
        external
        view
        returns (uint256 daoFee, uint256 deployerFee, uint256 flashloanFee, address asset);

    /// @notice Retrieves share tokens associated with a specific silo
    /// @dev This function reverts for incorrect silo address input
    /// @param _silo The address of the silo for which share tokens are being retrieved
    /// @return protectedShareToken The address of the protected (non-borrowable) share token
    /// @return collateralShareToken The address of the collateral share token
    /// @return debtShareToken The address of the debt share token
    function getShareTokens(address _silo)
        external
        view
        returns (address protectedShareToken, address collateralShareToken, address debtShareToken);

    /// @notice Retrieves the share token and the silo token associated with a specific silo
    /// @param _silo The address of the silo for which the share token and silo token are being retrieved
    /// @param _collateralType The type of collateral
    /// @return shareToken The address of the share token (collateral or protected collateral)
    /// @return asset The address of the silo token
    function getCollateralShareTokenAndAsset(address _silo, ISilo.CollateralType _collateralType)
        external
        view
        returns (address shareToken, address asset);

    /// @notice Retrieves the share token and the silo token associated with a specific silo
    /// @param _silo The address of the silo for which the share token and silo token are being retrieved
    /// @return shareToken The address of the share token (debt)
    /// @return asset The address of the silo token
    function getDebtShareTokenAndAsset(address _silo)
        external
        view
        returns (address shareToken, address asset);
}
"
    },
    "silo-core/contracts/interfaces/IPartialLiquidation.sol": {
      "content": "// SPDX-License-Identifier: MIT
pragma solidity >=0.5.0;

interface IPartialLiquidation {
    struct HookSetup {
        /// @param this is the same as in siloConfig
        address hookReceiver;
        /// @param hooks bitmap
        uint24 hooksBefore;
        /// @param hooks bitmap
        uint24 hooksAfter;
    }

    /// @dev Emitted when a borrower is liquidated.
    /// @param liquidator The address of the liquidator
    /// @param silo The address of the silo on which position was liquidated
    /// @param borrower The address of the borrower
    /// @param repayDebtAssets Repay amount
    /// @param withdrawCollateral Total (collateral + protected) withdraw amount, in case `receiveSToken` is TRUE
    /// then this is estimated withdraw, and representation of this amount in sToken was transferred
    /// @param receiveSToken True if the liquidators wants to receive the collateral sTokens, `false` if he wants
    /// to receive the underlying collateral asset directly
    event LiquidationCall(
        address indexed liquidator,
        address indexed silo,
        address indexed borrower,
        uint256 repayDebtAssets,
        uint256 withdrawCollateral,
        bool receiveSToken
    );

    error UnexpectedCollateralToken();
    error UnexpectedDebtToken();
    error NoDebtToCover();
    error FullLiquidationRequired();
    error UserIsSolvent();
    error UnknownRatio();
    error NoRepayAssets();

    /// @notice Function to liquidate insolvent position
    /// - The caller (liquidator) covers `debtToCover` amount of debt of the user getting liquidated, and receives
    ///   an equivalent amount in `collateralAsset` plus a liquidation fee to cover market risk
    /// @dev this method reverts when:
    /// - `_maxDebtToCover` is zero
    /// - `_collateralAsset` is not `_user` collateral token (note, that user can have both tokens in Silo, but only one
    ///   is for backing debt
    /// - `_debtAsset` is not a token that `_user` borrow
    /// - `_user` is solvent and there is no debt to cover
    /// - `_maxDebtToCover` is set to cover only part of the debt but full liquidation is required
    /// - when not enough liquidity to transfer from `_user` collateral to liquidator
    ///   (use `_receiveSToken == true` in that case)
    /// @param _collateralAsset The address of the underlying asset used as collateral, to receive as result
    /// @param _debtAsset The address of the underlying borrowed asset to be repaid with the liquidation
    /// @param _user The address of the borrower getting liquidated
    /// @param _maxDebtToCover The maximum debt amount of borrowed `asset` the liquidator wants to cover,
    /// in case this amount is too big, it will be reduced to maximum allowed liquidation amount
    /// @param _receiveSToken True if the liquidators wants to receive the collateral sTokens, `false` if he wants
    /// to receive the underlying collateral asset directly
    /// @return withdrawCollateral collateral that was send to `msg.sender`, in case of `_receiveSToken` is TRUE,
    /// `withdrawCollateral` will be estimated, on redeem one can expect this value to be rounded down
    /// @return repayDebtAssets actual debt value that was repaid by `msg.sender`
    function liquidationCall(
        address _collateralAsset,
        address _debtAsset,
        address _user,
        uint256 _maxDebtToCover,
        bool _receiveSToken
    )
        external
        returns (uint256 withdrawCollateral, uint256 repayDebtAssets);

    /// @dev debt is keep growing over time, so when dApp use this view to calculate max, tx should never revert
    /// because actual max can be only higher
    /// @return collateralToLiquidate underestimated amount of collateral liquidator will get
    /// @return debtToRepay debt amount needed to be repay to get `collateralToLiquidate`
    /// @return sTokenRequired TRUE, when liquidation with underlying asset is not possible because of not enough
    /// liquidity
    function maxLiquidation(address _borrower)
        external
        view
        returns (uint256 collateralToLiquidate, uint256 debtToRepay, bool sTokenRequired);
}
"
    },
    "silo-core/contracts/interfaces/IInterestRateModel.sol": {
      "content": "// SPDX-License-Identifier: MIT
pragma solidity >=0.5.0;

interface IInterestRateModel {
    event InterestRateModelError();

    /// @dev Sets config address for all Silos that will use this model
    /// @param _irmConfig address of IRM config contract
    function initialize(address _irmConfig) external;

    /// @dev get compound interest rate and update model storage for current block.timestamp
    /// @param _collateralAssets total silo collateral assets
    /// @param _debtAssets total silo debt assets
    /// @param _interestRateTimestamp last IRM timestamp
    /// @return rcomp compounded interest rate from last update until now (1e18 == 100%)
    function getCompoundInterestRateAndUpdate(
        uint256 _collateralAssets,
        uint256 _debtAssets,
        uint256 _interestRateTimestamp
    )
        external
        returns (uint256 rcomp);

    /// @dev get compound interest rate
    /// @param _silo address of Silo for which interest rate should be calculated
    /// @param _blockTimestamp current block timestamp
    /// @return rcomp compounded interest rate from last update until now (1e18 == 100%)
    function getCompoundInterestRate(address _silo, uint256 _blockTimestamp)
        external
        view
        returns (uint256 rcomp);

    /// @dev get current annual interest rate
    /// @param _silo address of Silo for which interest rate should be calculated
    /// @param _blockTimestamp current block timestamp
    /// @return rcur current annual interest rate (1e18 == 100%)
    function getCurrentInterestRate(address _silo, uint256 _blockTimestamp)
        external
        view
        returns (uint256 rcur);

    /// @dev returns decimal points used by model
    function decimals() external view returns (uint256);
}
"
    },
    "silo-core/contracts/lib/SiloLensLib.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.28;

// solhint-disable ordering

import {ISilo} from "../interfaces/ISilo.sol";
import {IShareToken} from "../interfaces/IShareToken.sol";

import {ISiloConfig} from "../interfaces/ISiloConfig.sol";
import {IInterestRateModel} from "../interfaces/IInterestRateModel.sol";
import {IPartialLiquidation} from "../interfaces/IPartialLiquidation.sol";
import {ISiloOracle} from "../interfaces/ISiloOracle.sol";

import {SiloSolvencyLib} from "./SiloSolvencyLib.sol";
import {SiloMathLib} from "./SiloMathLib.sol";

library SiloLensLib {
    uint256 internal constant _PRECISION_DECIMALS = 1e18;

    function getRawLiquidity(ISilo _silo) internal view returns (uint256 liquidity) {
        return SiloMathLib.liquidity(
            _silo.getTotalAssetsStorage(ISilo.AssetType.Collateral),
            _silo.getTotalAssetsStorage(ISilo.AssetType.Debt)
        );
    }

    function getMaxLtv(ISilo _silo) internal view returns (uint256 maxLtv) {
        maxLtv = _silo.config().getConfig(address(_silo)).maxLtv;
    }

    function getLt(ISilo _silo) internal view returns (uint256 lt) {
        lt = _silo.config().getConfig(address(_silo)).lt;
    }

    function getInterestRateModel(ISilo _silo) internal view returns (address irm) {
        irm = _silo.config().getConfig(address(_silo)).interestRateModel;
    }

    function getBorrowAPR(ISilo _silo) internal view returns (uint256 borrowAPR) {
        IInterestRateModel model = IInterestRateModel(_silo.config().getConfig((address(_silo))).interestRateModel);
        borrowAPR = model.getCurrentInterestRate(address(_silo), block.timestamp);
    }

    function getDepositAPR(ISilo _silo) internal view returns (uint256 depositAPR) {
        uint256 collateralAssets = _silo.getCollateralAssets();

        if (collateralAssets == 0) {
            return 0;
        }

        ISiloConfig.ConfigData memory cfg = _silo.config().getConfig((address(_silo)));
        depositAPR = getBorrowAPR(_silo) * _silo.getDebtAssets() / collateralAssets;
        depositAPR = depositAPR * (_PRECISION_DECIMALS - cfg.daoFee - cfg.deployerFee) / _PRECISION_DECIMALS;
    }

    /// @dev calculate profitable liquidation values, in case of bad debt, it will calculate max debt to cover
    /// based on available collateral.
    /// Result returned by this method might not work for case, when full liquidation is required.
    function calculateProfitableLiquidation(ISilo _silo, address _borrower)
        internal
        view
        returns (uint256 collateralToLiquidate, uint256 debtToCover)
    {
        IPartialLiquidation _hook = IPartialLiquidation(IShareToken(address(_silo)).hookReceiver());
        (collateralToLiquidate, debtToCover,) = _hook.maxLiquidation(_borrower);

        if (collateralToLiquidate == 0) return (0, 0);

        (ISiloConfig.ConfigData memory collateralConfig, ISiloConfig.ConfigData memory debtConfig) =
            _silo.config().getConfigsForSolvency(_borrower);

        uint256 collateralV

Tags:
ERC20, ERC721, ERC165, Multisig, Mintable, Burnable, Non-Fungible, Liquidity, Yield, Upgradeable, Multi-Signature, Factory, Oracle|addr:0x80e3f3d136f4b3b8a1f0693d3290184445cdee8e|verified:true|block:23683548|tx:0x1fc3e5814130a772084b5e3927dba37b97333ddcdcf55f9a78a09568297c8432|first_check:1761750541

Submitted on: 2025-10-29 16:09:01

Comments

Log in to comment.

No comments yet.