Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
Latest 25 from a total of 26 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Transfer Ownersh... | 17926486 | 476 days ago | IN | 0 ETH | 0.00057984 | ||||
Set Config | 17868821 | 484 days ago | IN | 0 ETH | 0.00372038 | ||||
Set Config | 17868820 | 484 days ago | IN | 0 ETH | 0.00360472 | ||||
Set Config | 17834943 | 489 days ago | IN | 0 ETH | 0.01441237 | ||||
Set Config | 17834942 | 489 days ago | IN | 0 ETH | 0.014639 | ||||
Set Config | 17834506 | 489 days ago | IN | 0 ETH | 0.00433176 | ||||
Set Config | 17834505 | 489 days ago | IN | 0 ETH | 0.0042383 | ||||
Set Config | 17834071 | 489 days ago | IN | 0 ETH | 0.00316185 | ||||
Set Config | 17834070 | 489 days ago | IN | 0 ETH | 0.00327538 | ||||
Set Config | 17823097 | 491 days ago | IN | 0 ETH | 0.00425653 | ||||
Set Config | 17823096 | 491 days ago | IN | 0 ETH | 0.00406582 | ||||
Set Config | 17821971 | 491 days ago | IN | 0 ETH | 0.00707082 | ||||
Set Config | 17821970 | 491 days ago | IN | 0 ETH | 0.00746784 | ||||
Set Config | 17820622 | 491 days ago | IN | 0 ETH | 0.00665571 | ||||
Set Config | 17820621 | 491 days ago | IN | 0 ETH | 0.00665931 | ||||
Set Config | 17820254 | 491 days ago | IN | 0 ETH | 0.00467037 | ||||
Set Config | 17820253 | 491 days ago | IN | 0 ETH | 0.00416008 | ||||
Set Config | 17819787 | 491 days ago | IN | 0 ETH | 0.00385319 | ||||
Set Config | 17819786 | 491 days ago | IN | 0 ETH | 0.00393616 | ||||
Set Config | 17819026 | 491 days ago | IN | 0 ETH | 0.00378273 | ||||
Set Config | 17819025 | 491 days ago | IN | 0 ETH | 0.00332974 | ||||
Set Config | 17814603 | 492 days ago | IN | 0 ETH | 0.00804569 | ||||
Set Config | 17814602 | 492 days ago | IN | 0 ETH | 0.00738251 | ||||
Set Config | 17813383 | 492 days ago | IN | 0 ETH | 0.00582889 | ||||
Set Config | 17813382 | 492 days ago | IN | 0 ETH | 0.00601481 |
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
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) && _owner != msg.sender) { 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/EasyMathV2.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] abstract 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 = 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; } 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 = 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 (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; /// @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
[{"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
60806040523480156200001157600080fd5b5060405162003825380380620038258339810160408190526200003491620005e4565b8162000040336200008a565b6200004e6000808362000147565b506001600160a01b038116158015906200007157506001600160a01b0381163314155b15620000825762000082816200043d565b505062000694565b6000546001600160a01b03808316911603620000e15760405162461bcd60e51b81526020600482015260116024820152704f776e65724469644e6f744368616e676560781b60448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b038316908117825560405190917f04dba622d284ed0014ee4b9a6a68386be1a4c08a4913ae272de89199cc68616391a26001546001600160a01b0316156200014457620001446000620004e6565b50565b8051670de0b6b3a764000090600012158062000164575081518113155b1562000183576040516313e9c00360e21b815260040160405180910390fd5b815160208301511315806200019c575080826020015112155b15620001bb576040516339bda99160e11b815260040160405180910390fd5b60008260400151131580620001d557508151604083015112155b15620001f457604051635c65494d60e01b815260040160405180910390fd5b6000826060015112156200021b5760405163fe06781560e01b815260040160405180910390fd5b60008260800151121562000242576040516320d12cb560e21b815260040160405180910390fd5b60008260a0015112156200026c576040516001627ddb5960e01b0319815260040160405180910390fd5b60008260c0015112156200029357604051634e435a2160e01b815260040160405180910390fd5b60008260e001511215620002ba576040516378a8371160e01b815260040160405180910390fd5b60008261010001511215620002e2576040516330eecc6b60e21b815260040160405180910390fd5b600082610120015112156200030a57604051630266493760e31b815260040160405180910390fd5b6001600160a01b03808516600081815260026020818152604080842095891680855295825292839020875181559087015160018201558287015191810191909155606086015160038201556080860151600482015560a0860151600582015560c0860151600682015560e086015160078201556101008601516008820155610120860151600990910155517ff254631d9ea3e3ab061b1c56e1215a268abf5ff28a460b255f308aac112df458906200042f908690600061014082019050825182526020830151602083015260408301516040830152606083015160608301526080830151608083015260a083015160a083015260c083015160c083015260e083015160e083015261010080840151818401525061012080840151818401525092915050565b60405180910390a350505050565b33620004516000546001600160a01b031690565b6001600160a01b031614620004955760405162461bcd60e51b815260206004820152600960248201526827b7363ca7bbb732b960b91b6044820152606401620000d8565b6001600160a01b038116620004db5760405162461bcd60e51b815260206004820152600b60248201526a4f776e657249735a65726f60a81b6044820152606401620000d8565b62000144816200008a565b6001546001600160a01b03808316911603620005455760405162461bcd60e51b815260206004820152601860248201527f50656e64696e674f776e65724469644e6f744368616e676500000000000000006044820152606401620000d8565b600180546001600160a01b0319166001600160a01b0383169081179091556040517fd6aad444c90d39fb0eee1c6e357a7fad83d63f719ac5f880445a2beb0ff3ab5890600090a250565b60405161014081016001600160401b0381118282101715620005c157634e487b7160e01b600052604160045260246000fd5b60405290565b80516001600160a01b0381168114620005df57600080fd5b919050565b600080828403610160811215620005fa57600080fd5b610140808212156200060b57600080fd5b620006156200058f565b9150845182526020850151602083015260408501516040830152606085015160608301526080850151608083015260a085015160a083015260c085015160c083015260e085015160e083015261010080860151818401525061012080860151818401525081935062000689818601620005c7565b925050509250929050565b61318180620006a46000396000f3fe608060405234801561001057600080fd5b506004361061014d5760003560e01c806374a3e924116100c3578063c42401f11161007c578063c42401f1146102e5578063c63de8bc146102fa578063cbf75c9a1461030d578063e076a551146103c6578063e30c3978146103d7578063f2fde38b146103e857600080fd5b806374a3e9241461026357806379ba50971461027657806381b51e0c1461027e5780638da5cb5b1461028d578063b1e01765146102b2578063bbdcbed6146102c557600080fd5b80633278c694116101155780633278c694146101e75780633ced7d0d146101fc57806344552b5d1461020f5780636bcc8216146102175780636e1a414014610226578063715018a61461025b57600080fd5b8063023279ce1461015257806303dc12fc14610185578063071962ff146101a6578063109a006e146101b957806311e5152b146101c4575b600080fd5b6101656101603660046129d2565b6103fb565b604080519384526020840192909252908201526060015b60405180910390f35b610198610193366004612a2f565b61041f565b60405190815260200161017c565b6101986101b4366004612a5b565b6104f6565b610198600160c41b81565b6101d76101d2366004612a5b565b610599565b604051901515815260200161017c565b6101fa6101f5366004612a9c565b61063f565b005b61019861020a3660046129d2565b61068d565b6101fa61090f565b610198670de0b6b3a764000081565b6102396102343660046129d2565b610954565b604080519485526020850193909352918301521515606082015260800161017c565b6101fa610dd5565b6101fa610271366004612ab9565b610e18565b6101fa610f04565b6101986799e8e8e3d530368181565b6000546001600160a01b03165b6040516001600160a01b03909116815260200161017c565b6101986102c0366004612a5b565b610f6b565b6102d86102d3366004612b0e565b611011565b60405161017c9190612b47565b60405163c42401f160e01b815260200161017c565b6101fa610308366004612bb8565b611293565b61037c61031b366004612b0e565b600260205281600052604060002060205280600052604060002060009150915050806000015490806001015490806002015490806003015490806004015490806005015490806006015490806007015490806008015490806009015490508a565b604080519a8b5260208b0199909952978901969096526060880194909452608087019290925260a086015260c085015260e08401526101008301526101208201526101400161017c565b610198690de0b6b3a7640000000081565b6001546001600160a01b031661029a565b6101fa6103f6366004612a9c565b611734565b600080600061040d8888888888610954565b50919a90995090975095505050505050565b604051631f0f875560e31b81526001600160a01b038316600482015260009033908290829063f87c3aa890602401606060405180830381865afa15801561046a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061048e9190612c3e565b6001600160a01b038084166000908152600260209081526040808320938a168352929052209091506104df6104c38488611011565b83516020850151604086015167ffffffffffffffff16896103fb565b600984015560089092019190915595945050505050565b604051631f0f875560e31b81526001600160a01b038381166004830152600091829186169063f87c3aa890602401606060405180830381865afa158015610541573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105659190612c3e565b90506105906105748686611011565b82516020840151604085015167ffffffffffffffff168761068d565b95945050505050565b604051631f0f875560e31b81526001600160a01b038381166004830152600091829186169063f87c3aa890602401606060405180830381865afa1580156105e4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106089190612c3e565b90506106336106178686611011565b82516020840151604085015167ffffffffffffffff1687610954565b98975050505050505050565b336106526000546001600160a01b031690565b6001600160a01b0316146106815760405162461bcd60e51b815260040161067890612ca8565b60405180910390fd5b61068a816117ba565b50565b6000818311156106b05760405163d22806e360e01b815260040160405180910390fd5b60006040518060e001604052806000815260200160008152602001600081526020016000815260200160008152602001600081526020016000151581525090506106fd8787878787610954565b15801560c08601529250610718915050576000915050610590565b610723848403611861565b815261074061073b670de0b6b3a764000088886118cf565b611861565b6020808301829052670de0b6b3a7640000604084015288015112156107e4578060400151876020015182602001516107789190612ce1565b6040830151835160e08b015161078e9190612d20565b8a610120015185604001516107a39190612da5565b6107ad9190612da5565b8a608001516107bc9190612d20565b6107c69190612dfc565b6107d09190612d20565b6107da9190612dfc565b6060820152610826565b61082060008260400151896040015184602001516108029190612ce1565b8a60a001516108119190612d20565b61081b9190612dfc565b611919565b60608201525b806040015181602001518860c0015161083f9190612d20565b6108499190612dfc565b6080820181905261010088015161085f9161192f565b60a082015260408101518151885160208401516108bd93929161088191612ce1565b8a606001516108909190612d20565b61089a9190612d20565b6108a49190612dfc565b8260a001516108b39190612da5565b826080015161192f565b60a0820181905260608201516108e9916108e4916108da91612da5565b836080015161192f565b61193e565b91506108f96301e1338083612e38565b915061090482611990565b979650505050505050565b336109226000546001600160a01b031690565b6001600160a01b0316146109485760405162461bcd60e51b815260040161067890612ca8565b61095260006117ba565b565b60008060008088610100015192508861012001519150600060405180610140016040528060008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152509050858711156109df5760405163d22806e360e01b815260040160405180910390fd5b6109ea878703611861565b8152670de0b6b3a7640000610a0361073b828c8c6118cf565b61012083018190528b518291610a199190612ce1565b8c60600151610a289190612d20565b610a329190612dfc565b6020808401919091528b01516101208301511315610b1c57808b60200151836101200151610a609190612ce1565b82610a6b8782612da5565b8e60800151610a7a9190612d20565b610a849190612dfc565b610a8e9190612d20565b610a989190612dfc565b604083015260208b01516101208301518291610ab391612ce1565b828d60e001518e60800151610ac89190612d20565b610ad29190612dfc565b610adc9190612d20565b610ae69190612dfc565b8260200151610af59190612da5565b6060830152815160e08c0151610b0b9190612d20565b610b159085612da5565b9350610b7f565b610b466000828d60400151856101200151610b379190612ce1565b8e60a001516108119190612d20565b604083015260208201516060830152815160e08c0151610b7c91600091610b6d9190612d20565b610b779087612ce1565b61192f565b93505b808261012001518c60c00151610b959190612d20565b610b9f9190612dfc565b60a08301819052610bb190869061192f565b9450816040015185610bc39190612da5565b608083015281516060830151610bd99190612d20565b8260800151610be89190612da5565b60c083015260a0820151608083015112801590610c0d57508160a001518260c0015112155b15610c4957815160c0830151608084015160029291610c2b91612da5565b610c359190612d20565b610c3f9190612dfc565b60e0830152610d53565b8160a001518260800151128015610c6757508160a001518260c00151125b15610c7d57815160a0830151610c3f9190612d20565b8160a00151826080015112158015610c9c57508160a001518260c00151125b15610cf7576002826060015160028460a001518560800151610cbe9190612ce1565b610cc89190612f84565b610cd29190612dfc565b610cdc9190612dfc565b825160a0840151610ced9190612d20565b610c3f9190612ce1565b6002826060015160028460a001518560c00151610d149190612ce1565b610d1e9190612f84565b610d289190612dfc565b610d329190612dfc565b825160a0840151610d439190612d20565b610d4d9190612da5565b60e08301525b81516020830151610d7b91610d6791612d20565b610d719087612da5565b8360a0015161192f565b9450610d8c8a8a8460e001516119a9565b83519197509350600090610daa908890610da59061193e565b611ac7565b90975090508380610db85750805b15610dc65760009550600094505b50505095509550955095915050565b33610de86000546001600160a01b031690565b6001600160a01b031614610e0e5760405162461bcd60e51b815260040161067890612ca8565b6109526000611afc565b33610e2b6000546001600160a01b031690565b6001600160a01b031614610e515760405162461bcd60e51b815260040161067890612ca8565b6040516001600160a01b03838116602483015284169060440160408051601f198184030181529181526020820180516001600160e01b0316639198e51560e01b17905251610e9f9190612f93565b6000604051808303816000865af19150503d8060008114610edc576040519150601f19603f3d011682016040523d82523d6000602084013e610ee1565b606091505b505050610eff838383803603810190610efa9190612fce565b611bad565b505050565b6001546001600160a01b03163314610f515760405162461bcd60e51b815260206004820152601060248201526f27b7363ca832b73234b733a7bbb732b960811b6044820152606401610678565b610952610f666001546001600160a01b031690565b611afc565b604051631f0f875560e31b81526001600160a01b038381166004830152600091829186169063f87c3aa890602401606060405180830381865afa158015610fb6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fda9190612c3e565b9050611005610fe98686611011565b82516020840151604085015167ffffffffffffffff16876103fb565b50909695505050505050565b611067604051806101400160405280600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b6001600160a01b03808416600090815260026020908152604080832093861683529290522080541561110857604080516101408101825282548152600183015460208201526002830154918101919091526003820154606082015260048201546080820152600582015460a0820152600682015460c0820152600782015460e08201526008820154610100820152600990910154610120820152905061128d565b600080527fac33ff75c19e70fe83507db0d683fd3465c996598dc972688b7ace676c89077b602090815260408051610140810182527f6ee3efecae883df2d7ccda22610b4ca771a299e707cb0d65c4ec97dc4e6668ad5481527f6ee3efecae883df2d7ccda22610b4ca771a299e707cb0d65c4ec97dc4e6668ae54928101929092527f6ee3efecae883df2d7ccda22610b4ca771a299e707cb0d65c4ec97dc4e6668af54908201527f6ee3efecae883df2d7ccda22610b4ca771a299e707cb0d65c4ec97dc4e6668b05460608201527f6ee3efecae883df2d7ccda22610b4ca771a299e707cb0d65c4ec97dc4e6668b15460808201527f6ee3efecae883df2d7ccda22610b4ca771a299e707cb0d65c4ec97dc4e6668b25460a08201527f6ee3efecae883df2d7ccda22610b4ca771a299e707cb0d65c4ec97dc4e6668b35460c08201527f6ee3efecae883df2d7ccda22610b4ca771a299e707cb0d65c4ec97dc4e6668b45460e0820152600882015461010082015260099091015461012082015290505b92915050565b336112a66000546001600160a01b031690565b6001600160a01b0316146112cc5760405162461bcd60e51b815260040161067890612ca8565b6000805b8381101561172d5760008585838181106112ec576112ec612feb565b90506020020160208101906113019190612a9c565b6001600160a01b03166367e4ac2c6040518163ffffffff1660e01b8152600401600060405180830381865afa15801561133e573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526113669190810190613001565b90506001600160a01b03831661143e57836001600160a01b03166348b3eabc8787600081811061139857611398612feb565b90506020020160208101906113ad9190612a9c565b836000815181106113c0576113c0612feb565b60200260200101516040518363ffffffff1660e01b81526004016113fa9291906001600160a01b0392831681529116602082015260400190565b602060405180830381865afa158015611417573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061143b91906130a7565b92505b60005b8151811015611723576000846001600160a01b031663cbf75c9a89898781811061146d5761146d612feb565b90506020020160208101906114829190612a9c565b85858151811061149457611494612feb565b60200260200101516040518363ffffffff1660e01b81526004016114ce9291906001600160a01b0392831681529116602082015260400190565b61014060405180830381865afa1580156114ec573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061151091906130c4565b80519091506000036116ab576000866001600160a01b03166348b3eabc8a8a8881811061153f5761153f612feb565b90506020020160208101906115549190612a9c565b86868151811061156657611566612feb565b60200260200101516040518363ffffffff1660e01b81526004016115a09291906001600160a01b0392831681529116602082015260400190565b602060405180830381865afa1580156115bd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115e191906130a7565b9050806001600160a01b031663cbf75c9a8a8a8881811061160457611604612feb565b90506020020160208101906116199190612a9c565b86868151811061162b5761162b612feb565b60200260200101516040518363ffffffff1660e01b81526004016116659291906001600160a01b0392831681529116602082015260400190565b61014060405180830381865afa158015611683573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116a791906130c4565b9150505b80511561171a578060e0015165fca32dc55c72036116d057653f28cb71571c60e08201525b61171a8888868181106116e5576116e5612feb565b90506020020160208101906116fa9190612a9c565b84848151811061170c5761170c612feb565b602002602001015183611bad565b50600101611441565b50506001016112d0565b5050505050565b336117476000546001600160a01b031690565b6001600160a01b03161461176d5760405162461bcd60e51b815260040161067890612ca8565b6001600160a01b0381166117b15760405162461bcd60e51b815260206004820152600b60248201526a4f776e657249735a65726f60a81b6044820152606401610678565b61068a81611afc565b6001546001600160a01b038083169116036118175760405162461bcd60e51b815260206004820152601860248201527f50656e64696e674f776e65724469644e6f744368616e676500000000000000006044820152606401610678565b600180546001600160a01b0319166001600160a01b0383169081179091556040517fd6aad444c90d39fb0eee1c6e357a7fad83d63f719ac5f880445a2beb0ff3ab5890600090a250565b60006001600160ff1b038211156118cb5760405162461bcd60e51b815260206004820152602860248201527f53616665436173743a2076616c756520646f65736e27742066697420696e2061604482015267371034b73a191a9b60c11b6064820152608401610678565b5090565b60008215806118dc575081155b156118e957506000611912565b6118f38483612e38565b905082818161190457611904612de6565b049050838111156119125750825b9392505050565b60008183126119285781611912565b5090919050565b60008183136119285781611912565b6000808212156118cb5760405162461bcd60e51b815260206004820181905260248201527f53616665436173743a2076616c7565206d75737420626520706f7369746976656044820152606401610678565b600068056bc75e2d6310000080831161128d5782611912565b60008060006799e8e8e3d530368184126119d357690de0b6b3a76400000000925060019150611a0c565b670de0b6b3a76400006119e585611e29565b6119ef9190612ce1565b905060008113611a00576000611a09565b611a098161193e565b92505b6000858711611a1b5785611a1d565b865b9050600160c41b8110611a395760006001935093505050611abf565b8386026000819003611a4d57505050611abf565b86858281611a5d57611a5d612de6565b04141580611a87575081600160c41b03670de0b6b3a76400008281611a8457611a84612de6565b04115b15611abb5786670de0b6b3a764000083600160c41b030281611aab57611aab612de6565b04945060019350611abf92505050565b5050505b935093915050565b60008080611adb846502e24d16b5a8612e38565b9050808511611aec57846000611af0565b8060015b92509250509250929050565b6000546001600160a01b03808316911603611b4d5760405162461bcd60e51b81526020600482015260116024820152704f776e65724469644e6f744368616e676560781b6044820152606401610678565b600080546001600160a01b0319166001600160a01b038316908117825560405190917f04dba622d284ed0014ee4b9a6a68386be1a4c08a4913ae272de89199cc68616391a26001546001600160a01b03161561068a5761068a60006117ba565b8051670de0b6b3a7640000906000121580611bc9575081518113155b15611be7576040516313e9c00360e21b815260040160405180910390fd5b81516020830151131580611bff575080826020015112155b15611c1d576040516339bda99160e11b815260040160405180910390fd5b60008260400151131580611c3657508151604083015112155b15611c5457604051635c65494d60e01b815260040160405180910390fd5b600082606001511215611c7a5760405163fe06781560e01b815260040160405180910390fd5b600082608001511215611ca0576040516320d12cb560e21b815260040160405180910390fd5b60008260a001511215611cc9576040516001627ddb5960e01b0319815260040160405180910390fd5b60008260c001511215611cef57604051634e435a2160e01b815260040160405180910390fd5b60008260e001511215611d15576040516378a8371160e01b815260040160405180910390fd5b60008261010001511215611d3c576040516330eecc6b60e21b815260040160405180910390fd5b60008261012001511215611d6357604051630266493760e31b815260040160405180910390fd5b6001600160a01b03808516600081815260026020818152604080842095891680855295825292839020875181559087015160018201558287015191810191909155606086015160038201556080860151600482015560a0860151600582015560c0860151600682015560e086015160078201556101008601516008820155610120860151600990910155517ff254631d9ea3e3ab061b1c56e1215a268abf5ff28a460b255f308aac112df45890611e1b908690612b47565b60405180910390a350505050565b600068023f2fa8f6da5b9d3119821215611e4557506000919050565b6804cf46d8192b672ecc8212611e5a57600080fd5b6714057b7ef767814f8202611912670de0b6b3a76400006706f05b59d3b200008301055b600080821215611ed25768033dd1780914b9711419821215611ea257506000919050565b611eae82600003611e7e565b6ec097ce7bc90715b34b9f100000000081611ecb57611ecb612de6565b0592915050565b6806f05b59d3b20000008212611ee757600080fd5b670de0b6b3a7640000608083901b04611912816001607f1b80821615611f1e5770016a09e667f3bcc908b2fb1366ea957d3e0260801c5b6001607e1b821615611f41577001306fe0a31b7152de8d5a46305c85eded0260801c5b6001607d1b821615611f64577001172b83c7d517adcdf7c8c50eb14a79200260801c5b6001607c1b821615611f875770010b5586cf9890f6298b92b71842a983640260801c5b6001607b1b821615611faa577001059b0d31585743ae7c548eb68ca417fe0260801c5b6001607a1b821615611fcd57700102c9a3e778060ee6f7caca4f7a29bde90260801c5b600160791b821615611ff05770010163da9fb33356d84a66ae336dcdfa400260801c5b600160781b82161561201357700100b1afa5abcbed6129ab13ec11dc95440260801c5b600160771b8216156120365770010058c86da1c09ea1ff19d294cf2f679c0260801c5b600160761b821615612059577001002c605e2e8cec506d21bfc89a23a0110260801c5b600160751b82161561207c57700100162f3904051fa128bca9c55c31e5e00260801c5b600160741b82161561209f577001000b175effdc76ba38e31671ca9397260260801c5b600160731b8216156120c257700100058ba01fb9f96d6cacd4b180917c3e0260801c5b600160721b8216156120e55770010002c5cc37da9491d0985c348c68e7b40260801c5b600160711b821615612108577001000162e525ee054754457d59952920270260801c5b600160701b82161561212b5770010000b17255775c040618bf4a4ade83fd0260801c5b6001606f1b82161561214e577001000058b91b5bc9ae2eed81e9b7d4cfac0260801c5b6001606e1b82161561217157700100002c5c89d5ec6ca4d7c8acc017b7ca0260801c5b6001606d1b8216156121945770010000162e43f4f831060e02d839a9d16d0260801c5b6001606c1b8216156121b757700100000b1721bcfc99d9f890ea069117630260801c5b6001606b1b8216156121da5770010000058b90cf1e6d97f9ca14dbcc16290260801c5b6001606a1b8216156121fd577001000002c5c863b73f016468f6bac5ca2c0260801c5b600160691b82161561222057700100000162e430e5a18f6119e3c02282a60260801c5b600160681b821615612243577001000000b1721835514b86e6d96efd1bff0260801c5b600160671b82161561226657700100000058b90c0b48c6be5df846c5b2f00260801c5b600160661b8216156122895770010000002c5c8601cc6b9e94213c72737b0260801c5b600160651b8216156122ac577001000000162e42fff037df38aa2b219f070260801c5b600160641b8216156122cf5770010000000b17217fba9c739aa5819f44fa0260801c5b600160631b8216156122f2577001000000058b90bfcdee5acd3c1cedc8240260801c5b600160621b82161561231557700100000002c5c85fe31f35a6a30da1be510260801c5b600160611b8216156123385770010000000162e42ff0999ce3541b9fffd00260801c5b600160601b82161561235b57700100000000b17217f80f4ef5aadda455540260801c5b6001605f1b82161561237e5770010000000058b90bfbf8479bd5a81b51ae0260801c5b6001605e1b8216156123a1577001000000002c5c85fdf84bd62ae30a74cd0260801c5b6001605d1b8216156123c457700100000000162e42fefb2fed257559bdaa0260801c5b6001605c1b8216156123e7577001000000000b17217f7d5a7716bba4a9af0260801c5b6001605b1b82161561240a57700100000000058b90bfbe9ddbac5e109ccf0260801c5b6001605a1b82161561242d5770010000000002c5c85fdf4b15de6f17eb0e0260801c5b600160591b821615612450577001000000000162e42fefa494f1478fde050260801c5b600160581b8216156124735770010000000000b17217f7d20cf927c8e94d0260801c5b600160571b821615612496577001000000000058b90bfbe8f71cb4e4b33e0260801c5b600160561b8216156124b957700100000000002c5c85fdf477b662b269460260801c5b600160551b8216156124dc5770010000000000162e42fefa3ae53369388d0260801c5b600160541b8216156124ff57700100000000000b17217f7d1d351a389d410260801c5b600160531b8216156125225770010000000000058b90bfbe8e8b2d3d4edf0260801c5b600160521b821615612545577001000000000002c5c85fdf4741bea6e77f0260801c5b600160511b82161561256857700100000000000162e42fefa39fe95583c30260801c5b600160501b82161561258b577001000000000000b17217f7d1cfb72b45e30260801c5b69800000000000000000008216156125b457700100000000000058b90bfbe8e7cc35c3f20260801c5b69400000000000000000008216156125dd5770010000000000002c5c85fdf473e242ea390260801c5b6920000000000000000000821615612606577001000000000000162e42fefa39f02b772c0260801c5b691000000000000000000082161561262f5770010000000000000b17217f7d1cf7d83c1a0260801c5b6908000000000000000000821615612658577001000000000000058b90bfbe8e7bdcbe2e0260801c5b690400000000000000000082161561268157700100000000000002c5c85fdf473dea871f0260801c5b69020000000000000000008216156126aa5770010000000000000162e42fefa39ef44d920260801c5b69010000000000000000008216156126d357700100000000000000b17217f7d1cf79e9490260801c5b688000000000000000008216156126fb5770010000000000000058b90bfbe8e7bce5450260801c5b68400000000000000000821615612723577001000000000000002c5c85fdf473de6eca0260801c5b6820000000000000000082161561274b57700100000000000000162e42fefa39ef366f0260801c5b68100000000000000000821615612773577001000000000000000b17217f7d1cf79afa0260801c5b6808000000000000000082161561279b57700100000000000000058b90bfbe8e7bcd6e0260801c5b680400000000000000008216156127c35770010000000000000002c5c85fdf473de6b30260801c5b680200000000000000008216156127eb577001000000000000000162e42fefa39ef3590260801c5b680100000000000000008216156128135770010000000000000000b17217f7d1cf79ac0260801c5b6001608083901c011b61128d81670de0b6b3a7640000600160801b6000808060001985870985870292508281108382030391505080600003612867576000841161285c57600080fd5b508290049050611912565b80841161287357600080fd5b60008486880960026001871981018816978890046003810283188082028403028082028403028082028403028082028403028082028403029081029092039091026000889003889004909101858311909403939093029303949094049190911702949350505050565b634e487b7160e01b600052604160045260246000fd5b604051610140810167ffffffffffffffff81118282101715612916576129166128dc565b60405290565b604051601f8201601f1916810167ffffffffffffffff81118282101715612945576129456128dc565b604052919050565b6000610140828403121561296057600080fd5b6129686128f2565b9050813581526020820135602082015260408201356040820152606082013560608201526080820135608082015260a082013560a082015260c082013560c082015260e082013560e082015261010080830135818301525061012080830135818301525092915050565b60008060008060006101c086880312156129eb57600080fd5b6129f5878761294d565b9761014087013597506101608701359661018081013596506101a00135945092505050565b6001600160a01b038116811461068a57600080fd5b60008060408385031215612a4257600080fd5b8235612a4d81612a1a565b946020939093013593505050565b600080600060608486031215612a7057600080fd5b8335612a7b81612a1a565b92506020840135612a8b81612a1a565b929592945050506040919091013590565b600060208284031215612aae57600080fd5b813561191281612a1a565b6000806000838503610180811215612ad057600080fd5b8435612adb81612a1a565b93506020850135612aeb81612a1a565b9250610140603f1982011215612b0057600080fd5b506040840190509250925092565b60008060408385031215612b2157600080fd5b8235612b2c81612a1a565b91506020830135612b3c81612a1a565b809150509250929050565b600061014082019050825182526020830151602083015260408301516040830152606083015160608301526080830151608083015260a083015160a083015260c083015160c083015260e083015160e083015261010080840151818401525061012080840151818401525092915050565b600080600060408486031215612bcd57600080fd5b833567ffffffffffffffff80821115612be557600080fd5b818601915086601f830112612bf957600080fd5b813581811115612c0857600080fd5b8760208260051b8501011115612c1d57600080fd5b60209283019550935050840135612c3381612a1a565b809150509250925092565b600060608284031215612c5057600080fd5b6040516060810167ffffffffffffffff8282108183111715612c7457612c746128dc565b816040528451835260208501516020840152604085015191508082168214612c9b57600080fd5b5060408201529392505050565b60208082526009908201526827b7363ca7bbb732b960b91b604082015260600190565b634e487b7160e01b600052601160045260246000fd5b60008083128015600160ff1b850184121615612cff57612cff612ccb565b6001600160ff1b0384018313811615612d1a57612d1a612ccb565b50500390565b60006001600160ff1b0381841382841380821686840486111615612d4657612d46612ccb565b600160ff1b6000871282811687830589121615612d6557612d65612ccb565b60008712925087820587128484161615612d8157612d81612ccb565b87850587128184161615612d9757612d97612ccb565b505050929093029392505050565b600080821280156001600160ff1b0384900385131615612dc757612dc7612ccb565b600160ff1b8390038412811615612de057612de0612ccb565b50500190565b634e487b7160e01b600052601260045260246000fd5b600082612e1957634e487b7160e01b600052601260045260246000fd5b600160ff1b821460001984141615612e3357612e33612ccb565b500590565b6000816000190483118215151615612e5257612e52612ccb565b500290565b80825b6001808611612e695750611abf565b6001600160ff1b03829004821115612e8357612e83612ccb565b80861615612e9057918102915b9490941c938002612e5a565b6000828015612eb25760018114612ebc57612ec5565b600191505061128d565b8291505061128d565b5081612ed35750600061128d565b50600160008213808214612eec578015612f0b57612f25565b6001600160ff1b03839004831115612f0657612f06612ccb565b612f25565b6001600160ff1b03839005831215612f2557612f25612ccb565b5080831615612f315750805b612f418360011c83840283612e57565b600082136001600160ff1b0382900483111615612f6057612f60612ccb565b60008212600160ff1b82900583121615612f7c57612f7c612ccb565b029392505050565b600061191260ff841683612e9c565b6000825160005b81811015612fb45760208186018101518583015201612f9a565b81811115612fc3576000828501525b509190910192915050565b60006101408284031215612fe157600080fd5b611912838361294d565b634e487b7160e01b600052603260045260246000fd5b6000602080838503121561301457600080fd5b825167ffffffffffffffff8082111561302c57600080fd5b818501915085601f83011261304057600080fd5b815181811115613052576130526128dc565b8060051b915061306384830161291c565b818152918301840191848101908884111561307d57600080fd5b938501935b83851015610633578451925061309783612a1a565b8282529385019390850190613082565b6000602082840312156130b957600080fd5b815161191281612a1a565b600061014082840312156130d757600080fd5b6130df6128f2565b825181526020830151602082015260408301516040820152606083015160608201526080830151608082015260a083015160a082015260c083015160c082015260e083015160e0820152610100808401518183015250610120808401518183015250809150509291505056fea2646970667358221220ddfa5ead388fd75ef088c15f21a491a73c35cbd5fd7e002c31ad7298c139b8ec64736f6c634300080d003300000000000000000000000000000000000000000000000006f05b59d3b200000000000000000000000000000000000000000000000000000c7d713b49da00000000000000000000000000000000000000000000000000000429d069189e00000000000000000000000000000000000000000000000000000000000000023d7500000000000000000000000000000000000000000000000000000049d482455e000000000000000000000000000000000000000000000000000000189c2b6c750000000000000000000000000000000000000000000000000000000071672e7f00000000000000000000000000000000000000000000000000003f28cb71571c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006d228fa4dad2163056a48fc2186d716f5c65e89a
Deployed Bytecode
0x608060405234801561001057600080fd5b506004361061014d5760003560e01c806374a3e924116100c3578063c42401f11161007c578063c42401f1146102e5578063c63de8bc146102fa578063cbf75c9a1461030d578063e076a551146103c6578063e30c3978146103d7578063f2fde38b146103e857600080fd5b806374a3e9241461026357806379ba50971461027657806381b51e0c1461027e5780638da5cb5b1461028d578063b1e01765146102b2578063bbdcbed6146102c557600080fd5b80633278c694116101155780633278c694146101e75780633ced7d0d146101fc57806344552b5d1461020f5780636bcc8216146102175780636e1a414014610226578063715018a61461025b57600080fd5b8063023279ce1461015257806303dc12fc14610185578063071962ff146101a6578063109a006e146101b957806311e5152b146101c4575b600080fd5b6101656101603660046129d2565b6103fb565b604080519384526020840192909252908201526060015b60405180910390f35b610198610193366004612a2f565b61041f565b60405190815260200161017c565b6101986101b4366004612a5b565b6104f6565b610198600160c41b81565b6101d76101d2366004612a5b565b610599565b604051901515815260200161017c565b6101fa6101f5366004612a9c565b61063f565b005b61019861020a3660046129d2565b61068d565b6101fa61090f565b610198670de0b6b3a764000081565b6102396102343660046129d2565b610954565b604080519485526020850193909352918301521515606082015260800161017c565b6101fa610dd5565b6101fa610271366004612ab9565b610e18565b6101fa610f04565b6101986799e8e8e3d530368181565b6000546001600160a01b03165b6040516001600160a01b03909116815260200161017c565b6101986102c0366004612a5b565b610f6b565b6102d86102d3366004612b0e565b611011565b60405161017c9190612b47565b60405163c42401f160e01b815260200161017c565b6101fa610308366004612bb8565b611293565b61037c61031b366004612b0e565b600260205281600052604060002060205280600052604060002060009150915050806000015490806001015490806002015490806003015490806004015490806005015490806006015490806007015490806008015490806009015490508a565b604080519a8b5260208b0199909952978901969096526060880194909452608087019290925260a086015260c085015260e08401526101008301526101208201526101400161017c565b610198690de0b6b3a7640000000081565b6001546001600160a01b031661029a565b6101fa6103f6366004612a9c565b611734565b600080600061040d8888888888610954565b50919a90995090975095505050505050565b604051631f0f875560e31b81526001600160a01b038316600482015260009033908290829063f87c3aa890602401606060405180830381865afa15801561046a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061048e9190612c3e565b6001600160a01b038084166000908152600260209081526040808320938a168352929052209091506104df6104c38488611011565b83516020850151604086015167ffffffffffffffff16896103fb565b600984015560089092019190915595945050505050565b604051631f0f875560e31b81526001600160a01b038381166004830152600091829186169063f87c3aa890602401606060405180830381865afa158015610541573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105659190612c3e565b90506105906105748686611011565b82516020840151604085015167ffffffffffffffff168761068d565b95945050505050565b604051631f0f875560e31b81526001600160a01b038381166004830152600091829186169063f87c3aa890602401606060405180830381865afa1580156105e4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106089190612c3e565b90506106336106178686611011565b82516020840151604085015167ffffffffffffffff1687610954565b98975050505050505050565b336106526000546001600160a01b031690565b6001600160a01b0316146106815760405162461bcd60e51b815260040161067890612ca8565b60405180910390fd5b61068a816117ba565b50565b6000818311156106b05760405163d22806e360e01b815260040160405180910390fd5b60006040518060e001604052806000815260200160008152602001600081526020016000815260200160008152602001600081526020016000151581525090506106fd8787878787610954565b15801560c08601529250610718915050576000915050610590565b610723848403611861565b815261074061073b670de0b6b3a764000088886118cf565b611861565b6020808301829052670de0b6b3a7640000604084015288015112156107e4578060400151876020015182602001516107789190612ce1565b6040830151835160e08b015161078e9190612d20565b8a610120015185604001516107a39190612da5565b6107ad9190612da5565b8a608001516107bc9190612d20565b6107c69190612dfc565b6107d09190612d20565b6107da9190612dfc565b6060820152610826565b61082060008260400151896040015184602001516108029190612ce1565b8a60a001516108119190612d20565b61081b9190612dfc565b611919565b60608201525b806040015181602001518860c0015161083f9190612d20565b6108499190612dfc565b6080820181905261010088015161085f9161192f565b60a082015260408101518151885160208401516108bd93929161088191612ce1565b8a606001516108909190612d20565b61089a9190612d20565b6108a49190612dfc565b8260a001516108b39190612da5565b826080015161192f565b60a0820181905260608201516108e9916108e4916108da91612da5565b836080015161192f565b61193e565b91506108f96301e1338083612e38565b915061090482611990565b979650505050505050565b336109226000546001600160a01b031690565b6001600160a01b0316146109485760405162461bcd60e51b815260040161067890612ca8565b61095260006117ba565b565b60008060008088610100015192508861012001519150600060405180610140016040528060008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152509050858711156109df5760405163d22806e360e01b815260040160405180910390fd5b6109ea878703611861565b8152670de0b6b3a7640000610a0361073b828c8c6118cf565b61012083018190528b518291610a199190612ce1565b8c60600151610a289190612d20565b610a329190612dfc565b6020808401919091528b01516101208301511315610b1c57808b60200151836101200151610a609190612ce1565b82610a6b8782612da5565b8e60800151610a7a9190612d20565b610a849190612dfc565b610a8e9190612d20565b610a989190612dfc565b604083015260208b01516101208301518291610ab391612ce1565b828d60e001518e60800151610ac89190612d20565b610ad29190612dfc565b610adc9190612d20565b610ae69190612dfc565b8260200151610af59190612da5565b6060830152815160e08c0151610b0b9190612d20565b610b159085612da5565b9350610b7f565b610b466000828d60400151856101200151610b379190612ce1565b8e60a001516108119190612d20565b604083015260208201516060830152815160e08c0151610b7c91600091610b6d9190612d20565b610b779087612ce1565b61192f565b93505b808261012001518c60c00151610b959190612d20565b610b9f9190612dfc565b60a08301819052610bb190869061192f565b9450816040015185610bc39190612da5565b608083015281516060830151610bd99190612d20565b8260800151610be89190612da5565b60c083015260a0820151608083015112801590610c0d57508160a001518260c0015112155b15610c4957815160c0830151608084015160029291610c2b91612da5565b610c359190612d20565b610c3f9190612dfc565b60e0830152610d53565b8160a001518260800151128015610c6757508160a001518260c00151125b15610c7d57815160a0830151610c3f9190612d20565b8160a00151826080015112158015610c9c57508160a001518260c00151125b15610cf7576002826060015160028460a001518560800151610cbe9190612ce1565b610cc89190612f84565b610cd29190612dfc565b610cdc9190612dfc565b825160a0840151610ced9190612d20565b610c3f9190612ce1565b6002826060015160028460a001518560c00151610d149190612ce1565b610d1e9190612f84565b610d289190612dfc565b610d329190612dfc565b825160a0840151610d439190612d20565b610d4d9190612da5565b60e08301525b81516020830151610d7b91610d6791612d20565b610d719087612da5565b8360a0015161192f565b9450610d8c8a8a8460e001516119a9565b83519197509350600090610daa908890610da59061193e565b611ac7565b90975090508380610db85750805b15610dc65760009550600094505b50505095509550955095915050565b33610de86000546001600160a01b031690565b6001600160a01b031614610e0e5760405162461bcd60e51b815260040161067890612ca8565b6109526000611afc565b33610e2b6000546001600160a01b031690565b6001600160a01b031614610e515760405162461bcd60e51b815260040161067890612ca8565b6040516001600160a01b03838116602483015284169060440160408051601f198184030181529181526020820180516001600160e01b0316639198e51560e01b17905251610e9f9190612f93565b6000604051808303816000865af19150503d8060008114610edc576040519150601f19603f3d011682016040523d82523d6000602084013e610ee1565b606091505b505050610eff838383803603810190610efa9190612fce565b611bad565b505050565b6001546001600160a01b03163314610f515760405162461bcd60e51b815260206004820152601060248201526f27b7363ca832b73234b733a7bbb732b960811b6044820152606401610678565b610952610f666001546001600160a01b031690565b611afc565b604051631f0f875560e31b81526001600160a01b038381166004830152600091829186169063f87c3aa890602401606060405180830381865afa158015610fb6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fda9190612c3e565b9050611005610fe98686611011565b82516020840151604085015167ffffffffffffffff16876103fb565b50909695505050505050565b611067604051806101400160405280600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b6001600160a01b03808416600090815260026020908152604080832093861683529290522080541561110857604080516101408101825282548152600183015460208201526002830154918101919091526003820154606082015260048201546080820152600582015460a0820152600682015460c0820152600782015460e08201526008820154610100820152600990910154610120820152905061128d565b600080527fac33ff75c19e70fe83507db0d683fd3465c996598dc972688b7ace676c89077b602090815260408051610140810182527f6ee3efecae883df2d7ccda22610b4ca771a299e707cb0d65c4ec97dc4e6668ad5481527f6ee3efecae883df2d7ccda22610b4ca771a299e707cb0d65c4ec97dc4e6668ae54928101929092527f6ee3efecae883df2d7ccda22610b4ca771a299e707cb0d65c4ec97dc4e6668af54908201527f6ee3efecae883df2d7ccda22610b4ca771a299e707cb0d65c4ec97dc4e6668b05460608201527f6ee3efecae883df2d7ccda22610b4ca771a299e707cb0d65c4ec97dc4e6668b15460808201527f6ee3efecae883df2d7ccda22610b4ca771a299e707cb0d65c4ec97dc4e6668b25460a08201527f6ee3efecae883df2d7ccda22610b4ca771a299e707cb0d65c4ec97dc4e6668b35460c08201527f6ee3efecae883df2d7ccda22610b4ca771a299e707cb0d65c4ec97dc4e6668b45460e0820152600882015461010082015260099091015461012082015290505b92915050565b336112a66000546001600160a01b031690565b6001600160a01b0316146112cc5760405162461bcd60e51b815260040161067890612ca8565b6000805b8381101561172d5760008585838181106112ec576112ec612feb565b90506020020160208101906113019190612a9c565b6001600160a01b03166367e4ac2c6040518163ffffffff1660e01b8152600401600060405180830381865afa15801561133e573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526113669190810190613001565b90506001600160a01b03831661143e57836001600160a01b03166348b3eabc8787600081811061139857611398612feb565b90506020020160208101906113ad9190612a9c565b836000815181106113c0576113c0612feb565b60200260200101516040518363ffffffff1660e01b81526004016113fa9291906001600160a01b0392831681529116602082015260400190565b602060405180830381865afa158015611417573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061143b91906130a7565b92505b60005b8151811015611723576000846001600160a01b031663cbf75c9a89898781811061146d5761146d612feb565b90506020020160208101906114829190612a9c565b85858151811061149457611494612feb565b60200260200101516040518363ffffffff1660e01b81526004016114ce9291906001600160a01b0392831681529116602082015260400190565b61014060405180830381865afa1580156114ec573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061151091906130c4565b80519091506000036116ab576000866001600160a01b03166348b3eabc8a8a8881811061153f5761153f612feb565b90506020020160208101906115549190612a9c565b86868151811061156657611566612feb565b60200260200101516040518363ffffffff1660e01b81526004016115a09291906001600160a01b0392831681529116602082015260400190565b602060405180830381865afa1580156115bd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115e191906130a7565b9050806001600160a01b031663cbf75c9a8a8a8881811061160457611604612feb565b90506020020160208101906116199190612a9c565b86868151811061162b5761162b612feb565b60200260200101516040518363ffffffff1660e01b81526004016116659291906001600160a01b0392831681529116602082015260400190565b61014060405180830381865afa158015611683573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116a791906130c4565b9150505b80511561171a578060e0015165fca32dc55c72036116d057653f28cb71571c60e08201525b61171a8888868181106116e5576116e5612feb565b90506020020160208101906116fa9190612a9c565b84848151811061170c5761170c612feb565b602002602001015183611bad565b50600101611441565b50506001016112d0565b5050505050565b336117476000546001600160a01b031690565b6001600160a01b03161461176d5760405162461bcd60e51b815260040161067890612ca8565b6001600160a01b0381166117b15760405162461bcd60e51b815260206004820152600b60248201526a4f776e657249735a65726f60a81b6044820152606401610678565b61068a81611afc565b6001546001600160a01b038083169116036118175760405162461bcd60e51b815260206004820152601860248201527f50656e64696e674f776e65724469644e6f744368616e676500000000000000006044820152606401610678565b600180546001600160a01b0319166001600160a01b0383169081179091556040517fd6aad444c90d39fb0eee1c6e357a7fad83d63f719ac5f880445a2beb0ff3ab5890600090a250565b60006001600160ff1b038211156118cb5760405162461bcd60e51b815260206004820152602860248201527f53616665436173743a2076616c756520646f65736e27742066697420696e2061604482015267371034b73a191a9b60c11b6064820152608401610678565b5090565b60008215806118dc575081155b156118e957506000611912565b6118f38483612e38565b905082818161190457611904612de6565b049050838111156119125750825b9392505050565b60008183126119285781611912565b5090919050565b60008183136119285781611912565b6000808212156118cb5760405162461bcd60e51b815260206004820181905260248201527f53616665436173743a2076616c7565206d75737420626520706f7369746976656044820152606401610678565b600068056bc75e2d6310000080831161128d5782611912565b60008060006799e8e8e3d530368184126119d357690de0b6b3a76400000000925060019150611a0c565b670de0b6b3a76400006119e585611e29565b6119ef9190612ce1565b905060008113611a00576000611a09565b611a098161193e565b92505b6000858711611a1b5785611a1d565b865b9050600160c41b8110611a395760006001935093505050611abf565b8386026000819003611a4d57505050611abf565b86858281611a5d57611a5d612de6565b04141580611a87575081600160c41b03670de0b6b3a76400008281611a8457611a84612de6565b04115b15611abb5786670de0b6b3a764000083600160c41b030281611aab57611aab612de6565b04945060019350611abf92505050565b5050505b935093915050565b60008080611adb846502e24d16b5a8612e38565b9050808511611aec57846000611af0565b8060015b92509250509250929050565b6000546001600160a01b03808316911603611b4d5760405162461bcd60e51b81526020600482015260116024820152704f776e65724469644e6f744368616e676560781b6044820152606401610678565b600080546001600160a01b0319166001600160a01b038316908117825560405190917f04dba622d284ed0014ee4b9a6a68386be1a4c08a4913ae272de89199cc68616391a26001546001600160a01b03161561068a5761068a60006117ba565b8051670de0b6b3a7640000906000121580611bc9575081518113155b15611be7576040516313e9c00360e21b815260040160405180910390fd5b81516020830151131580611bff575080826020015112155b15611c1d576040516339bda99160e11b815260040160405180910390fd5b60008260400151131580611c3657508151604083015112155b15611c5457604051635c65494d60e01b815260040160405180910390fd5b600082606001511215611c7a5760405163fe06781560e01b815260040160405180910390fd5b600082608001511215611ca0576040516320d12cb560e21b815260040160405180910390fd5b60008260a001511215611cc9576040516001627ddb5960e01b0319815260040160405180910390fd5b60008260c001511215611cef57604051634e435a2160e01b815260040160405180910390fd5b60008260e001511215611d15576040516378a8371160e01b815260040160405180910390fd5b60008261010001511215611d3c576040516330eecc6b60e21b815260040160405180910390fd5b60008261012001511215611d6357604051630266493760e31b815260040160405180910390fd5b6001600160a01b03808516600081815260026020818152604080842095891680855295825292839020875181559087015160018201558287015191810191909155606086015160038201556080860151600482015560a0860151600582015560c0860151600682015560e086015160078201556101008601516008820155610120860151600990910155517ff254631d9ea3e3ab061b1c56e1215a268abf5ff28a460b255f308aac112df45890611e1b908690612b47565b60405180910390a350505050565b600068023f2fa8f6da5b9d3119821215611e4557506000919050565b6804cf46d8192b672ecc8212611e5a57600080fd5b6714057b7ef767814f8202611912670de0b6b3a76400006706f05b59d3b200008301055b600080821215611ed25768033dd1780914b9711419821215611ea257506000919050565b611eae82600003611e7e565b6ec097ce7bc90715b34b9f100000000081611ecb57611ecb612de6565b0592915050565b6806f05b59d3b20000008212611ee757600080fd5b670de0b6b3a7640000608083901b04611912816001607f1b80821615611f1e5770016a09e667f3bcc908b2fb1366ea957d3e0260801c5b6001607e1b821615611f41577001306fe0a31b7152de8d5a46305c85eded0260801c5b6001607d1b821615611f64577001172b83c7d517adcdf7c8c50eb14a79200260801c5b6001607c1b821615611f875770010b5586cf9890f6298b92b71842a983640260801c5b6001607b1b821615611faa577001059b0d31585743ae7c548eb68ca417fe0260801c5b6001607a1b821615611fcd57700102c9a3e778060ee6f7caca4f7a29bde90260801c5b600160791b821615611ff05770010163da9fb33356d84a66ae336dcdfa400260801c5b600160781b82161561201357700100b1afa5abcbed6129ab13ec11dc95440260801c5b600160771b8216156120365770010058c86da1c09ea1ff19d294cf2f679c0260801c5b600160761b821615612059577001002c605e2e8cec506d21bfc89a23a0110260801c5b600160751b82161561207c57700100162f3904051fa128bca9c55c31e5e00260801c5b600160741b82161561209f577001000b175effdc76ba38e31671ca9397260260801c5b600160731b8216156120c257700100058ba01fb9f96d6cacd4b180917c3e0260801c5b600160721b8216156120e55770010002c5cc37da9491d0985c348c68e7b40260801c5b600160711b821615612108577001000162e525ee054754457d59952920270260801c5b600160701b82161561212b5770010000b17255775c040618bf4a4ade83fd0260801c5b6001606f1b82161561214e577001000058b91b5bc9ae2eed81e9b7d4cfac0260801c5b6001606e1b82161561217157700100002c5c89d5ec6ca4d7c8acc017b7ca0260801c5b6001606d1b8216156121945770010000162e43f4f831060e02d839a9d16d0260801c5b6001606c1b8216156121b757700100000b1721bcfc99d9f890ea069117630260801c5b6001606b1b8216156121da5770010000058b90cf1e6d97f9ca14dbcc16290260801c5b6001606a1b8216156121fd577001000002c5c863b73f016468f6bac5ca2c0260801c5b600160691b82161561222057700100000162e430e5a18f6119e3c02282a60260801c5b600160681b821615612243577001000000b1721835514b86e6d96efd1bff0260801c5b600160671b82161561226657700100000058b90c0b48c6be5df846c5b2f00260801c5b600160661b8216156122895770010000002c5c8601cc6b9e94213c72737b0260801c5b600160651b8216156122ac577001000000162e42fff037df38aa2b219f070260801c5b600160641b8216156122cf5770010000000b17217fba9c739aa5819f44fa0260801c5b600160631b8216156122f2577001000000058b90bfcdee5acd3c1cedc8240260801c5b600160621b82161561231557700100000002c5c85fe31f35a6a30da1be510260801c5b600160611b8216156123385770010000000162e42ff0999ce3541b9fffd00260801c5b600160601b82161561235b57700100000000b17217f80f4ef5aadda455540260801c5b6001605f1b82161561237e5770010000000058b90bfbf8479bd5a81b51ae0260801c5b6001605e1b8216156123a1577001000000002c5c85fdf84bd62ae30a74cd0260801c5b6001605d1b8216156123c457700100000000162e42fefb2fed257559bdaa0260801c5b6001605c1b8216156123e7577001000000000b17217f7d5a7716bba4a9af0260801c5b6001605b1b82161561240a57700100000000058b90bfbe9ddbac5e109ccf0260801c5b6001605a1b82161561242d5770010000000002c5c85fdf4b15de6f17eb0e0260801c5b600160591b821615612450577001000000000162e42fefa494f1478fde050260801c5b600160581b8216156124735770010000000000b17217f7d20cf927c8e94d0260801c5b600160571b821615612496577001000000000058b90bfbe8f71cb4e4b33e0260801c5b600160561b8216156124b957700100000000002c5c85fdf477b662b269460260801c5b600160551b8216156124dc5770010000000000162e42fefa3ae53369388d0260801c5b600160541b8216156124ff57700100000000000b17217f7d1d351a389d410260801c5b600160531b8216156125225770010000000000058b90bfbe8e8b2d3d4edf0260801c5b600160521b821615612545577001000000000002c5c85fdf4741bea6e77f0260801c5b600160511b82161561256857700100000000000162e42fefa39fe95583c30260801c5b600160501b82161561258b577001000000000000b17217f7d1cfb72b45e30260801c5b69800000000000000000008216156125b457700100000000000058b90bfbe8e7cc35c3f20260801c5b69400000000000000000008216156125dd5770010000000000002c5c85fdf473e242ea390260801c5b6920000000000000000000821615612606577001000000000000162e42fefa39f02b772c0260801c5b691000000000000000000082161561262f5770010000000000000b17217f7d1cf7d83c1a0260801c5b6908000000000000000000821615612658577001000000000000058b90bfbe8e7bdcbe2e0260801c5b690400000000000000000082161561268157700100000000000002c5c85fdf473dea871f0260801c5b69020000000000000000008216156126aa5770010000000000000162e42fefa39ef44d920260801c5b69010000000000000000008216156126d357700100000000000000b17217f7d1cf79e9490260801c5b688000000000000000008216156126fb5770010000000000000058b90bfbe8e7bce5450260801c5b68400000000000000000821615612723577001000000000000002c5c85fdf473de6eca0260801c5b6820000000000000000082161561274b57700100000000000000162e42fefa39ef366f0260801c5b68100000000000000000821615612773577001000000000000000b17217f7d1cf79afa0260801c5b6808000000000000000082161561279b57700100000000000000058b90bfbe8e7bcd6e0260801c5b680400000000000000008216156127c35770010000000000000002c5c85fdf473de6b30260801c5b680200000000000000008216156127eb577001000000000000000162e42fefa39ef3590260801c5b680100000000000000008216156128135770010000000000000000b17217f7d1cf79ac0260801c5b6001608083901c011b61128d81670de0b6b3a7640000600160801b6000808060001985870985870292508281108382030391505080600003612867576000841161285c57600080fd5b508290049050611912565b80841161287357600080fd5b60008486880960026001871981018816978890046003810283188082028403028082028403028082028403028082028403028082028403029081029092039091026000889003889004909101858311909403939093029303949094049190911702949350505050565b634e487b7160e01b600052604160045260246000fd5b604051610140810167ffffffffffffffff81118282101715612916576129166128dc565b60405290565b604051601f8201601f1916810167ffffffffffffffff81118282101715612945576129456128dc565b604052919050565b6000610140828403121561296057600080fd5b6129686128f2565b9050813581526020820135602082015260408201356040820152606082013560608201526080820135608082015260a082013560a082015260c082013560c082015260e082013560e082015261010080830135818301525061012080830135818301525092915050565b60008060008060006101c086880312156129eb57600080fd5b6129f5878761294d565b9761014087013597506101608701359661018081013596506101a00135945092505050565b6001600160a01b038116811461068a57600080fd5b60008060408385031215612a4257600080fd5b8235612a4d81612a1a565b946020939093013593505050565b600080600060608486031215612a7057600080fd5b8335612a7b81612a1a565b92506020840135612a8b81612a1a565b929592945050506040919091013590565b600060208284031215612aae57600080fd5b813561191281612a1a565b6000806000838503610180811215612ad057600080fd5b8435612adb81612a1a565b93506020850135612aeb81612a1a565b9250610140603f1982011215612b0057600080fd5b506040840190509250925092565b60008060408385031215612b2157600080fd5b8235612b2c81612a1a565b91506020830135612b3c81612a1a565b809150509250929050565b600061014082019050825182526020830151602083015260408301516040830152606083015160608301526080830151608083015260a083015160a083015260c083015160c083015260e083015160e083015261010080840151818401525061012080840151818401525092915050565b600080600060408486031215612bcd57600080fd5b833567ffffffffffffffff80821115612be557600080fd5b818601915086601f830112612bf957600080fd5b813581811115612c0857600080fd5b8760208260051b8501011115612c1d57600080fd5b60209283019550935050840135612c3381612a1a565b809150509250925092565b600060608284031215612c5057600080fd5b6040516060810167ffffffffffffffff8282108183111715612c7457612c746128dc565b816040528451835260208501516020840152604085015191508082168214612c9b57600080fd5b5060408201529392505050565b60208082526009908201526827b7363ca7bbb732b960b91b604082015260600190565b634e487b7160e01b600052601160045260246000fd5b60008083128015600160ff1b850184121615612cff57612cff612ccb565b6001600160ff1b0384018313811615612d1a57612d1a612ccb565b50500390565b60006001600160ff1b0381841382841380821686840486111615612d4657612d46612ccb565b600160ff1b6000871282811687830589121615612d6557612d65612ccb565b60008712925087820587128484161615612d8157612d81612ccb565b87850587128184161615612d9757612d97612ccb565b505050929093029392505050565b600080821280156001600160ff1b0384900385131615612dc757612dc7612ccb565b600160ff1b8390038412811615612de057612de0612ccb565b50500190565b634e487b7160e01b600052601260045260246000fd5b600082612e1957634e487b7160e01b600052601260045260246000fd5b600160ff1b821460001984141615612e3357612e33612ccb565b500590565b6000816000190483118215151615612e5257612e52612ccb565b500290565b80825b6001808611612e695750611abf565b6001600160ff1b03829004821115612e8357612e83612ccb565b80861615612e9057918102915b9490941c938002612e5a565b6000828015612eb25760018114612ebc57612ec5565b600191505061128d565b8291505061128d565b5081612ed35750600061128d565b50600160008213808214612eec578015612f0b57612f25565b6001600160ff1b03839004831115612f0657612f06612ccb565b612f25565b6001600160ff1b03839005831215612f2557612f25612ccb565b5080831615612f315750805b612f418360011c83840283612e57565b600082136001600160ff1b0382900483111615612f6057612f60612ccb565b60008212600160ff1b82900583121615612f7c57612f7c612ccb565b029392505050565b600061191260ff841683612e9c565b6000825160005b81811015612fb45760208186018101518583015201612f9a565b81811115612fc3576000828501525b509190910192915050565b60006101408284031215612fe157600080fd5b611912838361294d565b634e487b7160e01b600052603260045260246000fd5b6000602080838503121561301457600080fd5b825167ffffffffffffffff8082111561302c57600080fd5b818501915085601f83011261304057600080fd5b815181811115613052576130526128dc565b8060051b915061306384830161291c565b818152918301840191848101908884111561307d57600080fd5b938501935b83851015610633578451925061309783612a1a565b8282529385019390850190613082565b6000602082840312156130b957600080fd5b815161191281612a1a565b600061014082840312156130d757600080fd5b6130df6128f2565b825181526020830151602082015260408301516040820152606083015160608201526080830151608082015260a083015160a082015260c083015160c082015260e083015160e0820152610100808401518183015250610120808401518183015250809150509291505056fea2646970667358221220ddfa5ead388fd75ef088c15f21a491a73c35cbd5fd7e002c31ad7298c139b8ec64736f6c634300080d0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
00000000000000000000000000000000000000000000000006f05b59d3b200000000000000000000000000000000000000000000000000000c7d713b49da00000000000000000000000000000000000000000000000000000429d069189e00000000000000000000000000000000000000000000000000000000000000023d7500000000000000000000000000000000000000000000000000000049d482455e000000000000000000000000000000000000000000000000000000189c2b6c750000000000000000000000000000000000000000000000000000000071672e7f00000000000000000000000000000000000000000000000000003f28cb71571c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006d228fa4dad2163056a48fc2186d716f5c65e89a
-----Decoded View---------------
Arg [0] : _config (tuple): System.Collections.Generic.List`1[Nethereum.ABI.FunctionEncoding.ParameterOutput]
Arg [1] : _owner (address): 0x6d228Fa4daD2163056A48Fc2186d716f5c65E89A
-----Encoded View---------------
11 Constructor Arguments found :
Arg [0] : 00000000000000000000000000000000000000000000000006f05b59d3b20000
Arg [1] : 0000000000000000000000000000000000000000000000000c7d713b49da0000
Arg [2] : 0000000000000000000000000000000000000000000000000429d069189e0000
Arg [3] : 0000000000000000000000000000000000000000000000000000000000023d75
Arg [4] : 00000000000000000000000000000000000000000000000000000049d482455e
Arg [5] : 000000000000000000000000000000000000000000000000000000189c2b6c75
Arg [6] : 0000000000000000000000000000000000000000000000000000000071672e7f
Arg [7] : 00000000000000000000000000000000000000000000000000003f28cb71571c
Arg [8] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [9] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [10] : 0000000000000000000000006d228fa4dad2163056a48fc2186d716f5c65e89a
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
[ Download: CSV Export ]
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.