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
Submitted on: 2025-10-29 16:09:01
Comments
Log in to comment.
No comments yet.