DynamicKinkModelFactory

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/interestRateModel/kink/DynamicKinkModelFactory.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.28;

import {Clones} from "openzeppelin5/proxy/Clones.sol";
import {SafeCast} from "openzeppelin5/utils/math/SafeCast.sol";

import {Create2Factory} from "common/utils/Create2Factory.sol";

import {IInterestRateModel} from "../../interfaces/IInterestRateModel.sol";
import {IDynamicKinkModel} from "../../interfaces/IDynamicKinkModel.sol";
import {IDynamicKinkModelFactory} from "../../interfaces/IDynamicKinkModelFactory.sol";

import {DynamicKinkModel} from "./DynamicKinkModel.sol";
import {KinkMath} from "../../lib/KinkMath.sol";

contract DynamicKinkModelFactory is Create2Factory, IDynamicKinkModelFactory {
    using KinkMath for int256;

    /// @dev DP in 18 decimal points used for integer calculations
    int256 public constant DP = int256(1e18);

    /// @dev seconds per year used in interest calculations.
    int256 public constant ONE_YEAR = 365 days;

    /// @dev IRM contract implementation address to clone
    DynamicKinkModel public immutable IRM;

    mapping(address irm => bool) public createdByFactory;

    constructor(DynamicKinkModel _implementation) {
        IRM = _implementation;
    }

    /// @inheritdoc IDynamicKinkModelFactory
    function create(
        IDynamicKinkModel.Config calldata _config,
        IDynamicKinkModel.ImmutableArgs calldata _immutableArgs,
        address _initialOwner,
        address _silo,
        bytes32 _externalSalt
    )
        external
        virtual
        returns (IInterestRateModel irm)
    {
        return IInterestRateModel(address(_create(_config, _immutableArgs, _initialOwner, _silo, _externalSalt)));
    }

    /// @inheritdoc IDynamicKinkModelFactory
    // solhint-disable-next-line code-complexity, function-max-lines
    function generateConfig(IDynamicKinkModel.UserFriendlyConfig calldata _default)
        external
        view
        virtual
        returns (IDynamicKinkModel.Config memory config)
    {
        IDynamicKinkModel.UserFriendlyConfigInt memory defaultInt = _castConfig(_default);

        // 0 <= ulow < u1 < u2 < ucrit < DP
        require(defaultInt.u1.inOpenInterval(defaultInt.ulow, defaultInt.u2), IDynamicKinkModel.InvalidU1());
        require(defaultInt.u2.inOpenInterval(defaultInt.u1, defaultInt.ucrit), IDynamicKinkModel.InvalidU2());
        require(defaultInt.ucrit.inOpenInterval(defaultInt.u2, DP), IDynamicKinkModel.InvalidUcrit());

        config.ulow = defaultInt.ulow;
        config.u1 = defaultInt.u1;
        config.u2 = defaultInt.u2;
        config.ucrit = defaultInt.ucrit;

        // 0 <= rmin < rcritMin <= rcritMax < r100

        require(
            defaultInt.rcritMin.inOpenIntervalTopIncluded(defaultInt.rmin, defaultInt.rcritMax),
            IDynamicKinkModel.InvalidRcritMin()
        );

        require(
            defaultInt.rcritMax.inOpenIntervalLowIncluded(defaultInt.rcritMin, defaultInt.r100),
            IDynamicKinkModel.InvalidRcritMax()
        );

        int256 s = 365 days;

        // 0 < tMin <= tcrit <= t2 < 100y
        require(defaultInt.tMin != 0, IDynamicKinkModel.InvalidTMin());
        require(defaultInt.tcrit.inClosedInterval(defaultInt.tMin, defaultInt.t2), IDynamicKinkModel.InvalidTCrit());
        require(defaultInt.t2.inOpenIntervalLowIncluded(defaultInt.tcrit, 100 * s), IDynamicKinkModel.InvalidT2());

        // 0 < tlow <= t1 < 100y
        require(defaultInt.tlow != 0, IDynamicKinkModel.InvalidTLow());
        require(defaultInt.t1.inOpenIntervalLowIncluded(defaultInt.tlow, 100 * s), IDynamicKinkModel.InvalidT1());

        // r check is move to the last, so it will be easier to detect issues with scallar values
        int256 rCheckHi = (defaultInt.r100 - defaultInt.rmin) * DP / (defaultInt.rcritMax - defaultInt.rmin);
        int256 rCheckLo = (DP - defaultInt.ulow) * DP / (defaultInt.ucrit - defaultInt.ulow);
        require(rCheckHi >= rCheckLo, IDynamicKinkModel.InvalidDefaultConfig());

        config.rmin = defaultInt.rmin / s;

        config.kmin =
            SafeCast.toInt96((defaultInt.rcritMin - defaultInt.rmin) * DP / (defaultInt.ucrit - defaultInt.ulow) / s);

        config.kmax =
            SafeCast.toInt96((defaultInt.rcritMax - defaultInt.rmin) * DP / (defaultInt.ucrit - defaultInt.ulow) / s);

        config.alpha =
            (rCheckHi * (defaultInt.ucrit - defaultInt.ulow) - (DP - defaultInt.ulow) * DP) / (DP - defaultInt.ucrit);

        config.c1 = (config.kmax - config.kmin) * DP / defaultInt.t1;
        config.c2 = (config.kmax - config.kmin) * DP / defaultInt.t2;

        config.cminus =
            ((config.kmax - config.kmin) * DP / defaultInt.tlow - config.c1) / (defaultInt.u1 - defaultInt.ulow);

        config.cplus =
            ((config.kmax - config.kmin) * DP / defaultInt.tcrit - config.c2) / (defaultInt.ucrit - defaultInt.u2);

        config.c1 /= DP;
        config.c2 /= DP;

        config.dmax = (config.kmax - config.kmin) / defaultInt.tMin;

        IDynamicKinkModel(address(IRM)).verifyConfig(config);
    }

    /// @inheritdoc IDynamicKinkModelFactory
    function verifyConfig(IDynamicKinkModel.Config calldata _config) external view virtual {
        IRM.verifyConfig(_config);
    }

    function predictAddress(address _deployer, bytes32 _externalSalt)
        external
        view
        returns (address predictedAddress)
    {
        require(_deployer != address(0), DeployerCannotBeZero());

        predictedAddress = Clones.predictDeterministicAddress(address(IRM), _createSalt(_deployer, _externalSalt));
    }

    function _create(
        IDynamicKinkModel.Config memory _config,
        IDynamicKinkModel.ImmutableArgs memory _immutableArgs,
        address _initialOwner,
        address _silo,
        bytes32 _externalSalt
    )
        internal
        virtual
        returns (IDynamicKinkModel irm)
    {
        IRM.verifyConfig(_config);

        bytes32 salt = _salt(_externalSalt);

        irm = IDynamicKinkModel(Clones.cloneDeterministic(address(IRM), salt));
        irm.initialize(_config, _immutableArgs, _initialOwner, _silo);

        createdByFactory[address(irm)] = true;
        emit NewDynamicKinkModel(irm);
    }

    function _castConfig(IDynamicKinkModel.UserFriendlyConfig calldata _default)
        internal
        pure
        returns (IDynamicKinkModel.UserFriendlyConfigInt memory config)
    {
        config.ulow = SafeCast.toInt256(_default.ulow);
        config.u1 = SafeCast.toInt256(_default.u1);
        config.u2 = SafeCast.toInt256(_default.u2);
        config.ucrit = SafeCast.toInt256(_default.ucrit);
        config.rmin = SafeCast.toInt256(_default.rmin);
        config.rcritMin = SafeCast.toInt256(_default.rcritMin);
        config.rcritMax = SafeCast.toInt256(_default.rcritMax);
        config.r100 = SafeCast.toInt256(_default.r100);
        config.t1 = SafeCast.toInt256(_default.t1);
        config.t2 = SafeCast.toInt256(_default.t2);
        config.tlow = SafeCast.toInt256(_default.tlow);
        config.tcrit = SafeCast.toInt256(_default.tcrit);
        config.tMin = SafeCast.toInt256(_default.tMin);
    }
}
"
    },
    "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));
    }
}
"
    },
    "gitmodules/openzeppelin-contracts-5/contracts/utils/math/SafeCast.sol": {
      "content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/math/SafeCast.sol)
// This file was procedurally generated from scripts/generate/templates/SafeCast.js.

pragma solidity ^0.8.20;

/**
 * @dev Wrappers over Solidity's uintXX/intXX/bool casting operators with added overflow
 * checks.
 *
 * Downcasting from uint256/int256 in Solidity does not revert on overflow. This can
 * easily result in undesired exploitation or bugs, since developers usually
 * assume that overflows raise errors. `SafeCast` restores this intuition by
 * reverting the transaction when such an operation overflows.
 *
 * Using this library instead of the unchecked operations eliminates an entire
 * class of bugs, so it's recommended to use it always.
 */
library SafeCast {
    /**
     * @dev Value doesn't fit in an uint of `bits` size.
     */
    error SafeCastOverflowedUintDowncast(uint8 bits, uint256 value);

    /**
     * @dev An int value doesn't fit in an uint of `bits` size.
     */
    error SafeCastOverflowedIntToUint(int256 value);

    /**
     * @dev Value doesn't fit in an int of `bits` size.
     */
    error SafeCastOverflowedIntDowncast(uint8 bits, int256 value);

    /**
     * @dev An uint value doesn't fit in an int of `bits` size.
     */
    error SafeCastOverflowedUintToInt(uint256 value);

    /**
     * @dev Returns the downcasted uint248 from uint256, reverting on
     * overflow (when the input is greater than largest uint248).
     *
     * Counterpart to Solidity's `uint248` operator.
     *
     * Requirements:
     *
     * - input must fit into 248 bits
     */
    function toUint248(uint256 value) internal pure returns (uint248) {
        if (value > type(uint248).max) {
            revert SafeCastOverflowedUintDowncast(248, value);
        }
        return uint248(value);
    }

    /**
     * @dev Returns the downcasted uint240 from uint256, reverting on
     * overflow (when the input is greater than largest uint240).
     *
     * Counterpart to Solidity's `uint240` operator.
     *
     * Requirements:
     *
     * - input must fit into 240 bits
     */
    function toUint240(uint256 value) internal pure returns (uint240) {
        if (value > type(uint240).max) {
            revert SafeCastOverflowedUintDowncast(240, value);
        }
        return uint240(value);
    }

    /**
     * @dev Returns the downcasted uint232 from uint256, reverting on
     * overflow (when the input is greater than largest uint232).
     *
     * Counterpart to Solidity's `uint232` operator.
     *
     * Requirements:
     *
     * - input must fit into 232 bits
     */
    function toUint232(uint256 value) internal pure returns (uint232) {
        if (value > type(uint232).max) {
            revert SafeCastOverflowedUintDowncast(232, value);
        }
        return uint232(value);
    }

    /**
     * @dev Returns the downcasted uint224 from uint256, reverting on
     * overflow (when the input is greater than largest uint224).
     *
     * Counterpart to Solidity's `uint224` operator.
     *
     * Requirements:
     *
     * - input must fit into 224 bits
     */
    function toUint224(uint256 value) internal pure returns (uint224) {
        if (value > type(uint224).max) {
            revert SafeCastOverflowedUintDowncast(224, value);
        }
        return uint224(value);
    }

    /**
     * @dev Returns the downcasted uint216 from uint256, reverting on
     * overflow (when the input is greater than largest uint216).
     *
     * Counterpart to Solidity's `uint216` operator.
     *
     * Requirements:
     *
     * - input must fit into 216 bits
     */
    function toUint216(uint256 value) internal pure returns (uint216) {
        if (value > type(uint216).max) {
            revert SafeCastOverflowedUintDowncast(216, value);
        }
        return uint216(value);
    }

    /**
     * @dev Returns the downcasted uint208 from uint256, reverting on
     * overflow (when the input is greater than largest uint208).
     *
     * Counterpart to Solidity's `uint208` operator.
     *
     * Requirements:
     *
     * - input must fit into 208 bits
     */
    function toUint208(uint256 value) internal pure returns (uint208) {
        if (value > type(uint208).max) {
            revert SafeCastOverflowedUintDowncast(208, value);
        }
        return uint208(value);
    }

    /**
     * @dev Returns the downcasted uint200 from uint256, reverting on
     * overflow (when the input is greater than largest uint200).
     *
     * Counterpart to Solidity's `uint200` operator.
     *
     * Requirements:
     *
     * - input must fit into 200 bits
     */
    function toUint200(uint256 value) internal pure returns (uint200) {
        if (value > type(uint200).max) {
            revert SafeCastOverflowedUintDowncast(200, value);
        }
        return uint200(value);
    }

    /**
     * @dev Returns the downcasted uint192 from uint256, reverting on
     * overflow (when the input is greater than largest uint192).
     *
     * Counterpart to Solidity's `uint192` operator.
     *
     * Requirements:
     *
     * - input must fit into 192 bits
     */
    function toUint192(uint256 value) internal pure returns (uint192) {
        if (value > type(uint192).max) {
            revert SafeCastOverflowedUintDowncast(192, value);
        }
        return uint192(value);
    }

    /**
     * @dev Returns the downcasted uint184 from uint256, reverting on
     * overflow (when the input is greater than largest uint184).
     *
     * Counterpart to Solidity's `uint184` operator.
     *
     * Requirements:
     *
     * - input must fit into 184 bits
     */
    function toUint184(uint256 value) internal pure returns (uint184) {
        if (value > type(uint184).max) {
            revert SafeCastOverflowedUintDowncast(184, value);
        }
        return uint184(value);
    }

    /**
     * @dev Returns the downcasted uint176 from uint256, reverting on
     * overflow (when the input is greater than largest uint176).
     *
     * Counterpart to Solidity's `uint176` operator.
     *
     * Requirements:
     *
     * - input must fit into 176 bits
     */
    function toUint176(uint256 value) internal pure returns (uint176) {
        if (value > type(uint176).max) {
            revert SafeCastOverflowedUintDowncast(176, value);
        }
        return uint176(value);
    }

    /**
     * @dev Returns the downcasted uint168 from uint256, reverting on
     * overflow (when the input is greater than largest uint168).
     *
     * Counterpart to Solidity's `uint168` operator.
     *
     * Requirements:
     *
     * - input must fit into 168 bits
     */
    function toUint168(uint256 value) internal pure returns (uint168) {
        if (value > type(uint168).max) {
            revert SafeCastOverflowedUintDowncast(168, value);
        }
        return uint168(value);
    }

    /**
     * @dev Returns the downcasted uint160 from uint256, reverting on
     * overflow (when the input is greater than largest uint160).
     *
     * Counterpart to Solidity's `uint160` operator.
     *
     * Requirements:
     *
     * - input must fit into 160 bits
     */
    function toUint160(uint256 value) internal pure returns (uint160) {
        if (value > type(uint160).max) {
            revert SafeCastOverflowedUintDowncast(160, value);
        }
        return uint160(value);
    }

    /**
     * @dev Returns the downcasted uint152 from uint256, reverting on
     * overflow (when the input is greater than largest uint152).
     *
     * Counterpart to Solidity's `uint152` operator.
     *
     * Requirements:
     *
     * - input must fit into 152 bits
     */
    function toUint152(uint256 value) internal pure returns (uint152) {
        if (value > type(uint152).max) {
            revert SafeCastOverflowedUintDowncast(152, value);
        }
        return uint152(value);
    }

    /**
     * @dev Returns the downcasted uint144 from uint256, reverting on
     * overflow (when the input is greater than largest uint144).
     *
     * Counterpart to Solidity's `uint144` operator.
     *
     * Requirements:
     *
     * - input must fit into 144 bits
     */
    function toUint144(uint256 value) internal pure returns (uint144) {
        if (value > type(uint144).max) {
            revert SafeCastOverflowedUintDowncast(144, value);
        }
        return uint144(value);
    }

    /**
     * @dev Returns the downcasted uint136 from uint256, reverting on
     * overflow (when the input is greater than largest uint136).
     *
     * Counterpart to Solidity's `uint136` operator.
     *
     * Requirements:
     *
     * - input must fit into 136 bits
     */
    function toUint136(uint256 value) internal pure returns (uint136) {
        if (value > type(uint136).max) {
            revert SafeCastOverflowedUintDowncast(136, value);
        }
        return uint136(value);
    }

    /**
     * @dev Returns the downcasted uint128 from uint256, reverting on
     * overflow (when the input is greater than largest uint128).
     *
     * Counterpart to Solidity's `uint128` operator.
     *
     * Requirements:
     *
     * - input must fit into 128 bits
     */
    function toUint128(uint256 value) internal pure returns (uint128) {
        if (value > type(uint128).max) {
            revert SafeCastOverflowedUintDowncast(128, value);
        }
        return uint128(value);
    }

    /**
     * @dev Returns the downcasted uint120 from uint256, reverting on
     * overflow (when the input is greater than largest uint120).
     *
     * Counterpart to Solidity's `uint120` operator.
     *
     * Requirements:
     *
     * - input must fit into 120 bits
     */
    function toUint120(uint256 value) internal pure returns (uint120) {
        if (value > type(uint120).max) {
            revert SafeCastOverflowedUintDowncast(120, value);
        }
        return uint120(value);
    }

    /**
     * @dev Returns the downcasted uint112 from uint256, reverting on
     * overflow (when the input is greater than largest uint112).
     *
     * Counterpart to Solidity's `uint112` operator.
     *
     * Requirements:
     *
     * - input must fit into 112 bits
     */
    function toUint112(uint256 value) internal pure returns (uint112) {
        if (value > type(uint112).max) {
            revert SafeCastOverflowedUintDowncast(112, value);
        }
        return uint112(value);
    }

    /**
     * @dev Returns the downcasted uint104 from uint256, reverting on
     * overflow (when the input is greater than largest uint104).
     *
     * Counterpart to Solidity's `uint104` operator.
     *
     * Requirements:
     *
     * - input must fit into 104 bits
     */
    function toUint104(uint256 value) internal pure returns (uint104) {
        if (value > type(uint104).max) {
            revert SafeCastOverflowedUintDowncast(104, value);
        }
        return uint104(value);
    }

    /**
     * @dev Returns the downcasted uint96 from uint256, reverting on
     * overflow (when the input is greater than largest uint96).
     *
     * Counterpart to Solidity's `uint96` operator.
     *
     * Requirements:
     *
     * - input must fit into 96 bits
     */
    function toUint96(uint256 value) internal pure returns (uint96) {
        if (value > type(uint96).max) {
            revert SafeCastOverflowedUintDowncast(96, value);
        }
        return uint96(value);
    }

    /**
     * @dev Returns the downcasted uint88 from uint256, reverting on
     * overflow (when the input is greater than largest uint88).
     *
     * Counterpart to Solidity's `uint88` operator.
     *
     * Requirements:
     *
     * - input must fit into 88 bits
     */
    function toUint88(uint256 value) internal pure returns (uint88) {
        if (value > type(uint88).max) {
            revert SafeCastOverflowedUintDowncast(88, value);
        }
        return uint88(value);
    }

    /**
     * @dev Returns the downcasted uint80 from uint256, reverting on
     * overflow (when the input is greater than largest uint80).
     *
     * Counterpart to Solidity's `uint80` operator.
     *
     * Requirements:
     *
     * - input must fit into 80 bits
     */
    function toUint80(uint256 value) internal pure returns (uint80) {
        if (value > type(uint80).max) {
            revert SafeCastOverflowedUintDowncast(80, value);
        }
        return uint80(value);
    }

    /**
     * @dev Returns the downcasted uint72 from uint256, reverting on
     * overflow (when the input is greater than largest uint72).
     *
     * Counterpart to Solidity's `uint72` operator.
     *
     * Requirements:
     *
     * - input must fit into 72 bits
     */
    function toUint72(uint256 value) internal pure returns (uint72) {
        if (value > type(uint72).max) {
            revert SafeCastOverflowedUintDowncast(72, value);
        }
        return uint72(value);
    }

    /**
     * @dev Returns the downcasted uint64 from uint256, reverting on
     * overflow (when the input is greater than largest uint64).
     *
     * Counterpart to Solidity's `uint64` operator.
     *
     * Requirements:
     *
     * - input must fit into 64 bits
     */
    function toUint64(uint256 value) internal pure returns (uint64) {
        if (value > type(uint64).max) {
            revert SafeCastOverflowedUintDowncast(64, value);
        }
        return uint64(value);
    }

    /**
     * @dev Returns the downcasted uint56 from uint256, reverting on
     * overflow (when the input is greater than largest uint56).
     *
     * Counterpart to Solidity's `uint56` operator.
     *
     * Requirements:
     *
     * - input must fit into 56 bits
     */
    function toUint56(uint256 value) internal pure returns (uint56) {
        if (value > type(uint56).max) {
            revert SafeCastOverflowedUintDowncast(56, value);
        }
        return uint56(value);
    }

    /**
     * @dev Returns the downcasted uint48 from uint256, reverting on
     * overflow (when the input is greater than largest uint48).
     *
     * Counterpart to Solidity's `uint48` operator.
     *
     * Requirements:
     *
     * - input must fit into 48 bits
     */
    function toUint48(uint256 value) internal pure returns (uint48) {
        if (value > type(uint48).max) {
            revert SafeCastOverflowedUintDowncast(48, value);
        }
        return uint48(value);
    }

    /**
     * @dev Returns the downcasted uint40 from uint256, reverting on
     * overflow (when the input is greater than largest uint40).
     *
     * Counterpart to Solidity's `uint40` operator.
     *
     * Requirements:
     *
     * - input must fit into 40 bits
     */
    function toUint40(uint256 value) internal pure returns (uint40) {
        if (value > type(uint40).max) {
            revert SafeCastOverflowedUintDowncast(40, value);
        }
        return uint40(value);
    }

    /**
     * @dev Returns the downcasted uint32 from uint256, reverting on
     * overflow (when the input is greater than largest uint32).
     *
     * Counterpart to Solidity's `uint32` operator.
     *
     * Requirements:
     *
     * - input must fit into 32 bits
     */
    function toUint32(uint256 value) internal pure returns (uint32) {
        if (value > type(uint32).max) {
            revert SafeCastOverflowedUintDowncast(32, value);
        }
        return uint32(value);
    }

    /**
     * @dev Returns the downcasted uint24 from uint256, reverting on
     * overflow (when the input is greater than largest uint24).
     *
     * Counterpart to Solidity's `uint24` operator.
     *
     * Requirements:
     *
     * - input must fit into 24 bits
     */
    function toUint24(uint256 value) internal pure returns (uint24) {
        if (value > type(uint24).max) {
            revert SafeCastOverflowedUintDowncast(24, value);
        }
        return uint24(value);
    }

    /**
     * @dev Returns the downcasted uint16 from uint256, reverting on
     * overflow (when the input is greater than largest uint16).
     *
     * Counterpart to Solidity's `uint16` operator.
     *
     * Requirements:
     *
     * - input must fit into 16 bits
     */
    function toUint16(uint256 value) internal pure returns (uint16) {
        if (value > type(uint16).max) {
            revert SafeCastOverflowedUintDowncast(16, value);
        }
        return uint16(value);
    }

    /**
     * @dev Returns the downcasted uint8 from uint256, reverting on
     * overflow (when the input is greater than largest uint8).
     *
     * Counterpart to Solidity's `uint8` operator.
     *
     * Requirements:
     *
     * - input must fit into 8 bits
     */
    function toUint8(uint256 value) internal pure returns (uint8) {
        if (value > type(uint8).max) {
            revert SafeCastOverflowedUintDowncast(8, value);
        }
        return uint8(value);
    }

    /**
     * @dev Converts a signed int256 into an unsigned uint256.
     *
     * Requirements:
     *
     * - input must be greater than or equal to 0.
     */
    function toUint256(int256 value) internal pure returns (uint256) {
        if (value < 0) {
            revert SafeCastOverflowedIntToUint(value);
        }
        return uint256(value);
    }

    /**
     * @dev Returns the downcasted int248 from int256, reverting on
     * overflow (when the input is less than smallest int248 or
     * greater than largest int248).
     *
     * Counterpart to Solidity's `int248` operator.
     *
     * Requirements:
     *
     * - input must fit into 248 bits
     */
    function toInt248(int256 value) internal pure returns (int248 downcasted) {
        downcasted = int248(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(248, value);
        }
    }

    /**
     * @dev Returns the downcasted int240 from int256, reverting on
     * overflow (when the input is less than smallest int240 or
     * greater than largest int240).
     *
     * Counterpart to Solidity's `int240` operator.
     *
     * Requirements:
     *
     * - input must fit into 240 bits
     */
    function toInt240(int256 value) internal pure returns (int240 downcasted) {
        downcasted = int240(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(240, value);
        }
    }

    /**
     * @dev Returns the downcasted int232 from int256, reverting on
     * overflow (when the input is less than smallest int232 or
     * greater than largest int232).
     *
     * Counterpart to Solidity's `int232` operator.
     *
     * Requirements:
     *
     * - input must fit into 232 bits
     */
    function toInt232(int256 value) internal pure returns (int232 downcasted) {
        downcasted = int232(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(232, value);
        }
    }

    /**
     * @dev Returns the downcasted int224 from int256, reverting on
     * overflow (when the input is less than smallest int224 or
     * greater than largest int224).
     *
     * Counterpart to Solidity's `int224` operator.
     *
     * Requirements:
     *
     * - input must fit into 224 bits
     */
    function toInt224(int256 value) internal pure returns (int224 downcasted) {
        downcasted = int224(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(224, value);
        }
    }

    /**
     * @dev Returns the downcasted int216 from int256, reverting on
     * overflow (when the input is less than smallest int216 or
     * greater than largest int216).
     *
     * Counterpart to Solidity's `int216` operator.
     *
     * Requirements:
     *
     * - input must fit into 216 bits
     */
    function toInt216(int256 value) internal pure returns (int216 downcasted) {
        downcasted = int216(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(216, value);
        }
    }

    /**
     * @dev Returns the downcasted int208 from int256, reverting on
     * overflow (when the input is less than smallest int208 or
     * greater than largest int208).
     *
     * Counterpart to Solidity's `int208` operator.
     *
     * Requirements:
     *
     * - input must fit into 208 bits
     */
    function toInt208(int256 value) internal pure returns (int208 downcasted) {
        downcasted = int208(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(208, value);
        }
    }

    /**
     * @dev Returns the downcasted int200 from int256, reverting on
     * overflow (when the input is less than smallest int200 or
     * greater than largest int200).
     *
     * Counterpart to Solidity's `int200` operator.
     *
     * Requirements:
     *
     * - input must fit into 200 bits
     */
    function toInt200(int256 value) internal pure returns (int200 downcasted) {
        downcasted = int200(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(200, value);
        }
    }

    /**
     * @dev Returns the downcasted int192 from int256, reverting on
     * overflow (when the input is less than smallest int192 or
     * greater than largest int192).
     *
     * Counterpart to Solidity's `int192` operator.
     *
     * Requirements:
     *
     * - input must fit into 192 bits
     */
    function toInt192(int256 value) internal pure returns (int192 downcasted) {
        downcasted = int192(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(192, value);
        }
    }

    /**
     * @dev Returns the downcasted int184 from int256, reverting on
     * overflow (when the input is less than smallest int184 or
     * greater than largest int184).
     *
     * Counterpart to Solidity's `int184` operator.
     *
     * Requirements:
     *
     * - input must fit into 184 bits
     */
    function toInt184(int256 value) internal pure returns (int184 downcasted) {
        downcasted = int184(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(184, value);
        }
    }

    /**
     * @dev Returns the downcasted int176 from int256, reverting on
     * overflow (when the input is less than smallest int176 or
     * greater than largest int176).
     *
     * Counterpart to Solidity's `int176` operator.
     *
     * Requirements:
     *
     * - input must fit into 176 bits
     */
    function toInt176(int256 value) internal pure returns (int176 downcasted) {
        downcasted = int176(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(176, value);
        }
    }

    /**
     * @dev Returns the downcasted int168 from int256, reverting on
     * overflow (when the input is less than smallest int168 or
     * greater than largest int168).
     *
     * Counterpart to Solidity's `int168` operator.
     *
     * Requirements:
     *
     * - input must fit into 168 bits
     */
    function toInt168(int256 value) internal pure returns (int168 downcasted) {
        downcasted = int168(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(168, value);
        }
    }

    /**
     * @dev Returns the downcasted int160 from int256, reverting on
     * overflow (when the input is less than smallest int160 or
     * greater than largest int160).
     *
     * Counterpart to Solidity's `int160` operator.
     *
     * Requirements:
     *
     * - input must fit into 160 bits
     */
    function toInt160(int256 value) internal pure returns (int160 downcasted) {
        downcasted = int160(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(160, value);
        }
    }

    /**
     * @dev Returns the downcasted int152 from int256, reverting on
     * overflow (when the input is less than smallest int152 or
     * greater than largest int152).
     *
     * Counterpart to Solidity's `int152` operator.
     *
     * Requirements:
     *
     * - input must fit into 152 bits
     */
    function toInt152(int256 value) internal pure returns (int152 downcasted) {
        downcasted = int152(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(152, value);
        }
    }

    /**
     * @dev Returns the downcasted int144 from int256, reverting on
     * overflow (when the input is less than smallest int144 or
     * greater than largest int144).
     *
     * Counterpart to Solidity's `int144` operator.
     *
     * Requirements:
     *
     * - input must fit into 144 bits
     */
    function toInt144(int256 value) internal pure returns (int144 downcasted) {
        downcasted = int144(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(144, value);
        }
    }

    /**
     * @dev Returns the downcasted int136 from int256, reverting on
     * overflow (when the input is less than smallest int136 or
     * greater than largest int136).
     *
     * Counterpart to Solidity's `int136` operator.
     *
     * Requirements:
     *
     * - input must fit into 136 bits
     */
    function toInt136(int256 value) internal pure returns (int136 downcasted) {
        downcasted = int136(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(136, value);
        }
    }

    /**
     * @dev Returns the downcasted int128 from int256, reverting on
     * overflow (when the input is less than smallest int128 or
     * greater than largest int128).
     *
     * Counterpart to Solidity's `int128` operator.
     *
     * Requirements:
     *
     * - input must fit into 128 bits
     */
    function toInt128(int256 value) internal pure returns (int128 downcasted) {
        downcasted = int128(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(128, value);
        }
    }

    /**
     * @dev Returns the downcasted int120 from int256, reverting on
     * overflow (when the input is less than smallest int120 or
     * greater than largest int120).
     *
     * Counterpart to Solidity's `int120` operator.
     *
     * Requirements:
     *
     * - input must fit into 120 bits
     */
    function toInt120(int256 value) internal pure returns (int120 downcasted) {
        downcasted = int120(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(120, value);
        }
    }

    /**
     * @dev Returns the downcasted int112 from int256, reverting on
     * overflow (when the input is less than smallest int112 or
     * greater than largest int112).
     *
     * Counterpart to Solidity's `int112` operator.
     *
     * Requirements:
     *
     * - input must fit into 112 bits
     */
    function toInt112(int256 value) internal pure returns (int112 downcasted) {
        downcasted = int112(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(112, value);
        }
    }

    /**
     * @dev Returns the downcasted int104 from int256, reverting on
     * overflow (when the input is less than smallest int104 or
     * greater than largest int104).
     *
     * Counterpart to Solidity's `int104` operator.
     *
     * Requirements:
     *
     * - input must fit into 104 bits
     */
    function toInt104(int256 value) internal pure returns (int104 downcasted) {
        downcasted = int104(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(104, value);
        }
    }

    /**
     * @dev Returns the downcasted int96 from int256, reverting on
     * overflow (when the input is less than smallest int96 or
     * greater than largest int96).
     *
     * Counterpart to Solidity's `int96` operator.
     *
     * Requirements:
     *
     * - input must fit into 96 bits
     */
    function toInt96(int256 value) internal pure returns (int96 downcasted) {
        downcasted = int96(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(96, value);
        }
    }

    /**
     * @dev Returns the downcasted int88 from int256, reverting on
     * overflow (when the input is less than smallest int88 or
     * greater than largest int88).
     *
     * Counterpart to Solidity's `int88` operator.
     *
     * Requirements:
     *
     * - input must fit into 88 bits
     */
    function toInt88(int256 value) internal pure returns (int88 downcasted) {
        downcasted = int88(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(88, value);
        }
    }

    /**
     * @dev Returns the downcasted int80 from int256, reverting on
     * overflow (when the input is less than smallest int80 or
     * greater than largest int80).
     *
     * Counterpart to Solidity's `int80` operator.
     *
     * Requirements:
     *
     * - input must fit into 80 bits
     */
    function toInt80(int256 value) internal pure returns (int80 downcasted) {
        downcasted = int80(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(80, value);
        }
    }

    /**
     * @dev Returns the downcasted int72 from int256, reverting on
     * overflow (when the input is less than smallest int72 or
     * greater than largest int72).
     *
     * Counterpart to Solidity's `int72` operator.
     *
     * Requirements:
     *
     * - input must fit into 72 bits
     */
    function toInt72(int256 value) internal pure returns (int72 downcasted) {
        downcasted = int72(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(72, value);
        }
    }

    /**
     * @dev Returns the downcasted int64 from int256, reverting on
     * overflow (when the input is less than smallest int64 or
     * greater than largest int64).
     *
     * Counterpart to Solidity's `int64` operator.
     *
     * Requirements:
     *
     * - input must fit into 64 bits
     */
    function toInt64(int256 value) internal pure returns (int64 downcasted) {
        downcasted = int64(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(64, value);
        }
    }

    /**
     * @dev Returns the downcasted int56 from int256, reverting on
     * overflow (when the input is less than smallest int56 or
     * greater than largest int56).
     *
     * Counterpart to Solidity's `int56` operator.
     *
     * Requirements:
     *
     * - input must fit into 56 bits
     */
    function toInt56(int256 value) internal pure returns (int56 downcasted) {
        downcasted = int56(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(56, value);
        }
    }

    /**
     * @dev Returns the downcasted int48 from int256, reverting on
     * overflow (when the input is less than smallest int48 or
     * greater than largest int48).
     *
     * Counterpart to Solidity's `int48` operator.
     *
     * Requirements:
     *
     * - input must fit into 48 bits
     */
    function toInt48(int256 value) internal pure returns (int48 downcasted) {
        downcasted = int48(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(48, value);
        }
    }

    /**
     * @dev Returns the downcasted int40 from int256, reverting on
     * overflow (when the input is less than smallest int40 or
     * greater than largest int40).
     *
     * Counterpart to Solidity's `int40` operator.
     *
     * Requirements:
     *
     * - input must fit into 40 bits
     */
    function toInt40(int256 value) internal pure returns (int40 downcasted) {
        downcasted = int40(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(40, value);
        }
    }

    /**
     * @dev Returns the downcasted int32 from int256, reverting on
     * overflow (when the input is less than smallest int32 or
     * greater than largest int32).
     *
     * Counterpart to Solidity's `int32` operator.
     *
     * Requirements:
     *
     * - input must fit into 32 bits
     */
    function toInt32(int256 value) internal pure returns (int32 downcasted) {
        downcasted = int32(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(32, value);
        }
    }

    /**
     * @dev Returns the downcasted int24 from int256, reverting on
     * overflow (when the input is less than smallest int24 or
     * greater than largest int24).
     *
     * Counterpart to Solidity's `int24` operator.
     *
     * Requirements:
     *
     * - input must fit into 24 bits
     */
    function toInt24(int256 value) internal pure returns (int24 downcasted) {
        downcasted = int24(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(24, value);
        }
    }

    /**
     * @dev Returns the downcasted int16 from int256, reverting on
     * overflow (when the input is less than smallest int16 or
     * greater than largest int16).
     *
     * Counterpart to Solidity's `int16` operator.
     *
     * Requirements:
     *
     * - input must fit into 16 bits
     */
    function toInt16(int256 value) internal pure returns (int16 downcasted) {
        downcasted = int16(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(16, value);
        }
    }

    /**
     * @dev Returns the downcasted int8 from int256, reverting on
     * overflow (when the input is less than smallest int8 or
     * greater than largest int8).
     *
     * Counterpart to Solidity's `int8` operator.
     *
     * Requirements:
     *
     * - input must fit into 8 bits
     */
    function toInt8(int256 value) internal pure returns (int8 downcasted) {
        downcasted = int8(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(8, value);
        }
    }

    /**
     * @dev Converts an unsigned uint256 into a signed int256.
     *
     * Requirements:
     *
     * - input must be less than or equal to maxInt256.
     */
    function toInt256(uint256 value) internal pure returns (int256) {
        // Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive
        if (value > uint256(type(int256).max)) {
            revert SafeCastOverflowedUintToInt(value);
        }
        return int256(value);
    }

    /**
     * @dev Cast a boolean (false or true) to a uint256 (0 or 1) with no jump.
     */
    function toUint(bool b) internal pure returns (uint256 u) {
        /// @solidity memory-safe-assembly
        assembly {
            u := iszero(iszero(b))
        }
    }
}
"
    },
    "common/utils/Create2Factory.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.28;

