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/SiloDeployer.sol": {
"content": "// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.28;
import {Clones} from "openzeppelin5/proxy/Clones.sol";
import {ISiloConfig} from "silo-core/contracts/interfaces/ISiloConfig.sol";
import {ISiloFactory} from "silo-core/contracts/interfaces/ISiloFactory.sol";
import {IInterestRateModelV2} from "silo-core/contracts/interfaces/IInterestRateModelV2.sol";
import {IInterestRateModelV2Factory} from "silo-core/contracts/interfaces/IInterestRateModelV2Factory.sol";
import {IDynamicKinkModelFactory} from "silo-core/contracts/interfaces/IDynamicKinkModelFactory.sol";
import {IInterestRateModel} from "silo-core/contracts/interfaces/IInterestRateModel.sol";
import {IHookReceiver} from "silo-core/contracts/interfaces/IHookReceiver.sol";
import {ISiloDeployer} from "silo-core/contracts/interfaces/ISiloDeployer.sol";
import {SiloConfig} from "silo-core/contracts/SiloConfig.sol";
import {CloneDeterministic} from "silo-core/contracts/lib/CloneDeterministic.sol";
import {Views} from "silo-core/contracts/lib/Views.sol";
import {Create2Factory} from "common/utils/Create2Factory.sol";
/// @notice Silo Deployer
contract SiloDeployer is Create2Factory, ISiloDeployer {
// solhint-disable var-name-mixedcase
IInterestRateModelV2Factory public immutable IRM_CONFIG_FACTORY;
IDynamicKinkModelFactory public immutable DYNAMIC_KINK_MODEL_FACTORY;
ISiloFactory public immutable SILO_FACTORY;
address public immutable SILO_IMPL;
address public immutable SHARE_PROTECTED_COLLATERAL_TOKEN_IMPL;
address public immutable SHARE_DEBT_TOKEN_IMPL;
// solhint-enable var-name-mixedcase
constructor(
IInterestRateModelV2Factory _irmConfigFactory,
IDynamicKinkModelFactory _dynamicKinkModelFactory,
ISiloFactory _siloFactory,
address _siloImpl,
address _shareProtectedCollateralTokenImpl,
address _shareDebtTokenImpl
) {
IRM_CONFIG_FACTORY = _irmConfigFactory;
DYNAMIC_KINK_MODEL_FACTORY = _dynamicKinkModelFactory;
SILO_FACTORY = _siloFactory;
SILO_IMPL = _siloImpl;
SHARE_PROTECTED_COLLATERAL_TOKEN_IMPL = _shareProtectedCollateralTokenImpl;
SHARE_DEBT_TOKEN_IMPL = _shareDebtTokenImpl;
}
/// @inheritdoc ISiloDeployer
function deploy(
Oracles calldata _oracles,
bytes calldata _irmConfigData0,
bytes calldata _irmConfigData1,
ClonableHookReceiver calldata _clonableHookReceiver,
ISiloConfig.InitData memory _siloInitData
)
external
returns (ISiloConfig siloConfig)
{
// setUp IRMs (create if needed) and update `_siloInitData`
_setUpIRMs(_irmConfigData0, _irmConfigData1, _siloInitData);
// create oracles and update `_siloInitData`
_createOracles(_siloInitData, _oracles);
// clone hook receiver if needed
_cloneHookReceiver(_siloInitData, _clonableHookReceiver.implementation);
// deploy `SiloConfig` (with predicted addresses)
siloConfig = _deploySiloConfig(_siloInitData);
// create silo
SILO_FACTORY.createSilo({
_siloConfig: siloConfig,
_siloImpl: SILO_IMPL,
_shareProtectedCollateralTokenImpl: SHARE_PROTECTED_COLLATERAL_TOKEN_IMPL,
_shareDebtTokenImpl: SHARE_DEBT_TOKEN_IMPL,
_deployer: _siloInitData.deployer,
_creator: msg.sender
});
// initialize hook receiver only if it was cloned
_initializeHookReceiver(_siloInitData, siloConfig, _clonableHookReceiver);
emit SiloCreated(siloConfig);
}
/// @notice Deploy `SiloConfig` with predicted addresses
/// @param _siloInitData Silo configuration for the silo creation
/// @return siloConfig Deployed `SiloConfig`
// solhint-disable-next-line function-max-lines
function _deploySiloConfig(ISiloConfig.InitData memory _siloInitData) internal returns (ISiloConfig siloConfig) {
uint256 creatorSiloCounter = SILO_FACTORY.creatorSiloCounter(msg.sender);
ISiloConfig.ConfigData memory configData0;
ISiloConfig.ConfigData memory configData1;
(configData0, configData1) = Views.copySiloConfig(
_siloInitData,
SILO_FACTORY.daoFeeRange(),
SILO_FACTORY.maxDeployerFee(),
SILO_FACTORY.maxFlashloanFee(),
SILO_FACTORY.maxLiquidationFee()
);
configData0.silo = CloneDeterministic.predictSilo0Addr(
SILO_IMPL,
creatorSiloCounter,
address(SILO_FACTORY),
msg.sender
);
configData1.silo = CloneDeterministic.predictSilo1Addr(
SILO_IMPL,
creatorSiloCounter,
address(SILO_FACTORY),
msg.sender
);
configData0.collateralShareToken = configData0.silo;
configData1.collateralShareToken = configData1.silo;
configData0.protectedShareToken = CloneDeterministic.predictShareProtectedCollateralToken0Addr(
SHARE_PROTECTED_COLLATERAL_TOKEN_IMPL,
creatorSiloCounter,
address(SILO_FACTORY),
msg.sender
);
configData1.protectedShareToken = CloneDeterministic.predictShareProtectedCollateralToken1Addr(
SHARE_PROTECTED_COLLATERAL_TOKEN_IMPL,
creatorSiloCounter,
address(SILO_FACTORY),
msg.sender
);
configData0.debtShareToken = CloneDeterministic.predictShareDebtToken0Addr(
SHARE_DEBT_TOKEN_IMPL,
creatorSiloCounter,
address(SILO_FACTORY),
msg.sender
);
configData1.debtShareToken = CloneDeterministic.predictShareDebtToken1Addr(
SHARE_DEBT_TOKEN_IMPL,
creatorSiloCounter,
address(SILO_FACTORY),
msg.sender
);
uint256 nextSiloId = SILO_FACTORY.getNextSiloId();
siloConfig = ISiloConfig(address(new SiloConfig{salt: _salt()}(nextSiloId, configData0, configData1)));
}
/// @notice Create IRMs and update `_siloInitData`
/// @param _irmConfigData0 IRM config data for a silo `_TOKEN0`
/// @param _irmConfigData1 IRM config data for a silo `_TOKEN1`
/// @param _siloInitData Silo configuration for the silo creation
function _setUpIRMs(
bytes calldata _irmConfigData0,
bytes calldata _irmConfigData1,
ISiloConfig.InitData memory _siloInitData
) internal {
bytes32 salt = _salt();
if (_siloInitData.interestRateModel0 == address(IRM_CONFIG_FACTORY)) {
_siloInitData.interestRateModel0 = _createInterestRateModel(_irmConfigData0, salt);
}
if (_siloInitData.interestRateModel1 == address(IRM_CONFIG_FACTORY)) {
_siloInitData.interestRateModel1 = _createInterestRateModel(_irmConfigData1, salt);
}
uint256 creatorSiloCounter = SILO_FACTORY.creatorSiloCounter(msg.sender);
if (_siloInitData.interestRateModel0 == address(DYNAMIC_KINK_MODEL_FACTORY)) {
address silo = CloneDeterministic.predictSilo0Addr(
SILO_IMPL,
creatorSiloCounter,
address(SILO_FACTORY),
msg.sender
);
_siloInitData.interestRateModel0 = _createDKinkIRM(_irmConfigData0, silo, salt);
}
if (_siloInitData.interestRateModel1 == address(DYNAMIC_KINK_MODEL_FACTORY)) {
address silo = CloneDeterministic.predictSilo1Addr(
SILO_IMPL,
creatorSiloCounter,
address(SILO_FACTORY),
msg.sender
);
_siloInitData.interestRateModel1 = _createDKinkIRM(_irmConfigData1, silo, salt);
}
}
/// @notice Create an interest rate model
/// @param _irmConfigData IRM config data
/// @return interestRateModel Deployed interest rate model
function _createInterestRateModel(bytes memory _irmConfigData, bytes32 _salt) internal returns (address) {
IInterestRateModelV2.Config memory config = abi.decode(_irmConfigData, (IInterestRateModelV2.Config));
(, IInterestRateModelV2 interestRateModel) = IRM_CONFIG_FACTORY.create(config, _salt);
return address(interestRateModel);
}
/// @notice Create a DKinkIRM
/// @param _irmConfigData DKinkIRM config data
/// @param _silo Silo address
/// @return interestRateModel Deployed DKinkIRM
function _createDKinkIRM(bytes memory _irmConfigData, address _silo, bytes32 _salt) internal returns (address) {
DKinkIRMConfig memory dkink = abi.decode(_irmConfigData, (DKinkIRMConfig));
IInterestRateModel interestRateModel = DYNAMIC_KINK_MODEL_FACTORY.create(
dkink.config,
dkink.immutableArgs,
dkink.initialOwner,
_silo,
_salt
);
return address(interestRateModel);
}
/// @notice Create an oracle if it is not specified in the `_siloInitData` and has tx details for the creation
/// @param _siloInitData Silo configuration for the silo creation
/// @param _oracles Oracles creation details (factory and creation tx input)
function _createOracles(ISiloConfig.InitData memory _siloInitData, Oracles memory _oracles) internal {
if (_siloInitData.solvencyOracle0 == address(0)) {
_siloInitData.solvencyOracle0 = _createOracle(_oracles.solvencyOracle0);
}
if (_siloInitData.maxLtvOracle0 == address(0)) {
_siloInitData.maxLtvOracle0 = _createOracle(_oracles.maxLtvOracle0);
}
if (_siloInitData.solvencyOracle1 == address(0)) {
_siloInitData.solvencyOracle1 = _createOracle(_oracles.solvencyOracle1);
}
if (_siloInitData.maxLtvOracle1 == address(0)) {
_siloInitData.maxLtvOracle1 = _createOracle(_oracles.maxLtvOracle1);
}
}
/// @notice Create an oracle
/// @param _txData Oracle creation details (factory and creation tx input)
function _createOracle(OracleCreationTxData memory _txData) internal returns (address _oracle) {
if (_txData.deployed != address(0)) return _txData.deployed;
address factory = _txData.factory;
if (factory == address(0)) return address(0);
_updateSalt(_txData.txInput);
// solhint-disable-next-line avoid-low-level-calls
(bool success, bytes memory data) = factory.call(_txData.txInput);
require(success && data.length == 32, FailedToCreateAnOracle(factory));
_oracle = address(uint160(uint256(bytes32(data))));
}
/// @notice Clone hook receiver if it is provided
/// @param _siloInitData Silo configuration for the silo creation
/// @param _hookReceiverImplementation Hook receiver implementation to clone
function _cloneHookReceiver(
ISiloConfig.InitData memory _siloInitData,
address _hookReceiverImplementation
) internal {
require(
_hookReceiverImplementation == address(0) || _siloInitData.hookReceiver == address(0),
HookReceiverMisconfigured()
);
if (_hookReceiverImplementation != address(0)) {
_siloInitData.hookReceiver = Clones.cloneDeterministic(_hookReceiverImplementation, _salt());
}
}
/// @notice Initialize hook receiver if it was cloned
/// @param _siloInitData Silo configuration for the silo creation
/// (where _siloInitData.hookReceiver is the cloned hook receiver)
/// @param _siloConfig Configuration of the created silo
/// @param _clonableHookReceiver Hook receiver implementation and initialization data
function _initializeHookReceiver(
ISiloConfig.InitData memory _siloInitData,
ISiloConfig _siloConfig,
ClonableHookReceiver calldata _clonableHookReceiver
) internal {
if (_clonableHookReceiver.implementation != address(0)) {
IHookReceiver(_siloInitData.hookReceiver).initialize(
_siloConfig,
_clonableHookReceiver.initializationData
);
}
}
/// @notice Update the salt of the tx input
/// @param _txInput The tx input for the oracle factory
function _updateSalt(bytes memory _txInput) internal {
bytes32 salt = _salt();
assembly { // solhint-disable-line no-inline-assembly
let pointer := add(add(_txInput, 0x20), sub(mload(_txInput), 0x20))
mstore(pointer, salt)
}
}
}
"
},
"gitmodules/openzeppelin-contracts-5/contracts/proxy/Clones.sol": {
"content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (proxy/Clones.sol)
pragma solidity ^0.8.20;
import {Errors} from "../utils/Errors.sol";
/**
* @dev https://eips.ethereum.org/EIPS/eip-1167[ERC-1167] is a standard for
* deploying minimal proxy contracts, also known as "clones".
*
* > To simply and cheaply clone contract functionality in an immutable way, this standard specifies
* > a minimal bytecode implementation that delegates all calls to a known, fixed address.
*
* The library includes functions to deploy a proxy using either `create` (traditional deployment) or `create2`
* (salted deterministic deployment). It also includes functions to predict the addresses of clones deployed using the
* deterministic method.
*/
library Clones {
/**
* @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation`.
*
* This function uses the create opcode, which should never revert.
*/
function clone(address implementation) internal returns (address instance) {
return clone(implementation, 0);
}
/**
* @dev Same as {xref-Clones-clone-address-}[clone], but with a `value` parameter to send native currency
* to the new contract.
*
* NOTE: Using a non-zero value at creation will require the contract using this function (e.g. a factory)
* to always have enough balance for new deployments. Consider exposing this function under a payable method.
*/
function clone(address implementation, uint256 value) internal returns (address instance) {
if (address(this).balance < value) {
revert Errors.InsufficientBalance(address(this).balance, value);
}
/// @solidity memory-safe-assembly
assembly {
// Stores the bytecode after address
mstore(0x20, 0x5af43d82803e903d91602b57fd5bf3)
// implementation address
mstore(0x11, implementation)
// Packs the first 3 bytes of the `implementation` address with the bytecode before the address.
mstore(0x00, or(shr(0x88, implementation), 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000))
instance := create(value, 0x09, 0x37)
}
if (instance == address(0)) {
revert Errors.FailedDeployment();
}
}
/**
* @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation`.
*
* This function uses the create2 opcode and a `salt` to deterministically deploy
* the clone. Using the same `implementation` and `salt` multiple time will revert, since
* the clones cannot be deployed twice at the same address.
*/
function cloneDeterministic(address implementation, bytes32 salt) internal returns (address instance) {
return cloneDeterministic(implementation, salt, 0);
}
/**
* @dev Same as {xref-Clones-cloneDeterministic-address-bytes32-}[cloneDeterministic], but with
* a `value` parameter to send native currency to the new contract.
*
* NOTE: Using a non-zero value at creation will require the contract using this function (e.g. a factory)
* to always have enough balance for new deployments. Consider exposing this function under a payable method.
*/
function cloneDeterministic(
address implementation,
bytes32 salt,
uint256 value
) internal returns (address instance) {
if (address(this).balance < value) {
revert Errors.InsufficientBalance(address(this).balance, value);
}
/// @solidity memory-safe-assembly
assembly {
// Stores the bytecode after address
mstore(0x20, 0x5af43d82803e903d91602b57fd5bf3)
// implementation address
mstore(0x11, implementation)
// Packs the first 3 bytes of the `implementation` address with the bytecode before the address.
mstore(0x00, or(shr(0x88, implementation), 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000))
instance := create2(value, 0x09, 0x37, salt)
}
if (instance == address(0)) {
revert Errors.FailedDeployment();
}
}
/**
* @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}.
*/
function predictDeterministicAddress(
address implementation,
bytes32 salt,
address deployer
) internal pure returns (address predicted) {
/// @solidity memory-safe-assembly
assembly {
let ptr := mload(0x40)
mstore(add(ptr, 0x38), deployer)
mstore(add(ptr, 0x24), 0x5af43d82803e903d91602b57fd5bf3ff)
mstore(add(ptr, 0x14), implementation)
mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73)
mstore(add(ptr, 0x58), salt)
mstore(add(ptr, 0x78), keccak256(add(ptr, 0x0c), 0x37))
predicted := keccak256(add(ptr, 0x43), 0x55)
}
}
/**
* @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}.
*/
function predictDeterministicAddress(
address implementation,
bytes32 salt
) internal view returns (address predicted) {
return predictDeterministicAddress(implementation, salt, address(this));
}
}
"
},
"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/ISiloFactory.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity >=0.5.0;
import {IERC721} from "openzeppelin5/interfaces/IERC721.sol";
import {ISiloConfig} from "./ISiloConfig.sol";
interface ISiloFactory is IERC721 {
struct Range {
uint128 min;
uint128 max;
}
/// @notice Emitted on the creation of a Silo.
/// @param implementation Address of the Silo implementation.
/// @param token0 Address of the first Silo token.
/// @param token1 Address of the second Silo token.
/// @param silo0 Address of the first Silo.
/// @param silo1 Address of the second Silo.
/// @param siloConfig Address of the SiloConfig.
event NewSilo(
address indexed implementation,
address indexed token0,
address indexed token1,
address silo0,
address silo1,
address siloConfig
);
event BaseURI(string newBaseURI);
/// @notice Emitted on the update of DAO fee.
/// @param minDaoFee Value of the new minimal DAO fee.
/// @param maxDaoFee Value of the new maximal DAO fee.
event DaoFeeChanged(uint128 minDaoFee, uint128 maxDaoFee);
/// @notice Emitted on the update of max deployer fee.
/// @param maxDeployerFee Value of the new max deployer fee.
event MaxDeployerFeeChanged(uint256 maxDeployerFee);
/// @notice Emitted on the update of max flashloan fee.
/// @param maxFlashloanFee Value of the new max flashloan fee.
event MaxFlashloanFeeChanged(uint256 maxFlashloanFee);
/// @notice Emitted on the update of max liquidation fee.
/// @param maxLiquidationFee Value of the new max liquidation fee.
event MaxLiquidationFeeChanged(uint256 maxLiquidationFee);
/// @notice Emitted on the change of DAO fee receiver.
/// @param daoFeeReceiver Address of the new DAO fee receiver.
event DaoFeeReceiverChanged(address daoFeeReceiver);
/// @notice Emitted on the change of DAO fee receiver for particular silo
/// @param silo Address for which new DAO fee receiver is set.
/// @param daoFeeReceiver Address of the new DAO fee receiver.
event DaoFeeReceiverChangedForSilo(address silo, address daoFeeReceiver);
/// @notice Emitted on the change of DAO fee receiver for particular asset
/// @param asset Address for which new DAO fee receiver is set.
/// @param daoFeeReceiver Address of the new DAO fee receiver.
event DaoFeeReceiverChangedForAsset(address asset, address daoFeeReceiver);
error MissingHookReceiver();
error ZeroAddress();
error DaoFeeReceiverZeroAddress();
error SameDaoFeeReceiver();
error EmptyToken0();
error EmptyToken1();
error MaxFeeExceeded();
error InvalidFeeRange();
error SameAsset();
error SameRange();
error InvalidIrm();
error InvalidMaxLtv();
error InvalidLt();
error InvalidDeployer();
error DaoMinRangeExceeded();
error DaoMaxRangeExceeded();
error MaxDeployerFeeExceeded();
error MaxFlashloanFeeExceeded();
error MaxLiquidationFeeExceeded();
error InvalidCallBeforeQuote();
error OracleMisconfiguration();
error InvalidQuoteToken();
error HookIsZeroAddress();
error LiquidationTargetLtvTooHigh();
error NotYourSilo();
error ConfigMismatchSilo();
error ConfigMismatchShareProtectedToken();
error ConfigMismatchShareDebtToken();
error ConfigMismatchShareCollateralToken();
/// @notice Create a new Silo.
/// @param _siloConfig Silo configuration.
/// @param _siloImpl Address of the `Silo` implementation.
/// @param _shareProtectedCollateralTokenImpl Address of the `ShareProtectedCollateralToken` implementation.
/// @param _shareDebtTokenImpl Address of the `ShareDebtToken` implementation.
/// @param _deployer Address of the deployer.
/// @param _creator Address of the creator.
function createSilo(
ISiloConfig _siloConfig,
address _siloImpl,
address _shareProtectedCollateralTokenImpl,
address _shareDebtTokenImpl,
address _deployer,
address _creator
)
external;
/// @notice NFT ownership represents the deployer fee receiver for the each Silo ID. After burning,
/// the deployer fee is sent to the DAO. Burning doesn't affect Silo's behavior. It is only about fee distribution.
/// @param _siloIdToBurn silo ID to burn.
function burn(uint256 _siloIdToBurn) external;
/// @notice Update the value of DAO fee. Updated value will be used only for a new Silos.
/// Previously deployed SiloConfigs are immutable.
/// @param _minFee Value of the new DAO minimal fee.
/// @param _maxFee Value of the new DAO maximal fee.
function setDaoFee(uint128 _minFee, uint128 _maxFee) external;
/// @notice Set the default DAO fee receiver.
/// @param _newDaoFeeReceiver Address of the new DAO fee receiver.
function setDaoFeeReceiver(address _newDaoFeeReceiver) external;
/// @notice Set the new DAO fee receiver for asset, this setup will be used when fee receiver for silo is empty.
/// @param _asset Address for which new DAO fee receiver is set.
/// @param _newDaoFeeReceiver Address of the new DAO fee receiver.
function setDaoFeeReceiverForAsset(address _asset, address _newDaoFeeReceiver) external;
/// @notice Set the new DAO fee receiver for silo. This setup has highest priority.
/// @param _silo Address for which new DAO fee receiver is set.
/// @param _newDaoFeeReceiver Address of the new DAO fee receiver.
function setDaoFeeReceiverForSilo(address _silo, address _newDaoFeeReceiver) external;
/// @notice Update the value of max deployer fee. Updated value will be used only for a new Silos max deployer
/// fee validation. Previously deployed SiloConfigs are immutable.
/// @param _newMaxDeployerFee Value of the new max deployer fee.
function setMaxDeployerFee(uint256 _newMaxDeployerFee) external;
/// @notice Update the value of max flashloan fee. Updated value will be used only for a new Silos max flashloan
/// fee validation. Previously deployed SiloConfigs are immutable.
/// @param _newMaxFlashloanFee Value of the new max flashloan fee.
function setMaxFlashloanFee(uint256 _newMaxFlashloanFee) external;
/// @notice Update the value of max liquidation fee. Updated value will be used only for a new Silos max
/// liquidation fee validation. Previously deployed SiloConfigs are immutable.
/// @param _newMaxLiquidationFee Value of the new max liquidation fee.
function setMaxLiquidationFee(uint256 _newMaxLiquidationFee) external;
/// @notice Update the base URI.
/// @param _newBaseURI Value of the new base URI.
function setBaseURI(string calldata _newBaseURI) external;
/// @notice Acceptable DAO fee range for new Silos. Denominated in 18 decimals points. 1e18 == 100%.
function daoFeeRange() external view returns (Range memory);
/// @notice Max deployer fee for a new Silos. Denominated in 18 decimals points. 1e18 == 100%.
function maxDeployerFee() external view returns (uint256);
/// @notice Max flashloan fee for a new Silos. Denominated in 18 decimals points. 1e18 == 100%.
function maxFlashloanFee() external view returns (uint256);
/// @notice Max liquidation fee for a new Silos. Denominated in 18 decimals points. 1e18 == 100%.
function maxLiquidationFee() external view returns (uint256);
/// @notice The recipient of DAO fees.
function daoFeeReceiver() external view returns (address);
/// @notice Get SiloConfig address by Silo id.
function idToSiloConfig(uint256 _id) external view returns (address);
/// @notice Get the counter of silos created by the wallet.
function creatorSiloCounter(address _creator) external view returns (uint256);
/// @notice Do not use this method to check if silo is secure. Anyone can deploy silo with any configuration
/// and implementation. Most critical part of verification would be to check who deployed it.
/// @dev True if the address was deployed using SiloFactory.
function isSilo(address _silo) external view returns (bool);
/// @notice Id of a next Silo to be deployed. This is an ID of non-existing Silo outside of createSilo
/// function call. ID of a first Silo is 1.
function getNextSiloId() external view returns (uint256);
/// @notice Get the DAO and deployer fee receivers for a particular Silo address.
/// @param _silo Silo address.
/// @return dao DAO fee receiver.
/// @return deployer Deployer fee receiver.
function getFeeReceivers(address _silo) external view returns (address dao, address deployer);
/// @notice Validate InitData for a new Silo. Config will be checked for the fee limits, missing parameters.
/// @param _initData Silo init data.
function validateSiloInitData(ISiloConfig.InitData memory _initData) external view returns (bool);
}
"
},
"silo-core/contracts/interfaces/IInterestRateModelV2.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity >=0.5.0;
import {IInterestRateModelV2Config} from "./IInterestRateModelV2Config.sol";
interface IInterestRateModelV2 {
struct Config {
// uopt ∈ (0, 1) – optimal utilization;
int256 uopt;
// ucrit ∈ (uopt, 1) – threshold of large utilization;
int256 ucrit;
// ulow ∈ (0, uopt) – threshold of low utilization
int256 ulow;
// ki > 0 – integrator gain
int256 ki;
// kcrit > 0 – proportional gain for large utilization
int256 kcrit;
// klow ≥ 0 – proportional gain for low utilization
int256 klow;
// klin ≥ 0 – coefficient of the lower linear bound
int256 klin;
// beta ≥ 0 - a scaling factor
int256 beta;
// ri ≥ 0 – initial value of the integrator
int112 ri;
// Tcrit ≥ 0 - initial value of the time during which the utilization exceeds the critical value
int112 Tcrit;
}
struct Setup {
// ri ≥ 0 – the integrator
int112 ri;
// Tcrit ≥ 0 - the time during which the utilization exceeds the critical value
int112 Tcrit;
// flag that informs if setup is initialized
bool initialized;
}
/* solhint-enable */
error AddressZero();
error DeployConfigFirst();
error AlreadyInitialized();
error InvalidBeta();
error InvalidKcrit();
error InvalidKi();
error InvalidKlin();
error InvalidKlow();
error InvalidTcrit();
error InvalidTimestamps();
error InvalidUcrit();
error InvalidUlow();
error InvalidUopt();
error InvalidRi();
/// @dev Get config for given asset in a Silo.
/// @param _silo Silo address for which config should be set
/// @return Config struct for asset in Silo
function getConfig(address _silo) external view returns (Config memory);
/// @notice get the flag to detect rcomp restriction (zero current interest) due to overflow
/// overflow boolean flag to detect rcomp restriction
function overflowDetected(address _silo, uint256 _blockTimestamp)
external
view
returns (bool overflow);
/// @dev pure function that calculates current annual interest rate
/// @param _c configuration object, IInterestRateModel.Config
/// @param _totalBorrowAmount current total borrows for asset
/// @param _totalDeposits current total deposits for asset
/// @param _interestRateTimestamp timestamp of last interest rate update
/// @param _blockTimestamp current block timestamp
/// @return rcur current annual interest rate (1e18 == 100%)
function calculateCurrentInterestRate(
Config calldata _c,
uint256 _totalDeposits,
uint256 _totalBorrowAmount,
uint256 _interestRateTimestamp,
uint256 _blockTimestamp
) external pure returns (uint256 rcur);
/// @dev pure function that calculates interest rate based on raw input data
/// @param _c configuration object, IInterestRateModel.Config
/// @param _totalBorrowAmount current total borrows for asset
/// @param _totalDeposits current total deposits for asset
/// @param _interestRateTimestamp timestamp of last interest rate update
/// @param _blockTimestamp current block timestamp
/// @return rcomp compounded interest rate from last update until now (1e18 == 100%)
/// @return ri current integral part of the rate
/// @return Tcrit time during which the utilization exceeds the critical value
/// @return overflow boolean flag to detect rcomp restriction
function calculateCompoundInterestRateWithOverflowDetection(
Config memory _c,
uint256 _totalDeposits,
uint256 _totalBorrowAmount,
uint256 _interestRateTimestamp,
uint256 _blockTimestamp
)
external
pure
returns (
uint256 rcomp,
int256 ri,
int256 Tcrit,
bool overflow
);
/// @dev pure function that calculates interest rate based on raw input data
/// @param _c configuration object, IInterestRateModel.Config
/// @param _totalBorrowAmount current total borrows for asset
/// @param _totalDeposits current total deposits for asset
/// @param _interestRateTimestamp timestamp of last interest rate update
/// @param _blockTimestamp current block timestamp
/// @return rcomp compounded interest rate from last update until now (1e18 == 100%)
/// @return ri current integral part of the rate
/// @return Tcrit time during which the utilization exceeds the critical value
function calculateCompoundInterestRate(
Config memory _c,
uint256 _totalDeposits,
uint256 _totalBorrowAmount,
uint256 _interestRateTimestamp,
uint256 _blockTimestamp
) external pure returns (uint256 rcomp, int256 ri, int256 Tcrit);
}
"
},
"silo-core/contracts/interfaces/IInterestRateModelV2Factory.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity >=0.5.0;
import {IInterestRateModelV2} from "./IInterestRateModelV2.sol";
interface IInterestRateModelV2Factory {
/// @dev config hash and IRM should be easily accessible directly from oracle contract
event NewInterestRateModelV2(bytes32 indexed configHash, IInterestRateModelV2 indexed irm);
/// @dev verifies config and creates IRM config contract
/// @notice it can be used in separate tx eg config can be prepared before it will be used for Silo creation
/// @param _config IRM configuration
/// @param _externalSalt external salt for the create2 call
/// @return configHash the hashed config used as a key for IRM contract
/// @return irm deployed (or existing one, depends on the config) contract address
function create(IInterestRateModelV2.Config calldata _config, bytes32 _externalSalt)
external
returns (bytes32 configHash, IInterestRateModelV2 irm);
/// @dev DP is 18 decimal points used for integer calculations
// solhint-disable-next-line func-name-mixedcase
function DP() external view returns (uint256);
/// @dev verifies if config has correct values for a model, throws on invalid `_config`
/// @param _config config that will ve verified
function verifyConfig(IInterestRateModelV2.Config calldata _config) external view;
/// @dev hashes IRM config
/// @param _config IRM config
/// @return configId hash of `_config`
function hashConfig(IInterestRateModelV2.Config calldata _config) external pure returns (bytes32 configId);
}
"
},
"silo-core/contracts/interfaces/IDynamicKinkModelFactory.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity >=0.5.0;
import {IDynamicKinkModel} from "./IDynamicKinkModel.sol";
import {IInterestRateModel} from "./IInterestRateModel.sol";
/// @title IDynamicKinkModelFactory
/// @notice Factory interface for creating Dynamic Kink Interest Rate Model instances
/// @dev This factory creates and manages DynamicKinkModel instances using a clone pattern.
/// It provides utilities for configuration generation, validation, and deterministic
/// address prediction using CREATE2.
///
/// Key Features:
/// - Creates DynamicKinkModel instances via cloning
/// - Converts user-friendly configs to internal model parameters
/// - Validates configurations before deployment
/// - Predicts deterministic addresses for CREATE2 deployments
/// - Tracks which models were created by this factory
///
/// Usage Flow:
/// 1. Use generateConfig() to convert UserFriendlyConfig to internal Config
/// 2. Use verifyConfig() to validate the configuration
/// 3. Use create() to deploy a new DynamicKinkModel instance
/// 4. Use predictAddress() to determine the deployment address beforehand
interface IDynamicKinkModelFactory {
/// @notice Emitted when a new DynamicKinkModel instance is created
/// @param irm The address of the newly created DynamicKinkModel instance
event NewDynamicKinkModel(IDynamicKinkModel indexed irm);
/// @notice Thrown when trying to predict address with zero deployer address
error DeployerCannotBeZero();
/// @notice Creates a new DynamicKinkModel instance using CREATE2
/// @dev This function verifies the configuration, creates a clone of the implementation,
/// initializes it with the provided parameters, and tracks it in the factory.
/// The same salt will always produce the same address, enabling deterministic deployments.
///
/// The function can be used in separate transactions - configurations can be prepared
/// and validated before being used for Silo creation.
///
/// @param _config Updatable configuration parameters
/// @param _immutableArgs Immutable configuration arguments
/// @param _initialOwner Address that will own and control the created model instance
/// @param _silo Address of the Silo contract this model will serve
/// @param _externalSalt External salt for the CREATE2 deterministic deployment
/// @return irm The deployed DynamicKinkModel instance (IInterestRateModel interface)
function create(
IDynamicKinkModel.Config calldata _config,
IDynamicKinkModel.ImmutableArgs calldata _immutableArgs,
address _initialOwner,
address _silo,
bytes32 _externalSalt
)
external
returns (IInterestRateModel irm);
/// @notice Converts user-friendly configuration to internal model parameters
/// @dev This function takes intuitive configuration parameters and converts them to the
/// internal mathematical parameters used by the DynamicKinkModel. It performs
/// validation to ensure the configuration is mathematically sound and within
/// acceptable limits.
///
/// The conversion includes:
/// - Converting annual rates to per-second rates
/// - Calculating slope parameters (kmin, kmax) from rate ranges
/// - Computing time-based coefficients (c1, c2, cminus, cplus)
/// - Validating parameter relationships and constraints
///
/// @param _default User-friendly configuration parameters (utilization thresholds, rates, times)
/// @return config Internal configuration parameters ready for model initialization
function generateConfig(IDynamicKinkModel.UserFriendlyConfig calldata _default)
external
view
returns (IDynamicKinkModel.Config memory config);
/// @notice Validates that configuration parameters are within acceptable limits
/// @dev This function checks if all configuration parameters are within the safe operating ranges
/// defined by the model whitepaper. Some limits are narrower than the original whitepaper
/// due to additional research and safety considerations.
///
/// For detailed limits, see:
/// https://silofinance.atlassian.net/wiki/spaces/SF/pages/347963393/DynamicKink+model+config+limits+V1
///
/// @param _config The configuration to validate (does not include model state)
/// @custom:throws Reverts if any parameter is outside acceptable limits
function verifyConfig(IDynamicKinkModel.Config calldata _config) external view;
/// @notice Predicts the deterministic address of a DynamicKinkModel that would be created
/// @dev This function calculates the address that would be generated by CREATE2 when
/// creating a DynamicKinkModel with the given deployer and salt. This enables
/// front-running protection and allows users to know the address before deployment.
///
/// The same deployer and salt will always produce the same predicted address.
///
/// @param _deployer Address of the account that will deploy the model
/// @param _externalSalt External salt for the CREATE2 deterministic deployment
/// @return predictedAddress The address where the DynamicKinkModel would be deployed
function predictAddress(address _deployer, bytes32 _externalSalt)
external
view
returns (address predictedAddress);
/// @notice Checks if a DynamicKinkModel was created by this factory
/// @dev This function verifies whether a given address corresponds to a DynamicKinkModel
/// instance that was deployed through this factory. This is useful for:
/// - Verifying the authenticity of model instances
/// - Implementing access controls based on factory creation
/// - Tracking and managing factory-deployed models
///
/// @param _irm Address of the DynamicKinkModel contract to check
/// @return isCreated True if the model was created by this factory, false otherwise
function createdByFactory(address _irm) external view returns (bool isCreated);
}
"
},
"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/interfaces/IHookReceiver.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity >=0.5.0;
import {ISiloConfig} from "./ISiloConfig.sol";
interface IHookReceiver {
struct HookConfig {
uint24 hooksBefore;
uint24 hooksAfter;
}
event HookConfigured(address silo, uint24 hooksBefore, uint24 hooksAfter);
/// @dev Revert if provided silo configuration during initialization is empty
error EmptySiloConfig();
/// @dev Revert if the hook receiver is already configured/initialized
error AlreadyConfigured();
/// @dev Revert if the caller is not a silo
error OnlySilo();
/// @dev Revert if the caller is not a silo or a share token
error OnlySiloOrShareToken();
/// @notice Initialize a hook receiver
/// @param _siloConfig Silo configuration with all the details about the silo
/// @param _data Data to initialize the hook receiver (if needed)
function initialize(ISiloConfig _siloConfig, bytes calldata _data) external;
/// @notice state of Silo before action, can be also without interest, if you need them, call silo.accrueInterest()
function beforeAction(address _silo, uint256 _action, bytes calldata _input) external;
function afterAction(address _silo, uint256 _action, bytes calldata _inputAndOutput) external;
/// @notice return hooksBefore and hooksAfter configuration
function hookReceiverConfig(address _silo) external view returns (uint24 hooksBefore, uint24 hooksAfter);
}
"
},
"silo-core/contracts/interfaces/ISiloDeployer.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0;
import {IInterestRateModelV2} from "./IInterestRateModelV2.sol";
import {IDynamicKinkModel} from "./IDynamicKinkModel.sol";
import {ISiloConfig} from "./ISiloConfig.sol";
/// @notice Silo Deployer
interface ISiloDeployer {
/// @dev Details of the oracle creation transaction
struct OracleCreationTxData {
address deployed; // if oracle is already deployed, this will be the address to use
address factory; // oracle factory (chainlinkV3, uniswapV3, etc)
bytes txInput; // fn input `abi.encodeCall(fn, params...)`
}
/// @dev Hook receiver to be cloned and initialized during the Silo creation
struct ClonableHookReceiver {
address implementation;
bytes initializationData;
}
/// @dev Oracles to be create during the Silo creation.
/// If an oracle for the provided config is already created an oracle factory will return its address.
struct Oracles {
OracleCreationTxData solvencyOracle0;
OracleCreationTxData maxLtvOracle0;
OracleCreationTxData solvencyOracle1;
OracleCreationTxData maxLtvOracle1;
}
/// @dev DKinkIRM config to be created during the Silo creation.
struct DKinkIRMConfig {
IDynamicKinkModel.Config config;
IDynamicKinkModel.ImmutableArgs immutableArgs;
address initialOwner;
}
/// @dev Emit after the Silo creation
event SiloCreated(ISiloConfig siloConfig);
/// @dev Revert if an oracle factory fails to create an oracle
error FailedToCreateAnOracle(address _factory);
/// @dev Revert if for the deployment provided both hook receiver and hook receiver implementation
error HookReceiverMisconfigured();
/// @notice Deploy silo
/// @param _oracles Oracles to be create during the silo creation
/// @param _irmConfigData0 IRM config data for a silo `_TOKEN0`
/// @param _irmConfigData1 IRM config data for a silo `_TOKEN1`
/// @param _clonableHookReceiver Hook receiver implementation to clone (ignored if implementation has address(0))
/// @param _siloInitData Silo configuration for the silo creation
function deploy(
Oracles calldata _oracles,
bytes calldata _irmConfigData0,
bytes calldata _irmConfigData1,
ClonableHookReceiver calldata _clonableHookReceiver,
ISiloConfig.InitData memory _siloInitData
)
external
returns (ISiloConfig siloConfig);
}
"
},
"silo-core/contracts/SiloConfig.sol": {
"content": "// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.28;
import {IERC20} from "openzeppelin5/token/ERC20/IERC20.sol";
import {ISilo} from "./interfaces/ISilo.sol";
import {ISiloConfig} from "./interfaces/ISiloConfig.sol";
import {CrossReentrancyGuard} from "./utils/CrossReentrancyGuard.sol";
import {Hook} from "./lib/Hook.sol";
/// @notice SiloConfig stores full configuration of Silo in immutable manner
/// @dev Immutable contract is more expensive to deploy than minimal proxy however it provides nearly 10x cheaper
/// data access using immutable variables.
contract SiloConfig is ISiloConfig, CrossReentrancyGuard {
using Hook for uint256;
uint256 public immutable SILO_ID;
uint256 internal immutable _DAO_FEE;
uint256 internal immutable _DEPLOYER_FEE;
address internal immutable _HOOK_RECEIVER;
// TOKEN #0
address internal immutable _SILO0;
address internal immutable _TOKEN0;
/// @dev Token that represents a share in total protected deposits of Silo
address internal immutable _PROTECTED_COLLATERAL_SHARE_TOKEN0;
/// @dev Token that represents a share in total deposits of Silo
address internal immutable _COLLATERAL_SHARE_TOKEN0;
/// @dev Token that represents a share in total debt of Silo
address internal immutable _DEBT_SHARE_TOKEN0;
address internal immutable _SOLVENCY_ORACLE0;
address internal immutable _MAX_LTV_ORACLE0;
address internal immutable _INTEREST_RATE_MODEL0;
uint256 internal immutable _MAX_LTV0;
uint256 internal immutable _LT0;
/// @dev target LTV after liquidation
uint256 internal immutable _LIQUIDATION_TARGET_LTV0;
uint256 internal immutable _LIQUIDATION_FEE0;
uint256 internal immutable _FLASHLOAN_FEE0;
bool internal immutable _CALL_BEFORE_QUOTE0;
// TOKEN #1
address internal immutable _SILO1;
address internal immutable _TOKEN1;
/// @dev Token that represents a share in total protected deposits of Silo
address internal immutable _PROTECTED_COLLATERAL_SHARE_TOKEN1;
/// @dev Token that represents a share in total deposits of Silo
address internal immutable _COLLATERAL_SHARE_TOKEN1;
/// @dev Token that represents a share in total debt of Silo
address internal immutable _DEBT_SHARE_TOKEN1;
address internal immutable _SOLVENCY_ORACLE1;
address internal immutable _MAX_LTV_ORACLE1;
address internal immutable _INTEREST_RATE_MODEL1;
uint256 inte
Submitted on: 2025-10-21 10:18:52
Comments
Log in to comment.
No comments yet.