Overview
ETH Balance
0 ETH
Eth Value
$0.00View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Cross-Chain Transactions
Loading...
Loading
Contract Name:
InterestRateModelV2
Compiler Version
v0.8.13+commit.abaa5c0e
Optimization Enabled:
Yes with 200 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.13;
import "./InterestRateModelXAI.sol";
import "./lib/EasyMathV2.sol";
interface IGenericInterestRateModel {
function config(address _silo, address _asset) external view returns (IInterestRateModel.Config memory);
}
/// @title InterestRateModelV2
/// @notice Dynamic interest rate model implementation
/// @dev Model stores some Silo specific data. If model is replaced, it needs to set proper config after redeployment
/// for seamless service. Please refer to separate litepaper about model for design details.
/// @custom:security-contact [email protected]
contract InterestRateModelV2 is InterestRateModelXAI {
using SafeCast for int256;
using SafeCast for uint256;
constructor(Config memory _config, address _owner) InterestRateModelXAI(_config) {
if (_owner != address(0)) {
transferOwnership(_owner);
}
}
/// @dev migration method for models before InterestRateModelV2
/// @param _silos array of Silos addresses for which config will be cloned
/// @param _siloRepository SiloRepository addresses
function migrationFromV1(address[] calldata _silos, ISiloRepository _siloRepository)
external
virtual
onlyOwner
{
IInterestRateModel model;
for (uint256 i; i < _silos.length;) {
address[] memory assets = ISilo(_silos[i]).getAssets();
if (address(model) == address(0)) {
// assumption is that XAI is not first asset otherwise this optimisation will not work
model = _siloRepository.getInterestRateModel(_silos[0], assets[0]);
}
for (uint256 j; j < assets.length;) {
Config memory clonedConfig = IGenericInterestRateModel(address(model)).config(_silos[i], assets[j]);
if (clonedConfig.uopt == 0) {
IInterestRateModel secondModel = _siloRepository.getInterestRateModel(_silos[i], assets[j]);
clonedConfig = IGenericInterestRateModel(address(secondModel)).config(_silos[i], assets[j]);
}
// in order not to clone empty config, check `uopt` - based on requirements it can not be 0
if (clonedConfig.uopt != 0) {
// beta is divided by value of 4 for all configs, except stableLowCap, stableHighCap and bridgeXAI
// With current values of beta parameter, volatile assets will get their interest rate
// (proportional term) multiplied by 2 in one hour. Division of beta coefficient by 4 will result
// in changing time for to double from one hour to four hours, which will make the interest rate
// model behaviour less risky,
// If we will forget about integral term (which will have less impact in first hours of critical
// utilisation), proportional term will grow linear. It will double in first 4 hours,
// triple in 8, x4 in 12, etc.
if (clonedConfig.beta == 277777777777778) {
clonedConfig.beta = 69444444444444;
}
// when we `setConfig()` we call `accrueInterest()`
// we don't have to do it when we cloning, because config will not change
_setConfig(_silos[i], assets[j], clonedConfig);
}
unchecked { j++; }
}
unchecked { i++; }
}
}
/// @inheritdoc IInterestRateModel
function calculateCurrentInterestRate( // solhint-disable-line function-max-lines
Config memory _c,
uint256 _totalDeposits,
uint256 _totalBorrowAmount,
uint256 _interestRateTimestamp,
uint256 _blockTimestamp
) public pure virtual override returns (uint256 rcur) {
if (_interestRateTimestamp > _blockTimestamp) revert InvalidTimestamps();
// struct for local vars to avoid "Stack too deep"
LocalVarsRCur memory _l = LocalVarsRCur(0,0,0,0,0,0,false);
(,,,_l.overflow) = calculateCompoundInterestRateWithOverflowDetection(
_c,
_totalDeposits,
_totalBorrowAmount,
_interestRateTimestamp,
_blockTimestamp
);
if (_l.overflow) {
return 0;
}
// There can't be an underflow in the subtraction because of the previous check
unchecked {
// T := t1 - t0 # length of time period in seconds
_l.T = (_blockTimestamp - _interestRateTimestamp).toInt256();
}
_l.u = EasyMathV2.calculateUtilization(DP, _totalDeposits, _totalBorrowAmount).toInt256();
_l.DP = int256(DP);
if (_l.u > _c.ucrit) {
// rp := kcrit *(1 + Tcrit + beta *T)*( u0 - ucrit )
_l.rp = _c.kcrit * (_l.DP + _c.Tcrit + _c.beta * _l.T) / _l.DP * (_l.u - _c.ucrit) / _l.DP;
} else {
// rp := min (0, klow * (u0 - ulow ))
_l.rp = _min(0, _c.klow * (_l.u - _c.ulow) / _l.DP);
}
// rlin := klin * u0 # lower bound between t0 and t1
_l.rlin = _c.klin * _l.u / _l.DP;
// ri := max(ri , rlin )
_l.ri = _max(_c.ri, _l.rlin);
// ri := max(ri + ki * (u0 - uopt ) * T, rlin )
_l.ri = _max(_l.ri + _c.ki * (_l.u - _c.uopt) * _l.T / _l.DP, _l.rlin);
// rcur := max (ri + rp , rlin ) # current per second interest rate
rcur = (_max(_l.ri + _l.rp, _l.rlin)).toUint256();
rcur *= 365 days;
return _currentInterestRateCAP(rcur);
}
/// @inheritdoc IInterestRateModel
function calculateCompoundInterestRateWithOverflowDetection( // solhint-disable-line function-max-lines
Config memory _c,
uint256 _totalDeposits,
uint256 _totalBorrowAmount,
uint256 _interestRateTimestamp,
uint256 _blockTimestamp
) public pure virtual override returns (
uint256 rcomp,
int256 ri,
int256 Tcrit, // solhint-disable-line var-name-mixedcase
bool overflow
) {
ri = _c.ri;
Tcrit = _c.Tcrit;
// struct for local vars to avoid "Stack too deep"
LocalVarsRComp memory _l = LocalVarsRComp(0,0,0,0,0,0,0,0,0,0);
if (_interestRateTimestamp > _blockTimestamp) revert InvalidTimestamps();
// There can't be an underflow in the subtraction because of the previous check
unchecked {
// length of time period in seconds
_l.T = (_blockTimestamp - _interestRateTimestamp).toInt256();
}
int256 _DP = int256(DP); // solhint-disable-line var-name-mixedcase
_l.u = EasyMathV2.calculateUtilization(DP, _totalDeposits, _totalBorrowAmount).toInt256();
// slopei := ki * (u0 - uopt )
_l.slopei = _c.ki * (_l.u - _c.uopt) / _DP;
if (_l.u > _c.ucrit) {
// rp := kcrit * (1 + Tcrit) * (u0 - ucrit )
_l.rp = _c.kcrit * (_DP + Tcrit) / _DP * (_l.u - _c.ucrit) / _DP;
// slope := slopei + kcrit * beta * (u0 - ucrit )
_l.slope = _l.slopei + _c.kcrit * _c.beta / _DP * (_l.u - _c.ucrit) / _DP;
// Tcrit := Tcrit + beta * T
Tcrit = Tcrit + _c.beta * _l.T;
} else {
// rp := min (0, klow * (u0 - ulow ))
_l.rp = _min(0, _c.klow * (_l.u - _c.ulow) / _DP);
// slope := slopei
_l.slope = _l.slopei;
// Tcrit := max (0, Tcrit - beta * T)
Tcrit = _max(0, Tcrit - _c.beta * _l.T);
}
// rlin := klin * u0 # lower bound between t0 and t1
_l.rlin = _c.klin * _l.u / _DP;
// ri := max(ri , rlin )
ri = _max(ri , _l.rlin);
// r0 := ri + rp # interest rate at t0 ignoring lower bound
_l.r0 = ri + _l.rp;
// r1 := r0 + slope *T # what interest rate would be at t1 ignoring lower bound
_l.r1 = _l.r0 + _l.slope * _l.T;
// Calculating the compound interest
if (_l.r0 >= _l.rlin && _l.r1 >= _l.rlin) {
// lower bound isn’t activated
// rcomp := exp (( r0 + r1) * T / 2) - 1
_l.x = (_l.r0 + _l.r1) * _l.T / 2;
} else if (_l.r0 < _l.rlin && _l.r1 < _l.rlin) {
// lower bound is active during the whole time
// rcomp := exp( rlin * T) - 1
_l.x = _l.rlin * _l.T;
} else if (_l.r0 >= _l.rlin && _l.r1 < _l.rlin) {
// lower bound is active after some time
// rcomp := exp( rlin *T - (r0 - rlin )^2/ slope /2) - 1
_l.x = _l.rlin * _l.T - (_l.r0 - _l.rlin)**2 / _l.slope / 2;
} else {
// lower bound is active before some time
// rcomp := exp( rlin *T + (r1 - rlin )^2/ slope /2) - 1
_l.x = _l.rlin * _l.T + (_l.r1 - _l.rlin)**2 / _l.slope / 2;
}
// ri := max(ri + slopei * T, rlin )
ri = _max(ri + _l.slopei * _l.T, _l.rlin);
// Checking for the overflow below. In case of the overflow, ri and Tcrit will be set back to zeros. Rcomp is
// calculated to not make an overflow in totalBorrowedAmount, totalDeposits.
(rcomp, overflow) = _calculateRComp(_totalDeposits, _totalBorrowAmount, _l.x);
// if we got a limit for rcomp, we reset Tcrit and Ri model parameters to zeros
// Resetting parameters will make IR drop from 10k%/year to 100% per year and it will start growing again.
// If we don’t reset, we will have to wait ~2 weeks to make IR drop (low utilisation ratio required).
// So zeroing parameters is a only hope for a market to get well again, otherwise it will be almost impossible.
bool capApplied;
(rcomp, capApplied) = _compoundInterestRateCAP(rcomp, _l.T.toUint256());
if (overflow || capApplied) {
ri = 0;
Tcrit = 0;
}
}
/// @dev in order to keep methods pure and bee able to deploy easily new caps,
/// that method with hardcoded CAP was created
/// @notice limit for compounding interest rcomp := RCOMP_CAP * _l.T.
/// The limit is simple. Let’s threat our interest rate model as the black box. And for past _l.T time we got
/// a value for rcomp. We need to provide the top limit this value to take into account the limit for current
/// interest. Let’s imagine, if we had maximum allowed interest for _l.T. `RCOMP_CAP * _l.T` will be the value of
/// rcomp in this case, which will serve as the limit.
/// If we got this limit, we should make Tcrit and Ri equal to zero, otherwise there is a low probability of the
/// market going back below the limit.
function _compoundInterestRateCAP(uint256 _rcomp, uint256 _t)
internal
pure
virtual
returns (uint256 updatedRcomp, bool capApplied) {
// uint256 cap = 10**20 / (365 * 24 * 3600); // this is per-second rate because _l.T is in seconds.
uint256 cap = 3170979198376 * _t;
return _rcomp > cap ? (cap, true) : (_rcomp, false);
}
/// @notice limit for rcur - RCUR_CAP (FE/integrations, does not affect our protocol).
/// This is the limit for current interest rate, we picked 10k% of interest per year. Interest rate model is working
/// as expected before that threshold and simply sets the maximum value in case of limit.
/// 10k% is a really significant threshold, which will mean the death of market in most of cases.
/// Before 10k% interest rate can be good for certain market conditions.
/// We don’t read the current interest rate in our protocol, because we care only about the interest we compounded
/// over the past time since the last update. It is used in UI and other protocols integrations,
/// for example investing strategies.
function _currentInterestRateCAP(uint256 _rcur) internal pure virtual returns (uint256) {
uint256 cap = 1e20; // 10**20; this is 10,000% APR in the 18-decimals format.
return _rcur > cap ? cap : _rcur;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)
pragma solidity ^0.8.0;
import "../IERC20.sol";
/**
* @dev Interface for the optional metadata functions from the ERC20 standard.
*
* _Available since v4.1._
*/
interface IERC20Metadata is IERC20 {
/**
* @dev Returns the name of the token.
*/
function name() external view returns (string memory);
/**
* @dev Returns the symbol of the token.
*/
function symbol() external view returns (string memory);
/**
* @dev Returns the decimals places of the token.
*/
function decimals() external view returns (uint8);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/IERC20.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @dev Returns the amount of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the amount of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves `amount` tokens from the caller's account to `recipient`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address recipient, uint256 amount) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 amount) external returns (bool);
/**
* @dev Moves `amount` tokens from `sender` to `recipient` using the
* allowance mechanism. `amount` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(
address sender,
address recipient,
uint256 amount
) external returns (bool);
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/math/Math.sol)
pragma solidity ^0.8.0;
/**
* @dev Standard math utilities missing in the Solidity language.
*/
library Math {
/**
* @dev Returns the largest of two numbers.
*/
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return a >= b ? a : b;
}
/**
* @dev Returns the smallest of two numbers.
*/
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return a < b ? a : b;
}
/**
* @dev Returns the average of two numbers. The result is rounded towards
* zero.
*/
function average(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b) / 2 can overflow.
return (a & b) + (a ^ b) / 2;
}
/**
* @dev Returns the ceiling of the division of two numbers.
*
* This differs from standard division with `/` in that it rounds up instead
* of rounding down.
*/
function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b - 1) / b can overflow on addition, so we distribute.
return a / b + (a % b == 0 ? 0 : 1);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/math/SafeCast.sol)
pragma solidity ^0.8.0;
/**
* @dev Wrappers over Solidity's uintXX/intXX 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.
*
* Can be combined with {SafeMath} and {SignedSafeMath} to extend it to smaller types, by performing
* all math on `uint256` and `int256` and then downcasting.
*/
library SafeCast {
/**
* @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) {
require(value <= type(uint224).max, "SafeCast: value doesn't fit in 224 bits");
return uint224(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) {
require(value <= type(uint128).max, "SafeCast: value doesn't fit in 128 bits");
return uint128(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) {
require(value <= type(uint96).max, "SafeCast: value doesn't fit in 96 bits");
return uint96(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) {
require(value <= type(uint64).max, "SafeCast: value doesn't fit in 64 bits");
return uint64(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) {
require(value <= type(uint32).max, "SafeCast: value doesn't fit in 32 bits");
return uint32(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) {
require(value <= type(uint16).max, "SafeCast: value doesn't fit in 16 bits");
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) {
require(value <= type(uint8).max, "SafeCast: value doesn't fit in 8 bits");
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) {
require(value >= 0, "SafeCast: value must be positive");
return uint256(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
*
* _Available since v3.1._
*/
function toInt128(int256 value) internal pure returns (int128) {
require(value >= type(int128).min && value <= type(int128).max, "SafeCast: value doesn't fit in 128 bits");
return int128(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
*
* _Available since v3.1._
*/
function toInt64(int256 value) internal pure returns (int64) {
require(value >= type(int64).min && value <= type(int64).max, "SafeCast: value doesn't fit in 64 bits");
return int64(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
*
* _Available since v3.1._
*/
function toInt32(int256 value) internal pure returns (int32) {
require(value >= type(int32).min && value <= type(int32).max, "SafeCast: value doesn't fit in 32 bits");
return int32(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
*
* _Available since v3.1._
*/
function toInt16(int256 value) internal pure returns (int16) {
require(value >= type(int16).min && value <= type(int16).max, "SafeCast: value doesn't fit in 16 bits");
return int16(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.
*
* _Available since v3.1._
*/
function toInt8(int256 value) internal pure returns (int8) {
require(value >= type(int8).min && value <= type(int8).max, "SafeCast: value doesn't fit in 8 bits");
return int8(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
require(value <= uint256(type(int256).max), "SafeCast: value doesn't fit in an int256");
return int256(value);
}
}// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.13; import "@openzeppelin/contracts/utils/math/SafeCast.sol"; import "@openzeppelin/contracts/utils/math/Math.sol"; import "./lib/PRBMathSD59x18.sol"; import "./lib/EasyMath.sol"; import "./interfaces/ISilo.sol"; import "./interfaces/IInterestRateModel.sol"; import "./utils/TwoStepOwnable.sol"; /// @title InterestRateModelXAI /// @notice Dynamic interest rate model implementation /// @dev Model stores some Silo specific data. If model is replaced, it needs to set proper config after redeployment /// for seamless service. Please refer to separate litepaper about model for design details. /// Difference between original `InterestRateModel` is that we made methods to be `virtual` and : /// if (_config.ki < 0) revert InvalidKi(); --- was ... <= 0 // if (_config.kcrit < 0) revert InvalidKcrit(); --- was ... <= 0 /// @custom:security-contact [email protected] contract InterestRateModelXAI is IInterestRateModel, TwoStepOwnable { using PRBMathSD59x18 for int256; using SafeCast for int256; using SafeCast for uint256; /// @dev DP is 18 decimal points used for integer calculations uint256 public constant override DP = 1e18; /// @dev maximum value of compound interest the model will return uint256 public constant RCOMP_MAX = (2**16) * 1e18; /// @dev maximum value of X for which, RCOMP_MAX should be returned. If x > X_MAX => exp(x) > RCOMP_MAX. /// X_MAX = ln(RCOMP_MAX + 1) int256 public constant X_MAX = 11090370147631773313; /// @dev maximum allowed amount for accruedInterest, totalDeposits and totalBorrowedAmount /// after adding compounded interest. If rcomp cause this values to overflow, rcomp is reduced. /// 196 bits max allowed for an asset amounts because the multiplication product with /// decimal points (10^18) should not cause an overflow. 196 < log2(2^256 / 10^18) uint256 public constant ASSET_DATA_OVERFLOW_LIMIT = 2**196; // Silo => asset => ModelData mapping(address => mapping(address => Config)) public config; /// @notice Emitted on config change /// @param silo Silo address for which config should be set /// @param asset asset address for which config should be set /// @param config config struct for asset in Silo event ConfigUpdate(address indexed silo, address indexed asset, Config config); error InvalidBeta(); error InvalidKcrit(); error InvalidKi(); error InvalidKlin(); error InvalidKlow(); error InvalidTcrit(); error InvalidTimestamps(); error InvalidUcrit(); error InvalidUlow(); error InvalidUopt(); error InvalidRi(); constructor(Config memory _config) { _setConfig(address(0), address(0), _config); } /// @inheritdoc IInterestRateModel function setConfig(address _silo, address _asset, Config calldata _config) external virtual override onlyOwner { // we do not care, if accrueInterest call will be successful // solhint-disable-next-line avoid-low-level-calls _silo.call(abi.encodeCall(ISilo.accrueInterest, _asset)); _setConfig(_silo, _asset, _config); } /// @inheritdoc IInterestRateModel function getCompoundInterestRateAndUpdate( address _asset, uint256 _blockTimestamp ) external virtual override returns (uint256 rcomp) { // assume that caller is Silo address silo = msg.sender; ISilo.UtilizationData memory data = ISilo(silo).utilizationData(_asset); // TODO when depositing, we doing two calls for `calculateCompoundInterestRate`, maybe we can optimize? Config storage currentConfig = config[silo][_asset]; (rcomp, currentConfig.ri, currentConfig.Tcrit) = calculateCompoundInterestRate( getConfig(silo, _asset), data.totalDeposits, data.totalBorrowAmount, data.interestRateTimestamp, _blockTimestamp ); } /// @inheritdoc IInterestRateModel function getCompoundInterestRate( address _silo, address _asset, uint256 _blockTimestamp ) external view virtual override returns (uint256 rcomp) { ISilo.UtilizationData memory data = ISilo(_silo).utilizationData(_asset); (rcomp,,) = calculateCompoundInterestRate( getConfig(_silo, _asset), data.totalDeposits, data.totalBorrowAmount, data.interestRateTimestamp, _blockTimestamp ); } /// @inheritdoc IInterestRateModel function overflowDetected( address _silo, address _asset, uint256 _blockTimestamp ) external view virtual override returns (bool overflow) { ISilo.UtilizationData memory data = ISilo(_silo).utilizationData(_asset); (,,,overflow) = calculateCompoundInterestRateWithOverflowDetection( getConfig(_silo, _asset), data.totalDeposits, data.totalBorrowAmount, data.interestRateTimestamp, _blockTimestamp ); } /// @inheritdoc IInterestRateModel function getCurrentInterestRate( address _silo, address _asset, uint256 _blockTimestamp ) external view virtual override returns (uint256 rcur) { ISilo.UtilizationData memory data = ISilo(_silo).utilizationData(_asset); rcur = calculateCurrentInterestRate( getConfig(_silo, _asset), data.totalDeposits, data.totalBorrowAmount, data.interestRateTimestamp, _blockTimestamp ); } /// @inheritdoc IInterestRateModel function getConfig(address _silo, address _asset) public view virtual override returns (Config memory) { Config storage currentConfig = config[_silo][_asset]; if (currentConfig.uopt != 0) { return currentConfig; } // use default config Config memory c = config[address(0)][address(0)]; // model data is always stored for each silo and asset so default values must be replaced c.ri = currentConfig.ri; c.Tcrit = currentConfig.Tcrit; return c; } /* solhint-disable */ struct LocalVarsRCur { int256 T; int256 u; int256 DP; int256 rp; int256 rlin; int256 ri; bool overflow; } /// @inheritdoc IInterestRateModel function calculateCurrentInterestRate( Config memory _c, uint256 _totalDeposits, uint256 _totalBorrowAmount, uint256 _interestRateTimestamp, uint256 _blockTimestamp ) public pure virtual override returns (uint256 rcur) { if (_interestRateTimestamp > _blockTimestamp) revert InvalidTimestamps(); // struct for local vars to avoid "Stack too deep" LocalVarsRCur memory _l = LocalVarsRCur(0,0,0,0,0,0,false); (,,,_l.overflow) = calculateCompoundInterestRateWithOverflowDetection( _c, _totalDeposits, _totalBorrowAmount, _interestRateTimestamp, _blockTimestamp ); if (_l.overflow) { return 0; } // There can't be an underflow in the subtraction because of the previous check unchecked { // T := t1 - t0 # length of time period in seconds _l.T = (_blockTimestamp - _interestRateTimestamp).toInt256(); } _l.u = EasyMath.calculateUtilization(DP, _totalDeposits, _totalBorrowAmount).toInt256(); _l.DP = int256(DP); if (_l.u > _c.ucrit) { // rp := kcrit *(1 + Tcrit + beta *T)*( u0 - ucrit ) _l.rp = _c.kcrit * (_l.DP + _c.Tcrit + _c.beta * _l.T) / _l.DP * (_l.u - _c.ucrit) / _l.DP; } else { // rp := min (0, klow * (u0 - ulow )) _l.rp = _min(0, _c.klow * (_l.u - _c.ulow) / _l.DP); } // rlin := klin * u0 # lower bound between t0 and t1 _l.rlin = _c.klin * _l.u / _l.DP; // ri := max(ri , rlin ) _l.ri = _max(_c.ri, _l.rlin); // ri := max(ri + ki * (u0 - uopt ) * T, rlin ) _l.ri = _max(_l.ri + _c.ki * (_l.u - _c.uopt) * _l.T / _l.DP, _l.rlin); // rcur := max (ri + rp , rlin ) # current per second interest rate rcur = (_max(_l.ri + _l.rp, _l.rlin)).toUint256(); rcur *= 365 days; } struct LocalVarsRComp { int256 T; int256 slopei; int256 rp; int256 slope; int256 r0; int256 rlin; int256 r1; int256 x; int256 rlin1; int256 u; } function interestRateModelPing() external pure virtual override returns (bytes4) { return this.interestRateModelPing.selector; } /// @inheritdoc IInterestRateModel function calculateCompoundInterestRate( Config memory _c, uint256 _totalDeposits, uint256 _totalBorrowAmount, uint256 _interestRateTimestamp, uint256 _blockTimestamp ) public pure virtual override returns ( uint256 rcomp, int256 ri, int256 Tcrit ) { (rcomp, ri, Tcrit,) = calculateCompoundInterestRateWithOverflowDetection( _c, _totalDeposits, _totalBorrowAmount, _interestRateTimestamp, _blockTimestamp ); } /// @inheritdoc IInterestRateModel function calculateCompoundInterestRateWithOverflowDetection( Config memory _c, uint256 _totalDeposits, uint256 _totalBorrowAmount, uint256 _interestRateTimestamp, uint256 _blockTimestamp ) public pure virtual override returns ( uint256 rcomp, int256 ri, int256 Tcrit, bool overflow ) { ri = _c.ri; Tcrit = _c.Tcrit; // struct for local vars to avoid "Stack too deep" LocalVarsRComp memory _l = LocalVarsRComp(0,0,0,0,0,0,0,0,0,0); if (_interestRateTimestamp > _blockTimestamp) revert InvalidTimestamps(); // There can't be an underflow in the subtraction because of the previous check unchecked { // length of time period in seconds _l.T = (_blockTimestamp - _interestRateTimestamp).toInt256(); } int256 _DP = int256(DP); _l.u = EasyMath.calculateUtilization(DP, _totalDeposits, _totalBorrowAmount).toInt256(); // slopei := ki * (u0 - uopt ) _l.slopei = _c.ki * (_l.u - _c.uopt) / _DP; if (_l.u > _c.ucrit) { // rp := kcrit * (1 + Tcrit) * (u0 - ucrit ) _l.rp = _c.kcrit * (_DP + Tcrit) / _DP * (_l.u - _c.ucrit) / _DP; // slope := slopei + kcrit * beta * (u0 - ucrit ) _l.slope = _l.slopei + _c.kcrit * _c.beta / _DP * (_l.u - _c.ucrit) / _DP; // Tcrit := Tcrit + beta * T Tcrit = Tcrit + _c.beta * _l.T; } else { // rp := min (0, klow * (u0 - ulow )) _l.rp = _min(0, _c.klow * (_l.u - _c.ulow) / _DP); // slope := slopei _l.slope = _l.slopei; // Tcrit := max (0, Tcrit - beta * T) Tcrit = _max(0, Tcrit - _c.beta * _l.T); } // rlin := klin * u0 # lower bound between t0 and t1 _l.rlin = _c.klin * _l.u / _DP; // ri := max(ri , rlin ) ri = _max(ri , _l.rlin); // r0 := ri + rp # interest rate at t0 ignoring lower bound _l.r0 = ri + _l.rp; // r1 := r0 + slope *T # what interest rate would be at t1 ignoring lower bound _l.r1 = _l.r0 + _l.slope * _l.T; // Calculating the compound interest if (_l.r0 >= _l.rlin && _l.r1 >= _l.rlin) { // lower bound isn’t activated // rcomp := exp (( r0 + r1) * T / 2) - 1 _l.x = (_l.r0 + _l.r1) * _l.T / 2; } else if (_l.r0 < _l.rlin && _l.r1 < _l.rlin) { // lower bound is active during the whole time // rcomp := exp( rlin * T) - 1 _l.x = _l.rlin * _l.T; } else if (_l.r0 >= _l.rlin && _l.r1 < _l.rlin) { // lower bound is active after some time // rcomp := exp( rlin *T - (r0 - rlin )^2/ slope /2) - 1 _l.x = _l.rlin * _l.T - (_l.r0 - _l.rlin)**2 / _l.slope / 2; } else { // lower bound is active before some time // rcomp := exp( rlin *T + (r1 - rlin )^2/ slope /2) - 1 _l.x = _l.rlin * _l.T + (_l.r1 - _l.rlin)**2 / _l.slope / 2; } // ri := max(ri + slopei * T, rlin ) ri = _max(ri + _l.slopei * _l.T, _l.rlin); // Checking for the overflow below. In case of the overflow, ri and Tcrit will be set back to zeros. Rcomp is // calculated to not make an overflow in totalBorrowedAmount, totalDeposits. (rcomp, overflow) = _calculateRComp(_totalDeposits, _totalBorrowAmount, _l.x); if (overflow) { ri = 0; Tcrit = 0; } } /// @dev set config for silo and asset function _setConfig(address _silo, address _asset, Config memory _config) internal virtual { int256 _DP = int256(DP); if (_config.uopt <= 0 || _config.uopt >= _DP) revert InvalidUopt(); if (_config.ucrit <= _config.uopt || _config.ucrit >= _DP) revert InvalidUcrit(); if (_config.ulow <= 0 || _config.ulow >= _config.uopt) revert InvalidUlow(); if (_config.ki < 0) revert InvalidKi(); if (_config.kcrit < 0) revert InvalidKcrit(); if (_config.klow < 0) revert InvalidKlow(); if (_config.klin < 0) revert InvalidKlin(); if (_config.beta < 0) revert InvalidBeta(); if (_config.ri < 0) revert InvalidRi(); if (_config.Tcrit < 0) revert InvalidTcrit(); config[_silo][_asset] = _config; emit ConfigUpdate(_silo, _asset, _config); } /* solhint-enable */ /// @dev checks for the overflow in rcomp calculations, accruedInterest, totalDeposits and totalBorrowedAmount. /// In case of the overflow, rcomp is reduced to make totalDeposits and totalBorrowedAmount <= 2**196. function _calculateRComp( uint256 _totalDeposits, uint256 _totalBorrowAmount, int256 _x ) internal pure virtual returns (uint256 rcomp, bool overflow) { int256 rcompSigned; if (_x >= X_MAX) { rcomp = RCOMP_MAX; // overflow, but not return now. It counts as an overflow to reset model parameters, // but later on we can get overflow worse. overflow = true; } else { rcompSigned = _x.exp() - int256(DP); rcomp = rcompSigned > 0 ? rcompSigned.toUint256() : 0; } unchecked { // maxAmount = max(_totalDeposits, _totalBorrowAmount) to see // if any of this variables overflow in result. uint256 maxAmount = _totalDeposits > _totalBorrowAmount ? _totalDeposits : _totalBorrowAmount; if (maxAmount >= ASSET_DATA_OVERFLOW_LIMIT) { return (0, true); } uint256 rcompMulTBA = rcomp * _totalBorrowAmount; if (rcompMulTBA == 0) { return (rcomp, overflow); } if ( rcompMulTBA / rcomp != _totalBorrowAmount || rcompMulTBA / DP > ASSET_DATA_OVERFLOW_LIMIT - maxAmount ) { rcomp = (ASSET_DATA_OVERFLOW_LIMIT - maxAmount) * DP / _totalBorrowAmount; return (rcomp, true); } } } /// @dev Returns the largest of two numbers function _max(int256 a, int256 b) internal pure virtual returns (int256) { return a > b ? a : b; } /// @dev Returns the smallest of two numbers function _min(int256 a, int256 b) internal pure virtual returns (int256) { return a < b ? a : b; } }
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.13;
import "./IShareToken.sol";
import "./IFlashLiquidationReceiver.sol";
import "./ISiloRepository.sol";
interface IBaseSilo {
enum AssetStatus { Undefined, Active, Removed }
/// @dev Storage struct that holds all required data for a single token market
struct AssetStorage {
/// @dev Token that represents a share in totalDeposits of Silo
IShareToken collateralToken;
/// @dev Token that represents a share in collateralOnlyDeposits of Silo
IShareToken collateralOnlyToken;
/// @dev Token that represents a share in totalBorrowAmount of Silo
IShareToken debtToken;
/// @dev COLLATERAL: Amount of asset token that has been deposited to Silo with interest earned by depositors.
/// It also includes token amount that has been borrowed.
uint256 totalDeposits;
/// @dev COLLATERAL ONLY: Amount of asset token that has been deposited to Silo that can be ONLY used
/// as collateral. These deposits do NOT earn interest and CANNOT be borrowed.
uint256 collateralOnlyDeposits;
/// @dev DEBT: Amount of asset token that has been borrowed with accrued interest.
uint256 totalBorrowAmount;
}
/// @dev Storage struct that holds data related to fees and interest
struct AssetInterestData {
/// @dev Total amount of already harvested protocol fees
uint256 harvestedProtocolFees;
/// @dev Total amount (ever growing) of asset token that has been earned by the protocol from
/// generated interest.
uint256 protocolFees;
/// @dev Timestamp of the last time `interestRate` has been updated in storage.
uint64 interestRateTimestamp;
/// @dev True if asset was removed from the protocol. If so, deposit and borrow functions are disabled
/// for that asset
AssetStatus status;
}
/// @notice data that InterestModel needs for calculations
struct UtilizationData {
uint256 totalDeposits;
uint256 totalBorrowAmount;
/// @dev timestamp of last interest accrual
uint64 interestRateTimestamp;
}
/// @dev Shares names and symbols that are generated while asset initialization
struct AssetSharesMetadata {
/// @dev Name for the collateral shares token
string collateralName;
/// @dev Symbol for the collateral shares token
string collateralSymbol;
/// @dev Name for the collateral only (protected collateral) shares token
string protectedName;
/// @dev Symbol for the collateral only (protected collateral) shares token
string protectedSymbol;
/// @dev Name for the debt shares token
string debtName;
/// @dev Symbol for the debt shares token
string debtSymbol;
}
/// @notice Emitted when deposit is made
/// @param asset asset address that was deposited
/// @param depositor wallet address that deposited asset
/// @param amount amount of asset that was deposited
/// @param collateralOnly type of deposit, true if collateralOnly deposit was used
event Deposit(address indexed asset, address indexed depositor, uint256 amount, bool collateralOnly);
/// @notice Emitted when withdraw is made
/// @param asset asset address that was withdrawn
/// @param depositor wallet address that deposited asset
/// @param receiver wallet address that received asset
/// @param amount amount of asset that was withdrew
/// @param collateralOnly type of withdraw, true if collateralOnly deposit was used
event Withdraw(
address indexed asset,
address indexed depositor,
address indexed receiver,
uint256 amount,
bool collateralOnly
);
/// @notice Emitted on asset borrow
/// @param asset asset address that was borrowed
/// @param user wallet address that borrowed asset
/// @param amount amount of asset that was borrowed
event Borrow(address indexed asset, address indexed user, uint256 amount);
/// @notice Emitted on asset repay
/// @param asset asset address that was repaid
/// @param user wallet address that repaid asset
/// @param amount amount of asset that was repaid
event Repay(address indexed asset, address indexed user, uint256 amount);
/// @notice Emitted on user liquidation
/// @param asset asset address that was liquidated
/// @param user wallet address that was liquidated
/// @param shareAmountRepaid amount of collateral-share token that was repaid. This is collateral token representing
/// ownership of underlying deposit.
/// @param seizedCollateral amount of underlying token that was seized by liquidator
event Liquidate(address indexed asset, address indexed user, uint256 shareAmountRepaid, uint256 seizedCollateral);
/// @notice Emitted when the status for an asset is updated
/// @param asset asset address that was updated
/// @param status new asset status
event AssetStatusUpdate(address indexed asset, AssetStatus indexed status);
/// @return version of the silo contract
function VERSION() external returns (uint128); // solhint-disable-line func-name-mixedcase
/// @notice Synchronize current bridge assets with Silo
/// @dev This function needs to be called on Silo deployment to setup all assets for Silo. It needs to be
/// called every time a bridged asset is added or removed. When bridge asset is removed, depositing and borrowing
/// should be disabled during asset sync.
function syncBridgeAssets() external;
/// @notice Get Silo Repository contract address
/// @return Silo Repository contract address
function siloRepository() external view returns (ISiloRepository);
/// @notice Get asset storage data
/// @param _asset asset address
/// @return AssetStorage struct
function assetStorage(address _asset) external view returns (AssetStorage memory);
/// @notice Get asset interest data
/// @param _asset asset address
/// @return AssetInterestData struct
function interestData(address _asset) external view returns (AssetInterestData memory);
/// @dev helper method for InterestRateModel calculations
function utilizationData(address _asset) external view returns (UtilizationData memory data);
/// @notice Calculates solvency of an account
/// @param _user wallet address for which solvency is calculated
/// @return true if solvent, false otherwise
function isSolvent(address _user) external view returns (bool);
/// @notice Returns all initialized (synced) assets of Silo including current and removed bridge assets
/// @return assets array of initialized assets of Silo
function getAssets() external view returns (address[] memory assets);
/// @notice Returns all initialized (synced) assets of Silo including current and removed bridge assets
/// with corresponding state
/// @return assets array of initialized assets of Silo
/// @return assetsStorage array of assets state corresponding to `assets` array
function getAssetsWithState() external view returns (address[] memory assets, AssetStorage[] memory assetsStorage);
/// @notice Check if depositing an asset for given account is possible
/// @dev Depositing an asset that has been already borrowed (and vice versa) is disallowed
/// @param _asset asset we want to deposit
/// @param _depositor depositor address
/// @return true if asset can be deposited by depositor
function depositPossible(address _asset, address _depositor) external view returns (bool);
/// @notice Check if borrowing an asset for given account is possible
/// @dev Borrowing an asset that has been already deposited (and vice versa) is disallowed
/// @param _asset asset we want to deposit
/// @param _borrower borrower address
/// @return true if asset can be borrowed by borrower
function borrowPossible(address _asset, address _borrower) external view returns (bool);
/// @dev Amount of token that is available for borrowing
/// @param _asset asset to get liquidity for
/// @return Silo liquidity
function liquidity(address _asset) external view returns (uint256);
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.13;
/// @dev when performing Silo flash liquidation, FlashReceiver contract will receive all collaterals
interface IFlashLiquidationReceiver {
/// @dev this method is called when doing Silo flash liquidation
/// one can NOT assume, that if _seizedCollateral[i] != 0, then _shareAmountsToRepaid[i] must be 0
/// one should assume, that any combination of amounts is possible
/// on callback, one must call `Silo.repayFor` because at the end of transaction,
/// Silo will check if borrower is solvent.
/// @param _user user address, that is liquidated
/// @param _assets array of collateral assets received during user liquidation
/// this array contains all assets (collateral borrowed) without any order
/// @param _receivedCollaterals array of collateral amounts received during user liquidation
/// indexes of amounts are related to `_assets`,
/// @param _shareAmountsToRepaid array of amounts to repay for each asset
/// indexes of amounts are related to `_assets`,
/// @param _flashReceiverData data that are passed from sender that executes liquidation
function siloLiquidationCallback(
address _user,
address[] calldata _assets,
uint256[] calldata _receivedCollaterals,
uint256[] calldata _shareAmountsToRepaid,
bytes memory _flashReceiverData
) external;
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.13;
interface IInterestRateModel {
/* solhint-disable */
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
int256 ri;
// Tcrit ≥ 0 - the time during which the utilization exceeds the critical value
int256 Tcrit;
}
/* solhint-enable */
/// @dev Set dedicated config for given asset in a Silo. Config is per asset per Silo so different assets
/// in different Silo can have different configs.
/// It will try to call `_silo.accrueInterest(_asset)` before updating config, but it is not guaranteed,
/// that this call will be successful, if it fail config will be set anyway.
/// @param _silo Silo address for which config should be set
/// @param _asset asset address for which config should be set
function setConfig(address _silo, address _asset, Config calldata _config) external;
/// @dev get compound interest rate and update model storage
/// @param _asset address of an asset in 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 getCompoundInterestRateAndUpdate(
address _asset,
uint256 _blockTimestamp
) external returns (uint256 rcomp);
/// @dev Get config for given asset in a Silo. If dedicated config is not set, default one will be returned.
/// @param _silo Silo address for which config should be set
/// @param _asset asset address for which config should be set
/// @return Config struct for asset in Silo
function getConfig(address _silo, address _asset) external view returns (Config memory);
/// @dev get compound interest rate
/// @param _silo address of Silo
/// @param _asset address of an asset in 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,
address _asset,
uint256 _blockTimestamp
) external view returns (uint256 rcomp);
/// @dev get current annual interest rate
/// @param _silo address of Silo
/// @param _asset address of an asset in 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,
address _asset,
uint256 _blockTimestamp
) external view returns (uint256 rcur);
/// @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,
address _asset,
uint256 _blockTimestamp
) external view returns (bool overflow);
/// @dev pure function that calculates current annual interest rate
/// @param _c configuration object, InterestRateModel.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 memory _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, InterestRateModel.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, // solhint-disable-line var-name-mixedcase
bool overflow
);
/// @dev pure function that calculates interest rate based on raw input data
/// @param _c configuration object, InterestRateModel.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 // solhint-disable-line var-name-mixedcase
);
/// @dev returns decimal points used by model
function DP() external pure returns (uint256); // solhint-disable-line func-name-mixedcase
/// @dev just a helper method to see if address is a InterestRateModel
/// @return always true
function interestRateModelPing() external pure returns (bytes4);
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.13;
/// @title Common interface for Silo Incentive Contract
interface INotificationReceiver {
/// @dev Informs the contract about token transfer
/// @param _token address of the token that was transferred
/// @param _from sender
/// @param _to receiver
/// @param _amount amount that was transferred
function onAfterTransfer(address _token, address _from, address _to, uint256 _amount) external;
/// @dev Sanity check function
/// @return always true
function notificationReceiverPing() external pure returns (bytes4);
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity >=0.7.6 <0.9.0;
/// @title Common interface for Silo Price Providers
interface IPriceProvider {
/// @notice Returns "Time-Weighted Average Price" for an asset. Calculates TWAP price for quote/asset.
/// It unifies all tokens decimal to 18, examples:
/// - if asses == quote it returns 1e18
/// - if asset is USDC and quote is ETH and ETH costs ~$3300 then it returns ~0.0003e18 WETH per 1 USDC
/// @param _asset address of an asset for which to read price
/// @return price of asses with 18 decimals, throws when pool is not ready yet to provide price
function getPrice(address _asset) external view returns (uint256 price);
/// @dev Informs if PriceProvider is setup for asset. It does not means PriceProvider can provide price right away.
/// Some providers implementations need time to "build" buffer for TWAP price,
/// so price may not be available yet but this method will return true.
/// @param _asset asset in question
/// @return TRUE if asset has been setup, otherwise false
function assetSupported(address _asset) external view returns (bool);
/// @notice Gets token address in which prices are quoted
/// @return quoteToken address
function quoteToken() external view returns (address);
/// @notice Helper method that allows easily detects, if contract is PriceProvider
/// @dev this can save us from simple human errors, in case we use invalid address
/// but this should NOT be treated as security check
/// @return always true
function priceProviderPing() external pure returns (bytes4);
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity >=0.7.6 <0.9.0;
import "./IPriceProvider.sol";
interface IPriceProvidersRepository {
/// @notice Emitted when price provider is added
/// @param newPriceProvider new price provider address
event NewPriceProvider(IPriceProvider indexed newPriceProvider);
/// @notice Emitted when price provider is removed
/// @param priceProvider removed price provider address
event PriceProviderRemoved(IPriceProvider indexed priceProvider);
/// @notice Emitted when asset is assigned to price provider
/// @param asset assigned asset address
/// @param priceProvider price provider address
event PriceProviderForAsset(address indexed asset, IPriceProvider indexed priceProvider);
/// @notice Register new price provider
/// @param _priceProvider address of price provider
function addPriceProvider(IPriceProvider _priceProvider) external;
/// @notice Unregister price provider
/// @param _priceProvider address of price provider to be removed
function removePriceProvider(IPriceProvider _priceProvider) external;
/// @notice Sets price provider for asset
/// @dev Request for asset price is forwarded to the price provider assigned to that asset
/// @param _asset address of an asset for which price provider will be used
/// @param _priceProvider address of price provider
function setPriceProviderForAsset(address _asset, IPriceProvider _priceProvider) external;
/// @notice Returns "Time-Weighted Average Price" for an asset
/// @param _asset address of an asset for which to read price
/// @return price TWAP price of a token with 18 decimals
function getPrice(address _asset) external view returns (uint256 price);
/// @notice Gets price provider assigned to an asset
/// @param _asset address of an asset for which to get price provider
/// @return priceProvider address of price provider
function priceProviders(address _asset) external view returns (IPriceProvider priceProvider);
/// @notice Gets token address in which prices are quoted
/// @return quoteToken address
function quoteToken() external view returns (address);
/// @notice Gets manager role address
/// @return manager role address
function manager() external view returns (address);
/// @notice Checks if providers are available for an asset
/// @param _asset asset address to check
/// @return returns TRUE if price feed is ready, otherwise false
function providersReadyForAsset(address _asset) external view returns (bool);
/// @notice Returns true if address is a registered price provider
/// @param _provider address of price provider to be removed
/// @return true if address is a registered price provider, otherwise false
function isPriceProvider(IPriceProvider _provider) external view returns (bool);
/// @notice Gets number of price providers registered
/// @return number of price providers registered
function providersCount() external view returns (uint256);
/// @notice Gets an array of price providers
/// @return array of price providers
function providerList() external view returns (address[] memory);
/// @notice Sanity check function
/// @return returns always TRUE
function priceProvidersRepositoryPing() external pure returns (bytes4);
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.13;
import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import "./INotificationReceiver.sol";
interface IShareToken is IERC20Metadata {
/// @notice Emitted every time receiver is notified about token transfer
/// @param notificationReceiver receiver address
/// @param success false if TX reverted on `notificationReceiver` side, otherwise true
event NotificationSent(
INotificationReceiver indexed notificationReceiver,
bool success
);
/// @notice Mint method for Silo to create debt position
/// @param _account wallet for which to mint token
/// @param _amount amount of token to be minted
function mint(address _account, uint256 _amount) external;
/// @notice Burn method for Silo to close debt position
/// @param _account wallet for which to burn token
/// @param _amount amount of token to be burned
function burn(address _account, uint256 _amount) external;
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.13;
import "./IBaseSilo.sol";
interface ISilo is IBaseSilo {
/// @notice Deposit `_amount` of `_asset` tokens from `msg.sender` to the Silo
/// @param _asset The address of the token to deposit
/// @param _amount The amount of the token to deposit
/// @param _collateralOnly True if depositing collateral only
/// @return collateralAmount deposited amount
/// @return collateralShare user collateral shares based on deposited amount
function deposit(address _asset, uint256 _amount, bool _collateralOnly)
external
returns (uint256 collateralAmount, uint256 collateralShare);
/// @notice Router function to deposit `_amount` of `_asset` tokens to the Silo for the `_depositor`
/// @param _asset The address of the token to deposit
/// @param _depositor The address of the recipient of collateral tokens
/// @param _amount The amount of the token to deposit
/// @param _collateralOnly True if depositing collateral only
/// @return collateralAmount deposited amount
/// @return collateralShare `_depositor` collateral shares based on deposited amount
function depositFor(address _asset, address _depositor, uint256 _amount, bool _collateralOnly)
external
returns (uint256 collateralAmount, uint256 collateralShare);
/// @notice Withdraw `_amount` of `_asset` tokens from the Silo to `msg.sender`
/// @param _asset The address of the token to withdraw
/// @param _amount The amount of the token to withdraw
/// @param _collateralOnly True if withdrawing collateral only deposit
/// @return withdrawnAmount withdrawn amount that was transferred to user
/// @return withdrawnShare burned share based on `withdrawnAmount`
function withdraw(address _asset, uint256 _amount, bool _collateralOnly)
external
returns (uint256 withdrawnAmount, uint256 withdrawnShare);
/// @notice Router function to withdraw `_amount` of `_asset` tokens from the Silo for the `_depositor`
/// @param _asset The address of the token to withdraw
/// @param _depositor The address that originally deposited the collateral tokens being withdrawn,
/// it should be the one initiating the withdrawal through the router
/// @param _receiver The address that will receive the withdrawn tokens
/// @param _amount The amount of the token to withdraw
/// @param _collateralOnly True if withdrawing collateral only deposit
/// @return withdrawnAmount withdrawn amount that was transferred to `_receiver`
/// @return withdrawnShare burned share based on `withdrawnAmount`
function withdrawFor(
address _asset,
address _depositor,
address _receiver,
uint256 _amount,
bool _collateralOnly
) external returns (uint256 withdrawnAmount, uint256 withdrawnShare);
/// @notice Borrow `_amount` of `_asset` tokens from the Silo to `msg.sender`
/// @param _asset The address of the token to borrow
/// @param _amount The amount of the token to borrow
/// @return debtAmount borrowed amount
/// @return debtShare user debt share based on borrowed amount
function borrow(address _asset, uint256 _amount) external returns (uint256 debtAmount, uint256 debtShare);
/// @notice Router function to borrow `_amount` of `_asset` tokens from the Silo for the `_receiver`
/// @param _asset The address of the token to borrow
/// @param _borrower The address that will take the loan,
/// it should be the one initiating the borrowing through the router
/// @param _receiver The address of the asset receiver
/// @param _amount The amount of the token to borrow
/// @return debtAmount borrowed amount
/// @return debtShare `_receiver` debt share based on borrowed amount
function borrowFor(address _asset, address _borrower, address _receiver, uint256 _amount)
external
returns (uint256 debtAmount, uint256 debtShare);
/// @notice Repay `_amount` of `_asset` tokens from `msg.sender` to the Silo
/// @param _asset The address of the token to repay
/// @param _amount amount of asset to repay, includes interests
/// @return repaidAmount amount repaid
/// @return burnedShare burned debt share
function repay(address _asset, uint256 _amount) external returns (uint256 repaidAmount, uint256 burnedShare);
/// @notice Allows to repay in behalf of borrower to execute liquidation
/// @param _asset The address of the token to repay
/// @param _borrower The address of the user to have debt tokens burned
/// @param _amount amount of asset to repay, includes interests
/// @return repaidAmount amount repaid
/// @return burnedShare burned debt share
function repayFor(address _asset, address _borrower, uint256 _amount)
external
returns (uint256 repaidAmount, uint256 burnedShare);
/// @dev harvest protocol fees from an array of assets
/// @return harvestedAmounts amount harvested during tx execution for each of silo asset
function harvestProtocolFees() external returns (uint256[] memory harvestedAmounts);
/// @notice Function to update interests for `_asset` token since the last saved state
/// @param _asset The address of the token to be updated
/// @return interest accrued interest
function accrueInterest(address _asset) external returns (uint256 interest);
/// @notice this methods does not requires to have tokens in order to liquidate user
/// @dev during liquidation process, msg.sender will be notified once all collateral will be send to him
/// msg.sender needs to be `IFlashLiquidationReceiver`
/// @param _users array of users to liquidate
/// @param _flashReceiverData this data will be forward to msg.sender on notification
/// @return assets array of all processed assets (collateral + debt, including removed)
/// @return receivedCollaterals receivedCollaterals[userId][assetId] => amount
/// amounts of collaterals send to `_flashReceiver`
/// @return shareAmountsToRepaid shareAmountsToRepaid[userId][assetId] => amount
/// required amounts of debt to be repaid
function flashLiquidate(address[] memory _users, bytes memory _flashReceiverData)
external
returns (
address[] memory assets,
uint256[][] memory receivedCollaterals,
uint256[][] memory shareAmountsToRepaid
);
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.13;
interface ISiloFactory {
/// @notice Emitted when Silo is deployed
/// @param silo address of deployed Silo
/// @param asset address of asset for which Silo was deployed
/// @param version version of silo implementation
event NewSiloCreated(address indexed silo, address indexed asset, uint128 version);
/// @notice Must be called by repository on constructor
/// @param _siloRepository the SiloRepository to set
function initRepository(address _siloRepository) external;
/// @notice Deploys Silo
/// @param _siloAsset unique asset for which Silo is deployed
/// @param _version version of silo implementation
/// @param _data (optional) data that may be needed during silo creation
/// @return silo deployed Silo address
function createSilo(address _siloAsset, uint128 _version, bytes memory _data) external returns (address silo);
/// @dev just a helper method to see if address is a factory
function siloFactoryPing() external pure returns (bytes4);
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.13;
import "./ISiloFactory.sol";
import "./ITokensFactory.sol";
import "./IPriceProvidersRepository.sol";
import "./INotificationReceiver.sol";
import "./IInterestRateModel.sol";
interface ISiloRepository {
/// @dev protocol fees in precision points (Solvency._PRECISION_DECIMALS), we do allow for fee == 0
struct Fees {
/// @dev One time protocol fee for opening a borrow position in precision points (Solvency._PRECISION_DECIMALS)
uint64 entryFee;
/// @dev Protocol revenue share in interest paid in precision points (Solvency._PRECISION_DECIMALS)
uint64 protocolShareFee;
/// @dev Protocol share in liquidation profit in precision points (Solvency._PRECISION_DECIMALS).
/// It's calculated from total collateral amount to be transferred to liquidator.
uint64 protocolLiquidationFee;
}
struct SiloVersion {
/// @dev Default version of Silo. If set to 0, it means it is not set. By default it is set to 1
uint128 byDefault;
/// @dev Latest added version of Silo. If set to 0, it means it is not set. By default it is set to 1
uint128 latest;
}
/// @dev AssetConfig struct represents configurable parameters for each Silo
struct AssetConfig {
/// @dev Loan-to-Value ratio represents the maximum borrowing power of a specific collateral.
/// For example, if the collateral asset has an LTV of 75%, the user can borrow up to 0.75 worth
/// of quote token in the principal currency for every quote token worth of collateral.
/// value uses 18 decimals eg. 100% == 1e18
/// max valid value is 1e18 so it needs storage of 60 bits
uint64 maxLoanToValue;
/// @dev Liquidation Threshold represents the threshold at which a borrow position will be considered
/// undercollateralized and subject to liquidation for each collateral. For example,
/// if a collateral has a liquidation threshold of 80%, it means that the loan will be
/// liquidated when the borrowAmount value is worth 80% of the collateral value.
/// value uses 18 decimals eg. 100% == 1e18
uint64 liquidationThreshold;
/// @dev interest rate model address
IInterestRateModel interestRateModel;
}
event NewDefaultMaximumLTV(uint64 defaultMaximumLTV);
event NewDefaultLiquidationThreshold(uint64 defaultLiquidationThreshold);
/// @notice Emitted on new Silo creation
/// @param silo deployed Silo address
/// @param asset unique asset for deployed Silo
/// @param siloVersion version of deployed Silo
event NewSilo(address indexed silo, address indexed asset, uint128 siloVersion);
/// @notice Emitted when new Silo (or existing one) becomes a bridge pool (pool with only bridge tokens).
/// @param pool address of the bridge pool, It can be zero address when bridge asset is removed and pool no longer
/// is treated as bridge pool
event BridgePool(address indexed pool);
/// @notice Emitted on new bridge asset
/// @param newBridgeAsset address of added bridge asset
event BridgeAssetAdded(address indexed newBridgeAsset);
/// @notice Emitted on removed bridge asset
/// @param bridgeAssetRemoved address of removed bridge asset
event BridgeAssetRemoved(address indexed bridgeAssetRemoved);
/// @notice Emitted when default interest rate model is changed
/// @param newModel address of new interest rate model
event InterestRateModel(IInterestRateModel indexed newModel);
/// @notice Emitted on price provider repository address update
/// @param newProvider address of new oracle repository
event PriceProvidersRepositoryUpdate(
IPriceProvidersRepository indexed newProvider
);
/// @notice Emitted on token factory address update
/// @param newTokensFactory address of new token factory
event TokensFactoryUpdate(address indexed newTokensFactory);
/// @notice Emitted on router address update
/// @param newRouter address of new router
event RouterUpdate(address indexed newRouter);
/// @notice Emitted on INotificationReceiver address update
/// @param newIncentiveContract address of new INotificationReceiver
event NotificationReceiverUpdate(INotificationReceiver indexed newIncentiveContract);
/// @notice Emitted when new Silo version is registered
/// @param factory factory address that deploys registered Silo version
/// @param siloLatestVersion Silo version of registered Silo
/// @param siloDefaultVersion current default Silo version
event RegisterSiloVersion(address indexed factory, uint128 siloLatestVersion, uint128 siloDefaultVersion);
/// @notice Emitted when Silo version is unregistered
/// @param factory factory address that deploys unregistered Silo version
/// @param siloVersion version that was unregistered
event UnregisterSiloVersion(address indexed factory, uint128 siloVersion);
/// @notice Emitted when default Silo version is updated
/// @param newDefaultVersion new default version
event SiloDefaultVersion(uint128 newDefaultVersion);
/// @notice Emitted when default fee is updated
/// @param newEntryFee new entry fee
/// @param newProtocolShareFee new protocol share fee
/// @param newProtocolLiquidationFee new protocol liquidation fee
event FeeUpdate(
uint64 newEntryFee,
uint64 newProtocolShareFee,
uint64 newProtocolLiquidationFee
);
/// @notice Emitted when asset config is updated for a silo
/// @param silo silo for which asset config is being set
/// @param asset asset for which asset config is being set
/// @param assetConfig new asset config
event AssetConfigUpdate(address indexed silo, address indexed asset, AssetConfig assetConfig);
/// @notice Emitted when silo (silo factory) version is set for asset
/// @param asset asset for which asset config is being set
/// @param version Silo version
event VersionForAsset(address indexed asset, uint128 version);
/// @param _siloAsset silo asset
/// @return version of Silo that is assigned for provided asset, if not assigned it returns zero (default)
function getVersionForAsset(address _siloAsset) external returns (uint128);
/// @notice setter for `getVersionForAsset` mapping
/// @param _siloAsset silo asset
/// @param _version version of Silo that will be assigned for `_siloAsset`, zero (default) is acceptable
function setVersionForAsset(address _siloAsset, uint128 _version) external;
/// @notice use this method only when off-chain verification is OFF
/// @dev Silo does NOT support rebase and deflationary tokens
/// @param _siloAsset silo asset
/// @param _siloData (optional) data that may be needed during silo creation
/// @return createdSilo address of created silo
function newSilo(address _siloAsset, bytes memory _siloData) external returns (address createdSilo);
/// @notice use this method to deploy new version of Silo for an asset that already has Silo deployed.
/// Only owner (DAO) can replace.
/// @dev Silo does NOT support rebase and deflationary tokens
/// @param _siloAsset silo asset
/// @param _siloVersion version of silo implementation. Use 0 for default version which is fine
/// for 99% of cases.
/// @param _siloData (optional) data that may be needed during silo creation
/// @return createdSilo address of created silo
function replaceSilo(
address _siloAsset,
uint128 _siloVersion,
bytes memory _siloData
) external returns (address createdSilo);
/// @notice Set factory contract for debt and collateral tokens for each Silo asset
/// @dev Callable only by owner
/// @param _tokensFactory address of TokensFactory contract that deploys debt and collateral tokens
function setTokensFactory(address _tokensFactory) external;
/// @notice Set default fees
/// @dev Callable only by owner
/// @param _fees:
/// - _entryFee one time protocol fee for opening a borrow position in precision points
/// (Solvency._PRECISION_DECIMALS)
/// - _protocolShareFee protocol revenue share in interest paid in precision points
/// (Solvency._PRECISION_DECIMALS)
/// - _protocolLiquidationFee protocol share in liquidation profit in precision points
/// (Solvency._PRECISION_DECIMALS). It's calculated from total collateral amount to be transferred
/// to liquidator.
function setFees(Fees calldata _fees) external;
/// @notice Set configuration for given asset in given Silo
/// @dev Callable only by owner
/// @param _silo Silo address for which config applies
/// @param _asset asset address for which config applies
/// @param _assetConfig:
/// - _maxLoanToValue maximum Loan-to-Value, for details see `Repository.AssetConfig.maxLoanToValue`
/// - _liquidationThreshold liquidation threshold, for details see `Repository.AssetConfig.maxLoanToValue`
/// - _interestRateModel interest rate model address, for details see `Repository.AssetConfig.interestRateModel`
function setAssetConfig(
address _silo,
address _asset,
AssetConfig calldata _assetConfig
) external;
/// @notice Set default interest rate model
/// @dev Callable only by owner
/// @param _defaultInterestRateModel default interest rate model
function setDefaultInterestRateModel(IInterestRateModel _defaultInterestRateModel) external;
/// @notice Set default maximum LTV
/// @dev Callable only by owner
/// @param _defaultMaxLTV default maximum LTV in precision points (Solvency._PRECISION_DECIMALS)
function setDefaultMaximumLTV(uint64 _defaultMaxLTV) external;
/// @notice Set default liquidation threshold
/// @dev Callable only by owner
/// @param _defaultLiquidationThreshold default liquidation threshold in precision points
/// (Solvency._PRECISION_DECIMALS)
function setDefaultLiquidationThreshold(uint64 _defaultLiquidationThreshold) external;
/// @notice Set price provider repository
/// @dev Callable only by owner
/// @param _repository price provider repository address
function setPriceProvidersRepository(IPriceProvidersRepository _repository) external;
/// @notice Set router contract
/// @dev Callable only by owner
/// @param _router router address
function setRouter(address _router) external;
/// @notice Set NotificationReceiver contract
/// @dev Callable only by owner
/// @param _silo silo address for which to set `_notificationReceiver`
/// @param _notificationReceiver NotificationReceiver address
function setNotificationReceiver(address _silo, INotificationReceiver _notificationReceiver) external;
/// @notice Adds new bridge asset
/// @dev New bridge asset must be unique. Duplicates in bridge assets are not allowed. It's possible to add
/// bridge asset that has been removed in the past. Note that all Silos must be synced manually. Callable
/// only by owner.
/// @param _newBridgeAsset bridge asset address
function addBridgeAsset(address _newBridgeAsset) external;
/// @notice Removes bridge asset
/// @dev Note that all Silos must be synced manually. Callable only by owner.
/// @param _bridgeAssetToRemove bridge asset address to be removed
function removeBridgeAsset(address _bridgeAssetToRemove) external;
/// @notice Registers new Silo version
/// @dev User can choose which Silo version he wants to deploy. It's possible to have multiple versions of Silo.
/// Callable only by owner.
/// @param _factory factory contract that deploys new version of Silo
/// @param _isDefault true if this version should be used as default
function registerSiloVersion(ISiloFactory _factory, bool _isDefault) external;
/// @notice Unregisters Silo version
/// @dev Callable only by owner.
/// @param _siloVersion Silo version to be unregistered
function unregisterSiloVersion(uint128 _siloVersion) external;
/// @notice Sets default Silo version
/// @dev Callable only by owner.
/// @param _defaultVersion Silo version to be set as default
function setDefaultSiloVersion(uint128 _defaultVersion) external;
/// @notice Check if contract address is a Silo deployment
/// @param _silo address of expected Silo
/// @return true if address is Silo deployment, otherwise false
function isSilo(address _silo) external view returns (bool);
/// @notice Get Silo address of asset
/// @param _asset address of asset
/// @return address of corresponding Silo deployment
function getSilo(address _asset) external view returns (address);
/// @notice Get Silo Factory for given version
/// @param _siloVersion version of Silo implementation
/// @return ISiloFactory contract that deploys Silos of given version
function siloFactory(uint256 _siloVersion) external view returns (ISiloFactory);
/// @notice Get debt and collateral Token Factory
/// @return ITokensFactory contract that deploys debt and collateral tokens
function tokensFactory() external view returns (ITokensFactory);
/// @notice Get Router contract
/// @return address of router contract
function router() external view returns (address);
/// @notice Get current bridge assets
/// @dev Keep in mind that not all Silos may be synced with current bridge assets so it's possible that some
/// assets in that list are not part of given Silo.
/// @return address array of bridge assets
function getBridgeAssets() external view returns (address[] memory);
/// @notice Get removed bridge assets
/// @dev Keep in mind that not all Silos may be synced with bridge assets so it's possible that some
/// assets in that list are still part of given Silo.
/// @return address array of bridge assets
function getRemovedBridgeAssets() external view returns (address[] memory);
/// @notice Get maximum LTV for asset in given Silo
/// @dev If dedicated config is not set, method returns default config
/// @param _silo address of Silo
/// @param _asset address of an asset
/// @return maximum LTV in precision points (Solvency._PRECISION_DECIMALS)
function getMaximumLTV(address _silo, address _asset) external view returns (uint256);
/// @notice Get Interest Rate Model address for asset in given Silo
/// @dev If dedicated config is not set, method returns default config
/// @param _silo address of Silo
/// @param _asset address of an asset
/// @return address of interest rate model
function getInterestRateModel(address _silo, address _asset) external view returns (IInterestRateModel);
/// @notice Get liquidation threshold for asset in given Silo
/// @dev If dedicated config is not set, method returns default config
/// @param _silo address of Silo
/// @param _asset address of an asset
/// @return liquidation threshold in precision points (Solvency._PRECISION_DECIMALS)
function getLiquidationThreshold(address _silo, address _asset) external view returns (uint256);
/// @notice Get incentive contract address. Incentive contracts are responsible for distributing rewards
/// to debt and/or collateral token holders of given Silo
/// @param _silo address of Silo
/// @return incentive contract address
function getNotificationReceiver(address _silo) external view returns (INotificationReceiver);
/// @notice Get owner role address of Repository
/// @return owner role address
function owner() external view returns (address);
/// @notice get PriceProvidersRepository contract that manages price providers implementations
/// @return IPriceProvidersRepository address
function priceProvidersRepository() external view returns (IPriceProvidersRepository);
/// @dev Get protocol fee for opening a borrow position
/// @return fee in precision points (Solvency._PRECISION_DECIMALS == 100%)
function entryFee() external view returns (uint256);
/// @dev Get protocol share fee
/// @return protocol share fee in precision points (Solvency._PRECISION_DECIMALS == 100%)
function protocolShareFee() external view returns (uint256);
/// @dev Get protocol liquidation fee
/// @return protocol liquidation fee in precision points (Solvency._PRECISION_DECIMALS == 100%)
function protocolLiquidationFee() external view returns (uint256);
/// @dev Checks all conditions for new silo creation and throws when not possible to create
/// @param _asset address of asset for which you want to create silo
/// @param _assetIsABridge bool TRUE when `_asset` is bridge asset, FALSE when it is not
function ensureCanCreateSiloFor(address _asset, bool _assetIsABridge) external view;
function siloRepositoryPing() external pure returns (bytes4);
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.13;
import "./IShareToken.sol";
interface ITokensFactory {
/// @notice Emitted when collateral token is deployed
/// @param token address of deployed collateral token
event NewShareCollateralTokenCreated(address indexed token);
/// @notice Emitted when collateral token is deployed
/// @param token address of deployed debt token
event NewShareDebtTokenCreated(address indexed token);
///@notice Must be called by repository on constructor
/// @param _siloRepository the SiloRepository to set
function initRepository(address _siloRepository) external;
/// @notice Deploys collateral token
/// @param _name name of the token
/// @param _symbol symbol of the token
/// @param _asset underlying asset for which token is deployed
/// @return address of deployed collateral share token
function createShareCollateralToken(
string memory _name,
string memory _symbol,
address _asset
) external returns (IShareToken);
/// @notice Deploys debt token
/// @param _name name of the token
/// @param _symbol symbol of the token
/// @param _asset underlying asset for which token is deployed
/// @return address of deployed debt share token
function createShareDebtToken(
string memory _name,
string memory _symbol,
address _asset
)
external
returns (IShareToken);
/// @dev just a helper method to see if address is a factory
/// @return always true
function tokensFactoryPing() external pure returns (bytes4);
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.13;
library EasyMath {
error ZeroAssets();
error ZeroShares();
function toShare(uint256 amount, uint256 totalAmount, uint256 totalShares) internal pure returns (uint256) {
if (totalShares == 0 || totalAmount == 0) {
return amount;
}
uint256 result = amount * totalShares / totalAmount;
// Prevent rounding error
if (result == 0 && amount != 0) {
revert ZeroShares();
}
return result;
}
function toShareRoundUp(uint256 amount, uint256 totalAmount, uint256 totalShares) internal pure returns (uint256) {
if (totalShares == 0 || totalAmount == 0) {
return amount;
}
uint256 numerator = amount * totalShares;
uint256 result = numerator / totalAmount;
// Round up
if (numerator % totalAmount != 0) {
result += 1;
}
return result;
}
function toAmount(uint256 share, uint256 totalAmount, uint256 totalShares) internal pure returns (uint256) {
if (totalShares == 0 || totalAmount == 0) {
return 0;
}
uint256 result = share * totalAmount / totalShares;
// Prevent rounding error
if (result == 0 && share != 0) {
revert ZeroAssets();
}
return result;
}
function toAmountRoundUp(uint256 share, uint256 totalAmount, uint256 totalShares) internal pure returns (uint256) {
if (totalShares == 0 || totalAmount == 0) {
return 0;
}
uint256 numerator = share * totalAmount;
uint256 result = numerator / totalShares;
// Round up
if (numerator % totalShares != 0) {
result += 1;
}
return result;
}
function toValue(uint256 _assetAmount, uint256 _assetPrice, uint256 _assetDecimals)
internal
pure
returns (uint256)
{
return _assetAmount * _assetPrice / 10 ** _assetDecimals;
}
function sum(uint256[] memory _numbers) internal pure returns (uint256 s) {
for(uint256 i; i < _numbers.length; i++) {
s += _numbers[i];
}
}
/// @notice Calculates fraction between borrowed and deposited amount of tokens denominated in percentage
/// @dev It assumes `_dp` = 100%.
/// @param _dp decimal points used by model
/// @param _totalDeposits current total deposits for assets
/// @param _totalBorrowAmount current total borrows for assets
/// @return utilization value
function calculateUtilization(uint256 _dp, uint256 _totalDeposits, uint256 _totalBorrowAmount)
internal
pure
returns (uint256)
{
if (_totalDeposits == 0 || _totalBorrowAmount == 0) return 0;
return _totalBorrowAmount * _dp / _totalDeposits;
}
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.13;
/// @dev EasyMathV2 is optimised version of EasyMath, many places was `unchecked` for lower gas cost.
/// There is also fixed version of `calculateUtilization()` method.
library EasyMathV2 {
error ZeroAssets();
error ZeroShares();
function toShare(uint256 amount, uint256 totalAmount, uint256 totalShares)
internal
pure
returns (uint256 result)
{
if (totalShares == 0 || totalAmount == 0) {
return amount;
}
result = amount * totalShares;
// totalAmount is never 0 based on above check, so we can uncheck
unchecked { result /= totalAmount; }
// Prevent rounding error
if (result == 0 && amount != 0) {
revert ZeroShares();
}
}
function toShareRoundUp(uint256 amount, uint256 totalAmount, uint256 totalShares)
internal
pure
returns (uint256 result)
{
if (totalShares == 0 || totalAmount == 0) {
return amount;
}
uint256 numerator = amount * totalShares;
// totalAmount is not 0, so it is safe to uncheck
unchecked { result = numerator / totalAmount; }
// Round up
if (numerator % totalAmount != 0) {
unchecked { result += 1; }
}
}
function toAmount(uint256 share, uint256 totalAmount, uint256 totalShares)
internal
pure
returns (uint256 result)
{
if (totalShares == 0 || totalAmount == 0) {
return 0;
}
result = share * totalAmount;
// totalShares are not 0, so we can uncheck
unchecked { result /= totalShares; }
// Prevent rounding error
if (result == 0 && share != 0) {
revert ZeroAssets();
}
}
function toAmountRoundUp(uint256 share, uint256 totalAmount, uint256 totalShares)
internal
pure
returns (uint256 result)
{
if (totalShares == 0 || totalAmount == 0) {
return 0;
}
uint256 numerator = share * totalAmount;
// totalShares are not 0, based on above check, so we can uncheck
unchecked { result = numerator / totalShares; }
// Round up
if (numerator % totalShares != 0) {
unchecked { result += 1; }
}
}
function toValue(uint256 _assetAmount, uint256 _assetPrice, uint256 _assetDecimals)
internal
pure
returns (uint256 value)
{
value = _assetAmount * _assetPrice;
// power of 10 can not be 0, so we can uncheck
unchecked { value /= 10 ** _assetDecimals; }
}
function sum(uint256[] memory _numbers) internal pure returns (uint256 s) {
for(uint256 i; i < _numbers.length;) {
s += _numbers[i];
unchecked { i++; }
}
}
/// @notice Calculates fraction between borrowed and deposited amount of tokens denominated in percentage
/// @dev It assumes `_dp` = 100%.
/// @param _dp decimal points used by model
/// @param _totalDeposits current total deposits for assets
/// @param _totalBorrowAmount current total borrows for assets
/// @return utilization value, capped to 100%
/// Limiting utilisation ratio by 100% max will allows us to perform better interest rate computations
/// and should not affect any other part of protocol.
function calculateUtilization(uint256 _dp, uint256 _totalDeposits, uint256 _totalBorrowAmount)
internal
pure
returns (uint256 utilization)
{
if (_totalDeposits == 0 || _totalBorrowAmount == 0) return 0;
utilization = _totalBorrowAmount * _dp;
// _totalDeposits is not 0 based on above check, so it is safe to uncheck this division
unchecked { utilization /= _totalDeposits; }
// cap at 100%
if (utilization > _dp) utilization = _dp;
}
}// SPDX-License-Identifier: Unlicense
pragma solidity 0.8.13;
/* solhint-disable */
/// @dev Common mathematical functions used in both PRBMathSD59x18 and PRBMathUD60x18. Note that this shared library
/// does not always assume the signed 59.18-decimal fixed-point or the unsigned 60.18-decimal fixed-point
// representation. When it does not, it is annonated in the function's NatSpec documentation.
/// @author Paul Razvan Berg
library PRBMathCommon {
/// @dev How many trailing decimals can be represented.
uint256 internal constant SCALE = 1e18;
/// @notice Calculates the binary exponent of x using the binary fraction method.
/// @dev Uses 128.128-bit fixed-point numbers - it is the most efficient way.
/// @param x The exponent as an unsigned 128.128-bit fixed-point number.
/// @return result The result as an unsigned 60x18 decimal fixed-point number.
function exp2(uint256 x) internal pure returns (uint256 result) {
unchecked {
// Start from 0.5 in the 128.128-bit fixed-point format. We need to use uint256 because the intermediary
// may get very close to 2^256, which doesn't fit in int256.
result = 0x80000000000000000000000000000000;
// Multiply the result by root(2, 2^-i) when the bit at position i is 1. None of the intermediary results overflows
// because the initial result is 2^127 and all magic factors are less than 2^129.
if (x & 0x80000000000000000000000000000000 > 0) result = (result * 0x16A09E667F3BCC908B2FB1366EA957D3E) >> 128;
if (x & 0x40000000000000000000000000000000 > 0) result = (result * 0x1306FE0A31B7152DE8D5A46305C85EDED) >> 128;
if (x & 0x20000000000000000000000000000000 > 0) result = (result * 0x1172B83C7D517ADCDF7C8C50EB14A7920) >> 128;
if (x & 0x10000000000000000000000000000000 > 0) result = (result * 0x10B5586CF9890F6298B92B71842A98364) >> 128;
if (x & 0x8000000000000000000000000000000 > 0) result = (result * 0x1059B0D31585743AE7C548EB68CA417FE) >> 128;
if (x & 0x4000000000000000000000000000000 > 0) result = (result * 0x102C9A3E778060EE6F7CACA4F7A29BDE9) >> 128;
if (x & 0x2000000000000000000000000000000 > 0) result = (result * 0x10163DA9FB33356D84A66AE336DCDFA40) >> 128;
if (x & 0x1000000000000000000000000000000 > 0) result = (result * 0x100B1AFA5ABCBED6129AB13EC11DC9544) >> 128;
if (x & 0x800000000000000000000000000000 > 0) result = (result * 0x10058C86DA1C09EA1FF19D294CF2F679C) >> 128;
if (x & 0x400000000000000000000000000000 > 0) result = (result * 0x1002C605E2E8CEC506D21BFC89A23A011) >> 128;
if (x & 0x200000000000000000000000000000 > 0) result = (result * 0x100162F3904051FA128BCA9C55C31E5E0) >> 128;
if (x & 0x100000000000000000000000000000 > 0) result = (result * 0x1000B175EFFDC76BA38E31671CA939726) >> 128;
if (x & 0x80000000000000000000000000000 > 0) result = (result * 0x100058BA01FB9F96D6CACD4B180917C3E) >> 128;
if (x & 0x40000000000000000000000000000 > 0) result = (result * 0x10002C5CC37DA9491D0985C348C68E7B4) >> 128;
if (x & 0x20000000000000000000000000000 > 0) result = (result * 0x1000162E525EE054754457D5995292027) >> 128;
if (x & 0x10000000000000000000000000000 > 0) result = (result * 0x10000B17255775C040618BF4A4ADE83FD) >> 128;
if (x & 0x8000000000000000000000000000 > 0) result = (result * 0x1000058B91B5BC9AE2EED81E9B7D4CFAC) >> 128;
if (x & 0x4000000000000000000000000000 > 0) result = (result * 0x100002C5C89D5EC6CA4D7C8ACC017B7CA) >> 128;
if (x & 0x2000000000000000000000000000 > 0) result = (result * 0x10000162E43F4F831060E02D839A9D16D) >> 128;
if (x & 0x1000000000000000000000000000 > 0) result = (result * 0x100000B1721BCFC99D9F890EA06911763) >> 128;
if (x & 0x800000000000000000000000000 > 0) result = (result * 0x10000058B90CF1E6D97F9CA14DBCC1629) >> 128;
if (x & 0x400000000000000000000000000 > 0) result = (result * 0x1000002C5C863B73F016468F6BAC5CA2C) >> 128;
if (x & 0x200000000000000000000000000 > 0) result = (result * 0x100000162E430E5A18F6119E3C02282A6) >> 128;
if (x & 0x100000000000000000000000000 > 0) result = (result * 0x1000000B1721835514B86E6D96EFD1BFF) >> 128;
if (x & 0x80000000000000000000000000 > 0) result = (result * 0x100000058B90C0B48C6BE5DF846C5B2F0) >> 128;
if (x & 0x40000000000000000000000000 > 0) result = (result * 0x10000002C5C8601CC6B9E94213C72737B) >> 128;
if (x & 0x20000000000000000000000000 > 0) result = (result * 0x1000000162E42FFF037DF38AA2B219F07) >> 128;
if (x & 0x10000000000000000000000000 > 0) result = (result * 0x10000000B17217FBA9C739AA5819F44FA) >> 128;
if (x & 0x8000000000000000000000000 > 0) result = (result * 0x1000000058B90BFCDEE5ACD3C1CEDC824) >> 128;
if (x & 0x4000000000000000000000000 > 0) result = (result * 0x100000002C5C85FE31F35A6A30DA1BE51) >> 128;
if (x & 0x2000000000000000000000000 > 0) result = (result * 0x10000000162E42FF0999CE3541B9FFFD0) >> 128;
if (x & 0x1000000000000000000000000 > 0) result = (result * 0x100000000B17217F80F4EF5AADDA45554) >> 128;
if (x & 0x800000000000000000000000 > 0) result = (result * 0x10000000058B90BFBF8479BD5A81B51AE) >> 128;
if (x & 0x400000000000000000000000 > 0) result = (result * 0x1000000002C5C85FDF84BD62AE30A74CD) >> 128;
if (x & 0x200000000000000000000000 > 0) result = (result * 0x100000000162E42FEFB2FED257559BDAA) >> 128;
if (x & 0x100000000000000000000000 > 0) result = (result * 0x1000000000B17217F7D5A7716BBA4A9AF) >> 128;
if (x & 0x80000000000000000000000 > 0) result = (result * 0x100000000058B90BFBE9DDBAC5E109CCF) >> 128;
if (x & 0x40000000000000000000000 > 0) result = (result * 0x10000000002C5C85FDF4B15DE6F17EB0E) >> 128;
if (x & 0x20000000000000000000000 > 0) result = (result * 0x1000000000162E42FEFA494F1478FDE05) >> 128;
if (x & 0x10000000000000000000000 > 0) result = (result * 0x10000000000B17217F7D20CF927C8E94D) >> 128;
if (x & 0x8000000000000000000000 > 0) result = (result * 0x1000000000058B90BFBE8F71CB4E4B33E) >> 128;
if (x & 0x4000000000000000000000 > 0) result = (result * 0x100000000002C5C85FDF477B662B26946) >> 128;
if (x & 0x2000000000000000000000 > 0) result = (result * 0x10000000000162E42FEFA3AE53369388D) >> 128;
if (x & 0x1000000000000000000000 > 0) result = (result * 0x100000000000B17217F7D1D351A389D41) >> 128;
if (x & 0x800000000000000000000 > 0) result = (result * 0x10000000000058B90BFBE8E8B2D3D4EDF) >> 128;
if (x & 0x400000000000000000000 > 0) result = (result * 0x1000000000002C5C85FDF4741BEA6E77F) >> 128;
if (x & 0x200000000000000000000 > 0) result = (result * 0x100000000000162E42FEFA39FE95583C3) >> 128;
if (x & 0x100000000000000000000 > 0) result = (result * 0x1000000000000B17217F7D1CFB72B45E3) >> 128;
if (x & 0x80000000000000000000 > 0) result = (result * 0x100000000000058B90BFBE8E7CC35C3F2) >> 128;
if (x & 0x40000000000000000000 > 0) result = (result * 0x10000000000002C5C85FDF473E242EA39) >> 128;
if (x & 0x20000000000000000000 > 0) result = (result * 0x1000000000000162E42FEFA39F02B772C) >> 128;
if (x & 0x10000000000000000000 > 0) result = (result * 0x10000000000000B17217F7D1CF7D83C1A) >> 128;
if (x & 0x8000000000000000000 > 0) result = (result * 0x1000000000000058B90BFBE8E7BDCBE2E) >> 128;
if (x & 0x4000000000000000000 > 0) result = (result * 0x100000000000002C5C85FDF473DEA871F) >> 128;
if (x & 0x2000000000000000000 > 0) result = (result * 0x10000000000000162E42FEFA39EF44D92) >> 128;
if (x & 0x1000000000000000000 > 0) result = (result * 0x100000000000000B17217F7D1CF79E949) >> 128;
if (x & 0x800000000000000000 > 0) result = (result * 0x10000000000000058B90BFBE8E7BCE545) >> 128;
if (x & 0x400000000000000000 > 0) result = (result * 0x1000000000000002C5C85FDF473DE6ECA) >> 128;
if (x & 0x200000000000000000 > 0) result = (result * 0x100000000000000162E42FEFA39EF366F) >> 128;
if (x & 0x100000000000000000 > 0) result = (result * 0x1000000000000000B17217F7D1CF79AFA) >> 128;
if (x & 0x80000000000000000 > 0) result = (result * 0x100000000000000058B90BFBE8E7BCD6E) >> 128;
if (x & 0x40000000000000000 > 0) result = (result * 0x10000000000000002C5C85FDF473DE6B3) >> 128;
if (x & 0x20000000000000000 > 0) result = (result * 0x1000000000000000162E42FEFA39EF359) >> 128;
if (x & 0x10000000000000000 > 0) result = (result * 0x10000000000000000B17217F7D1CF79AC) >> 128;
// Multiply the result by the integer part 2^n + 1. We have to shift by one bit extra because we have already divided
// by two when we set the result equal to 0.5 above.
result = result << ((x >> 128) + 1);
// Convert the result to the signed 60.18-decimal fixed-point format.
result = PRBMathCommon.mulDiv(result, 1e18, 2**128);
}
}
/// @notice Calculates floor(x*y÷denominator) with full precision.
///
/// @dev Credit to Remco Bloemen under MIT license https://xn--2-umb.com/21/muldiv.
///
/// Requirements:
/// - The denominator cannot be zero.
/// - The result must fit within uint256.
///
/// Caveats:
/// - This function does not work with fixed-point numbers.
///
/// @param x The multiplicand as an uint256.
/// @param y The multiplier as an uint256.
/// @param denominator The divisor as an uint256.
/// @return result The result as an uint256.
function mulDiv(
uint256 x,
uint256 y,
uint256 denominator
) internal pure returns (uint256 result) {
// 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2**256 and mod 2**256 - 1, then use
// use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
// variables such that product = prod1 * 2**256 + prod0.
uint256 prod0; // Least significant 256 bits of the product
uint256 prod1; // Most significant 256 bits of the product
assembly {
let mm := mulmod(x, y, not(0))
prod0 := mul(x, y)
prod1 := sub(sub(mm, prod0), lt(mm, prod0))
}
// Handle non-overflow cases, 256 by 256 division
if (prod1 == 0) {
require(denominator > 0);
assembly {
result := div(prod0, denominator)
}
return result;
}
// Make sure the result is less than 2**256. Also prevents denominator == 0.
require(denominator > prod1);
///////////////////////////////////////////////
// 512 by 256 division.
///////////////////////////////////////////////
// Make division exact by subtracting the remainder from [prod1 prod0].
uint256 remainder;
assembly {
// Compute remainder using mulmod.
remainder := mulmod(x, y, denominator)
// Subtract 256 bit number from 512 bit number
prod1 := sub(prod1, gt(remainder, prod0))
prod0 := sub(prod0, remainder)
}
// Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.
// See https://cs.stackexchange.com/q/138556/92363.
unchecked {
// Does not overflow because the denominator cannot be zero at this stage in the function.
uint256 lpotdod = denominator & (~denominator + 1);
assembly {
// Divide denominator by lpotdod.
denominator := div(denominator, lpotdod)
// Divide [prod1 prod0] by lpotdod.
prod0 := div(prod0, lpotdod)
// Flip lpotdod such that it is 2**256 / lpotdod. If lpotdod is zero, then it becomes one.
lpotdod := add(div(sub(0, lpotdod), lpotdod), 1)
}
// Shift in bits from prod1 into prod0.
prod0 |= prod1 * lpotdod;
// Invert denominator mod 2**256. Now that denominator is an odd number, it has an inverse modulo 2**256 such
// that denominator * inv = 1 mod 2**256. Compute the inverse by starting with a seed that is correct for
// four bits. That is, denominator * inv = 1 mod 2**4
uint256 inverse = (3 * denominator) ^ 2;
// Now use Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works
// in modular arithmetic, doubling the correct bits in each step.
inverse *= 2 - denominator * inverse; // inverse mod 2**8
inverse *= 2 - denominator * inverse; // inverse mod 2**16
inverse *= 2 - denominator * inverse; // inverse mod 2**32
inverse *= 2 - denominator * inverse; // inverse mod 2**64
inverse *= 2 - denominator * inverse; // inverse mod 2**128
inverse *= 2 - denominator * inverse; // inverse mod 2**256
// Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
// This will give us the correct result modulo 2**256. Since the precoditions guarantee that the outcome is
// less than 2**256, this is the final result. We don't need to compute the high bits of the result and prod1
// is no longer required.
result = prod0 * inverse;
return result;
}
}
}
/* solhint-enable */// SPDX-License-Identifier: Unlicense
pragma solidity 0.8.13;
import "./PRBMathCommon.sol";
/* solhint-disable */
/// @title PRBMathSD59x18
/// @author Paul Razvan Berg
/// @notice Smart contract library for advanced fixed-point math. It works with int256 numbers considered to have 18
/// trailing decimals. We call this number representation signed 59.18-decimal fixed-point, since the numbers can have
/// a sign and there can be up to 59 digits in the integer part and up to 18 decimals in the fractional part. The numbers
/// are bound by the minimum and the maximum values permitted by the Solidity type int256.
library PRBMathSD59x18 {
/// @dev log2(e) as a signed 59.18-decimal fixed-point number.
int256 internal constant LOG2_E = 1442695040888963407;
/// @dev Half the SCALE number.
int256 internal constant HALF_SCALE = 5e17;
/// @dev The maximum value a signed 59.18-decimal fixed-point number can have.
int256 internal constant MAX_SD59x18 = 57896044618658097711785492504343953926634992332820282019728792003956564819967;
/// @dev How many trailing decimals can be represented.
int256 internal constant SCALE = 1e18;
/// INTERNAL FUNCTIONS ///
/// @notice Calculates the natural exponent of x.
///
/// @dev Based on the insight that e^x = 2^(x * log2(e)).
///
/// Requirements:
/// - All from "log2".
/// - x must be less than 88722839111672999628.
///
/// @param x The exponent as a signed 59.18-decimal fixed-point number.
/// @return result The result as a signed 59.18-decimal fixed-point number.
function exp(int256 x) internal pure returns (int256 result) {
// Without this check, the value passed to "exp2" would be less than -59794705707972522261.
if (x < -41446531673892822322) {
return 0;
}
// Without this check, the value passed to "exp2" would be greater than 128e18.
require(x < 88722839111672999628);
// Do the fixed-point multiplication inline to save gas.
unchecked {
int256 doubleScaleProduct = x * LOG2_E;
result = exp2((doubleScaleProduct + HALF_SCALE) / SCALE);
}
}
/// @notice Calculates the binary exponent of x using the binary fraction method.
///
/// @dev See https://ethereum.stackexchange.com/q/79903/24693.
///
/// Requirements:
/// - x must be 128e18 or less.
/// - The result must fit within MAX_SD59x18.
///
/// Caveats:
/// - For any x less than -59794705707972522261, the result is zero.
///
/// @param x The exponent as a signed 59.18-decimal fixed-point number.
/// @return result The result as a signed 59.18-decimal fixed-point number.
function exp2(int256 x) internal pure returns (int256 result) {
// This works because 2^-x = 1/2^x.
if (x < 0) {
// 2**59.794705707972522262 is the maximum number whose inverse does not equal zero.
if (x < -59794705707972522261) {
return 0;
}
// Do the fixed-point inversion inline to save gas. The numerator is SCALE * SCALE.
unchecked { result = 1e36 / exp2(-x); }
return result;
} else {
// 2**128 doesn't fit within the 128.128-bit fixed-point representation.
require(x < 128e18);
unchecked {
// Convert x to the 128.128-bit fixed-point format.
uint256 x128x128 = (uint256(x) << 128) / uint256(SCALE);
// Safe to convert the result to int256 directly because the maximum input allowed is 128e18.
result = int256(PRBMathCommon.exp2(x128x128));
}
}
}
}
/* solhint-enable */// SPDX-License-Identifier: BUSL-1.1
pragma solidity >=0.7.6 <0.9.0;
/// @title TwoStepOwnable
/// @notice Contract that implements the same functionality as popular Ownable contract from openzeppelin library.
/// The only difference is that it adds a possibility to transfer ownership in two steps. Single step ownership
/// transfer is still supported.
/// @dev Two step ownership transfer is meant to be used by humans to avoid human error. Single step ownership
/// transfer is meant to be used by smart contracts to avoid over-complicated two step integration. For that reason,
/// both ways are supported.
abstract contract TwoStepOwnable {
/// @dev current owner
address private _owner;
/// @dev candidate to an owner
address private _pendingOwner;
/// @notice Emitted when ownership is transferred on `transferOwnership` and `acceptOwnership`
/// @param newOwner new owner
event OwnershipTransferred(address indexed newOwner);
/// @notice Emitted when ownership transfer is proposed, aka pending owner is set
/// @param newPendingOwner new proposed/pending owner
event OwnershipPending(address indexed newPendingOwner);
/**
* error OnlyOwner();
* error OnlyPendingOwner();
* error OwnerIsZero();
*/
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
if (owner() != msg.sender) revert("OnlyOwner");
_;
}
/**
* @dev Initializes the contract setting the deployer as the initial owner.
*/
constructor() {
_setOwner(msg.sender);
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions anymore. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby removing any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
_setOwner(address(0));
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
if (newOwner == address(0)) revert("OwnerIsZero");
_setOwner(newOwner);
}
/**
* @dev Transfers pending ownership of the contract to a new account (`newPendingOwner`) and clears any existing
* pending ownership.
* Can only be called by the current owner.
*/
function transferPendingOwnership(address newPendingOwner) public virtual onlyOwner {
_setPendingOwner(newPendingOwner);
}
/**
* @dev Clears the pending ownership.
* Can only be called by the current owner.
*/
function removePendingOwnership() public virtual onlyOwner {
_setPendingOwner(address(0));
}
/**
* @dev Transfers ownership of the contract to a pending owner
* Can only be called by the pending owner.
*/
function acceptOwnership() public virtual {
if (msg.sender != pendingOwner()) revert("OnlyPendingOwner");
_setOwner(pendingOwner());
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @dev Returns the address of the pending owner.
*/
function pendingOwner() public view virtual returns (address) {
return _pendingOwner;
}
/**
* @dev Sets the new owner and emits the corresponding event.
*/
function _setOwner(address newOwner) private {
if (_owner == newOwner) revert("OwnerDidNotChange");
_owner = newOwner;
emit OwnershipTransferred(newOwner);
if (_pendingOwner != address(0)) {
_setPendingOwner(address(0));
}
}
/**
* @dev Sets the new pending owner and emits the corresponding event.
*/
function _setPendingOwner(address newPendingOwner) private {
if (_pendingOwner == newPendingOwner) revert("PendingOwnerDidNotChange");
_pendingOwner = newPendingOwner;
emit OwnershipPending(newPendingOwner);
}
}{
"optimizer": {
"enabled": true,
"runs": 200
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"metadata": {
"useLiteralContent": true
},
"libraries": {}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"components":[{"internalType":"int256","name":"uopt","type":"int256"},{"internalType":"int256","name":"ucrit","type":"int256"},{"internalType":"int256","name":"ulow","type":"int256"},{"internalType":"int256","name":"ki","type":"int256"},{"internalType":"int256","name":"kcrit","type":"int256"},{"internalType":"int256","name":"klow","type":"int256"},{"internalType":"int256","name":"klin","type":"int256"},{"internalType":"int256","name":"beta","type":"int256"},{"internalType":"int256","name":"ri","type":"int256"},{"internalType":"int256","name":"Tcrit","type":"int256"}],"internalType":"struct IInterestRateModel.Config","name":"_config","type":"tuple"},{"internalType":"address","name":"_owner","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"InvalidBeta","type":"error"},{"inputs":[],"name":"InvalidKcrit","type":"error"},{"inputs":[],"name":"InvalidKi","type":"error"},{"inputs":[],"name":"InvalidKlin","type":"error"},{"inputs":[],"name":"InvalidKlow","type":"error"},{"inputs":[],"name":"InvalidRi","type":"error"},{"inputs":[],"name":"InvalidTcrit","type":"error"},{"inputs":[],"name":"InvalidTimestamps","type":"error"},{"inputs":[],"name":"InvalidUcrit","type":"error"},{"inputs":[],"name":"InvalidUlow","type":"error"},{"inputs":[],"name":"InvalidUopt","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"silo","type":"address"},{"indexed":true,"internalType":"address","name":"asset","type":"address"},{"components":[{"internalType":"int256","name":"uopt","type":"int256"},{"internalType":"int256","name":"ucrit","type":"int256"},{"internalType":"int256","name":"ulow","type":"int256"},{"internalType":"int256","name":"ki","type":"int256"},{"internalType":"int256","name":"kcrit","type":"int256"},{"internalType":"int256","name":"klow","type":"int256"},{"internalType":"int256","name":"klin","type":"int256"},{"internalType":"int256","name":"beta","type":"int256"},{"internalType":"int256","name":"ri","type":"int256"},{"internalType":"int256","name":"Tcrit","type":"int256"}],"indexed":false,"internalType":"struct IInterestRateModel.Config","name":"config","type":"tuple"}],"name":"ConfigUpdate","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"newPendingOwner","type":"address"}],"name":"OwnershipPending","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"inputs":[],"name":"ASSET_DATA_OVERFLOW_LIMIT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DP","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"RCOMP_MAX","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"X_MAX","outputs":[{"internalType":"int256","name":"","type":"int256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"acceptOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"int256","name":"uopt","type":"int256"},{"internalType":"int256","name":"ucrit","type":"int256"},{"internalType":"int256","name":"ulow","type":"int256"},{"internalType":"int256","name":"ki","type":"int256"},{"internalType":"int256","name":"kcrit","type":"int256"},{"internalType":"int256","name":"klow","type":"int256"},{"internalType":"int256","name":"klin","type":"int256"},{"internalType":"int256","name":"beta","type":"int256"},{"internalType":"int256","name":"ri","type":"int256"},{"internalType":"int256","name":"Tcrit","type":"int256"}],"internalType":"struct IInterestRateModel.Config","name":"_c","type":"tuple"},{"internalType":"uint256","name":"_totalDeposits","type":"uint256"},{"internalType":"uint256","name":"_totalBorrowAmount","type":"uint256"},{"internalType":"uint256","name":"_interestRateTimestamp","type":"uint256"},{"internalType":"uint256","name":"_blockTimestamp","type":"uint256"}],"name":"calculateCompoundInterestRate","outputs":[{"internalType":"uint256","name":"rcomp","type":"uint256"},{"internalType":"int256","name":"ri","type":"int256"},{"internalType":"int256","name":"Tcrit","type":"int256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"components":[{"internalType":"int256","name":"uopt","type":"int256"},{"internalType":"int256","name":"ucrit","type":"int256"},{"internalType":"int256","name":"ulow","type":"int256"},{"internalType":"int256","name":"ki","type":"int256"},{"internalType":"int256","name":"kcrit","type":"int256"},{"internalType":"int256","name":"klow","type":"int256"},{"internalType":"int256","name":"klin","type":"int256"},{"internalType":"int256","name":"beta","type":"int256"},{"internalType":"int256","name":"ri","type":"int256"},{"internalType":"int256","name":"Tcrit","type":"int256"}],"internalType":"struct IInterestRateModel.Config","name":"_c","type":"tuple"},{"internalType":"uint256","name":"_totalDeposits","type":"uint256"},{"internalType":"uint256","name":"_totalBorrowAmount","type":"uint256"},{"internalType":"uint256","name":"_interestRateTimestamp","type":"uint256"},{"internalType":"uint256","name":"_blockTimestamp","type":"uint256"}],"name":"calculateCompoundInterestRateWithOverflowDetection","outputs":[{"internalType":"uint256","name":"rcomp","type":"uint256"},{"internalType":"int256","name":"ri","type":"int256"},{"internalType":"int256","name":"Tcrit","type":"int256"},{"internalType":"bool","name":"overflow","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"components":[{"internalType":"int256","name":"uopt","type":"int256"},{"internalType":"int256","name":"ucrit","type":"int256"},{"internalType":"int256","name":"ulow","type":"int256"},{"internalType":"int256","name":"ki","type":"int256"},{"internalType":"int256","name":"kcrit","type":"int256"},{"internalType":"int256","name":"klow","type":"int256"},{"internalType":"int256","name":"klin","type":"int256"},{"internalType":"int256","name":"beta","type":"int256"},{"internalType":"int256","name":"ri","type":"int256"},{"internalType":"int256","name":"Tcrit","type":"int256"}],"internalType":"struct IInterestRateModel.Config","name":"_c","type":"tuple"},{"internalType":"uint256","name":"_totalDeposits","type":"uint256"},{"internalType":"uint256","name":"_totalBorrowAmount","type":"uint256"},{"internalType":"uint256","name":"_interestRateTimestamp","type":"uint256"},{"internalType":"uint256","name":"_blockTimestamp","type":"uint256"}],"name":"calculateCurrentInterestRate","outputs":[{"internalType":"uint256","name":"rcur","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"config","outputs":[{"internalType":"int256","name":"uopt","type":"int256"},{"internalType":"int256","name":"ucrit","type":"int256"},{"internalType":"int256","name":"ulow","type":"int256"},{"internalType":"int256","name":"ki","type":"int256"},{"internalType":"int256","name":"kcrit","type":"int256"},{"internalType":"int256","name":"klow","type":"int256"},{"internalType":"int256","name":"klin","type":"int256"},{"internalType":"int256","name":"beta","type":"int256"},{"internalType":"int256","name":"ri","type":"int256"},{"internalType":"int256","name":"Tcrit","type":"int256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_silo","type":"address"},{"internalType":"address","name":"_asset","type":"address"},{"internalType":"uint256","name":"_blockTimestamp","type":"uint256"}],"name":"getCompoundInterestRate","outputs":[{"internalType":"uint256","name":"rcomp","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_asset","type":"address"},{"internalType":"uint256","name":"_blockTimestamp","type":"uint256"}],"name":"getCompoundInterestRateAndUpdate","outputs":[{"internalType":"uint256","name":"rcomp","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_silo","type":"address"},{"internalType":"address","name":"_asset","type":"address"}],"name":"getConfig","outputs":[{"components":[{"internalType":"int256","name":"uopt","type":"int256"},{"internalType":"int256","name":"ucrit","type":"int256"},{"internalType":"int256","name":"ulow","type":"int256"},{"internalType":"int256","name":"ki","type":"int256"},{"internalType":"int256","name":"kcrit","type":"int256"},{"internalType":"int256","name":"klow","type":"int256"},{"internalType":"int256","name":"klin","type":"int256"},{"internalType":"int256","name":"beta","type":"int256"},{"internalType":"int256","name":"ri","type":"int256"},{"internalType":"int256","name":"Tcrit","type":"int256"}],"internalType":"struct IInterestRateModel.Config","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_silo","type":"address"},{"internalType":"address","name":"_asset","type":"address"},{"internalType":"uint256","name":"_blockTimestamp","type":"uint256"}],"name":"getCurrentInterestRate","outputs":[{"internalType":"uint256","name":"rcur","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"interestRateModelPing","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address[]","name":"_silos","type":"address[]"},{"internalType":"contract ISiloRepository","name":"_siloRepository","type":"address"}],"name":"migrationFromV1","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_silo","type":"address"},{"internalType":"address","name":"_asset","type":"address"},{"internalType":"uint256","name":"_blockTimestamp","type":"uint256"}],"name":"overflowDetected","outputs":[{"internalType":"bool","name":"overflow","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"removePendingOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_silo","type":"address"},{"internalType":"address","name":"_asset","type":"address"},{"components":[{"internalType":"int256","name":"uopt","type":"int256"},{"internalType":"int256","name":"ucrit","type":"int256"},{"internalType":"int256","name":"ulow","type":"int256"},{"internalType":"int256","name":"ki","type":"int256"},{"internalType":"int256","name":"kcrit","type":"int256"},{"internalType":"int256","name":"klow","type":"int256"},{"internalType":"int256","name":"klin","type":"int256"},{"internalType":"int256","name":"beta","type":"int256"},{"internalType":"int256","name":"ri","type":"int256"},{"internalType":"int256","name":"Tcrit","type":"int256"}],"internalType":"struct IInterestRateModel.Config","name":"_config","type":"tuple"}],"name":"setConfig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newPendingOwner","type":"address"}],"name":"transferPendingOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"}]Contract Creation Code
60806040523480156200001157600080fd5b506040516200380d3803806200380d8339810160408190526200003491620005cc565b81620000403362000072565b6200004e600080836200012f565b506001600160a01b038116156200006a576200006a8162000425565b50506200067c565b6000546001600160a01b03808316911603620000c95760405162461bcd60e51b81526020600482015260116024820152704f776e65724469644e6f744368616e676560781b60448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b038316908117825560405190917f04dba622d284ed0014ee4b9a6a68386be1a4c08a4913ae272de89199cc68616391a26001546001600160a01b0316156200012c576200012c6000620004ce565b50565b8051670de0b6b3a76400009060001215806200014c575081518113155b156200016b576040516313e9c00360e21b815260040160405180910390fd5b8151602083015113158062000184575080826020015112155b15620001a3576040516339bda99160e11b815260040160405180910390fd5b60008260400151131580620001bd57508151604083015112155b15620001dc57604051635c65494d60e01b815260040160405180910390fd5b600082606001511215620002035760405163fe06781560e01b815260040160405180910390fd5b6000826080015112156200022a576040516320d12cb560e21b815260040160405180910390fd5b60008260a00151121562000254576040516001627ddb5960e01b0319815260040160405180910390fd5b60008260c0015112156200027b57604051634e435a2160e01b815260040160405180910390fd5b60008260e001511215620002a2576040516378a8371160e01b815260040160405180910390fd5b60008261010001511215620002ca576040516330eecc6b60e21b815260040160405180910390fd5b60008261012001511215620002f257604051630266493760e31b815260040160405180910390fd5b6001600160a01b03808516600081815260026020818152604080842095891680855295825292839020875181559087015160018201558287015191810191909155606086015160038201556080860151600482015560a0860151600582015560c0860151600682015560e086015160078201556101008601516008820155610120860151600990910155517ff254631d9ea3e3ab061b1c56e1215a268abf5ff28a460b255f308aac112df4589062000417908690600061014082019050825182526020830151602083015260408301516040830152606083015160608301526080830151608083015260a083015160a083015260c083015160c083015260e083015160e083015261010080840151818401525061012080840151818401525092915050565b60405180910390a350505050565b33620004396000546001600160a01b031690565b6001600160a01b0316146200047d5760405162461bcd60e51b815260206004820152600960248201526827b7363ca7bbb732b960b91b6044820152606401620000c0565b6001600160a01b038116620004c35760405162461bcd60e51b815260206004820152600b60248201526a4f776e657249735a65726f60a81b6044820152606401620000c0565b6200012c8162000072565b6001546001600160a01b038083169116036200052d5760405162461bcd60e51b815260206004820152601860248201527f50656e64696e674f776e65724469644e6f744368616e676500000000000000006044820152606401620000c0565b600180546001600160a01b0319166001600160a01b0383169081179091556040517fd6aad444c90d39fb0eee1c6e357a7fad83d63f719ac5f880445a2beb0ff3ab5890600090a250565b60405161014081016001600160401b0381118282101715620005a957634e487b7160e01b600052604160045260246000fd5b60405290565b80516001600160a01b0381168114620005c757600080fd5b919050565b600080828403610160811215620005e257600080fd5b61014080821215620005f357600080fd5b620005fd62000577565b9150845182526020850151602083015260408501516040830152606085015160608301526080850151608083015260a085015160a083015260c085015160c083015260e085015160e083015261010080860151818401525061012080860151818401525081935062000671818601620005af565b925050509250929050565b613181806200068c6000396000f3fe608060405234801561001057600080fd5b506004361061014d5760003560e01c806374a3e924116100c3578063c42401f11161007c578063c42401f1146102e5578063c63de8bc146102fa578063cbf75c9a1461030d578063e076a551146103c6578063e30c3978146103d7578063f2fde38b146103e857600080fd5b806374a3e9241461026357806379ba50971461027657806381b51e0c1461027e5780638da5cb5b1461028d578063b1e01765146102b2578063bbdcbed6146102c557600080fd5b80633278c694116101155780633278c694146101e75780633ced7d0d146101fc57806344552b5d1461020f5780636bcc8216146102175780636e1a414014610226578063715018a61461025b57600080fd5b8063023279ce1461015257806303dc12fc14610185578063071962ff146101a6578063109a006e146101b957806311e5152b146101c4575b600080fd5b6101656101603660046129d2565b6103fb565b604080519384526020840192909252908201526060015b60405180910390f35b610198610193366004612a2f565b61041f565b60405190815260200161017c565b6101986101b4366004612a5b565b6104f6565b610198600160c41b81565b6101d76101d2366004612a5b565b610599565b604051901515815260200161017c565b6101fa6101f5366004612a9c565b61063f565b005b61019861020a3660046129d2565b61068d565b6101fa61090f565b610198670de0b6b3a764000081565b6102396102343660046129d2565b610954565b604080519485526020850193909352918301521515606082015260800161017c565b6101fa610dd5565b6101fa610271366004612ab9565b610e18565b6101fa610f04565b6101986799e8e8e3d530368181565b6000546001600160a01b03165b6040516001600160a01b03909116815260200161017c565b6101986102c0366004612a5b565b610f6b565b6102d86102d3366004612b0e565b611011565b60405161017c9190612b47565b60405163c42401f160e01b815260200161017c565b6101fa610308366004612bb8565b611293565b61037c61031b366004612b0e565b600260205281600052604060002060205280600052604060002060009150915050806000015490806001015490806002015490806003015490806004015490806005015490806006015490806007015490806008015490806009015490508a565b604080519a8b5260208b0199909952978901969096526060880194909452608087019290925260a086015260c085015260e08401526101008301526101208201526101400161017c565b610198690de0b6b3a7640000000081565b6001546001600160a01b031661029a565b6101fa6103f6366004612a9c565b611734565b600080600061040d8888888888610954565b50919a90995090975095505050505050565b604051631f0f875560e31b81526001600160a01b038316600482015260009033908290829063f87c3aa890602401606060405180830381865afa15801561046a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061048e9190612c3e565b6001600160a01b038084166000908152600260209081526040808320938a168352929052209091506104df6104c38488611011565b83516020850151604086015167ffffffffffffffff16896103fb565b600984015560089092019190915595945050505050565b604051631f0f875560e31b81526001600160a01b038381166004830152600091829186169063f87c3aa890602401606060405180830381865afa158015610541573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105659190612c3e565b90506105906105748686611011565b82516020840151604085015167ffffffffffffffff168761068d565b95945050505050565b604051631f0f875560e31b81526001600160a01b038381166004830152600091829186169063f87c3aa890602401606060405180830381865afa1580156105e4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106089190612c3e565b90506106336106178686611011565b82516020840151604085015167ffffffffffffffff1687610954565b98975050505050505050565b336106526000546001600160a01b031690565b6001600160a01b0316146106815760405162461bcd60e51b815260040161067890612ca8565b60405180910390fd5b61068a816117ba565b50565b6000818311156106b05760405163d22806e360e01b815260040160405180910390fd5b60006040518060e001604052806000815260200160008152602001600081526020016000815260200160008152602001600081526020016000151581525090506106fd8787878787610954565b15801560c08601529250610718915050576000915050610590565b610723848403611861565b815261074061073b670de0b6b3a764000088886118cf565b611861565b6020808301829052670de0b6b3a7640000604084015288015112156107e4578060400151876020015182602001516107789190612ce1565b6040830151835160e08b015161078e9190612d20565b8a610120015185604001516107a39190612da5565b6107ad9190612da5565b8a608001516107bc9190612d20565b6107c69190612dfc565b6107d09190612d20565b6107da9190612dfc565b6060820152610826565b61082060008260400151896040015184602001516108029190612ce1565b8a60a001516108119190612d20565b61081b9190612dfc565b611919565b60608201525b806040015181602001518860c0015161083f9190612d20565b6108499190612dfc565b6080820181905261010088015161085f9161192f565b60a082015260408101518151885160208401516108bd93929161088191612ce1565b8a606001516108909190612d20565b61089a9190612d20565b6108a49190612dfc565b8260a001516108b39190612da5565b826080015161192f565b60a0820181905260608201516108e9916108e4916108da91612da5565b836080015161192f565b61193e565b91506108f96301e1338083612e38565b915061090482611990565b979650505050505050565b336109226000546001600160a01b031690565b6001600160a01b0316146109485760405162461bcd60e51b815260040161067890612ca8565b61095260006117ba565b565b60008060008088610100015192508861012001519150600060405180610140016040528060008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152509050858711156109df5760405163d22806e360e01b815260040160405180910390fd5b6109ea878703611861565b8152670de0b6b3a7640000610a0361073b828c8c6118cf565b61012083018190528b518291610a199190612ce1565b8c60600151610a289190612d20565b610a329190612dfc565b6020808401919091528b01516101208301511315610b1c57808b60200151836101200151610a609190612ce1565b82610a6b8782612da5565b8e60800151610a7a9190612d20565b610a849190612dfc565b610a8e9190612d20565b610a989190612dfc565b604083015260208b01516101208301518291610ab391612ce1565b828d60e001518e60800151610ac89190612d20565b610ad29190612dfc565b610adc9190612d20565b610ae69190612dfc565b8260200151610af59190612da5565b6060830152815160e08c0151610b0b9190612d20565b610b159085612da5565b9350610b7f565b610b466000828d60400151856101200151610b379190612ce1565b8e60a001516108119190612d20565b604083015260208201516060830152815160e08c0151610b7c91600091610b6d9190612d20565b610b779087612ce1565b61192f565b93505b808261012001518c60c00151610b959190612d20565b610b9f9190612dfc565b60a08301819052610bb190869061192f565b9450816040015185610bc39190612da5565b608083015281516060830151610bd99190612d20565b8260800151610be89190612da5565b60c083015260a0820151608083015112801590610c0d57508160a001518260c0015112155b15610c4957815160c0830151608084015160029291610c2b91612da5565b610c359190612d20565b610c3f9190612dfc565b60e0830152610d53565b8160a001518260800151128015610c6757508160a001518260c00151125b15610c7d57815160a0830151610c3f9190612d20565b8160a00151826080015112158015610c9c57508160a001518260c00151125b15610cf7576002826060015160028460a001518560800151610cbe9190612ce1565b610cc89190612f84565b610cd29190612dfc565b610cdc9190612dfc565b825160a0840151610ced9190612d20565b610c3f9190612ce1565b6002826060015160028460a001518560c00151610d149190612ce1565b610d1e9190612f84565b610d289190612dfc565b610d329190612dfc565b825160a0840151610d439190612d20565b610d4d9190612da5565b60e08301525b81516020830151610d7b91610d6791612d20565b610d719087612da5565b8360a0015161192f565b9450610d8c8a8a8460e001516119a9565b83519197509350600090610daa908890610da59061193e565b611ac7565b90975090508380610db85750805b15610dc65760009550600094505b50505095509550955095915050565b33610de86000546001600160a01b031690565b6001600160a01b031614610e0e5760405162461bcd60e51b815260040161067890612ca8565b6109526000611afc565b33610e2b6000546001600160a01b031690565b6001600160a01b031614610e515760405162461bcd60e51b815260040161067890612ca8565b6040516001600160a01b03838116602483015284169060440160408051601f198184030181529181526020820180516001600160e01b0316639198e51560e01b17905251610e9f9190612f93565b6000604051808303816000865af19150503d8060008114610edc576040519150601f19603f3d011682016040523d82523d6000602084013e610ee1565b606091505b505050610eff838383803603810190610efa9190612fce565b611bad565b505050565b6001546001600160a01b03163314610f515760405162461bcd60e51b815260206004820152601060248201526f27b7363ca832b73234b733a7bbb732b960811b6044820152606401610678565b610952610f666001546001600160a01b031690565b611afc565b604051631f0f875560e31b81526001600160a01b038381166004830152600091829186169063f87c3aa890602401606060405180830381865afa158015610fb6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fda9190612c3e565b9050611005610fe98686611011565b82516020840151604085015167ffffffffffffffff16876103fb565b50909695505050505050565b611067604051806101400160405280600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b6001600160a01b03808416600090815260026020908152604080832093861683529290522080541561110857604080516101408101825282548152600183015460208201526002830154918101919091526003820154606082015260048201546080820152600582015460a0820152600682015460c0820152600782015460e08201526008820154610100820152600990910154610120820152905061128d565b600080527fac33ff75c19e70fe83507db0d683fd3465c996598dc972688b7ace676c89077b602090815260408051610140810182527f6ee3efecae883df2d7ccda22610b4ca771a299e707cb0d65c4ec97dc4e6668ad5481527f6ee3efecae883df2d7ccda22610b4ca771a299e707cb0d65c4ec97dc4e6668ae54928101929092527f6ee3efecae883df2d7ccda22610b4ca771a299e707cb0d65c4ec97dc4e6668af54908201527f6ee3efecae883df2d7ccda22610b4ca771a299e707cb0d65c4ec97dc4e6668b05460608201527f6ee3efecae883df2d7ccda22610b4ca771a299e707cb0d65c4ec97dc4e6668b15460808201527f6ee3efecae883df2d7ccda22610b4ca771a299e707cb0d65c4ec97dc4e6668b25460a08201527f6ee3efecae883df2d7ccda22610b4ca771a299e707cb0d65c4ec97dc4e6668b35460c08201527f6ee3efecae883df2d7ccda22610b4ca771a299e707cb0d65c4ec97dc4e6668b45460e0820152600882015461010082015260099091015461012082015290505b92915050565b336112a66000546001600160a01b031690565b6001600160a01b0316146112cc5760405162461bcd60e51b815260040161067890612ca8565b6000805b8381101561172d5760008585838181106112ec576112ec612feb565b90506020020160208101906113019190612a9c565b6001600160a01b03166367e4ac2c6040518163ffffffff1660e01b8152600401600060405180830381865afa15801561133e573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526113669190810190613001565b90506001600160a01b03831661143e57836001600160a01b03166348b3eabc8787600081811061139857611398612feb565b90506020020160208101906113ad9190612a9c565b836000815181106113c0576113c0612feb565b60200260200101516040518363ffffffff1660e01b81526004016113fa9291906001600160a01b0392831681529116602082015260400190565b602060405180830381865afa158015611417573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061143b91906130a7565b92505b60005b8151811015611723576000846001600160a01b031663cbf75c9a89898781811061146d5761146d612feb565b90506020020160208101906114829190612a9c565b85858151811061149457611494612feb565b60200260200101516040518363ffffffff1660e01b81526004016114ce9291906001600160a01b0392831681529116602082015260400190565b61014060405180830381865afa1580156114ec573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061151091906130c4565b80519091506000036116ab576000866001600160a01b03166348b3eabc8a8a8881811061153f5761153f612feb565b90506020020160208101906115549190612a9c565b86868151811061156657611566612feb565b60200260200101516040518363ffffffff1660e01b81526004016115a09291906001600160a01b0392831681529116602082015260400190565b602060405180830381865afa1580156115bd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115e191906130a7565b9050806001600160a01b031663cbf75c9a8a8a8881811061160457611604612feb565b90506020020160208101906116199190612a9c565b86868151811061162b5761162b612feb565b60200260200101516040518363ffffffff1660e01b81526004016116659291906001600160a01b0392831681529116602082015260400190565b61014060405180830381865afa158015611683573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116a791906130c4565b9150505b80511561171a578060e0015165fca32dc55c72036116d057653f28cb71571c60e08201525b61171a8888868181106116e5576116e5612feb565b90506020020160208101906116fa9190612a9c565b84848151811061170c5761170c612feb565b602002602001015183611bad565b50600101611441565b50506001016112d0565b5050505050565b336117476000546001600160a01b031690565b6001600160a01b03161461176d5760405162461bcd60e51b815260040161067890612ca8565b6001600160a01b0381166117b15760405162461bcd60e51b815260206004820152600b60248201526a4f776e657249735a65726f60a81b6044820152606401610678565b61068a81611afc565b6001546001600160a01b038083169116036118175760405162461bcd60e51b815260206004820152601860248201527f50656e64696e674f776e65724469644e6f744368616e676500000000000000006044820152606401610678565b600180546001600160a01b0319166001600160a01b0383169081179091556040517fd6aad444c90d39fb0eee1c6e357a7fad83d63f719ac5f880445a2beb0ff3ab5890600090a250565b60006001600160ff1b038211156118cb5760405162461bcd60e51b815260206004820152602860248201527f53616665436173743a2076616c756520646f65736e27742066697420696e2061604482015267371034b73a191a9b60c11b6064820152608401610678565b5090565b60008215806118dc575081155b156118e957506000611912565b6118f38483612e38565b905082818161190457611904612de6565b049050838111156119125750825b9392505050565b60008183126119285781611912565b5090919050565b60008183136119285781611912565b6000808212156118cb5760405162461bcd60e51b815260206004820181905260248201527f53616665436173743a2076616c7565206d75737420626520706f7369746976656044820152606401610678565b600068056bc75e2d6310000080831161128d5782611912565b60008060006799e8e8e3d530368184126119d357690de0b6b3a76400000000925060019150611a0c565b670de0b6b3a76400006119e585611e29565b6119ef9190612ce1565b905060008113611a00576000611a09565b611a098161193e565b92505b6000858711611a1b5785611a1d565b865b9050600160c41b8110611a395760006001935093505050611abf565b8386026000819003611a4d57505050611abf565b86858281611a5d57611a5d612de6565b04141580611a87575081600160c41b03670de0b6b3a76400008281611a8457611a84612de6565b04115b15611abb5786670de0b6b3a764000083600160c41b030281611aab57611aab612de6565b04945060019350611abf92505050565b5050505b935093915050565b60008080611adb846502e24d16b5a8612e38565b9050808511611aec57846000611af0565b8060015b92509250509250929050565b6000546001600160a01b03808316911603611b4d5760405162461bcd60e51b81526020600482015260116024820152704f776e65724469644e6f744368616e676560781b6044820152606401610678565b600080546001600160a01b0319166001600160a01b038316908117825560405190917f04dba622d284ed0014ee4b9a6a68386be1a4c08a4913ae272de89199cc68616391a26001546001600160a01b03161561068a5761068a60006117ba565b8051670de0b6b3a7640000906000121580611bc9575081518113155b15611be7576040516313e9c00360e21b815260040160405180910390fd5b81516020830151131580611bff575080826020015112155b15611c1d576040516339bda99160e11b815260040160405180910390fd5b60008260400151131580611c3657508151604083015112155b15611c5457604051635c65494d60e01b815260040160405180910390fd5b600082606001511215611c7a5760405163fe06781560e01b815260040160405180910390fd5b600082608001511215611ca0576040516320d12cb560e21b815260040160405180910390fd5b60008260a001511215611cc9576040516001627ddb5960e01b0319815260040160405180910390fd5b60008260c001511215611cef57604051634e435a2160e01b815260040160405180910390fd5b60008260e001511215611d15576040516378a8371160e01b815260040160405180910390fd5b60008261010001511215611d3c576040516330eecc6b60e21b815260040160405180910390fd5b60008261012001511215611d6357604051630266493760e31b815260040160405180910390fd5b6001600160a01b03808516600081815260026020818152604080842095891680855295825292839020875181559087015160018201558287015191810191909155606086015160038201556080860151600482015560a0860151600582015560c0860151600682015560e086015160078201556101008601516008820155610120860151600990910155517ff254631d9ea3e3ab061b1c56e1215a268abf5ff28a460b255f308aac112df45890611e1b908690612b47565b60405180910390a350505050565b600068023f2fa8f6da5b9d3119821215611e4557506000919050565b6804cf46d8192b672ecc8212611e5a57600080fd5b6714057b7ef767814f8202611912670de0b6b3a76400006706f05b59d3b200008301055b600080821215611ed25768033dd1780914b9711419821215611ea257506000919050565b611eae82600003611e7e565b6ec097ce7bc90715b34b9f100000000081611ecb57611ecb612de6565b0592915050565b6806f05b59d3b20000008212611ee757600080fd5b670de0b6b3a7640000608083901b04611912816001607f1b80821615611f1e5770016a09e667f3bcc908b2fb1366ea957d3e0260801c5b6001607e1b821615611f41577001306fe0a31b7152de8d5a46305c85eded0260801c5b6001607d1b821615611f64577001172b83c7d517adcdf7c8c50eb14a79200260801c5b6001607c1b821615611f875770010b5586cf9890f6298b92b71842a983640260801c5b6001607b1b821615611faa577001059b0d31585743ae7c548eb68ca417fe0260801c5b6001607a1b821615611fcd57700102c9a3e778060ee6f7caca4f7a29bde90260801c5b600160791b821615611ff05770010163da9fb33356d84a66ae336dcdfa400260801c5b600160781b82161561201357700100b1afa5abcbed6129ab13ec11dc95440260801c5b600160771b8216156120365770010058c86da1c09ea1ff19d294cf2f679c0260801c5b600160761b821615612059577001002c605e2e8cec506d21bfc89a23a0110260801c5b600160751b82161561207c57700100162f3904051fa128bca9c55c31e5e00260801c5b600160741b82161561209f577001000b175effdc76ba38e31671ca9397260260801c5b600160731b8216156120c257700100058ba01fb9f96d6cacd4b180917c3e0260801c5b600160721b8216156120e55770010002c5cc37da9491d0985c348c68e7b40260801c5b600160711b821615612108577001000162e525ee054754457d59952920270260801c5b600160701b82161561212b5770010000b17255775c040618bf4a4ade83fd0260801c5b6001606f1b82161561214e577001000058b91b5bc9ae2eed81e9b7d4cfac0260801c5b6001606e1b82161561217157700100002c5c89d5ec6ca4d7c8acc017b7ca0260801c5b6001606d1b8216156121945770010000162e43f4f831060e02d839a9d16d0260801c5b6001606c1b8216156121b757700100000b1721bcfc99d9f890ea069117630260801c5b6001606b1b8216156121da5770010000058b90cf1e6d97f9ca14dbcc16290260801c5b6001606a1b8216156121fd577001000002c5c863b73f016468f6bac5ca2c0260801c5b600160691b82161561222057700100000162e430e5a18f6119e3c02282a60260801c5b600160681b821615612243577001000000b1721835514b86e6d96efd1bff0260801c5b600160671b82161561226657700100000058b90c0b48c6be5df846c5b2f00260801c5b600160661b8216156122895770010000002c5c8601cc6b9e94213c72737b0260801c5b600160651b8216156122ac577001000000162e42fff037df38aa2b219f070260801c5b600160641b8216156122cf5770010000000b17217fba9c739aa5819f44fa0260801c5b600160631b8216156122f2577001000000058b90bfcdee5acd3c1cedc8240260801c5b600160621b82161561231557700100000002c5c85fe31f35a6a30da1be510260801c5b600160611b8216156123385770010000000162e42ff0999ce3541b9fffd00260801c5b600160601b82161561235b57700100000000b17217f80f4ef5aadda455540260801c5b6001605f1b82161561237e5770010000000058b90bfbf8479bd5a81b51ae0260801c5b6001605e1b8216156123a1577001000000002c5c85fdf84bd62ae30a74cd0260801c5b6001605d1b8216156123c457700100000000162e42fefb2fed257559bdaa0260801c5b6001605c1b8216156123e7577001000000000b17217f7d5a7716bba4a9af0260801c5b6001605b1b82161561240a57700100000000058b90bfbe9ddbac5e109ccf0260801c5b6001605a1b82161561242d5770010000000002c5c85fdf4b15de6f17eb0e0260801c5b600160591b821615612450577001000000000162e42fefa494f1478fde050260801c5b600160581b8216156124735770010000000000b17217f7d20cf927c8e94d0260801c5b600160571b821615612496577001000000000058b90bfbe8f71cb4e4b33e0260801c5b600160561b8216156124b957700100000000002c5c85fdf477b662b269460260801c5b600160551b8216156124dc5770010000000000162e42fefa3ae53369388d0260801c5b600160541b8216156124ff57700100000000000b17217f7d1d351a389d410260801c5b600160531b8216156125225770010000000000058b90bfbe8e8b2d3d4edf0260801c5b600160521b821615612545577001000000000002c5c85fdf4741bea6e77f0260801c5b600160511b82161561256857700100000000000162e42fefa39fe95583c30260801c5b600160501b82161561258b577001000000000000b17217f7d1cfb72b45e30260801c5b69800000000000000000008216156125b457700100000000000058b90bfbe8e7cc35c3f20260801c5b69400000000000000000008216156125dd5770010000000000002c5c85fdf473e242ea390260801c5b6920000000000000000000821615612606577001000000000000162e42fefa39f02b772c0260801c5b691000000000000000000082161561262f5770010000000000000b17217f7d1cf7d83c1a0260801c5b6908000000000000000000821615612658577001000000000000058b90bfbe8e7bdcbe2e0260801c5b690400000000000000000082161561268157700100000000000002c5c85fdf473dea871f0260801c5b69020000000000000000008216156126aa5770010000000000000162e42fefa39ef44d920260801c5b69010000000000000000008216156126d357700100000000000000b17217f7d1cf79e9490260801c5b688000000000000000008216156126fb5770010000000000000058b90bfbe8e7bce5450260801c5b68400000000000000000821615612723577001000000000000002c5c85fdf473de6eca0260801c5b6820000000000000000082161561274b57700100000000000000162e42fefa39ef366f0260801c5b68100000000000000000821615612773577001000000000000000b17217f7d1cf79afa0260801c5b6808000000000000000082161561279b57700100000000000000058b90bfbe8e7bcd6e0260801c5b680400000000000000008216156127c35770010000000000000002c5c85fdf473de6b30260801c5b680200000000000000008216156127eb577001000000000000000162e42fefa39ef3590260801c5b680100000000000000008216156128135770010000000000000000b17217f7d1cf79ac0260801c5b6001608083901c011b61128d81670de0b6b3a7640000600160801b6000808060001985870985870292508281108382030391505080600003612867576000841161285c57600080fd5b508290049050611912565b80841161287357600080fd5b60008486880960026001871981018816978890046003810283188082028403028082028403028082028403028082028403028082028403029081029092039091026000889003889004909101858311909403939093029303949094049190911702949350505050565b634e487b7160e01b600052604160045260246000fd5b604051610140810167ffffffffffffffff81118282101715612916576129166128dc565b60405290565b604051601f8201601f1916810167ffffffffffffffff81118282101715612945576129456128dc565b604052919050565b6000610140828403121561296057600080fd5b6129686128f2565b9050813581526020820135602082015260408201356040820152606082013560608201526080820135608082015260a082013560a082015260c082013560c082015260e082013560e082015261010080830135818301525061012080830135818301525092915050565b60008060008060006101c086880312156129eb57600080fd5b6129f5878761294d565b9761014087013597506101608701359661018081013596506101a00135945092505050565b6001600160a01b038116811461068a57600080fd5b60008060408385031215612a4257600080fd5b8235612a4d81612a1a565b946020939093013593505050565b600080600060608486031215612a7057600080fd5b8335612a7b81612a1a565b92506020840135612a8b81612a1a565b929592945050506040919091013590565b600060208284031215612aae57600080fd5b813561191281612a1a565b6000806000838503610180811215612ad057600080fd5b8435612adb81612a1a565b93506020850135612aeb81612a1a565b9250610140603f1982011215612b0057600080fd5b506040840190509250925092565b60008060408385031215612b2157600080fd5b8235612b2c81612a1a565b91506020830135612b3c81612a1a565b809150509250929050565b600061014082019050825182526020830151602083015260408301516040830152606083015160608301526080830151608083015260a083015160a083015260c083015160c083015260e083015160e083015261010080840151818401525061012080840151818401525092915050565b600080600060408486031215612bcd57600080fd5b833567ffffffffffffffff80821115612be557600080fd5b818601915086601f830112612bf957600080fd5b813581811115612c0857600080fd5b8760208260051b8501011115612c1d57600080fd5b60209283019550935050840135612c3381612a1a565b809150509250925092565b600060608284031215612c5057600080fd5b6040516060810167ffffffffffffffff8282108183111715612c7457612c746128dc565b816040528451835260208501516020840152604085015191508082168214612c9b57600080fd5b5060408201529392505050565b60208082526009908201526827b7363ca7bbb732b960b91b604082015260600190565b634e487b7160e01b600052601160045260246000fd5b60008083128015600160ff1b850184121615612cff57612cff612ccb565b6001600160ff1b0384018313811615612d1a57612d1a612ccb565b50500390565b60006001600160ff1b0381841382841380821686840486111615612d4657612d46612ccb565b600160ff1b6000871282811687830589121615612d6557612d65612ccb565b60008712925087820587128484161615612d8157612d81612ccb565b87850587128184161615612d9757612d97612ccb565b505050929093029392505050565b600080821280156001600160ff1b0384900385131615612dc757612dc7612ccb565b600160ff1b8390038412811615612de057612de0612ccb565b50500190565b634e487b7160e01b600052601260045260246000fd5b600082612e1957634e487b7160e01b600052601260045260246000fd5b600160ff1b821460001984141615612e3357612e33612ccb565b500590565b6000816000190483118215151615612e5257612e52612ccb565b500290565b80825b6001808611612e695750611abf565b6001600160ff1b03829004821115612e8357612e83612ccb565b80861615612e9057918102915b9490941c938002612e5a565b6000828015612eb25760018114612ebc57612ec5565b600191505061128d565b8291505061128d565b5081612ed35750600061128d565b50600160008213808214612eec578015612f0b57612f25565b6001600160ff1b03839004831115612f0657612f06612ccb565b612f25565b6001600160ff1b03839005831215612f2557612f25612ccb565b5080831615612f315750805b612f418360011c83840283612e57565b600082136001600160ff1b0382900483111615612f6057612f60612ccb565b60008212600160ff1b82900583121615612f7c57612f7c612ccb565b029392505050565b600061191260ff841683612e9c565b6000825160005b81811015612fb45760208186018101518583015201612f9a565b81811115612fc3576000828501525b509190910192915050565b60006101408284031215612fe157600080fd5b611912838361294d565b634e487b7160e01b600052603260045260246000fd5b6000602080838503121561301457600080fd5b825167ffffffffffffffff8082111561302c57600080fd5b818501915085601f83011261304057600080fd5b815181811115613052576130526128dc565b8060051b915061306384830161291c565b818152918301840191848101908884111561307d57600080fd5b938501935b83851015610633578451925061309783612a1a565b8282529385019390850190613082565b6000602082840312156130b957600080fd5b815161191281612a1a565b600061014082840312156130d757600080fd5b6130df6128f2565b825181526020830151602082015260408301516040820152606083015160608201526080830151608082015260a083015160a082015260c083015160c082015260e083015160e0820152610100808401518183015250610120808401518183015250809150509291505056fea2646970667358221220ac570d5b75aaadac4524f8ca53f6661aee67b7323169be605352e1812b3ae42264736f6c634300080d00330000000000000000000000000000000000000000000000000b1a2bc2ec5000000000000000000000000000000000000000000000000000000c7d713b49da000000000000000000000000000000000000000000000000000006f05b59d3b2000000000000000000000000000000000000000000000000000000000000000599a3000000000000000000000000000000000000000000000000000000dd7d86d0190000000000000000000000000000000000000000000000000000000ec41a0de00000000000000000000000000000000000000000000000000000000017a029b000000000000000000000000000000000000000000000000000003f28cb71571c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1f03b7b0ebf84e9b9f62a1db40f1efb8faa7d22
Deployed Bytecode
0x608060405234801561001057600080fd5b506004361061014d5760003560e01c806374a3e924116100c3578063c42401f11161007c578063c42401f1146102e5578063c63de8bc146102fa578063cbf75c9a1461030d578063e076a551146103c6578063e30c3978146103d7578063f2fde38b146103e857600080fd5b806374a3e9241461026357806379ba50971461027657806381b51e0c1461027e5780638da5cb5b1461028d578063b1e01765146102b2578063bbdcbed6146102c557600080fd5b80633278c694116101155780633278c694146101e75780633ced7d0d146101fc57806344552b5d1461020f5780636bcc8216146102175780636e1a414014610226578063715018a61461025b57600080fd5b8063023279ce1461015257806303dc12fc14610185578063071962ff146101a6578063109a006e146101b957806311e5152b146101c4575b600080fd5b6101656101603660046129d2565b6103fb565b604080519384526020840192909252908201526060015b60405180910390f35b610198610193366004612a2f565b61041f565b60405190815260200161017c565b6101986101b4366004612a5b565b6104f6565b610198600160c41b81565b6101d76101d2366004612a5b565b610599565b604051901515815260200161017c565b6101fa6101f5366004612a9c565b61063f565b005b61019861020a3660046129d2565b61068d565b6101fa61090f565b610198670de0b6b3a764000081565b6102396102343660046129d2565b610954565b604080519485526020850193909352918301521515606082015260800161017c565b6101fa610dd5565b6101fa610271366004612ab9565b610e18565b6101fa610f04565b6101986799e8e8e3d530368181565b6000546001600160a01b03165b6040516001600160a01b03909116815260200161017c565b6101986102c0366004612a5b565b610f6b565b6102d86102d3366004612b0e565b611011565b60405161017c9190612b47565b60405163c42401f160e01b815260200161017c565b6101fa610308366004612bb8565b611293565b61037c61031b366004612b0e565b600260205281600052604060002060205280600052604060002060009150915050806000015490806001015490806002015490806003015490806004015490806005015490806006015490806007015490806008015490806009015490508a565b604080519a8b5260208b0199909952978901969096526060880194909452608087019290925260a086015260c085015260e08401526101008301526101208201526101400161017c565b610198690de0b6b3a7640000000081565b6001546001600160a01b031661029a565b6101fa6103f6366004612a9c565b611734565b600080600061040d8888888888610954565b50919a90995090975095505050505050565b604051631f0f875560e31b81526001600160a01b038316600482015260009033908290829063f87c3aa890602401606060405180830381865afa15801561046a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061048e9190612c3e565b6001600160a01b038084166000908152600260209081526040808320938a168352929052209091506104df6104c38488611011565b83516020850151604086015167ffffffffffffffff16896103fb565b600984015560089092019190915595945050505050565b604051631f0f875560e31b81526001600160a01b038381166004830152600091829186169063f87c3aa890602401606060405180830381865afa158015610541573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105659190612c3e565b90506105906105748686611011565b82516020840151604085015167ffffffffffffffff168761068d565b95945050505050565b604051631f0f875560e31b81526001600160a01b038381166004830152600091829186169063f87c3aa890602401606060405180830381865afa1580156105e4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106089190612c3e565b90506106336106178686611011565b82516020840151604085015167ffffffffffffffff1687610954565b98975050505050505050565b336106526000546001600160a01b031690565b6001600160a01b0316146106815760405162461bcd60e51b815260040161067890612ca8565b60405180910390fd5b61068a816117ba565b50565b6000818311156106b05760405163d22806e360e01b815260040160405180910390fd5b60006040518060e001604052806000815260200160008152602001600081526020016000815260200160008152602001600081526020016000151581525090506106fd8787878787610954565b15801560c08601529250610718915050576000915050610590565b610723848403611861565b815261074061073b670de0b6b3a764000088886118cf565b611861565b6020808301829052670de0b6b3a7640000604084015288015112156107e4578060400151876020015182602001516107789190612ce1565b6040830151835160e08b015161078e9190612d20565b8a610120015185604001516107a39190612da5565b6107ad9190612da5565b8a608001516107bc9190612d20565b6107c69190612dfc565b6107d09190612d20565b6107da9190612dfc565b6060820152610826565b61082060008260400151896040015184602001516108029190612ce1565b8a60a001516108119190612d20565b61081b9190612dfc565b611919565b60608201525b806040015181602001518860c0015161083f9190612d20565b6108499190612dfc565b6080820181905261010088015161085f9161192f565b60a082015260408101518151885160208401516108bd93929161088191612ce1565b8a606001516108909190612d20565b61089a9190612d20565b6108a49190612dfc565b8260a001516108b39190612da5565b826080015161192f565b60a0820181905260608201516108e9916108e4916108da91612da5565b836080015161192f565b61193e565b91506108f96301e1338083612e38565b915061090482611990565b979650505050505050565b336109226000546001600160a01b031690565b6001600160a01b0316146109485760405162461bcd60e51b815260040161067890612ca8565b61095260006117ba565b565b60008060008088610100015192508861012001519150600060405180610140016040528060008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152509050858711156109df5760405163d22806e360e01b815260040160405180910390fd5b6109ea878703611861565b8152670de0b6b3a7640000610a0361073b828c8c6118cf565b61012083018190528b518291610a199190612ce1565b8c60600151610a289190612d20565b610a329190612dfc565b6020808401919091528b01516101208301511315610b1c57808b60200151836101200151610a609190612ce1565b82610a6b8782612da5565b8e60800151610a7a9190612d20565b610a849190612dfc565b610a8e9190612d20565b610a989190612dfc565b604083015260208b01516101208301518291610ab391612ce1565b828d60e001518e60800151610ac89190612d20565b610ad29190612dfc565b610adc9190612d20565b610ae69190612dfc565b8260200151610af59190612da5565b6060830152815160e08c0151610b0b9190612d20565b610b159085612da5565b9350610b7f565b610b466000828d60400151856101200151610b379190612ce1565b8e60a001516108119190612d20565b604083015260208201516060830152815160e08c0151610b7c91600091610b6d9190612d20565b610b779087612ce1565b61192f565b93505b808261012001518c60c00151610b959190612d20565b610b9f9190612dfc565b60a08301819052610bb190869061192f565b9450816040015185610bc39190612da5565b608083015281516060830151610bd99190612d20565b8260800151610be89190612da5565b60c083015260a0820151608083015112801590610c0d57508160a001518260c0015112155b15610c4957815160c0830151608084015160029291610c2b91612da5565b610c359190612d20565b610c3f9190612dfc565b60e0830152610d53565b8160a001518260800151128015610c6757508160a001518260c00151125b15610c7d57815160a0830151610c3f9190612d20565b8160a00151826080015112158015610c9c57508160a001518260c00151125b15610cf7576002826060015160028460a001518560800151610cbe9190612ce1565b610cc89190612f84565b610cd29190612dfc565b610cdc9190612dfc565b825160a0840151610ced9190612d20565b610c3f9190612ce1565b6002826060015160028460a001518560c00151610d149190612ce1565b610d1e9190612f84565b610d289190612dfc565b610d329190612dfc565b825160a0840151610d439190612d20565b610d4d9190612da5565b60e08301525b81516020830151610d7b91610d6791612d20565b610d719087612da5565b8360a0015161192f565b9450610d8c8a8a8460e001516119a9565b83519197509350600090610daa908890610da59061193e565b611ac7565b90975090508380610db85750805b15610dc65760009550600094505b50505095509550955095915050565b33610de86000546001600160a01b031690565b6001600160a01b031614610e0e5760405162461bcd60e51b815260040161067890612ca8565b6109526000611afc565b33610e2b6000546001600160a01b031690565b6001600160a01b031614610e515760405162461bcd60e51b815260040161067890612ca8565b6040516001600160a01b03838116602483015284169060440160408051601f198184030181529181526020820180516001600160e01b0316639198e51560e01b17905251610e9f9190612f93565b6000604051808303816000865af19150503d8060008114610edc576040519150601f19603f3d011682016040523d82523d6000602084013e610ee1565b606091505b505050610eff838383803603810190610efa9190612fce565b611bad565b505050565b6001546001600160a01b03163314610f515760405162461bcd60e51b815260206004820152601060248201526f27b7363ca832b73234b733a7bbb732b960811b6044820152606401610678565b610952610f666001546001600160a01b031690565b611afc565b604051631f0f875560e31b81526001600160a01b038381166004830152600091829186169063f87c3aa890602401606060405180830381865afa158015610fb6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fda9190612c3e565b9050611005610fe98686611011565b82516020840151604085015167ffffffffffffffff16876103fb565b50909695505050505050565b611067604051806101400160405280600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b6001600160a01b03808416600090815260026020908152604080832093861683529290522080541561110857604080516101408101825282548152600183015460208201526002830154918101919091526003820154606082015260048201546080820152600582015460a0820152600682015460c0820152600782015460e08201526008820154610100820152600990910154610120820152905061128d565b600080527fac33ff75c19e70fe83507db0d683fd3465c996598dc972688b7ace676c89077b602090815260408051610140810182527f6ee3efecae883df2d7ccda22610b4ca771a299e707cb0d65c4ec97dc4e6668ad5481527f6ee3efecae883df2d7ccda22610b4ca771a299e707cb0d65c4ec97dc4e6668ae54928101929092527f6ee3efecae883df2d7ccda22610b4ca771a299e707cb0d65c4ec97dc4e6668af54908201527f6ee3efecae883df2d7ccda22610b4ca771a299e707cb0d65c4ec97dc4e6668b05460608201527f6ee3efecae883df2d7ccda22610b4ca771a299e707cb0d65c4ec97dc4e6668b15460808201527f6ee3efecae883df2d7ccda22610b4ca771a299e707cb0d65c4ec97dc4e6668b25460a08201527f6ee3efecae883df2d7ccda22610b4ca771a299e707cb0d65c4ec97dc4e6668b35460c08201527f6ee3efecae883df2d7ccda22610b4ca771a299e707cb0d65c4ec97dc4e6668b45460e0820152600882015461010082015260099091015461012082015290505b92915050565b336112a66000546001600160a01b031690565b6001600160a01b0316146112cc5760405162461bcd60e51b815260040161067890612ca8565b6000805b8381101561172d5760008585838181106112ec576112ec612feb565b90506020020160208101906113019190612a9c565b6001600160a01b03166367e4ac2c6040518163ffffffff1660e01b8152600401600060405180830381865afa15801561133e573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526113669190810190613001565b90506001600160a01b03831661143e57836001600160a01b03166348b3eabc8787600081811061139857611398612feb565b90506020020160208101906113ad9190612a9c565b836000815181106113c0576113c0612feb565b60200260200101516040518363ffffffff1660e01b81526004016113fa9291906001600160a01b0392831681529116602082015260400190565b602060405180830381865afa158015611417573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061143b91906130a7565b92505b60005b8151811015611723576000846001600160a01b031663cbf75c9a89898781811061146d5761146d612feb565b90506020020160208101906114829190612a9c565b85858151811061149457611494612feb565b60200260200101516040518363ffffffff1660e01b81526004016114ce9291906001600160a01b0392831681529116602082015260400190565b61014060405180830381865afa1580156114ec573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061151091906130c4565b80519091506000036116ab576000866001600160a01b03166348b3eabc8a8a8881811061153f5761153f612feb565b90506020020160208101906115549190612a9c565b86868151811061156657611566612feb565b60200260200101516040518363ffffffff1660e01b81526004016115a09291906001600160a01b0392831681529116602082015260400190565b602060405180830381865afa1580156115bd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115e191906130a7565b9050806001600160a01b031663cbf75c9a8a8a8881811061160457611604612feb565b90506020020160208101906116199190612a9c565b86868151811061162b5761162b612feb565b60200260200101516040518363ffffffff1660e01b81526004016116659291906001600160a01b0392831681529116602082015260400190565b61014060405180830381865afa158015611683573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116a791906130c4565b9150505b80511561171a578060e0015165fca32dc55c72036116d057653f28cb71571c60e08201525b61171a8888868181106116e5576116e5612feb565b90506020020160208101906116fa9190612a9c565b84848151811061170c5761170c612feb565b602002602001015183611bad565b50600101611441565b50506001016112d0565b5050505050565b336117476000546001600160a01b031690565b6001600160a01b03161461176d5760405162461bcd60e51b815260040161067890612ca8565b6001600160a01b0381166117b15760405162461bcd60e51b815260206004820152600b60248201526a4f776e657249735a65726f60a81b6044820152606401610678565b61068a81611afc565b6001546001600160a01b038083169116036118175760405162461bcd60e51b815260206004820152601860248201527f50656e64696e674f776e65724469644e6f744368616e676500000000000000006044820152606401610678565b600180546001600160a01b0319166001600160a01b0383169081179091556040517fd6aad444c90d39fb0eee1c6e357a7fad83d63f719ac5f880445a2beb0ff3ab5890600090a250565b60006001600160ff1b038211156118cb5760405162461bcd60e51b815260206004820152602860248201527f53616665436173743a2076616c756520646f65736e27742066697420696e2061604482015267371034b73a191a9b60c11b6064820152608401610678565b5090565b60008215806118dc575081155b156118e957506000611912565b6118f38483612e38565b905082818161190457611904612de6565b049050838111156119125750825b9392505050565b60008183126119285781611912565b5090919050565b60008183136119285781611912565b6000808212156118cb5760405162461bcd60e51b815260206004820181905260248201527f53616665436173743a2076616c7565206d75737420626520706f7369746976656044820152606401610678565b600068056bc75e2d6310000080831161128d5782611912565b60008060006799e8e8e3d530368184126119d357690de0b6b3a76400000000925060019150611a0c565b670de0b6b3a76400006119e585611e29565b6119ef9190612ce1565b905060008113611a00576000611a09565b611a098161193e565b92505b6000858711611a1b5785611a1d565b865b9050600160c41b8110611a395760006001935093505050611abf565b8386026000819003611a4d57505050611abf565b86858281611a5d57611a5d612de6565b04141580611a87575081600160c41b03670de0b6b3a76400008281611a8457611a84612de6565b04115b15611abb5786670de0b6b3a764000083600160c41b030281611aab57611aab612de6565b04945060019350611abf92505050565b5050505b935093915050565b60008080611adb846502e24d16b5a8612e38565b9050808511611aec57846000611af0565b8060015b92509250509250929050565b6000546001600160a01b03808316911603611b4d5760405162461bcd60e51b81526020600482015260116024820152704f776e65724469644e6f744368616e676560781b6044820152606401610678565b600080546001600160a01b0319166001600160a01b038316908117825560405190917f04dba622d284ed0014ee4b9a6a68386be1a4c08a4913ae272de89199cc68616391a26001546001600160a01b03161561068a5761068a60006117ba565b8051670de0b6b3a7640000906000121580611bc9575081518113155b15611be7576040516313e9c00360e21b815260040160405180910390fd5b81516020830151131580611bff575080826020015112155b15611c1d576040516339bda99160e11b815260040160405180910390fd5b60008260400151131580611c3657508151604083015112155b15611c5457604051635c65494d60e01b815260040160405180910390fd5b600082606001511215611c7a5760405163fe06781560e01b815260040160405180910390fd5b600082608001511215611ca0576040516320d12cb560e21b815260040160405180910390fd5b60008260a001511215611cc9576040516001627ddb5960e01b0319815260040160405180910390fd5b60008260c001511215611cef57604051634e435a2160e01b815260040160405180910390fd5b60008260e001511215611d15576040516378a8371160e01b815260040160405180910390fd5b60008261010001511215611d3c576040516330eecc6b60e21b815260040160405180910390fd5b60008261012001511215611d6357604051630266493760e31b815260040160405180910390fd5b6001600160a01b03808516600081815260026020818152604080842095891680855295825292839020875181559087015160018201558287015191810191909155606086015160038201556080860151600482015560a0860151600582015560c0860151600682015560e086015160078201556101008601516008820155610120860151600990910155517ff254631d9ea3e3ab061b1c56e1215a268abf5ff28a460b255f308aac112df45890611e1b908690612b47565b60405180910390a350505050565b600068023f2fa8f6da5b9d3119821215611e4557506000919050565b6804cf46d8192b672ecc8212611e5a57600080fd5b6714057b7ef767814f8202611912670de0b6b3a76400006706f05b59d3b200008301055b600080821215611ed25768033dd1780914b9711419821215611ea257506000919050565b611eae82600003611e7e565b6ec097ce7bc90715b34b9f100000000081611ecb57611ecb612de6565b0592915050565b6806f05b59d3b20000008212611ee757600080fd5b670de0b6b3a7640000608083901b04611912816001607f1b80821615611f1e5770016a09e667f3bcc908b2fb1366ea957d3e0260801c5b6001607e1b821615611f41577001306fe0a31b7152de8d5a46305c85eded0260801c5b6001607d1b821615611f64577001172b83c7d517adcdf7c8c50eb14a79200260801c5b6001607c1b821615611f875770010b5586cf9890f6298b92b71842a983640260801c5b6001607b1b821615611faa577001059b0d31585743ae7c548eb68ca417fe0260801c5b6001607a1b821615611fcd57700102c9a3e778060ee6f7caca4f7a29bde90260801c5b600160791b821615611ff05770010163da9fb33356d84a66ae336dcdfa400260801c5b600160781b82161561201357700100b1afa5abcbed6129ab13ec11dc95440260801c5b600160771b8216156120365770010058c86da1c09ea1ff19d294cf2f679c0260801c5b600160761b821615612059577001002c605e2e8cec506d21bfc89a23a0110260801c5b600160751b82161561207c57700100162f3904051fa128bca9c55c31e5e00260801c5b600160741b82161561209f577001000b175effdc76ba38e31671ca9397260260801c5b600160731b8216156120c257700100058ba01fb9f96d6cacd4b180917c3e0260801c5b600160721b8216156120e55770010002c5cc37da9491d0985c348c68e7b40260801c5b600160711b821615612108577001000162e525ee054754457d59952920270260801c5b600160701b82161561212b5770010000b17255775c040618bf4a4ade83fd0260801c5b6001606f1b82161561214e577001000058b91b5bc9ae2eed81e9b7d4cfac0260801c5b6001606e1b82161561217157700100002c5c89d5ec6ca4d7c8acc017b7ca0260801c5b6001606d1b8216156121945770010000162e43f4f831060e02d839a9d16d0260801c5b6001606c1b8216156121b757700100000b1721bcfc99d9f890ea069117630260801c5b6001606b1b8216156121da5770010000058b90cf1e6d97f9ca14dbcc16290260801c5b6001606a1b8216156121fd577001000002c5c863b73f016468f6bac5ca2c0260801c5b600160691b82161561222057700100000162e430e5a18f6119e3c02282a60260801c5b600160681b821615612243577001000000b1721835514b86e6d96efd1bff0260801c5b600160671b82161561226657700100000058b90c0b48c6be5df846c5b2f00260801c5b600160661b8216156122895770010000002c5c8601cc6b9e94213c72737b0260801c5b600160651b8216156122ac577001000000162e42fff037df38aa2b219f070260801c5b600160641b8216156122cf5770010000000b17217fba9c739aa5819f44fa0260801c5b600160631b8216156122f2577001000000058b90bfcdee5acd3c1cedc8240260801c5b600160621b82161561231557700100000002c5c85fe31f35a6a30da1be510260801c5b600160611b8216156123385770010000000162e42ff0999ce3541b9fffd00260801c5b600160601b82161561235b57700100000000b17217f80f4ef5aadda455540260801c5b6001605f1b82161561237e5770010000000058b90bfbf8479bd5a81b51ae0260801c5b6001605e1b8216156123a1577001000000002c5c85fdf84bd62ae30a74cd0260801c5b6001605d1b8216156123c457700100000000162e42fefb2fed257559bdaa0260801c5b6001605c1b8216156123e7577001000000000b17217f7d5a7716bba4a9af0260801c5b6001605b1b82161561240a57700100000000058b90bfbe9ddbac5e109ccf0260801c5b6001605a1b82161561242d5770010000000002c5c85fdf4b15de6f17eb0e0260801c5b600160591b821615612450577001000000000162e42fefa494f1478fde050260801c5b600160581b8216156124735770010000000000b17217f7d20cf927c8e94d0260801c5b600160571b821615612496577001000000000058b90bfbe8f71cb4e4b33e0260801c5b600160561b8216156124b957700100000000002c5c85fdf477b662b269460260801c5b600160551b8216156124dc5770010000000000162e42fefa3ae53369388d0260801c5b600160541b8216156124ff57700100000000000b17217f7d1d351a389d410260801c5b600160531b8216156125225770010000000000058b90bfbe8e8b2d3d4edf0260801c5b600160521b821615612545577001000000000002c5c85fdf4741bea6e77f0260801c5b600160511b82161561256857700100000000000162e42fefa39fe95583c30260801c5b600160501b82161561258b577001000000000000b17217f7d1cfb72b45e30260801c5b69800000000000000000008216156125b457700100000000000058b90bfbe8e7cc35c3f20260801c5b69400000000000000000008216156125dd5770010000000000002c5c85fdf473e242ea390260801c5b6920000000000000000000821615612606577001000000000000162e42fefa39f02b772c0260801c5b691000000000000000000082161561262f5770010000000000000b17217f7d1cf7d83c1a0260801c5b6908000000000000000000821615612658577001000000000000058b90bfbe8e7bdcbe2e0260801c5b690400000000000000000082161561268157700100000000000002c5c85fdf473dea871f0260801c5b69020000000000000000008216156126aa5770010000000000000162e42fefa39ef44d920260801c5b69010000000000000000008216156126d357700100000000000000b17217f7d1cf79e9490260801c5b688000000000000000008216156126fb5770010000000000000058b90bfbe8e7bce5450260801c5b68400000000000000000821615612723577001000000000000002c5c85fdf473de6eca0260801c5b6820000000000000000082161561274b57700100000000000000162e42fefa39ef366f0260801c5b68100000000000000000821615612773577001000000000000000b17217f7d1cf79afa0260801c5b6808000000000000000082161561279b57700100000000000000058b90bfbe8e7bcd6e0260801c5b680400000000000000008216156127c35770010000000000000002c5c85fdf473de6b30260801c5b680200000000000000008216156127eb577001000000000000000162e42fefa39ef3590260801c5b680100000000000000008216156128135770010000000000000000b17217f7d1cf79ac0260801c5b6001608083901c011b61128d81670de0b6b3a7640000600160801b6000808060001985870985870292508281108382030391505080600003612867576000841161285c57600080fd5b508290049050611912565b80841161287357600080fd5b60008486880960026001871981018816978890046003810283188082028403028082028403028082028403028082028403028082028403029081029092039091026000889003889004909101858311909403939093029303949094049190911702949350505050565b634e487b7160e01b600052604160045260246000fd5b604051610140810167ffffffffffffffff81118282101715612916576129166128dc565b60405290565b604051601f8201601f1916810167ffffffffffffffff81118282101715612945576129456128dc565b604052919050565b6000610140828403121561296057600080fd5b6129686128f2565b9050813581526020820135602082015260408201356040820152606082013560608201526080820135608082015260a082013560a082015260c082013560c082015260e082013560e082015261010080830135818301525061012080830135818301525092915050565b60008060008060006101c086880312156129eb57600080fd5b6129f5878761294d565b9761014087013597506101608701359661018081013596506101a00135945092505050565b6001600160a01b038116811461068a57600080fd5b60008060408385031215612a4257600080fd5b8235612a4d81612a1a565b946020939093013593505050565b600080600060608486031215612a7057600080fd5b8335612a7b81612a1a565b92506020840135612a8b81612a1a565b929592945050506040919091013590565b600060208284031215612aae57600080fd5b813561191281612a1a565b6000806000838503610180811215612ad057600080fd5b8435612adb81612a1a565b93506020850135612aeb81612a1a565b9250610140603f1982011215612b0057600080fd5b506040840190509250925092565b60008060408385031215612b2157600080fd5b8235612b2c81612a1a565b91506020830135612b3c81612a1a565b809150509250929050565b600061014082019050825182526020830151602083015260408301516040830152606083015160608301526080830151608083015260a083015160a083015260c083015160c083015260e083015160e083015261010080840151818401525061012080840151818401525092915050565b600080600060408486031215612bcd57600080fd5b833567ffffffffffffffff80821115612be557600080fd5b818601915086601f830112612bf957600080fd5b813581811115612c0857600080fd5b8760208260051b8501011115612c1d57600080fd5b60209283019550935050840135612c3381612a1a565b809150509250925092565b600060608284031215612c5057600080fd5b6040516060810167ffffffffffffffff8282108183111715612c7457612c746128dc565b816040528451835260208501516020840152604085015191508082168214612c9b57600080fd5b5060408201529392505050565b60208082526009908201526827b7363ca7bbb732b960b91b604082015260600190565b634e487b7160e01b600052601160045260246000fd5b60008083128015600160ff1b850184121615612cff57612cff612ccb565b6001600160ff1b0384018313811615612d1a57612d1a612ccb565b50500390565b60006001600160ff1b0381841382841380821686840486111615612d4657612d46612ccb565b600160ff1b6000871282811687830589121615612d6557612d65612ccb565b60008712925087820587128484161615612d8157612d81612ccb565b87850587128184161615612d9757612d97612ccb565b505050929093029392505050565b600080821280156001600160ff1b0384900385131615612dc757612dc7612ccb565b600160ff1b8390038412811615612de057612de0612ccb565b50500190565b634e487b7160e01b600052601260045260246000fd5b600082612e1957634e487b7160e01b600052601260045260246000fd5b600160ff1b821460001984141615612e3357612e33612ccb565b500590565b6000816000190483118215151615612e5257612e52612ccb565b500290565b80825b6001808611612e695750611abf565b6001600160ff1b03829004821115612e8357612e83612ccb565b80861615612e9057918102915b9490941c938002612e5a565b6000828015612eb25760018114612ebc57612ec5565b600191505061128d565b8291505061128d565b5081612ed35750600061128d565b50600160008213808214612eec578015612f0b57612f25565b6001600160ff1b03839004831115612f0657612f06612ccb565b612f25565b6001600160ff1b03839005831215612f2557612f25612ccb565b5080831615612f315750805b612f418360011c83840283612e57565b600082136001600160ff1b0382900483111615612f6057612f60612ccb565b60008212600160ff1b82900583121615612f7c57612f7c612ccb565b029392505050565b600061191260ff841683612e9c565b6000825160005b81811015612fb45760208186018101518583015201612f9a565b81811115612fc3576000828501525b509190910192915050565b60006101408284031215612fe157600080fd5b611912838361294d565b634e487b7160e01b600052603260045260246000fd5b6000602080838503121561301457600080fd5b825167ffffffffffffffff8082111561302c57600080fd5b818501915085601f83011261304057600080fd5b815181811115613052576130526128dc565b8060051b915061306384830161291c565b818152918301840191848101908884111561307d57600080fd5b938501935b83851015610633578451925061309783612a1a565b8282529385019390850190613082565b6000602082840312156130b957600080fd5b815161191281612a1a565b600061014082840312156130d757600080fd5b6130df6128f2565b825181526020830151602082015260408301516040820152606083015160608201526080830151608082015260a083015160a082015260c083015160c082015260e083015160e0820152610100808401518183015250610120808401518183015250809150509291505056fea2646970667358221220ac570d5b75aaadac4524f8ca53f6661aee67b7323169be605352e1812b3ae42264736f6c634300080d0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000000000000000000000000000000b1a2bc2ec5000000000000000000000000000000000000000000000000000000c7d713b49da000000000000000000000000000000000000000000000000000006f05b59d3b2000000000000000000000000000000000000000000000000000000000000000599a3000000000000000000000000000000000000000000000000000000dd7d86d0190000000000000000000000000000000000000000000000000000000ec41a0de00000000000000000000000000000000000000000000000000000000017a029b000000000000000000000000000000000000000000000000000003f28cb71571c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1f03b7b0ebf84e9b9f62a1db40f1efb8faa7d22
-----Decoded View---------------
Arg [0] : _config (tuple):
Arg [1] : uopt (int256): 800000000000000000
Arg [2] : ucrit (int256): 900000000000000000
Arg [3] : ulow (int256): 500000000000000000
Arg [4] : ki (int256): 367011
Arg [5] : kcrit (int256): 951293759513
Arg [6] : klow (int256): 63419583968
Arg [7] : klin (int256): 396372400
Arg [8] : beta (int256): 69444444444444
Arg [9] : ri (int256): 0
Arg [10] : Tcrit (int256): 0
Arg [1] : _owner (address): 0xe1F03b7B0eBf84e9B9f62a1dB40f1Efb8FaA7d22
-----Encoded View---------------
11 Constructor Arguments found :
Arg [0] : 0000000000000000000000000000000000000000000000000b1a2bc2ec500000
Arg [1] : 0000000000000000000000000000000000000000000000000c7d713b49da0000
Arg [2] : 00000000000000000000000000000000000000000000000006f05b59d3b20000
Arg [3] : 00000000000000000000000000000000000000000000000000000000000599a3
Arg [4] : 000000000000000000000000000000000000000000000000000000dd7d86d019
Arg [5] : 0000000000000000000000000000000000000000000000000000000ec41a0de0
Arg [6] : 0000000000000000000000000000000000000000000000000000000017a029b0
Arg [7] : 00000000000000000000000000000000000000000000000000003f28cb71571c
Arg [8] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [9] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [10] : 000000000000000000000000e1f03b7b0ebf84e9b9f62a1db40f1efb8faa7d22
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 34 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.