import {Nonces} from "openzeppelin5/utils/Nonces.sol";

contract Create2Factory is Nonces {
    function _salt() internal returns (bytes32 salt) {
        salt = keccak256(abi.encodePacked(
            msg.sender,
            _useNonce(msg.sender)
        ));
    }

    function _salt(bytes32 _externalSalt) internal returns (bytes32 salt) {
        salt = keccak256(abi.encodePacked(
            msg.sender,
            _useNonce(msg.sender),
            _externalSalt
        ));
    }

    function _createSalt(address _deployer, bytes32 _externalSalt) internal view returns (bytes32 salt) {
        salt = keccak256(abi.encodePacked(
            _deployer,
            nonces(_deployer),
            _externalSalt
        ));
    }
}
"
    },
    "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/IDynamicKinkModel.sol": {
      "content": "// SPDX-License-Identifier: MIT
pragma solidity >=0.5.0;

import {IDynamicKinkModelConfig} from "./IDynamicKinkModelConfig.sol";

/// @title IDynamicKinkModel
/// @notice Interface for the Dynamic Kink Interest Rate Model
/// @dev This interface defines an adaptive interest rate model that dynamically adjusts rates based on market
///      utilization.
///      The model uses a "kink" mechanism where interest rates change more aggressively as utilization increases.
///      Unlike static models, this implementation adapts over time to market conditions.
/// 
///      Key Features:
///      - Dynamic rate adjustment based on utilization thresholds
///      - Time-based rate evolution to prevent sudden spikes
///      - Configurable parameters for different market conditions
///      - Compound interest calculation for accurate accrual
/// 
///      The model operates with several utilization zones:
///      - Low utilization (0 to ulow): Minimal rates to encourage borrowing
///      - Optimal range (u1 to u2): Stable rates for normal operations  
///      - High utilization (u2 to ucrit): Increasing rates to manage risk
///      - Critical utilization (ucrit to 1e18): Maximum rates
interface IDynamicKinkModel {
    /// @notice User-friendly configuration structure for setting up the Dynamic Kink Model
    /// @dev This structure provides intuitive parameters that are converted to internal model parameters.
    ///      All utilization values are in 18 decimals (e.g., 0.5e18 = 50% utilization).
    ///      All time values are in seconds.
    /// 
    /// @param ulow Utilization threshold below which rates are minimal
    /// @param ucrit Critical utilization threshold where rates become very high
    /// @param u1 lower bound of optimal utilization range (the model is static when utilization is in this interval).
    /// @param u2 upper bound of optimal utilization range (the model is static when utilization is in this interval).
    /// @param rmin Minimal per-second interest rate (minimal APR), active below ulow.
    /// @param rcritMin Minimal APR that the model can output at the critical utilization ucrit
    /// @param rcritMax Maximal APR that the model can output at the critical utilization ucrit
    /// @param r100 Maximum possible per-second rate at 100% utilization
    /// @param t1 Time in seconds for rate to decrease from max to min at u1 utilization
    /// @param t2 Time in seconds for rate to increase from min to max at u2 utilization
    /// @param tlow Time in seconds to reset rates when utilization drops to ulow
    /// @param tcrit Time in seconds for rate to increase from min to max at critical utilization
    /// @param tMin minimal time it takes to grow from the minimal to the maximal APR at any utilization
    struct UserFriendlyConfig {
        uint64 ulow;
        uint64 ucrit;
        uint64 u1;
        uint64 u2;
        uint72 rmin;
        uint72 rcritMin;
        uint72 rcritMax;
        uint72 r100;
        uint32 t1;
        uint32 t2;
        uint32 tlow;
        uint32 tcrit;
        uint32 tMin;
    }

    /// @dev same as UserFriendlyConfig but with int256 values to help with calculations
    struct UserFriendlyConfigInt {
        int256 ulow;
        int256 ucrit;
        int256 u1;
        int256 u2;
        int256 rmin;
        int256 rcritMin;
        int256 rcritMax;
        int256 r100;
        int256 t1;
        int256 t2;
        int256 tlow;
        int256 tcrit;
        int256 tMin;
    }

    /// @notice Internal configuration structure used by the model for calculations
    /// @dev These values are used in the mathematical calculations of the interest rate model.
    ///     Utilization values are in 18 decimals 1e18 = 100%.
    /// @param ulow ulow ∈ [0, 1e18) Low utilization threshold
    /// @param u1 u1 ∈ [0, 1e18) Lower bound of optimal utilization range
    /// @param u2 u2 ∈ [u1, 1e18) Upper bound of optimal utilization range
    /// @param ucrit ucrit ∈ [ulow, 1e18) Critical utilization threshold
    /// @param rmin rmin >= 0 Minimal per-second interest rate
    /// @param kmin kmin >= 0 Minimal slope k of central segment (curve) of the kink
    /// @param kmax kmax >= kmin Maximal slope k of central segment (curve) of the kink
    /// @param alpha alpha >= 0 Factor controlling the slope for the critical segment of the kink
    /// @param cminus cminus >= 0 Coefficient of decrease of the slope k
    /// @param cplus cplus >= 0 Coefficient for increasing the slope k
    /// @param c1 c1 >= 0 Minimal rate of decrease of the slope k
    /// @param c2 c2 >= 0 Minimal growth rate of the slope k
    /// @param dmax dmax >= 0 Maximum growth rate of the slope k
    struct Config {
        int256 ulow;
        int256 u1;
        int256 u2;
        int256 ucrit;
        int256 rmin;
        int96 kmin;
        int96 kmax;
        int256 alpha;
        int256 cminus;
        int256 cplus;
        int256 c1;
        int256 c2;
        int256 dmax;
    }

    struct ImmutableArgs {
        uint32 timelock;
        int96 rcompCap;
    }

    struct ImmutableConfig {
        uint32 timelock;
        int96 rcompCapPerSecond;
    }

    /// @notice Internal variables used during compound interest calculations
    /// @dev This structure contains temporary variables used in the mathematical calculations.
    ///      Integrators typically don't need to interact with these values directly.
    /// 
    /// @param T Time elapsed since the last interest rate update (in seconds)
    /// @param k1 Internal variable for slope calculations
    /// @param f Factor used in kink slope calculations
    /// @param roc Rate of change variable for slope calculations
    /// @param x Internal calculation variable
    /// @param interest Absolute value of compounded interest
    struct LocalVarsRCOMP {
        int256 T;
        int256 k1;
        int256 f;
        int256 roc;
        int256 x;
        int256 interest;
    }

    struct CompoundInterestRateArgs {
        address silo;
        uint256 collateralAssets;
        uint256 debtAssets;
        uint256 interestRateTimestamp;
        uint256 blockTimestamp;
        bool usePending;
    }

    /// @notice Current state of the Dynamic Kink Model
    /// @dev This structure tracks the current state of the model, including the dynamic slope value
    ///      that changes over time based on utilization patterns.
    /// 
    /// @param k Current slope value of the kink curve (changes dynamically over time)
    /// @param silo Address of the Silo contract this model is associated with
    struct ModelState {
        int96 k;
        address silo;
    }

    struct History {
        int96 k;
        IDynamicKinkModelConfig irmConfig;
    }

    /// @notice Emitted when the model is initialized with a new configuration
    /// @param owner Address that will own this model instance
    /// @param silo Address of the Silo contract this model is associated with
    event Initialized(address indexed owner, address indexed silo);

    /// @notice Emitted when a new configuration is set for the model
    /// @param config The new configuration contract address
    /// @param activeAt Timestamp at which the configuration becomes active
    event NewConfig(IDynamicKinkModelConfig indexed config, uint256 activeAt);

    /// @notice Emitted when a pending configuration update is canceled
    /// @param config The canceled configuration contract address
    event PendingUpdateConfigCanceled(IDynamicKinkModelConfig indexed config);

    error AddressZero();
    error AlphaDividerZero();
    error AlreadyInitialized();
    error EmptySilo();
    error InvalidAlpha();
    error InvalidC1();
    error InvalidC2();
    error InvalidCminus();
    error InvalidCplus();
    error InvalidDefaultConfig();
    error InvalidDmax();
    error InvalidKmax();
    error InvalidKmin();
    error InvalidKRange();
    error InvalidRcompCap();
    error InvalidRcritMax();
    error InvalidRcritMin();
    error InvalidRmin();
    error InvalidSilo();
    error InvalidT1();
    error InvalidT2();
    error InvalidTimelock();
    error InvalidTimestamp();
    error InvalidTMin();
    error InvalidTLow();
    error InvalidTCrit();
    error InvalidU1();
    error InvalidU2();
    error InvalidUcrit();
    error InvalidUlow();
    error NegativeRcomp();
    error NegativeRcur();
    error NoPendingUpdateToCancel();
    error NoPendingConfig();
    error OnlySilo();
    error PendingUpdate();
    error XOverflow();

    /// @notice Initialize the Dynamic Kink Model with configuration and ownership
    /// @dev This function sets up the model for a specific Silo contract. Can only be called once.
    /// @param _config The configuration parameters for the interest rate model
    /// @param _immutableArgs The immutable configuration parameters for the interest rate model
    /// @param _initialOwner Address that will own and control this model instance
    /// @param _silo Address of the Silo contract this model will serve
    function initialize(
        IDynamicKinkModel.Config calldata _config, 
        IDynamicKinkModel.ImmutableArgs calldata _immutableArgs, 
        address _initialOwner, 
        address _silo
    ) 
        external;

    /// @notice Update the model configuration
    /// @dev This function allows the model owner to update the configuration of the model.
    ///      By setting the same config, we can reset k to kmin.
    /// @param _config The new configuration parameters for the interest rate model
    function updateConfig(IDynamicKinkModel.Config calldata _config) external;

    /// @notice Cancel the pending configuration update
    /// @dev This function allows the model owner to cancel the pending configuration update.
    ///      It will revert if there is no pending update.
    function cancelPendingUpdateConfig() external;

    /// @notice Calculate compound interest rate and update the model's internal state
    /// @dev This function is the primary method used by Silo contracts to calculate
    ///      and accrue interest. Unlike getCompoundInterestRate(), this function
    ///      modifies the model's internal state by updating the dynamic slope value (k).
    /// 
    ///      This function should only be called by the associated Silo contract,
    ///      as it performs state updates that affect future interest calculations.
    ///      It includes comprehensive overflow protection and gracefully handles
    ///      calculation errors by returning 0 and resetting the slope to minimum.
    /// 
    ///      The function calculates interest based on:
    ///      - Current collateral and debt amounts
    ///      - Time elapsed since last interest rate update
    ///      - Dynamic slope adjustments based on utilization patterns
    /// 
    /// @param _collateralAssets Total collateral assets in the Silo (in asset units)
    /// @param _debtAssets Total debt assets in the Silo (in asset units)
    /// @param _interestRateTimestamp Timestamp of the last interest rate update
    /// @return rcomp Total compound interest multiplier (in 18 decimals, represents total accrued interest)
    /// @custom:throws OnlySilo() if called by any address other than the associated Silo contract
    function getCompoundInterestRateAndUpdate(
        uint256 _collateralAssets,
        uint256 _debtAssets,
        uint256 _interestRateTimestamp
    )
        external
        returns (uint256 rcomp);
    
    function configsHistory(IDynamicKinkModelConfig _irmConfig) 
        external 
        view 
        returns (int96 k, IDynamicKinkModelConfig irmConfig);

    /// @notice Get the current (active) configuration contract for this model
    /// @return config The IDynamicKinkModelConfig contract containing the model parameters
    function irmConfig() external view returns (IDynamicKinkModelConfig config);

    /// @notice Get the current (active) model state
    function modelState() external view returns (ModelState memory state);
    
    /// @notice Get both the current model state and configuration
    /// @param _usePending Whether to use the pending configuration to pull config from
    /// @return state Current state of the model (including dynamic slope value)
    /// @return config configuration parameters, either active or pending, depending on _usePending
    /// @return immutableConfig Immutable configuration parameters
    function getModelStateAndConfig(bool _usePending) 
        external 
        view 
        returns (ModelState memory state, Config memory config, ImmutableConfig memory immutableConfig);

    /// @notice Maximum compound interest rate per second (prevents extreme rates)
    /// @return cap Maximum per-second compound interest rate in 18 decimals
    function RCOMP_CAP_PER_SECOND() external view returns (int256 cap); // solhint-disable-line func-name-mixedcase
    
    /// @notice Maximum current interest rate (prevents extreme APRs)
    /// @return cap Maximum annual interest rate in 18 deci

Tags:
ERC20, ERC721, ERC165, Multisig, Mintable, Burnable, Non-Fungible, Liquidity, Yield, Upgradeable, Multi-Signature, Factory, Oracle|addr:0x315a8319e94eff8aa5fb11923c32e73fca00e479|verified:true|block:23620474|tx:0x9dd95d79ded35b623dec70ebca54fc9d12d92734fa4f0110edf6dc480f671bf0|first_check:1761034079

Submitted on: 2025-10-21 10:08:01

Comments

Log in to comment.

No comments yet.