Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
Sponsored
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Contract Name:
InterestRateModel
Compiler Version
v0.8.13+commit.abaa5c0e
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.13; import "@openzeppelin/contracts/utils/math/SafeCast.sol"; import "@openzeppelin/contracts/utils/math/Math.sol"; import "./lib/PRBMathSD59x18.sol"; import "./lib/EasyMath.sol"; import "./interfaces/ISilo.sol"; import "./interfaces/IInterestRateModel.sol"; import "./utils/TwoStepOwnable.sol"; /// @title InterestRateModel /// @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 InterestRateModel 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 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 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 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 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 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 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 override returns (uint256 rcur) { if (_interestRateTimestamp > _blockTimestamp) revert InvalidTimestamps(); // struct for local vars to avoid "Stack too deep" LocalVarsRCur memory _l = LocalVarsRCur(0,0,0,0,0,0,false); (,,,_l.overflow) = calculateCompoundInterestRateWithOverflowDetection( _c, _totalDeposits, _totalBorrowAmount, _interestRateTimestamp, _blockTimestamp ); if (_l.overflow) { return 0; } // There can't be an underflow in the subtraction because of the previous check unchecked { // T := t1 - t0 # length of time period in seconds _l.T = (_blockTimestamp - _interestRateTimestamp).toInt256(); } _l.u = EasyMath.calculateUtilization(DP, _totalDeposits, _totalBorrowAmount).toInt256(); _l.DP = int256(DP); if (_l.u > _c.ucrit) { // rp := kcrit *(1 + Tcrit + beta *T)*( u0 - ucrit ) _l.rp = _c.kcrit * (_l.DP + _c.Tcrit + _c.beta * _l.T) / _l.DP * (_l.u - _c.ucrit) / _l.DP; } else { // rp := min (0, klow * (u0 - ulow )) _l.rp = _min(0, _c.klow * (_l.u - _c.ulow) / _l.DP); } // rlin := klin * u0 # lower bound between t0 and t1 _l.rlin = _c.klin * _l.u / _l.DP; // ri := max(ri , rlin ) _l.ri = _max(_c.ri, _l.rlin); // ri := max(ri + ki * (u0 - uopt ) * T, rlin ) _l.ri = _max(_l.ri + _c.ki * (_l.u - _c.uopt) * _l.T / _l.DP, _l.rlin); // rcur := max (ri + rp , rlin ) # current per second interest rate rcur = (_max(_l.ri + _l.rp, _l.rlin)).toUint256(); rcur *= 365 days; } struct LocalVarsRComp { int256 T; int256 slopei; int256 rp; int256 slope; int256 r0; int256 rlin; int256 r1; int256 x; int256 rlin1; int256 u; } function interestRateModelPing() external pure override returns (bytes4) { return this.interestRateModelPing.selector; } /// @inheritdoc IInterestRateModel function calculateCompoundInterestRate( Config memory _c, uint256 _totalDeposits, uint256 _totalBorrowAmount, uint256 _interestRateTimestamp, uint256 _blockTimestamp ) public pure 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 override returns ( uint256 rcomp, int256 ri, int256 Tcrit, bool overflow ) { ri = _c.ri; Tcrit = _c.Tcrit; // struct for local vars to avoid "Stack too deep" LocalVarsRComp memory _l = LocalVarsRComp(0,0,0,0,0,0,0,0,0,0); if (_interestRateTimestamp > _blockTimestamp) revert InvalidTimestamps(); // There can't be an underflow in the subtraction because of the previous check unchecked { // length of time period in seconds _l.T = (_blockTimestamp - _interestRateTimestamp).toInt256(); } int256 _DP = int256(DP); _l.u = EasyMath.calculateUtilization(DP, _totalDeposits, _totalBorrowAmount).toInt256(); // slopei := ki * (u0 - uopt ) _l.slopei = _c.ki * (_l.u - _c.uopt) / _DP; if (_l.u > _c.ucrit) { // rp := kcrit * (1 + Tcrit) * (u0 - ucrit ) _l.rp = _c.kcrit * (_DP + Tcrit) / _DP * (_l.u - _c.ucrit) / _DP; // slope := slopei + kcrit * beta * (u0 - ucrit ) _l.slope = _l.slopei + _c.kcrit * _c.beta / _DP * (_l.u - _c.ucrit) / _DP; // Tcrit := Tcrit + beta * T Tcrit = Tcrit + _c.beta * _l.T; } else { // rp := min (0, klow * (u0 - ulow )) _l.rp = _min(0, _c.klow * (_l.u - _c.ulow) / _DP); // slope := slopei _l.slope = _l.slopei; // Tcrit := max (0, Tcrit - beta * T) Tcrit = _max(0, Tcrit - _c.beta * _l.T); } // rlin := klin * u0 # lower bound between t0 and t1 _l.rlin = _c.klin * _l.u / _DP; // ri := max(ri , rlin ) ri = _max(ri , _l.rlin); // r0 := ri + rp # interest rate at t0 ignoring lower bound _l.r0 = ri + _l.rp; // r1 := r0 + slope *T # what interest rate would be at t1 ignoring lower bound _l.r1 = _l.r0 + _l.slope * _l.T; // Calculating the compound interest if (_l.r0 >= _l.rlin && _l.r1 >= _l.rlin) { // lower bound isn’t activated // rcomp := exp (( r0 + r1) * T / 2) - 1 _l.x = (_l.r0 + _l.r1) * _l.T / 2; } else if (_l.r0 < _l.rlin && _l.r1 < _l.rlin) { // lower bound is active during the whole time // rcomp := exp( rlin * T) - 1 _l.x = _l.rlin * _l.T; } else if (_l.r0 >= _l.rlin && _l.r1 < _l.rlin) { // lower bound is active after some time // rcomp := exp( rlin *T - (r0 - rlin )^2/ slope /2) - 1 _l.x = _l.rlin * _l.T - (_l.r0 - _l.rlin)**2 / _l.slope / 2; } else { // lower bound is active before some time // rcomp := exp( rlin *T + (r1 - rlin )^2/ slope /2) - 1 _l.x = _l.rlin * _l.T + (_l.r1 - _l.rlin)**2 / _l.slope / 2; } // ri := max(ri + slopei * T, rlin ) ri = _max(ri + _l.slopei * _l.T, _l.rlin); // Checking for the overflow below. In case of the overflow, ri and Tcrit will be set back to zeros. Rcomp is // calculated to not make an overflow in totalBorrowedAmount, totalDeposits. (rcomp, overflow) = _calculateRComp(_totalDeposits, _totalBorrowAmount, _l.x); if (overflow) { ri = 0; Tcrit = 0; } } /// @dev set config for silo and asset function _setConfig(address _silo, address _asset, Config memory _config) internal { 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 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 returns (int256) { return a > b ? a : b; } /// @dev Returns the smallest of two numbers function _min(int256 a, int256 b) internal pure returns (int256) { return a < b ? a : b; } }
// 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 (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 (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 "./IShareToken.sol"; import "./IFlashLiquidationReceiver.sol"; import "./ISiloRepository.sol"; interface IBaseSilo { enum AssetStatus { Undefined, Active, Removed } /// @dev Storage struct that holds all required data for a single token market struct AssetStorage { /// @dev Token that represents a share in totalDeposits of Silo IShareToken collateralToken; /// @dev Token that represents a share in collateralOnlyDeposits of Silo IShareToken collateralOnlyToken; /// @dev Token that represents a share in totalBorrowAmount of Silo IShareToken debtToken; /// @dev COLLATERAL: Amount of asset token that has been deposited to Silo with interest earned by depositors. /// It also includes token amount that has been borrowed. uint256 totalDeposits; /// @dev COLLATERAL ONLY: Amount of asset token that has been deposited to Silo that can be ONLY used /// as collateral. These deposits do NOT earn interest and CANNOT be borrowed. uint256 collateralOnlyDeposits; /// @dev DEBT: Amount of asset token that has been borrowed with accrued interest. uint256 totalBorrowAmount; } /// @dev Storage struct that holds data related to fees and interest struct AssetInterestData { /// @dev Total amount of already harvested protocol fees uint256 harvestedProtocolFees; /// @dev Total amount (ever growing) of asset token that has been earned by the protocol from /// generated interest. uint256 protocolFees; /// @dev Timestamp of the last time `interestRate` has been updated in storage. uint64 interestRateTimestamp; /// @dev True if asset was removed from the protocol. If so, deposit and borrow functions are disabled /// for that asset AssetStatus status; } /// @notice data that InterestModel needs for calculations struct UtilizationData { uint256 totalDeposits; uint256 totalBorrowAmount; /// @dev timestamp of last interest accrual uint64 interestRateTimestamp; } /// @dev Shares names and symbols that are generated while asset initialization struct AssetSharesMetadata { /// @dev Name for the collateral shares token string collateralName; /// @dev Symbol for the collateral shares token string collateralSymbol; /// @dev Name for the collateral only (protected collateral) shares token string protectedName; /// @dev Symbol for the collateral only (protected collateral) shares token string protectedSymbol; /// @dev Name for the debt shares token string debtName; /// @dev Symbol for the debt shares token string debtSymbol; } /// @notice Emitted when deposit is made /// @param asset asset address that was deposited /// @param depositor wallet address that deposited asset /// @param amount amount of asset that was deposited /// @param collateralOnly type of deposit, true if collateralOnly deposit was used event Deposit(address indexed asset, address indexed depositor, uint256 amount, bool collateralOnly); /// @notice Emitted when withdraw is made /// @param asset asset address that was withdrawn /// @param depositor wallet address that deposited asset /// @param receiver wallet address that received asset /// @param amount amount of asset that was withdrew /// @param collateralOnly type of withdraw, true if collateralOnly deposit was used event Withdraw( address indexed asset, address indexed depositor, address indexed receiver, uint256 amount, bool collateralOnly ); /// @notice Emitted on asset borrow /// @param asset asset address that was borrowed /// @param user wallet address that borrowed asset /// @param amount amount of asset that was borrowed event Borrow(address indexed asset, address indexed user, uint256 amount); /// @notice Emitted on asset repay /// @param asset asset address that was repaid /// @param user wallet address that repaid asset /// @param amount amount of asset that was repaid event Repay(address indexed asset, address indexed user, uint256 amount); /// @notice Emitted on user liquidation /// @param asset asset address that was liquidated /// @param user wallet address that was liquidated /// @param shareAmountRepaid amount of collateral-share token that was repaid. This is collateral token representing /// ownership of underlying deposit. /// @param seizedCollateral amount of underlying token that was seized by liquidator event Liquidate(address indexed asset, address indexed user, uint256 shareAmountRepaid, uint256 seizedCollateral); /// @notice Emitted when the status for an asset is updated /// @param asset asset address that was updated /// @param status new asset status event AssetStatusUpdate(address indexed asset, AssetStatus indexed status); /// @return version of the silo contract function VERSION() external returns (uint128); // solhint-disable-line func-name-mixedcase /// @notice Synchronize current bridge assets with Silo /// @dev This function needs to be called on Silo deployment to setup all assets for Silo. It needs to be /// called every time a bridged asset is added or removed. When bridge asset is removed, depositing and borrowing /// should be disabled during asset sync. function syncBridgeAssets() external; /// @notice Get Silo Repository contract address /// @return Silo Repository contract address function siloRepository() external view returns (ISiloRepository); /// @notice Get asset storage data /// @param _asset asset address /// @return AssetStorage struct function assetStorage(address _asset) external view returns (AssetStorage memory); /// @notice Get asset interest data /// @param _asset asset address /// @return AssetInterestData struct function interestData(address _asset) external view returns (AssetInterestData memory); /// @dev helper method for InterestRateModel calculations function utilizationData(address _asset) external view returns (UtilizationData memory data); /// @notice Calculates solvency of an account /// @param _user wallet address for which solvency is calculated /// @return true if solvent, false otherwise function isSolvent(address _user) external view returns (bool); /// @notice Returns all initialized (synced) assets of Silo including current and removed bridge assets /// @return assets array of initialized assets of Silo function getAssets() external view returns (address[] memory assets); /// @notice Returns all initialized (synced) assets of Silo including current and removed bridge assets /// with corresponding state /// @return assets array of initialized assets of Silo /// @return assetsStorage array of assets state corresponding to `assets` array function getAssetsWithState() external view returns (address[] memory assets, AssetStorage[] memory assetsStorage); /// @notice Check if depositing an asset for given account is possible /// @dev Depositing an asset that has been already borrowed (and vice versa) is disallowed /// @param _asset asset we want to deposit /// @param _depositor depositor address /// @return true if asset can be deposited by depositor function depositPossible(address _asset, address _depositor) external view returns (bool); /// @notice Check if borrowing an asset for given account is possible /// @dev Borrowing an asset that has been already deposited (and vice versa) is disallowed /// @param _asset asset we want to deposit /// @param _borrower borrower address /// @return true if asset can be borrowed by borrower function borrowPossible(address _asset, address _borrower) external view returns (bool); /// @dev Amount of token that is available for borrowing /// @param _asset asset to get liquidity for /// @return Silo liquidity function liquidity(address _asset) external view returns (uint256); }
// SPDX-License-Identifier: MIT pragma solidity 0.8.13; /// @dev when performing Silo flash liquidation, FlashReceiver contract will receive all collaterals interface IFlashLiquidationReceiver { /// @dev this method is called when doing Silo flash liquidation /// one can NOT assume, that if _seizedCollateral[i] != 0, then _shareAmountsToRepaid[i] must be 0 /// one should assume, that any combination of amounts is possible /// on callback, one must call `Silo.repayFor` because at the end of transaction, /// Silo will check if borrower is solvent. /// @param _user user address, that is liquidated /// @param _assets array of collateral assets received during user liquidation /// this array contains all assets (collateral borrowed) without any order /// @param _receivedCollaterals array of collateral amounts received during user liquidation /// indexes of amounts are related to `_assets`, /// @param _shareAmountsToRepaid array of amounts to repay for each asset /// indexes of amounts are related to `_assets`, /// @param _flashReceiverData data that are passed from sender that executes liquidation function siloLiquidationCallback( address _user, address[] calldata _assets, uint256[] calldata _receivedCollaterals, uint256[] calldata _shareAmountsToRepaid, bytes memory _flashReceiverData ) external; }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.13; interface IInterestRateModel { /* solhint-disable */ struct Config { // uopt ∈ (0, 1) – optimal utilization; int256 uopt; // ucrit ∈ (uopt, 1) – threshold of large utilization; int256 ucrit; // ulow ∈ (0, uopt) – threshold of low utilization int256 ulow; // ki > 0 – integrator gain int256 ki; // kcrit > 0 – proportional gain for large utilization int256 kcrit; // klow ≥ 0 – proportional gain for low utilization int256 klow; // klin ≥ 0 – coefficient of the lower linear bound int256 klin; // beta ≥ 0 - a scaling factor int256 beta; // ri ≥ 0 – initial value of the integrator int256 ri; // Tcrit ≥ 0 - the time during which the utilization exceeds the critical value int256 Tcrit; } /* solhint-enable */ /// @dev Set dedicated config for given asset in a Silo. Config is per asset per Silo so different assets /// in different Silo can have different configs. /// It will try to call `_silo.accrueInterest(_asset)` before updating config, but it is not guaranteed, /// that this call will be successful, if it fail config will be set anyway. /// @param _silo Silo address for which config should be set /// @param _asset asset address for which config should be set function setConfig(address _silo, address _asset, Config calldata _config) external; /// @dev get compound interest rate and update model storage /// @param _asset address of an asset in Silo for which interest rate should be calculated /// @param _blockTimestamp current block timestamp /// @return rcomp compounded interest rate from last update until now (1e18 == 100%) function getCompoundInterestRateAndUpdate( address _asset, uint256 _blockTimestamp ) external returns (uint256 rcomp); /// @dev Get config for given asset in a Silo. If dedicated config is not set, default one will be returned. /// @param _silo Silo address for which config should be set /// @param _asset asset address for which config should be set /// @return Config struct for asset in Silo function getConfig(address _silo, address _asset) external view returns (Config memory); /// @dev get compound interest rate /// @param _silo address of Silo /// @param _asset address of an asset in Silo for which interest rate should be calculated /// @param _blockTimestamp current block timestamp /// @return rcomp compounded interest rate from last update until now (1e18 == 100%) function getCompoundInterestRate( address _silo, address _asset, uint256 _blockTimestamp ) external view returns (uint256 rcomp); /// @dev get current annual interest rate /// @param _silo address of Silo /// @param _asset address of an asset in Silo for which interest rate should be calculated /// @param _blockTimestamp current block timestamp /// @return rcur current annual interest rate (1e18 == 100%) function getCurrentInterestRate( address _silo, address _asset, uint256 _blockTimestamp ) external view returns (uint256 rcur); /// @notice get the flag to detect rcomp restriction (zero current interest) due to overflow /// overflow boolean flag to detect rcomp restriction function overflowDetected( address _silo, address _asset, uint256 _blockTimestamp ) external view returns (bool overflow); /// @dev pure function that calculates current annual interest rate /// @param _c configuration object, InterestRateModel.Config /// @param _totalBorrowAmount current total borrows for asset /// @param _totalDeposits current total deposits for asset /// @param _interestRateTimestamp timestamp of last interest rate update /// @param _blockTimestamp current block timestamp /// @return rcur current annual interest rate (1e18 == 100%) function calculateCurrentInterestRate( Config memory _c, uint256 _totalDeposits, uint256 _totalBorrowAmount, uint256 _interestRateTimestamp, uint256 _blockTimestamp ) external pure returns (uint256 rcur); /// @dev pure function that calculates interest rate based on raw input data /// @param _c configuration object, InterestRateModel.Config /// @param _totalBorrowAmount current total borrows for asset /// @param _totalDeposits current total deposits for asset /// @param _interestRateTimestamp timestamp of last interest rate update /// @param _blockTimestamp current block timestamp /// @return rcomp compounded interest rate from last update until now (1e18 == 100%) /// @return ri current integral part of the rate /// @return Tcrit time during which the utilization exceeds the critical value /// @return overflow boolean flag to detect rcomp restriction function calculateCompoundInterestRateWithOverflowDetection( Config memory _c, uint256 _totalDeposits, uint256 _totalBorrowAmount, uint256 _interestRateTimestamp, uint256 _blockTimestamp ) external pure returns ( uint256 rcomp, int256 ri, int256 Tcrit, // solhint-disable-line var-name-mixedcase bool overflow ); /// @dev pure function that calculates interest rate based on raw input data /// @param _c configuration object, InterestRateModel.Config /// @param _totalBorrowAmount current total borrows for asset /// @param _totalDeposits current total deposits for asset /// @param _interestRateTimestamp timestamp of last interest rate update /// @param _blockTimestamp current block timestamp /// @return rcomp compounded interest rate from last update until now (1e18 == 100%) /// @return ri current integral part of the rate /// @return Tcrit time during which the utilization exceeds the critical value function calculateCompoundInterestRate( Config memory _c, uint256 _totalDeposits, uint256 _totalBorrowAmount, uint256 _interestRateTimestamp, uint256 _blockTimestamp ) external pure returns ( uint256 rcomp, int256 ri, int256 Tcrit // solhint-disable-line var-name-mixedcase ); /// @dev returns decimal points used by model function DP() external pure returns (uint256); // solhint-disable-line func-name-mixedcase /// @dev just a helper method to see if address is a InterestRateModel /// @return always true function interestRateModelPing() external pure returns (bytes4); }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.13; /// @title Common interface for Silo Incentive Contract interface INotificationReceiver { /// @dev Informs the contract about token transfer /// @param _token address of the token that was transferred /// @param _from sender /// @param _to receiver /// @param _amount amount that was transferred function onAfterTransfer(address _token, address _from, address _to, uint256 _amount) external; /// @dev Sanity check function /// @return always true function notificationReceiverPing() external pure returns (bytes4); }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity >=0.7.6 <0.9.0; /// @title Common interface for Silo Price Providers interface IPriceProvider { /// @notice Returns "Time-Weighted Average Price" for an asset. Calculates TWAP price for quote/asset. /// It unifies all tokens decimal to 18, examples: /// - if asses == quote it returns 1e18 /// - if asset is USDC and quote is ETH and ETH costs ~$3300 then it returns ~0.0003e18 WETH per 1 USDC /// @param _asset address of an asset for which to read price /// @return price of asses with 18 decimals, throws when pool is not ready yet to provide price function getPrice(address _asset) external view returns (uint256 price); /// @dev Informs if PriceProvider is setup for asset. It does not means PriceProvider can provide price right away. /// Some providers implementations need time to "build" buffer for TWAP price, /// so price may not be available yet but this method will return true. /// @param _asset asset in question /// @return TRUE if asset has been setup, otherwise false function assetSupported(address _asset) external view returns (bool); /// @notice Gets token address in which prices are quoted /// @return quoteToken address function quoteToken() external view returns (address); /// @notice Helper method that allows easily detects, if contract is PriceProvider /// @dev this can save us from simple human errors, in case we use invalid address /// but this should NOT be treated as security check /// @return always true function priceProviderPing() external pure returns (bytes4); }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity >=0.7.6 <0.9.0; import "./IPriceProvider.sol"; interface IPriceProvidersRepository { /// @notice Emitted when price provider is added /// @param newPriceProvider new price provider address event NewPriceProvider(IPriceProvider indexed newPriceProvider); /// @notice Emitted when price provider is removed /// @param priceProvider removed price provider address event PriceProviderRemoved(IPriceProvider indexed priceProvider); /// @notice Emitted when asset is assigned to price provider /// @param asset assigned asset address /// @param priceProvider price provider address event PriceProviderForAsset(address indexed asset, IPriceProvider indexed priceProvider); /// @notice Register new price provider /// @param _priceProvider address of price provider function addPriceProvider(IPriceProvider _priceProvider) external; /// @notice Unregister price provider /// @param _priceProvider address of price provider to be removed function removePriceProvider(IPriceProvider _priceProvider) external; /// @notice Sets price provider for asset /// @dev Request for asset price is forwarded to the price provider assigned to that asset /// @param _asset address of an asset for which price provider will be used /// @param _priceProvider address of price provider function setPriceProviderForAsset(address _asset, IPriceProvider _priceProvider) external; /// @notice Returns "Time-Weighted Average Price" for an asset /// @param _asset address of an asset for which to read price /// @return price TWAP price of a token with 18 decimals function getPrice(address _asset) external view returns (uint256 price); /// @notice Gets price provider assigned to an asset /// @param _asset address of an asset for which to get price provider /// @return priceProvider address of price provider function priceProviders(address _asset) external view returns (IPriceProvider priceProvider); /// @notice Gets token address in which prices are quoted /// @return quoteToken address function quoteToken() external view returns (address); /// @notice Gets manager role address /// @return manager role address function manager() external view returns (address); /// @notice Checks if providers are available for an asset /// @param _asset asset address to check /// @return returns TRUE if price feed is ready, otherwise false function providersReadyForAsset(address _asset) external view returns (bool); /// @notice Returns true if address is a registered price provider /// @param _provider address of price provider to be removed /// @return true if address is a registered price provider, otherwise false function isPriceProvider(IPriceProvider _provider) external view returns (bool); /// @notice Gets number of price providers registered /// @return number of price providers registered function providersCount() external view returns (uint256); /// @notice Gets an array of price providers /// @return array of price providers function providerList() external view returns (address[] memory); /// @notice Sanity check function /// @return returns always TRUE function priceProvidersRepositoryPing() external pure returns (bytes4); }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.13; import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol"; import "./INotificationReceiver.sol"; interface IShareToken is IERC20Metadata { /// @notice Emitted every time receiver is notified about token transfer /// @param notificationReceiver receiver address /// @param success false if TX reverted on `notificationReceiver` side, otherwise true event NotificationSent( INotificationReceiver indexed notificationReceiver, bool success ); /// @notice Mint method for Silo to create debt position /// @param _account wallet for which to mint token /// @param _amount amount of token to be minted function mint(address _account, uint256 _amount) external; /// @notice Burn method for Silo to close debt position /// @param _account wallet for which to burn token /// @param _amount amount of token to be burned function burn(address _account, uint256 _amount) external; }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.13; import "./IBaseSilo.sol"; interface ISilo is IBaseSilo { /// @notice Deposit `_amount` of `_asset` tokens from `msg.sender` to the Silo /// @param _asset The address of the token to deposit /// @param _amount The amount of the token to deposit /// @param _collateralOnly True if depositing collateral only /// @return collateralAmount deposited amount /// @return collateralShare user collateral shares based on deposited amount function deposit(address _asset, uint256 _amount, bool _collateralOnly) external returns (uint256 collateralAmount, uint256 collateralShare); /// @notice Router function to deposit `_amount` of `_asset` tokens to the Silo for the `_depositor` /// @param _asset The address of the token to deposit /// @param _depositor The address of the recipient of collateral tokens /// @param _amount The amount of the token to deposit /// @param _collateralOnly True if depositing collateral only /// @return collateralAmount deposited amount /// @return collateralShare `_depositor` collateral shares based on deposited amount function depositFor(address _asset, address _depositor, uint256 _amount, bool _collateralOnly) external returns (uint256 collateralAmount, uint256 collateralShare); /// @notice Withdraw `_amount` of `_asset` tokens from the Silo to `msg.sender` /// @param _asset The address of the token to withdraw /// @param _amount The amount of the token to withdraw /// @param _collateralOnly True if withdrawing collateral only deposit /// @return withdrawnAmount withdrawn amount that was transferred to user /// @return withdrawnShare burned share based on `withdrawnAmount` function withdraw(address _asset, uint256 _amount, bool _collateralOnly) external returns (uint256 withdrawnAmount, uint256 withdrawnShare); /// @notice Router function to withdraw `_amount` of `_asset` tokens from the Silo for the `_depositor` /// @param _asset The address of the token to withdraw /// @param _depositor The address that originally deposited the collateral tokens being withdrawn, /// it should be the one initiating the withdrawal through the router /// @param _receiver The address that will receive the withdrawn tokens /// @param _amount The amount of the token to withdraw /// @param _collateralOnly True if withdrawing collateral only deposit /// @return withdrawnAmount withdrawn amount that was transferred to `_receiver` /// @return withdrawnShare burned share based on `withdrawnAmount` function withdrawFor( address _asset, address _depositor, address _receiver, uint256 _amount, bool _collateralOnly ) external returns (uint256 withdrawnAmount, uint256 withdrawnShare); /// @notice Borrow `_amount` of `_asset` tokens from the Silo to `msg.sender` /// @param _asset The address of the token to borrow /// @param _amount The amount of the token to borrow /// @return debtAmount borrowed amount /// @return debtShare user debt share based on borrowed amount function borrow(address _asset, uint256 _amount) external returns (uint256 debtAmount, uint256 debtShare); /// @notice Router function to borrow `_amount` of `_asset` tokens from the Silo for the `_receiver` /// @param _asset The address of the token to borrow /// @param _borrower The address that will take the loan, /// it should be the one initiating the borrowing through the router /// @param _receiver The address of the asset receiver /// @param _amount The amount of the token to borrow /// @return debtAmount borrowed amount /// @return debtShare `_receiver` debt share based on borrowed amount function borrowFor(address _asset, address _borrower, address _receiver, uint256 _amount) external returns (uint256 debtAmount, uint256 debtShare); /// @notice Repay `_amount` of `_asset` tokens from `msg.sender` to the Silo /// @param _asset The address of the token to repay /// @param _amount amount of asset to repay, includes interests /// @return repaidAmount amount repaid /// @return burnedShare burned debt share function repay(address _asset, uint256 _amount) external returns (uint256 repaidAmount, uint256 burnedShare); /// @notice Allows to repay in behalf of borrower to execute liquidation /// @param _asset The address of the token to repay /// @param _borrower The address of the user to have debt tokens burned /// @param _amount amount of asset to repay, includes interests /// @return repaidAmount amount repaid /// @return burnedShare burned debt share function repayFor(address _asset, address _borrower, uint256 _amount) external returns (uint256 repaidAmount, uint256 burnedShare); /// @dev harvest protocol fees from an array of assets /// @return harvestedAmounts amount harvested during tx execution for each of silo asset function harvestProtocolFees() external returns (uint256[] memory harvestedAmounts); /// @notice Function to update interests for `_asset` token since the last saved state /// @param _asset The address of the token to be updated /// @return interest accrued interest function accrueInterest(address _asset) external returns (uint256 interest); /// @notice this methods does not requires to have tokens in order to liquidate user /// @dev during liquidation process, msg.sender will be notified once all collateral will be send to him /// msg.sender needs to be `IFlashLiquidationReceiver` /// @param _users array of users to liquidate /// @param _flashReceiverData this data will be forward to msg.sender on notification /// @return assets array of all processed assets (collateral + debt, including removed) /// @return receivedCollaterals receivedCollaterals[userId][assetId] => amount /// amounts of collaterals send to `_flashReceiver` /// @return shareAmountsToRepaid shareAmountsToRepaid[userId][assetId] => amount /// required amounts of debt to be repaid function flashLiquidate(address[] memory _users, bytes memory _flashReceiverData) external returns ( address[] memory assets, uint256[][] memory receivedCollaterals, uint256[][] memory shareAmountsToRepaid ); }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.13; interface ISiloFactory { /// @notice Emitted when Silo is deployed /// @param silo address of deployed Silo /// @param asset address of asset for which Silo was deployed /// @param version version of silo implementation event NewSiloCreated(address indexed silo, address indexed asset, uint128 version); /// @notice Must be called by repository on constructor /// @param _siloRepository the SiloRepository to set function initRepository(address _siloRepository) external; /// @notice Deploys Silo /// @param _siloAsset unique asset for which Silo is deployed /// @param _version version of silo implementation /// @param _data (optional) data that may be needed during silo creation /// @return silo deployed Silo address function createSilo(address _siloAsset, uint128 _version, bytes memory _data) external returns (address silo); /// @dev just a helper method to see if address is a factory function siloFactoryPing() external pure returns (bytes4); }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.13; import "./ISiloFactory.sol"; import "./ITokensFactory.sol"; import "./IPriceProvidersRepository.sol"; import "./INotificationReceiver.sol"; import "./IInterestRateModel.sol"; interface ISiloRepository { /// @dev protocol fees in precision points (Solvency._PRECISION_DECIMALS), we do allow for fee == 0 struct Fees { /// @dev One time protocol fee for opening a borrow position in precision points (Solvency._PRECISION_DECIMALS) uint64 entryFee; /// @dev Protocol revenue share in interest paid in precision points (Solvency._PRECISION_DECIMALS) uint64 protocolShareFee; /// @dev Protocol share in liquidation profit in precision points (Solvency._PRECISION_DECIMALS). /// It's calculated from total collateral amount to be transferred to liquidator. uint64 protocolLiquidationFee; } struct SiloVersion { /// @dev Default version of Silo. If set to 0, it means it is not set. By default it is set to 1 uint128 byDefault; /// @dev Latest added version of Silo. If set to 0, it means it is not set. By default it is set to 1 uint128 latest; } /// @dev AssetConfig struct represents configurable parameters for each Silo struct AssetConfig { /// @dev Loan-to-Value ratio represents the maximum borrowing power of a specific collateral. /// For example, if the collateral asset has an LTV of 75%, the user can borrow up to 0.75 worth /// of quote token in the principal currency for every quote token worth of collateral. /// value uses 18 decimals eg. 100% == 1e18 /// max valid value is 1e18 so it needs storage of 60 bits uint64 maxLoanToValue; /// @dev Liquidation Threshold represents the threshold at which a borrow position will be considered /// undercollateralized and subject to liquidation for each collateral. For example, /// if a collateral has a liquidation threshold of 80%, it means that the loan will be /// liquidated when the borrowAmount value is worth 80% of the collateral value. /// value uses 18 decimals eg. 100% == 1e18 uint64 liquidationThreshold; /// @dev interest rate model address IInterestRateModel interestRateModel; } event NewDefaultMaximumLTV(uint64 defaultMaximumLTV); event NewDefaultLiquidationThreshold(uint64 defaultLiquidationThreshold); /// @notice Emitted on new Silo creation /// @param silo deployed Silo address /// @param asset unique asset for deployed Silo /// @param siloVersion version of deployed Silo event NewSilo(address indexed silo, address indexed asset, uint128 siloVersion); /// @notice Emitted when new Silo (or existing one) becomes a bridge pool (pool with only bridge tokens). /// @param pool address of the bridge pool, It can be zero address when bridge asset is removed and pool no longer /// is treated as bridge pool event BridgePool(address indexed pool); /// @notice Emitted on new bridge asset /// @param newBridgeAsset address of added bridge asset event BridgeAssetAdded(address indexed newBridgeAsset); /// @notice Emitted on removed bridge asset /// @param bridgeAssetRemoved address of removed bridge asset event BridgeAssetRemoved(address indexed bridgeAssetRemoved); /// @notice Emitted when default interest rate model is changed /// @param newModel address of new interest rate model event InterestRateModel(IInterestRateModel indexed newModel); /// @notice Emitted on price provider repository address update /// @param newProvider address of new oracle repository event PriceProvidersRepositoryUpdate( IPriceProvidersRepository indexed newProvider ); /// @notice Emitted on token factory address update /// @param newTokensFactory address of new token factory event TokensFactoryUpdate(address indexed newTokensFactory); /// @notice Emitted on router address update /// @param newRouter address of new router event RouterUpdate(address indexed newRouter); /// @notice Emitted on INotificationReceiver address update /// @param newIncentiveContract address of new INotificationReceiver event NotificationReceiverUpdate(INotificationReceiver indexed newIncentiveContract); /// @notice Emitted when new Silo version is registered /// @param factory factory address that deploys registered Silo version /// @param siloLatestVersion Silo version of registered Silo /// @param siloDefaultVersion current default Silo version event RegisterSiloVersion(address indexed factory, uint128 siloLatestVersion, uint128 siloDefaultVersion); /// @notice Emitted when Silo version is unregistered /// @param factory factory address that deploys unregistered Silo version /// @param siloVersion version that was unregistered event UnregisterSiloVersion(address indexed factory, uint128 siloVersion); /// @notice Emitted when default Silo version is updated /// @param newDefaultVersion new default version event SiloDefaultVersion(uint128 newDefaultVersion); /// @notice Emitted when default fee is updated /// @param newEntryFee new entry fee /// @param newProtocolShareFee new protocol share fee /// @param newProtocolLiquidationFee new protocol liquidation fee event FeeUpdate( uint64 newEntryFee, uint64 newProtocolShareFee, uint64 newProtocolLiquidationFee ); /// @notice Emitted when asset config is updated for a silo /// @param silo silo for which asset config is being set /// @param asset asset for which asset config is being set /// @param assetConfig new asset config event AssetConfigUpdate(address indexed silo, address indexed asset, AssetConfig assetConfig); /// @notice Emitted when silo (silo factory) version is set for asset /// @param asset asset for which asset config is being set /// @param version Silo version event VersionForAsset(address indexed asset, uint128 version); /// @param _siloAsset silo asset /// @return version of Silo that is assigned for provided asset, if not assigned it returns zero (default) function getVersionForAsset(address _siloAsset) external returns (uint128); /// @notice setter for `getVersionForAsset` mapping /// @param _siloAsset silo asset /// @param _version version of Silo that will be assigned for `_siloAsset`, zero (default) is acceptable function setVersionForAsset(address _siloAsset, uint128 _version) external; /// @notice use this method only when off-chain verification is OFF /// @dev Silo does NOT support rebase and deflationary tokens /// @param _siloAsset silo asset /// @param _siloData (optional) data that may be needed during silo creation /// @return createdSilo address of created silo function newSilo(address _siloAsset, bytes memory _siloData) external returns (address createdSilo); /// @notice use this method to deploy new version of Silo for an asset that already has Silo deployed. /// Only owner (DAO) can replace. /// @dev Silo does NOT support rebase and deflationary tokens /// @param _siloAsset silo asset /// @param _siloVersion version of silo implementation. Use 0 for default version which is fine /// for 99% of cases. /// @param _siloData (optional) data that may be needed during silo creation /// @return createdSilo address of created silo function replaceSilo( address _siloAsset, uint128 _siloVersion, bytes memory _siloData ) external returns (address createdSilo); /// @notice Set factory contract for debt and collateral tokens for each Silo asset /// @dev Callable only by owner /// @param _tokensFactory address of TokensFactory contract that deploys debt and collateral tokens function setTokensFactory(address _tokensFactory) external; /// @notice Set default fees /// @dev Callable only by owner /// @param _fees: /// - _entryFee one time protocol fee for opening a borrow position in precision points /// (Solvency._PRECISION_DECIMALS) /// - _protocolShareFee protocol revenue share in interest paid in precision points /// (Solvency._PRECISION_DECIMALS) /// - _protocolLiquidationFee protocol share in liquidation profit in precision points /// (Solvency._PRECISION_DECIMALS). It's calculated from total collateral amount to be transferred /// to liquidator. function setFees(Fees calldata _fees) external; /// @notice Set configuration for given asset in given Silo /// @dev Callable only by owner /// @param _silo Silo address for which config applies /// @param _asset asset address for which config applies /// @param _assetConfig: /// - _maxLoanToValue maximum Loan-to-Value, for details see `Repository.AssetConfig.maxLoanToValue` /// - _liquidationThreshold liquidation threshold, for details see `Repository.AssetConfig.maxLoanToValue` /// - _interestRateModel interest rate model address, for details see `Repository.AssetConfig.interestRateModel` function setAssetConfig( address _silo, address _asset, AssetConfig calldata _assetConfig ) external; /// @notice Set default interest rate model /// @dev Callable only by owner /// @param _defaultInterestRateModel default interest rate model function setDefaultInterestRateModel(IInterestRateModel _defaultInterestRateModel) external; /// @notice Set default maximum LTV /// @dev Callable only by owner /// @param _defaultMaxLTV default maximum LTV in precision points (Solvency._PRECISION_DECIMALS) function setDefaultMaximumLTV(uint64 _defaultMaxLTV) external; /// @notice Set default liquidation threshold /// @dev Callable only by owner /// @param _defaultLiquidationThreshold default liquidation threshold in precision points /// (Solvency._PRECISION_DECIMALS) function setDefaultLiquidationThreshold(uint64 _defaultLiquidationThreshold) external; /// @notice Set price provider repository /// @dev Callable only by owner /// @param _repository price provider repository address function setPriceProvidersRepository(IPriceProvidersRepository _repository) external; /// @notice Set router contract /// @dev Callable only by owner /// @param _router router address function setRouter(address _router) external; /// @notice Set NotificationReceiver contract /// @dev Callable only by owner /// @param _silo silo address for which to set `_notificationReceiver` /// @param _notificationReceiver NotificationReceiver address function setNotificationReceiver(address _silo, INotificationReceiver _notificationReceiver) external; /// @notice Adds new bridge asset /// @dev New bridge asset must be unique. Duplicates in bridge assets are not allowed. It's possible to add /// bridge asset that has been removed in the past. Note that all Silos must be synced manually. Callable /// only by owner. /// @param _newBridgeAsset bridge asset address function addBridgeAsset(address _newBridgeAsset) external; /// @notice Removes bridge asset /// @dev Note that all Silos must be synced manually. Callable only by owner. /// @param _bridgeAssetToRemove bridge asset address to be removed function removeBridgeAsset(address _bridgeAssetToRemove) external; /// @notice Registers new Silo version /// @dev User can choose which Silo version he wants to deploy. It's possible to have multiple versions of Silo. /// Callable only by owner. /// @param _factory factory contract that deploys new version of Silo /// @param _isDefault true if this version should be used as default function registerSiloVersion(ISiloFactory _factory, bool _isDefault) external; /// @notice Unregisters Silo version /// @dev Callable only by owner. /// @param _siloVersion Silo version to be unregistered function unregisterSiloVersion(uint128 _siloVersion) external; /// @notice Sets default Silo version /// @dev Callable only by owner. /// @param _defaultVersion Silo version to be set as default function setDefaultSiloVersion(uint128 _defaultVersion) external; /// @notice Check if contract address is a Silo deployment /// @param _silo address of expected Silo /// @return true if address is Silo deployment, otherwise false function isSilo(address _silo) external view returns (bool); /// @notice Get Silo address of asset /// @param _asset address of asset /// @return address of corresponding Silo deployment function getSilo(address _asset) external view returns (address); /// @notice Get Silo Factory for given version /// @param _siloVersion version of Silo implementation /// @return ISiloFactory contract that deploys Silos of given version function siloFactory(uint256 _siloVersion) external view returns (ISiloFactory); /// @notice Get debt and collateral Token Factory /// @return ITokensFactory contract that deploys debt and collateral tokens function tokensFactory() external view returns (ITokensFactory); /// @notice Get Router contract /// @return address of router contract function router() external view returns (address); /// @notice Get current bridge assets /// @dev Keep in mind that not all Silos may be synced with current bridge assets so it's possible that some /// assets in that list are not part of given Silo. /// @return address array of bridge assets function getBridgeAssets() external view returns (address[] memory); /// @notice Get removed bridge assets /// @dev Keep in mind that not all Silos may be synced with bridge assets so it's possible that some /// assets in that list are still part of given Silo. /// @return address array of bridge assets function getRemovedBridgeAssets() external view returns (address[] memory); /// @notice Get maximum LTV for asset in given Silo /// @dev If dedicated config is not set, method returns default config /// @param _silo address of Silo /// @param _asset address of an asset /// @return maximum LTV in precision points (Solvency._PRECISION_DECIMALS) function getMaximumLTV(address _silo, address _asset) external view returns (uint256); /// @notice Get Interest Rate Model address for asset in given Silo /// @dev If dedicated config is not set, method returns default config /// @param _silo address of Silo /// @param _asset address of an asset /// @return address of interest rate model function getInterestRateModel(address _silo, address _asset) external view returns (IInterestRateModel); /// @notice Get liquidation threshold for asset in given Silo /// @dev If dedicated config is not set, method returns default config /// @param _silo address of Silo /// @param _asset address of an asset /// @return liquidation threshold in precision points (Solvency._PRECISION_DECIMALS) function getLiquidationThreshold(address _silo, address _asset) external view returns (uint256); /// @notice Get incentive contract address. Incentive contracts are responsible for distributing rewards /// to debt and/or collateral token holders of given Silo /// @param _silo address of Silo /// @return incentive contract address function getNotificationReceiver(address _silo) external view returns (INotificationReceiver); /// @notice Get owner role address of Repository /// @return owner role address function owner() external view returns (address); /// @notice get PriceProvidersRepository contract that manages price providers implementations /// @return IPriceProvidersRepository address function priceProvidersRepository() external view returns (IPriceProvidersRepository); /// @dev Get protocol fee for opening a borrow position /// @return fee in precision points (Solvency._PRECISION_DECIMALS == 100%) function entryFee() external view returns (uint256); /// @dev Get protocol share fee /// @return protocol share fee in precision points (Solvency._PRECISION_DECIMALS == 100%) function protocolShareFee() external view returns (uint256); /// @dev Get protocol liquidation fee /// @return protocol liquidation fee in precision points (Solvency._PRECISION_DECIMALS == 100%) function protocolLiquidationFee() external view returns (uint256); /// @dev Checks all conditions for new silo creation and throws when not possible to create /// @param _asset address of asset for which you want to create silo /// @param _assetIsABridge bool TRUE when `_asset` is bridge asset, FALSE when it is not function ensureCanCreateSiloFor(address _asset, bool _assetIsABridge) external view; function siloRepositoryPing() external pure returns (bytes4); }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.13; import "./IShareToken.sol"; interface ITokensFactory { /// @notice Emitted when collateral token is deployed /// @param token address of deployed collateral token event NewShareCollateralTokenCreated(address indexed token); /// @notice Emitted when collateral token is deployed /// @param token address of deployed debt token event NewShareDebtTokenCreated(address indexed token); ///@notice Must be called by repository on constructor /// @param _siloRepository the SiloRepository to set function initRepository(address _siloRepository) external; /// @notice Deploys collateral token /// @param _name name of the token /// @param _symbol symbol of the token /// @param _asset underlying asset for which token is deployed /// @return address of deployed collateral share token function createShareCollateralToken( string memory _name, string memory _symbol, address _asset ) external returns (IShareToken); /// @notice Deploys debt token /// @param _name name of the token /// @param _symbol symbol of the token /// @param _asset underlying asset for which token is deployed /// @return address of deployed debt share token function createShareDebtToken( string memory _name, string memory _symbol, address _asset ) external returns (IShareToken); /// @dev just a helper method to see if address is a factory /// @return always true function tokensFactoryPing() external pure returns (bytes4); }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.13; library EasyMath { error ZeroAssets(); error ZeroShares(); function toShare(uint256 amount, uint256 totalAmount, uint256 totalShares) internal pure returns (uint256) { if (totalShares == 0 || totalAmount == 0) { return amount; } uint256 result = amount * totalShares / totalAmount; // Prevent rounding error if (result == 0 && amount != 0) { revert ZeroShares(); } return result; } function toShareRoundUp(uint256 amount, uint256 totalAmount, uint256 totalShares) internal pure returns (uint256) { if (totalShares == 0 || totalAmount == 0) { return amount; } uint256 numerator = amount * totalShares; uint256 result = numerator / totalAmount; // Round up if (numerator % totalAmount != 0) { result += 1; } return result; } function toAmount(uint256 share, uint256 totalAmount, uint256 totalShares) internal pure returns (uint256) { if (totalShares == 0 || totalAmount == 0) { return 0; } uint256 result = share * totalAmount / totalShares; // Prevent rounding error if (result == 0 && share != 0) { revert ZeroAssets(); } return result; } function toAmountRoundUp(uint256 share, uint256 totalAmount, uint256 totalShares) internal pure returns (uint256) { if (totalShares == 0 || totalAmount == 0) { return 0; } uint256 numerator = share * totalAmount; uint256 result = numerator / totalShares; // Round up if (numerator % totalShares != 0) { result += 1; } return result; } function toValue(uint256 _assetAmount, uint256 _assetPrice, uint256 _assetDecimals) internal pure returns (uint256) { return _assetAmount * _assetPrice / 10 ** _assetDecimals; } function sum(uint256[] memory _numbers) internal pure returns (uint256 s) { for(uint256 i; i < _numbers.length; i++) { s += _numbers[i]; } } /// @notice Calculates fraction between borrowed and deposited amount of tokens denominated in percentage /// @dev It assumes `_dp` = 100%. /// @param _dp decimal points used by model /// @param _totalDeposits current total deposits for assets /// @param _totalBorrowAmount current total borrows for assets /// @return utilization value function calculateUtilization(uint256 _dp, uint256 _totalDeposits, uint256 _totalBorrowAmount) internal pure returns (uint256) { if (_totalDeposits == 0 || _totalBorrowAmount == 0) return 0; return _totalBorrowAmount * _dp / _totalDeposits; } }
// SPDX-License-Identifier: 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); } }
{ "evmVersion": "london", "libraries": {}, "metadata": { "bytecodeHash": "ipfs", "useLiteralContent": true }, "optimizer": { "enabled": true, "runs": 200 }, "remappings": [], "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } } }
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"}],"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":"_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
60806040523480156200001157600080fd5b5060405162002f9d38038062002f9d8339810160408190526200003491620004e6565b6200003f3362000054565b6200004d6000808362000111565b5062000570565b6000546001600160a01b03808316911603620000ab5760405162461bcd60e51b81526020600482015260116024820152704f776e65724469644e6f744368616e676560781b60448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b038316908117825560405190917f04dba622d284ed0014ee4b9a6a68386be1a4c08a4913ae272de89199cc68616391a26001546001600160a01b0316156200010e576200010e600062000405565b50565b8051670de0b6b3a76400009060001215806200012e575081518113155b156200014d576040516313e9c00360e21b815260040160405180910390fd5b8151602083015113158062000166575080826020015112155b1562000185576040516339bda99160e11b815260040160405180910390fd5b600082604001511315806200019f57508151604083015112155b15620001be57604051635c65494d60e01b815260040160405180910390fd5b6000826060015113620001e45760405163fe06781560e01b815260040160405180910390fd5b60008260800151136200020a576040516320d12cb560e21b815260040160405180910390fd5b60008260a00151121562000234576040516001627ddb5960e01b0319815260040160405180910390fd5b60008260c0015112156200025b57604051634e435a2160e01b815260040160405180910390fd5b60008260e00151121562000282576040516378a8371160e01b815260040160405180910390fd5b60008261010001511215620002aa576040516330eecc6b60e21b815260040160405180910390fd5b60008261012001511215620002d257604051630266493760e31b815260040160405180910390fd5b6001600160a01b03808516600081815260026020818152604080842095891680855295825292839020875181559087015160018201558287015191810191909155606086015160038201556080860151600482015560a0860151600582015560c0860151600682015560e086015160078201556101008601516008820155610120860151600990910155517ff254631d9ea3e3ab061b1c56e1215a268abf5ff28a460b255f308aac112df45890620003f7908690600061014082019050825182526020830151602083015260408301516040830152606083015160608301526080830151608083015260a083015160a083015260c083015160c083015260e083015160e083015261010080840151818401525061012080840151818401525092915050565b60405180910390a350505050565b6001546001600160a01b03808316911603620004645760405162461bcd60e51b815260206004820152601860248201527f50656e64696e674f776e65724469644e6f744368616e676500000000000000006044820152606401620000a2565b600180546001600160a01b0319166001600160a01b0383169081179091556040517fd6aad444c90d39fb0eee1c6e357a7fad83d63f719ac5f880445a2beb0ff3ab5890600090a250565b60405161014081016001600160401b0381118282101715620004e057634e487b7160e01b600052604160045260246000fd5b60405290565b60006101408284031215620004fa57600080fd5b62000504620004ae565b825181526020830151602082015260408301516040820152606083015160608201526080830151608082015260a083015160a082015260c083015160c082015260e083015160e08201526101008084015181830152506101208084015181830152508091505092915050565b612a1d80620005806000396000f3fe608060405234801561001057600080fd5b50600436106101425760003560e01c806374a3e924116100b8578063bbdcbed61161007c578063bbdcbed6146102ba578063c42401f1146102da578063cbf75c9a146102ef578063e076a551146103a8578063e30c3978146103b9578063f2fde38b146103ca57600080fd5b806374a3e9241461025857806379ba50971461026b57806381b51e0c146102735780638da5cb5b14610282578063b1e01765146102a757600080fd5b80633278c6941161010a5780633278c694146101dc5780633ced7d0d146101f157806344552b5d146102045780636bcc82161461020c5780636e1a41401461021b578063715018a61461025057600080fd5b8063023279ce1461014757806303dc12fc1461017a578063071962ff1461019b578063109a006e146101ae57806311e5152b146101b9575b600080fd5b61015a610155366004612451565b6103dd565b604080519384526020840192909252908201526060015b60405180910390f35b61018d6101883660046124b0565b610401565b604051908152602001610171565b61018d6101a93660046124da565b6104d8565b61018d600160c41b81565b6101cc6101c73660046124da565b61057b565b6040519015158152602001610171565b6101ef6101ea366004612516565b610621565b005b61018d6101ff366004612451565b61066f565b6101ef6108e6565b61018d670de0b6b3a764000081565b61022e610229366004612451565b61092b565b6040805194855260208501939093529183015215156060820152608001610171565b6101ef610d85565b6101ef610266366004612531565b610dc8565b6101ef610eb4565b61018d6799e8e8e3d530368181565b6000546001600160a01b03165b6040516001600160a01b039091168152602001610171565b61018d6102b53660046124da565b610f1b565b6102cd6102c8366004612582565b610fc1565b60405161017191906125b5565b60405163c42401f160e01b8152602001610171565b61035e6102fd366004612582565b600260205281600052604060002060205280600052604060002060009150915050806000015490806001015490806002015490806003015490806004015490806005015490806006015490806007015490806008015490806009015490508a565b604080519a8b5260208b0199909952978901969096526060880194909452608087019290925260a086015260c085015260e084015261010083015261012082015261014001610171565b61018d690de0b6b3a7640000000081565b6001546001600160a01b031661028f565b6101ef6103d8366004612516565b611243565b60008060006103ef888888888861092b565b50919a90995090975095505050505050565b604051631f0f875560e31b81526001600160a01b038316600482015260009033908290829063f87c3aa890602401606060405180830381865afa15801561044c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104709190612626565b6001600160a01b038084166000908152600260209081526040808320938a168352929052209091506104c16104a58488610fc1565b83516020850151604086015167ffffffffffffffff16896103dd565b600984015560089092019190915595945050505050565b604051631f0f875560e31b81526001600160a01b038381166004830152600091829186169063f87c3aa890602401606060405180830381865afa158015610523573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105479190612626565b90506105726105568686610fc1565b82516020840151604085015167ffffffffffffffff168761066f565b95945050505050565b604051631f0f875560e31b81526001600160a01b038381166004830152600091829186169063f87c3aa890602401606060405180830381865afa1580156105c6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105ea9190612626565b90506106156105f98686610fc1565b82516020840151604085015167ffffffffffffffff168761092b565b98975050505050505050565b336106346000546001600160a01b031690565b6001600160a01b0316146106635760405162461bcd60e51b815260040161065a9061269e565b60405180910390fd5b61066c816112c9565b50565b6000818311156106925760405163d22806e360e01b815260040160405180910390fd5b60006040518060e001604052806000815260200160008152602001600081526020016000815260200160008152602001600081526020016000151581525090506106df878787878761092b565b15801560c086015292506106fa915050576000915050610572565b610705848403611370565b815261072261071d670de0b6b3a764000088886113de565b611370565b6020808301829052670de0b6b3a7640000604084015288015112156107c65780604001518760200151826020015161075a91906126d7565b6040830151835160e08b01516107709190612716565b8a61012001518560400151610785919061279b565b61078f919061279b565b8a6080015161079e9190612716565b6107a891906127f2565b6107b29190612716565b6107bc91906127f2565b6060820152610808565b61080260008260400151896040015184602001516107e491906126d7565b8a60a001516107f39190612716565b6107fd91906127f2565b611417565b60608201525b806040015181602001518860c001516108219190612716565b61082b91906127f2565b608082018190526101008801516108419161142d565b60a0820152604081015181518851602084015161089f939291610863916126d7565b8a606001516108729190612716565b61087c9190612716565b61088691906127f2565b8260a00151610895919061279b565b826080015161142d565b60a0820181905260608201516108cb916108c6916108bc9161279b565b836080015161142d565b61143c565b91506108db6301e1338083612820565b979650505050505050565b336108f96000546001600160a01b031690565b6001600160a01b03161461091f5760405162461bcd60e51b815260040161065a9061269e565b61092960006112c9565b565b60008060008088610100015192508861012001519150600060405180610140016040528060008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152509050858711156109b65760405163d22806e360e01b815260040160405180910390fd5b6109c1878703611370565b8152670de0b6b3a76400006109da61071d828c8c6113de565b61012083018190528b5182916109f091906126d7565b8c606001516109ff9190612716565b610a0991906127f2565b6020808401919091528b01516101208301511315610af357808b60200151836101200151610a3791906126d7565b82610a42878261279b565b8e60800151610a519190612716565b610a5b91906127f2565b610a659190612716565b610a6f91906127f2565b604083015260208b01516101208301518291610a8a916126d7565b828d60e001518e60800151610a9f9190612716565b610aa991906127f2565b610ab39190612716565b610abd91906127f2565b8260200151610acc919061279b565b6060830152815160e08c0151610ae29190612716565b610aec908561279b565b9350610b56565b610b1d6000828d60400151856101200151610b0e91906126d7565b8e60a001516107f39190612716565b604083015260208201516060830152815160e08c0151610b5391600091610b449190612716565b610b4e90876126d7565b61142d565b93505b808261012001518c60c00151610b6c9190612716565b610b7691906127f2565b60a08301819052610b8890869061142d565b9450816040015185610b9a919061279b565b608083015281516060830151610bb09190612716565b8260800151610bbf919061279b565b60c083015260a0820151608083015112801590610be457508160a001518260c0015112155b15610c2057815160c0830151608084015160029291610c029161279b565b610c0c9190612716565b610c1691906127f2565b60e0830152610d2a565b8160a001518260800151128015610c3e57508160a001518260c00151125b15610c5457815160a0830151610c169190612716565b8160a00151826080015112158015610c7357508160a001518260c00151125b15610cce576002826060015160028460a001518560800151610c9591906126d7565b610c9f919061296c565b610ca991906127f2565b610cb391906127f2565b825160a0840151610cc49190612716565b610c1691906126d7565b6002826060015160028460a001518560c00151610ceb91906126d7565b610cf5919061296c565b610cff91906127f2565b610d0991906127f2565b825160a0840151610d1a9190612716565b610d24919061279b565b60e08301525b81516020830151610d5291610d3e91612716565b610d48908761279b565b8360a0015161142d565b9450610d638a8a8460e0015161148e565b90965092508215610d775760009450600093505b505095509550955095915050565b33610d986000546001600160a01b031690565b6001600160a01b031614610dbe5760405162461bcd60e51b815260040161065a9061269e565b61092960006115ac565b33610ddb6000546001600160a01b031690565b6001600160a01b031614610e015760405162461bcd60e51b815260040161065a9061269e565b6040516001600160a01b03838116602483015284169060440160408051601f198184030181529181526020820180516001600160e01b0316639198e51560e01b17905251610e4f919061297b565b6000604051808303816000865af19150503d8060008114610e8c576040519150601f19603f3d011682016040523d82523d6000602084013e610e91565b606091505b505050610eaf838383803603810190610eaa91906129b6565b61165d565b505050565b6001546001600160a01b03163314610f015760405162461bcd60e51b815260206004820152601060248201526f27b7363ca832b73234b733a7bbb732b960811b604482015260640161065a565b610929610f166001546001600160a01b031690565b6115ac565b604051631f0f875560e31b81526001600160a01b038381166004830152600091829186169063f87c3aa890602401606060405180830381865afa158015610f66573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f8a9190612626565b9050610fb5610f998686610fc1565b82516020840151604085015167ffffffffffffffff16876103dd565b50909695505050505050565b611017604051806101400160405280600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b6001600160a01b0380841660009081526002602090815260408083209386168352929052208054156110b857604080516101408101825282548152600183015460208201526002830154918101919091526003820154606082015260048201546080820152600582015460a0820152600682015460c0820152600782015460e08201526008820154610100820152600990910154610120820152905061123d565b600080527fac33ff75c19e70fe83507db0d683fd3465c996598dc972688b7ace676c89077b602090815260408051610140810182527f6ee3efecae883df2d7ccda22610b4ca771a299e707cb0d65c4ec97dc4e6668ad5481527f6ee3efecae883df2d7ccda22610b4ca771a299e707cb0d65c4ec97dc4e6668ae54928101929092527f6ee3efecae883df2d7ccda22610b4ca771a299e707cb0d65c4ec97dc4e6668af54908201527f6ee3efecae883df2d7ccda22610b4ca771a299e707cb0d65c4ec97dc4e6668b05460608201527f6ee3efecae883df2d7ccda22610b4ca771a299e707cb0d65c4ec97dc4e6668b15460808201527f6ee3efecae883df2d7ccda22610b4ca771a299e707cb0d65c4ec97dc4e6668b25460a08201527f6ee3efecae883df2d7ccda22610b4ca771a299e707cb0d65c4ec97dc4e6668b35460c08201527f6ee3efecae883df2d7ccda22610b4ca771a299e707cb0d65c4ec97dc4e6668b45460e0820152600882015461010082015260099091015461012082015290505b92915050565b336112566000546001600160a01b031690565b6001600160a01b03161461127c5760405162461bcd60e51b815260040161065a9061269e565b6001600160a01b0381166112c05760405162461bcd60e51b815260206004820152600b60248201526a4f776e657249735a65726f60a81b604482015260640161065a565b61066c816115ac565b6001546001600160a01b038083169116036113265760405162461bcd60e51b815260206004820152601860248201527f50656e64696e674f776e65724469644e6f744368616e67650000000000000000604482015260640161065a565b600180546001600160a01b0319166001600160a01b0383169081179091556040517fd6aad444c90d39fb0eee1c6e357a7fad83d63f719ac5f880445a2beb0ff3ab5890600090a250565b60006001600160ff1b038211156113da5760405162461bcd60e51b815260206004820152602860248201527f53616665436173743a2076616c756520646f65736e27742066697420696e2061604482015267371034b73a191a9b60c11b606482015260840161065a565b5090565b60008215806113eb575081155b156113f857506000611410565b826114038584612820565b61140d91906129d3565b90505b9392505050565b60008183126114265781611410565b5090919050565b60008183136114265781611410565b6000808212156113da5760405162461bcd60e51b815260206004820181905260248201527f53616665436173743a2076616c7565206d75737420626520706f736974697665604482015260640161065a565b60008060006799e8e8e3d530368184126114b857690de0b6b3a764000000009250600191506114f1565b670de0b6b3a76400006114ca856118d7565b6114d491906126d7565b9050600081136114e55760006114ee565b6114ee8161143c565b92505b60008587116115005785611502565b865b9050600160c41b811061151e57600060019350935050506115a4565b8386026000819003611532575050506115a4565b86858281611542576115426127dc565b0414158061156c575081600160c41b03670de0b6b3a76400008281611569576115696127dc565b04115b156115a05786670de0b6b3a764000083600160c41b030281611590576115906127dc565b049450600193506115a492505050565b5050505b935093915050565b6000546001600160a01b038083169116036115fd5760405162461bcd60e51b81526020600482015260116024820152704f776e65724469644e6f744368616e676560781b604482015260640161065a565b600080546001600160a01b0319166001600160a01b038316908117825560405190917f04dba622d284ed0014ee4b9a6a68386be1a4c08a4913ae272de89199cc68616391a26001546001600160a01b03161561066c5761066c60006112c9565b8051670de0b6b3a7640000906000121580611679575081518113155b15611697576040516313e9c00360e21b815260040160405180910390fd5b815160208301511315806116af575080826020015112155b156116cd576040516339bda99160e11b815260040160405180910390fd5b600082604001511315806116e657508151604083015112155b1561170457604051635c65494d60e01b815260040160405180910390fd5b60008260600151136117295760405163fe06781560e01b815260040160405180910390fd5b600082608001511361174e576040516320d12cb560e21b815260040160405180910390fd5b60008260a001511215611777576040516001627ddb5960e01b0319815260040160405180910390fd5b60008260c00151121561179d57604051634e435a2160e01b815260040160405180910390fd5b60008260e0015112156117c3576040516378a8371160e01b815260040160405180910390fd5b600082610100015112156117ea576040516330eecc6b60e21b815260040160405180910390fd5b6000826101200151121561181157604051630266493760e31b815260040160405180910390fd5b6001600160a01b03808516600081815260026020818152604080842095891680855295825292839020875181559087015160018201558287015191810191909155606086015160038201556080860151600482015560a0860151600582015560c0860151600682015560e086015160078201556101008601516008820155610120860151600990910155517ff254631d9ea3e3ab061b1c56e1215a268abf5ff28a460b255f308aac112df458906118c99086906125b5565b60405180910390a350505050565b600068023f2fa8f6da5b9d31198212156118f357506000919050565b6804cf46d8192b672ecc821261190857600080fd5b6714057b7ef767814f8202611410670de0b6b3a76400006706f05b59d3b200008301055b6000808212156119805768033dd1780914b971141982121561195057506000919050565b61195c8260000361192c565b6ec097ce7bc90715b34b9f100000000081611979576119796127dc565b0592915050565b6806f05b59d3b2000000821261199557600080fd5b670de0b6b3a7640000608083901b04611410816119b2565b919050565b6001607f1b818116156119d65770016a09e667f3bcc908b2fb1366ea957d3e0260801c5b6001607e1b8216156119f9577001306fe0a31b7152de8d5a46305c85eded0260801c5b6001607d1b821615611a1c577001172b83c7d517adcdf7c8c50eb14a79200260801c5b6001607c1b821615611a3f5770010b5586cf9890f6298b92b71842a983640260801c5b6001607b1b821615611a62577001059b0d31585743ae7c548eb68ca417fe0260801c5b6001607a1b821615611a8557700102c9a3e778060ee6f7caca4f7a29bde90260801c5b600160791b821615611aa85770010163da9fb33356d84a66ae336dcdfa400260801c5b600160781b821615611acb57700100b1afa5abcbed6129ab13ec11dc95440260801c5b600160771b821615611aee5770010058c86da1c09ea1ff19d294cf2f679c0260801c5b600160761b821615611b11577001002c605e2e8cec506d21bfc89a23a0110260801c5b600160751b821615611b3457700100162f3904051fa128bca9c55c31e5e00260801c5b600160741b821615611b57577001000b175effdc76ba38e31671ca9397260260801c5b600160731b821615611b7a57700100058ba01fb9f96d6cacd4b180917c3e0260801c5b600160721b821615611b9d5770010002c5cc37da9491d0985c348c68e7b40260801c5b600160711b821615611bc0577001000162e525ee054754457d59952920270260801c5b600160701b821615611be35770010000b17255775c040618bf4a4ade83fd0260801c5b6001606f1b821615611c06577001000058b91b5bc9ae2eed81e9b7d4cfac0260801c5b6001606e1b821615611c2957700100002c5c89d5ec6ca4d7c8acc017b7ca0260801c5b6001606d1b821615611c4c5770010000162e43f4f831060e02d839a9d16d0260801c5b6001606c1b821615611c6f57700100000b1721bcfc99d9f890ea069117630260801c5b6001606b1b821615611c925770010000058b90cf1e6d97f9ca14dbcc16290260801c5b6001606a1b821615611cb5577001000002c5c863b73f016468f6bac5ca2c0260801c5b600160691b821615611cd857700100000162e430e5a18f6119e3c02282a60260801c5b600160681b821615611cfb577001000000b1721835514b86e6d96efd1bff0260801c5b600160671b821615611d1e57700100000058b90c0b48c6be5df846c5b2f00260801c5b600160661b821615611d415770010000002c5c8601cc6b9e94213c72737b0260801c5b600160651b821615611d64577001000000162e42fff037df38aa2b219f070260801c5b600160641b821615611d875770010000000b17217fba9c739aa5819f44fa0260801c5b600160631b821615611daa577001000000058b90bfcdee5acd3c1cedc8240260801c5b600160621b821615611dcd57700100000002c5c85fe31f35a6a30da1be510260801c5b600160611b821615611df05770010000000162e42ff0999ce3541b9fffd00260801c5b600160601b821615611e1357700100000000b17217f80f4ef5aadda455540260801c5b6001605f1b821615611e365770010000000058b90bfbf8479bd5a81b51ae0260801c5b6001605e1b821615611e59577001000000002c5c85fdf84bd62ae30a74cd0260801c5b6001605d1b821615611e7c57700100000000162e42fefb2fed257559bdaa0260801c5b6001605c1b821615611e9f577001000000000b17217f7d5a7716bba4a9af0260801c5b6001605b1b821615611ec257700100000000058b90bfbe9ddbac5e109ccf0260801c5b6001605a1b821615611ee55770010000000002c5c85fdf4b15de6f17eb0e0260801c5b600160591b821615611f08577001000000000162e42fefa494f1478fde050260801c5b600160581b821615611f2b5770010000000000b17217f7d20cf927c8e94d0260801c5b600160571b821615611f4e577001000000000058b90bfbe8f71cb4e4b33e0260801c5b600160561b821615611f7157700100000000002c5c85fdf477b662b269460260801c5b600160551b821615611f945770010000000000162e42fefa3ae53369388d0260801c5b600160541b821615611fb757700100000000000b17217f7d1d351a389d410260801c5b600160531b821615611fda5770010000000000058b90bfbe8e8b2d3d4edf0260801c5b600160521b821615611ffd577001000000000002c5c85fdf4741bea6e77f0260801c5b600160511b82161561202057700100000000000162e42fefa39fe95583c30260801c5b600160501b821615612043577001000000000000b17217f7d1cfb72b45e30260801c5b698000000000000000000082161561206c57700100000000000058b90bfbe8e7cc35c3f20260801c5b69400000000000000000008216156120955770010000000000002c5c85fdf473e242ea390260801c5b69200000000000000000008216156120be577001000000000000162e42fefa39f02b772c0260801c5b69100000000000000000008216156120e75770010000000000000b17217f7d1cf7d83c1a0260801c5b6908000000000000000000821615612110577001000000000000058b90bfbe8e7bdcbe2e0260801c5b690400000000000000000082161561213957700100000000000002c5c85fdf473dea871f0260801c5b69020000000000000000008216156121625770010000000000000162e42fefa39ef44d920260801c5b690100000000000000000082161561218b57700100000000000000b17217f7d1cf79e9490260801c5b688000000000000000008216156121b35770010000000000000058b90bfbe8e7bce5450260801c5b684000000000000000008216156121db577001000000000000002c5c85fdf473de6eca0260801c5b6820000000000000000082161561220357700100000000000000162e42fefa39ef366f0260801c5b6810000000000000000082161561222b577001000000000000000b17217f7d1cf79afa0260801c5b6808000000000000000082161561225357700100000000000000058b90bfbe8e7bcd6e0260801c5b6804000000000000000082161561227b5770010000000000000002c5c85fdf473de6b30260801c5b680200000000000000008216156122a3577001000000000000000162e42fefa39ef3590260801c5b680100000000000000008216156122cb5770010000000000000000b17217f7d1cf79ac0260801c5b6001608083901c011b61123d81670de0b6b3a7640000600160801b600080806000198587098587029250828110838203039150508060000361231f576000841161231457600080fd5b508290049050611410565b80841161232b57600080fd5b60008486880960026001871981018816978890046003810283188082028403028082028403028082028403028082028403028082028403029081029092039091026000889003889004909101858311909403939093029303949094049190911702949350505050565b604051610140810167ffffffffffffffff811182821017156123c657634e487b7160e01b600052604160045260246000fd5b60405290565b600061014082840312156123df57600080fd5b6123e7612394565b9050813581526020820135602082015260408201356040820152606082013560608201526080820135608082015260a082013560a082015260c082013560c082015260e082013560e082015261010080830135818301525061012080830135818301525092915050565b60008060008060006101c0868803121561246a57600080fd5b61247487876123cc565b9761014087013597506101608701359661018081013596506101a00135945092505050565b80356001600160a01b03811681146119ad57600080fd5b600080604083850312156124c357600080fd5b6124cc83612499565b946020939093013593505050565b6000806000606084860312156124ef57600080fd5b6124f884612499565b925061250660208501612499565b9150604084013590509250925092565b60006020828403121561252857600080fd5b61141082612499565b600080600083850361018081121561254857600080fd5b61255185612499565b935061255f60208601612499565b9250610140603f198201121561257457600080fd5b506040840190509250925092565b6000806040838503121561259557600080fd5b61259e83612499565b91506125ac60208401612499565b90509250929050565b600061014082019050825182526020830151602083015260408301516040830152606083015160608301526080830151608083015260a083015160a083015260c083015160c083015260e083015160e083015261010080840151818401525061012080840151818401525092915050565b60006060828403121561263857600080fd5b6040516060810167ffffffffffffffff828210818311171561266a57634e487b7160e01b600052604160045260246000fd5b81604052845183526020850151602084015260408501519150808216821461269157600080fd5b5060408201529392505050565b60208082526009908201526827b7363ca7bbb732b960b91b604082015260600190565b634e487b7160e01b600052601160045260246000fd5b60008083128015600160ff1b8501841216156126f5576126f56126c1565b6001600160ff1b0384018313811615612710576127106126c1565b50500390565b60006001600160ff1b038184138284138082168684048611161561273c5761273c6126c1565b600160ff1b600087128281168783058912161561275b5761275b6126c1565b60008712925087820587128484161615612777576127776126c1565b8785058712818416161561278d5761278d6126c1565b505050929093029392505050565b600080821280156001600160ff1b03849003851316156127bd576127bd6126c1565b600160ff1b83900384128116156127d6576127d66126c1565b50500190565b634e487b7160e01b600052601260045260246000fd5b600082612801576128016127dc565b600160ff1b82146000198414161561281b5761281b6126c1565b500590565b600081600019048311821515161561283a5761283a6126c1565b500290565b80825b600180861161285157506115a4565b6001600160ff1b0382900482111561286b5761286b6126c1565b8086161561287857918102915b9490941c938002612842565b600082801561289a57600181146128a4576128ad565b600191505061123d565b8291505061123d565b50816128bb5750600061123d565b506001600082138082146128d45780156128f35761290d565b6001600160ff1b038390048311156128ee576128ee6126c1565b61290d565b6001600160ff1b0383900583121561290d5761290d6126c1565b50808316156129195750805b6129298360011c8384028361283f565b600082136001600160ff1b0382900483111615612948576129486126c1565b60008212600160ff1b82900583121615612964576129646126c1565b029392505050565b600061141060ff841683612884565b6000825160005b8181101561299c5760208186018101518583015201612982565b818111156129ab576000828501525b509190910192915050565b600061014082840312156129c957600080fd5b61141083836123cc565b6000826129e2576129e26127dc565b50049056fea26469706673582212209d38983ce1161bdf9c0b50a9d8e97a718ddfaf9872ee997513ed285f97a65d2d64736f6c634300080d00330000000000000000000000000000000000000000000000000b1a2bc2ec5000000000000000000000000000000000000000000000000000000c7d713b49da000000000000000000000000000000000000000000000000000006f05b59d3b2000000000000000000000000000000000000000000000000000000000000000599a3000000000000000000000000000000000000000000000000000000dd7d86d0190000000000000000000000000000000000000000000000000000000ec41a0de00000000000000000000000000000000000000000000000000000000017a029b00000000000000000000000000000000000000000000000000000fca32dc55c7200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106101425760003560e01c806374a3e924116100b8578063bbdcbed61161007c578063bbdcbed6146102ba578063c42401f1146102da578063cbf75c9a146102ef578063e076a551146103a8578063e30c3978146103b9578063f2fde38b146103ca57600080fd5b806374a3e9241461025857806379ba50971461026b57806381b51e0c146102735780638da5cb5b14610282578063b1e01765146102a757600080fd5b80633278c6941161010a5780633278c694146101dc5780633ced7d0d146101f157806344552b5d146102045780636bcc82161461020c5780636e1a41401461021b578063715018a61461025057600080fd5b8063023279ce1461014757806303dc12fc1461017a578063071962ff1461019b578063109a006e146101ae57806311e5152b146101b9575b600080fd5b61015a610155366004612451565b6103dd565b604080519384526020840192909252908201526060015b60405180910390f35b61018d6101883660046124b0565b610401565b604051908152602001610171565b61018d6101a93660046124da565b6104d8565b61018d600160c41b81565b6101cc6101c73660046124da565b61057b565b6040519015158152602001610171565b6101ef6101ea366004612516565b610621565b005b61018d6101ff366004612451565b61066f565b6101ef6108e6565b61018d670de0b6b3a764000081565b61022e610229366004612451565b61092b565b6040805194855260208501939093529183015215156060820152608001610171565b6101ef610d85565b6101ef610266366004612531565b610dc8565b6101ef610eb4565b61018d6799e8e8e3d530368181565b6000546001600160a01b03165b6040516001600160a01b039091168152602001610171565b61018d6102b53660046124da565b610f1b565b6102cd6102c8366004612582565b610fc1565b60405161017191906125b5565b60405163c42401f160e01b8152602001610171565b61035e6102fd366004612582565b600260205281600052604060002060205280600052604060002060009150915050806000015490806001015490806002015490806003015490806004015490806005015490806006015490806007015490806008015490806009015490508a565b604080519a8b5260208b0199909952978901969096526060880194909452608087019290925260a086015260c085015260e084015261010083015261012082015261014001610171565b61018d690de0b6b3a7640000000081565b6001546001600160a01b031661028f565b6101ef6103d8366004612516565b611243565b60008060006103ef888888888861092b565b50919a90995090975095505050505050565b604051631f0f875560e31b81526001600160a01b038316600482015260009033908290829063f87c3aa890602401606060405180830381865afa15801561044c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104709190612626565b6001600160a01b038084166000908152600260209081526040808320938a168352929052209091506104c16104a58488610fc1565b83516020850151604086015167ffffffffffffffff16896103dd565b600984015560089092019190915595945050505050565b604051631f0f875560e31b81526001600160a01b038381166004830152600091829186169063f87c3aa890602401606060405180830381865afa158015610523573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105479190612626565b90506105726105568686610fc1565b82516020840151604085015167ffffffffffffffff168761066f565b95945050505050565b604051631f0f875560e31b81526001600160a01b038381166004830152600091829186169063f87c3aa890602401606060405180830381865afa1580156105c6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105ea9190612626565b90506106156105f98686610fc1565b82516020840151604085015167ffffffffffffffff168761092b565b98975050505050505050565b336106346000546001600160a01b031690565b6001600160a01b0316146106635760405162461bcd60e51b815260040161065a9061269e565b60405180910390fd5b61066c816112c9565b50565b6000818311156106925760405163d22806e360e01b815260040160405180910390fd5b60006040518060e001604052806000815260200160008152602001600081526020016000815260200160008152602001600081526020016000151581525090506106df878787878761092b565b15801560c086015292506106fa915050576000915050610572565b610705848403611370565b815261072261071d670de0b6b3a764000088886113de565b611370565b6020808301829052670de0b6b3a7640000604084015288015112156107c65780604001518760200151826020015161075a91906126d7565b6040830151835160e08b01516107709190612716565b8a61012001518560400151610785919061279b565b61078f919061279b565b8a6080015161079e9190612716565b6107a891906127f2565b6107b29190612716565b6107bc91906127f2565b6060820152610808565b61080260008260400151896040015184602001516107e491906126d7565b8a60a001516107f39190612716565b6107fd91906127f2565b611417565b60608201525b806040015181602001518860c001516108219190612716565b61082b91906127f2565b608082018190526101008801516108419161142d565b60a0820152604081015181518851602084015161089f939291610863916126d7565b8a606001516108729190612716565b61087c9190612716565b61088691906127f2565b8260a00151610895919061279b565b826080015161142d565b60a0820181905260608201516108cb916108c6916108bc9161279b565b836080015161142d565b61143c565b91506108db6301e1338083612820565b979650505050505050565b336108f96000546001600160a01b031690565b6001600160a01b03161461091f5760405162461bcd60e51b815260040161065a9061269e565b61092960006112c9565b565b60008060008088610100015192508861012001519150600060405180610140016040528060008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152509050858711156109b65760405163d22806e360e01b815260040160405180910390fd5b6109c1878703611370565b8152670de0b6b3a76400006109da61071d828c8c6113de565b61012083018190528b5182916109f091906126d7565b8c606001516109ff9190612716565b610a0991906127f2565b6020808401919091528b01516101208301511315610af357808b60200151836101200151610a3791906126d7565b82610a42878261279b565b8e60800151610a519190612716565b610a5b91906127f2565b610a659190612716565b610a6f91906127f2565b604083015260208b01516101208301518291610a8a916126d7565b828d60e001518e60800151610a9f9190612716565b610aa991906127f2565b610ab39190612716565b610abd91906127f2565b8260200151610acc919061279b565b6060830152815160e08c0151610ae29190612716565b610aec908561279b565b9350610b56565b610b1d6000828d60400151856101200151610b0e91906126d7565b8e60a001516107f39190612716565b604083015260208201516060830152815160e08c0151610b5391600091610b449190612716565b610b4e90876126d7565b61142d565b93505b808261012001518c60c00151610b6c9190612716565b610b7691906127f2565b60a08301819052610b8890869061142d565b9450816040015185610b9a919061279b565b608083015281516060830151610bb09190612716565b8260800151610bbf919061279b565b60c083015260a0820151608083015112801590610be457508160a001518260c0015112155b15610c2057815160c0830151608084015160029291610c029161279b565b610c0c9190612716565b610c1691906127f2565b60e0830152610d2a565b8160a001518260800151128015610c3e57508160a001518260c00151125b15610c5457815160a0830151610c169190612716565b8160a00151826080015112158015610c7357508160a001518260c00151125b15610cce576002826060015160028460a001518560800151610c9591906126d7565b610c9f919061296c565b610ca991906127f2565b610cb391906127f2565b825160a0840151610cc49190612716565b610c1691906126d7565b6002826060015160028460a001518560c00151610ceb91906126d7565b610cf5919061296c565b610cff91906127f2565b610d0991906127f2565b825160a0840151610d1a9190612716565b610d24919061279b565b60e08301525b81516020830151610d5291610d3e91612716565b610d48908761279b565b8360a0015161142d565b9450610d638a8a8460e0015161148e565b90965092508215610d775760009450600093505b505095509550955095915050565b33610d986000546001600160a01b031690565b6001600160a01b031614610dbe5760405162461bcd60e51b815260040161065a9061269e565b61092960006115ac565b33610ddb6000546001600160a01b031690565b6001600160a01b031614610e015760405162461bcd60e51b815260040161065a9061269e565b6040516001600160a01b03838116602483015284169060440160408051601f198184030181529181526020820180516001600160e01b0316639198e51560e01b17905251610e4f919061297b565b6000604051808303816000865af19150503d8060008114610e8c576040519150601f19603f3d011682016040523d82523d6000602084013e610e91565b606091505b505050610eaf838383803603810190610eaa91906129b6565b61165d565b505050565b6001546001600160a01b03163314610f015760405162461bcd60e51b815260206004820152601060248201526f27b7363ca832b73234b733a7bbb732b960811b604482015260640161065a565b610929610f166001546001600160a01b031690565b6115ac565b604051631f0f875560e31b81526001600160a01b038381166004830152600091829186169063f87c3aa890602401606060405180830381865afa158015610f66573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f8a9190612626565b9050610fb5610f998686610fc1565b82516020840151604085015167ffffffffffffffff16876103dd565b50909695505050505050565b611017604051806101400160405280600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b6001600160a01b0380841660009081526002602090815260408083209386168352929052208054156110b857604080516101408101825282548152600183015460208201526002830154918101919091526003820154606082015260048201546080820152600582015460a0820152600682015460c0820152600782015460e08201526008820154610100820152600990910154610120820152905061123d565b600080527fac33ff75c19e70fe83507db0d683fd3465c996598dc972688b7ace676c89077b602090815260408051610140810182527f6ee3efecae883df2d7ccda22610b4ca771a299e707cb0d65c4ec97dc4e6668ad5481527f6ee3efecae883df2d7ccda22610b4ca771a299e707cb0d65c4ec97dc4e6668ae54928101929092527f6ee3efecae883df2d7ccda22610b4ca771a299e707cb0d65c4ec97dc4e6668af54908201527f6ee3efecae883df2d7ccda22610b4ca771a299e707cb0d65c4ec97dc4e6668b05460608201527f6ee3efecae883df2d7ccda22610b4ca771a299e707cb0d65c4ec97dc4e6668b15460808201527f6ee3efecae883df2d7ccda22610b4ca771a299e707cb0d65c4ec97dc4e6668b25460a08201527f6ee3efecae883df2d7ccda22610b4ca771a299e707cb0d65c4ec97dc4e6668b35460c08201527f6ee3efecae883df2d7ccda22610b4ca771a299e707cb0d65c4ec97dc4e6668b45460e0820152600882015461010082015260099091015461012082015290505b92915050565b336112566000546001600160a01b031690565b6001600160a01b03161461127c5760405162461bcd60e51b815260040161065a9061269e565b6001600160a01b0381166112c05760405162461bcd60e51b815260206004820152600b60248201526a4f776e657249735a65726f60a81b604482015260640161065a565b61066c816115ac565b6001546001600160a01b038083169116036113265760405162461bcd60e51b815260206004820152601860248201527f50656e64696e674f776e65724469644e6f744368616e67650000000000000000604482015260640161065a565b600180546001600160a01b0319166001600160a01b0383169081179091556040517fd6aad444c90d39fb0eee1c6e357a7fad83d63f719ac5f880445a2beb0ff3ab5890600090a250565b60006001600160ff1b038211156113da5760405162461bcd60e51b815260206004820152602860248201527f53616665436173743a2076616c756520646f65736e27742066697420696e2061604482015267371034b73a191a9b60c11b606482015260840161065a565b5090565b60008215806113eb575081155b156113f857506000611410565b826114038584612820565b61140d91906129d3565b90505b9392505050565b60008183126114265781611410565b5090919050565b60008183136114265781611410565b6000808212156113da5760405162461bcd60e51b815260206004820181905260248201527f53616665436173743a2076616c7565206d75737420626520706f736974697665604482015260640161065a565b60008060006799e8e8e3d530368184126114b857690de0b6b3a764000000009250600191506114f1565b670de0b6b3a76400006114ca856118d7565b6114d491906126d7565b9050600081136114e55760006114ee565b6114ee8161143c565b92505b60008587116115005785611502565b865b9050600160c41b811061151e57600060019350935050506115a4565b8386026000819003611532575050506115a4565b86858281611542576115426127dc565b0414158061156c575081600160c41b03670de0b6b3a76400008281611569576115696127dc565b04115b156115a05786670de0b6b3a764000083600160c41b030281611590576115906127dc565b049450600193506115a492505050565b5050505b935093915050565b6000546001600160a01b038083169116036115fd5760405162461bcd60e51b81526020600482015260116024820152704f776e65724469644e6f744368616e676560781b604482015260640161065a565b600080546001600160a01b0319166001600160a01b038316908117825560405190917f04dba622d284ed0014ee4b9a6a68386be1a4c08a4913ae272de89199cc68616391a26001546001600160a01b03161561066c5761066c60006112c9565b8051670de0b6b3a7640000906000121580611679575081518113155b15611697576040516313e9c00360e21b815260040160405180910390fd5b815160208301511315806116af575080826020015112155b156116cd576040516339bda99160e11b815260040160405180910390fd5b600082604001511315806116e657508151604083015112155b1561170457604051635c65494d60e01b815260040160405180910390fd5b60008260600151136117295760405163fe06781560e01b815260040160405180910390fd5b600082608001511361174e576040516320d12cb560e21b815260040160405180910390fd5b60008260a001511215611777576040516001627ddb5960e01b0319815260040160405180910390fd5b60008260c00151121561179d57604051634e435a2160e01b815260040160405180910390fd5b60008260e0015112156117c3576040516378a8371160e01b815260040160405180910390fd5b600082610100015112156117ea576040516330eecc6b60e21b815260040160405180910390fd5b6000826101200151121561181157604051630266493760e31b815260040160405180910390fd5b6001600160a01b03808516600081815260026020818152604080842095891680855295825292839020875181559087015160018201558287015191810191909155606086015160038201556080860151600482015560a0860151600582015560c0860151600682015560e086015160078201556101008601516008820155610120860151600990910155517ff254631d9ea3e3ab061b1c56e1215a268abf5ff28a460b255f308aac112df458906118c99086906125b5565b60405180910390a350505050565b600068023f2fa8f6da5b9d31198212156118f357506000919050565b6804cf46d8192b672ecc821261190857600080fd5b6714057b7ef767814f8202611410670de0b6b3a76400006706f05b59d3b200008301055b6000808212156119805768033dd1780914b971141982121561195057506000919050565b61195c8260000361192c565b6ec097ce7bc90715b34b9f100000000081611979576119796127dc565b0592915050565b6806f05b59d3b2000000821261199557600080fd5b670de0b6b3a7640000608083901b04611410816119b2565b919050565b6001607f1b818116156119d65770016a09e667f3bcc908b2fb1366ea957d3e0260801c5b6001607e1b8216156119f9577001306fe0a31b7152de8d5a46305c85eded0260801c5b6001607d1b821615611a1c577001172b83c7d517adcdf7c8c50eb14a79200260801c5b6001607c1b821615611a3f5770010b5586cf9890f6298b92b71842a983640260801c5b6001607b1b821615611a62577001059b0d31585743ae7c548eb68ca417fe0260801c5b6001607a1b821615611a8557700102c9a3e778060ee6f7caca4f7a29bde90260801c5b600160791b821615611aa85770010163da9fb33356d84a66ae336dcdfa400260801c5b600160781b821615611acb57700100b1afa5abcbed6129ab13ec11dc95440260801c5b600160771b821615611aee5770010058c86da1c09ea1ff19d294cf2f679c0260801c5b600160761b821615611b11577001002c605e2e8cec506d21bfc89a23a0110260801c5b600160751b821615611b3457700100162f3904051fa128bca9c55c31e5e00260801c5b600160741b821615611b57577001000b175effdc76ba38e31671ca9397260260801c5b600160731b821615611b7a57700100058ba01fb9f96d6cacd4b180917c3e0260801c5b600160721b821615611b9d5770010002c5cc37da9491d0985c348c68e7b40260801c5b600160711b821615611bc0577001000162e525ee054754457d59952920270260801c5b600160701b821615611be35770010000b17255775c040618bf4a4ade83fd0260801c5b6001606f1b821615611c06577001000058b91b5bc9ae2eed81e9b7d4cfac0260801c5b6001606e1b821615611c2957700100002c5c89d5ec6ca4d7c8acc017b7ca0260801c5b6001606d1b821615611c4c5770010000162e43f4f831060e02d839a9d16d0260801c5b6001606c1b821615611c6f57700100000b1721bcfc99d9f890ea069117630260801c5b6001606b1b821615611c925770010000058b90cf1e6d97f9ca14dbcc16290260801c5b6001606a1b821615611cb5577001000002c5c863b73f016468f6bac5ca2c0260801c5b600160691b821615611cd857700100000162e430e5a18f6119e3c02282a60260801c5b600160681b821615611cfb577001000000b1721835514b86e6d96efd1bff0260801c5b600160671b821615611d1e57700100000058b90c0b48c6be5df846c5b2f00260801c5b600160661b821615611d415770010000002c5c8601cc6b9e94213c72737b0260801c5b600160651b821615611d64577001000000162e42fff037df38aa2b219f070260801c5b600160641b821615611d875770010000000b17217fba9c739aa5819f44fa0260801c5b600160631b821615611daa577001000000058b90bfcdee5acd3c1cedc8240260801c5b600160621b821615611dcd57700100000002c5c85fe31f35a6a30da1be510260801c5b600160611b821615611df05770010000000162e42ff0999ce3541b9fffd00260801c5b600160601b821615611e1357700100000000b17217f80f4ef5aadda455540260801c5b6001605f1b821615611e365770010000000058b90bfbf8479bd5a81b51ae0260801c5b6001605e1b821615611e59577001000000002c5c85fdf84bd62ae30a74cd0260801c5b6001605d1b821615611e7c57700100000000162e42fefb2fed257559bdaa0260801c5b6001605c1b821615611e9f577001000000000b17217f7d5a7716bba4a9af0260801c5b6001605b1b821615611ec257700100000000058b90bfbe9ddbac5e109ccf0260801c5b6001605a1b821615611ee55770010000000002c5c85fdf4b15de6f17eb0e0260801c5b600160591b821615611f08577001000000000162e42fefa494f1478fde050260801c5b600160581b821615611f2b5770010000000000b17217f7d20cf927c8e94d0260801c5b600160571b821615611f4e577001000000000058b90bfbe8f71cb4e4b33e0260801c5b600160561b821615611f7157700100000000002c5c85fdf477b662b269460260801c5b600160551b821615611f945770010000000000162e42fefa3ae53369388d0260801c5b600160541b821615611fb757700100000000000b17217f7d1d351a389d410260801c5b600160531b821615611fda5770010000000000058b90bfbe8e8b2d3d4edf0260801c5b600160521b821615611ffd577001000000000002c5c85fdf4741bea6e77f0260801c5b600160511b82161561202057700100000000000162e42fefa39fe95583c30260801c5b600160501b821615612043577001000000000000b17217f7d1cfb72b45e30260801c5b698000000000000000000082161561206c57700100000000000058b90bfbe8e7cc35c3f20260801c5b69400000000000000000008216156120955770010000000000002c5c85fdf473e242ea390260801c5b69200000000000000000008216156120be577001000000000000162e42fefa39f02b772c0260801c5b69100000000000000000008216156120e75770010000000000000b17217f7d1cf7d83c1a0260801c5b6908000000000000000000821615612110577001000000000000058b90bfbe8e7bdcbe2e0260801c5b690400000000000000000082161561213957700100000000000002c5c85fdf473dea871f0260801c5b69020000000000000000008216156121625770010000000000000162e42fefa39ef44d920260801c5b690100000000000000000082161561218b57700100000000000000b17217f7d1cf79e9490260801c5b688000000000000000008216156121b35770010000000000000058b90bfbe8e7bce5450260801c5b684000000000000000008216156121db577001000000000000002c5c85fdf473de6eca0260801c5b6820000000000000000082161561220357700100000000000000162e42fefa39ef366f0260801c5b6810000000000000000082161561222b577001000000000000000b17217f7d1cf79afa0260801c5b6808000000000000000082161561225357700100000000000000058b90bfbe8e7bcd6e0260801c5b6804000000000000000082161561227b5770010000000000000002c5c85fdf473de6b30260801c5b680200000000000000008216156122a3577001000000000000000162e42fefa39ef3590260801c5b680100000000000000008216156122cb5770010000000000000000b17217f7d1cf79ac0260801c5b6001608083901c011b61123d81670de0b6b3a7640000600160801b600080806000198587098587029250828110838203039150508060000361231f576000841161231457600080fd5b508290049050611410565b80841161232b57600080fd5b60008486880960026001871981018816978890046003810283188082028403028082028403028082028403028082028403028082028403029081029092039091026000889003889004909101858311909403939093029303949094049190911702949350505050565b604051610140810167ffffffffffffffff811182821017156123c657634e487b7160e01b600052604160045260246000fd5b60405290565b600061014082840312156123df57600080fd5b6123e7612394565b9050813581526020820135602082015260408201356040820152606082013560608201526080820135608082015260a082013560a082015260c082013560c082015260e082013560e082015261010080830135818301525061012080830135818301525092915050565b60008060008060006101c0868803121561246a57600080fd5b61247487876123cc565b9761014087013597506101608701359661018081013596506101a00135945092505050565b80356001600160a01b03811681146119ad57600080fd5b600080604083850312156124c357600080fd5b6124cc83612499565b946020939093013593505050565b6000806000606084860312156124ef57600080fd5b6124f884612499565b925061250660208501612499565b9150604084013590509250925092565b60006020828403121561252857600080fd5b61141082612499565b600080600083850361018081121561254857600080fd5b61255185612499565b935061255f60208601612499565b9250610140603f198201121561257457600080fd5b506040840190509250925092565b6000806040838503121561259557600080fd5b61259e83612499565b91506125ac60208401612499565b90509250929050565b600061014082019050825182526020830151602083015260408301516040830152606083015160608301526080830151608083015260a083015160a083015260c083015160c083015260e083015160e083015261010080840151818401525061012080840151818401525092915050565b60006060828403121561263857600080fd5b6040516060810167ffffffffffffffff828210818311171561266a57634e487b7160e01b600052604160045260246000fd5b81604052845183526020850151602084015260408501519150808216821461269157600080fd5b5060408201529392505050565b60208082526009908201526827b7363ca7bbb732b960b91b604082015260600190565b634e487b7160e01b600052601160045260246000fd5b60008083128015600160ff1b8501841216156126f5576126f56126c1565b6001600160ff1b0384018313811615612710576127106126c1565b50500390565b60006001600160ff1b038184138284138082168684048611161561273c5761273c6126c1565b600160ff1b600087128281168783058912161561275b5761275b6126c1565b60008712925087820587128484161615612777576127776126c1565b8785058712818416161561278d5761278d6126c1565b505050929093029392505050565b600080821280156001600160ff1b03849003851316156127bd576127bd6126c1565b600160ff1b83900384128116156127d6576127d66126c1565b50500190565b634e487b7160e01b600052601260045260246000fd5b600082612801576128016127dc565b600160ff1b82146000198414161561281b5761281b6126c1565b500590565b600081600019048311821515161561283a5761283a6126c1565b500290565b80825b600180861161285157506115a4565b6001600160ff1b0382900482111561286b5761286b6126c1565b8086161561287857918102915b9490941c938002612842565b600082801561289a57600181146128a4576128ad565b600191505061123d565b8291505061123d565b50816128bb5750600061123d565b506001600082138082146128d45780156128f35761290d565b6001600160ff1b038390048311156128ee576128ee6126c1565b61290d565b6001600160ff1b0383900583121561290d5761290d6126c1565b50808316156129195750805b6129298360011c8384028361283f565b600082136001600160ff1b0382900483111615612948576129486126c1565b60008212600160ff1b82900583121615612964576129646126c1565b029392505050565b600061141060ff841683612884565b6000825160005b8181101561299c5760208186018101518583015201612982565b818111156129ab576000828501525b509190910192915050565b600061014082840312156129c957600080fd5b61141083836123cc565b6000826129e2576129e26127dc565b50049056fea26469706673582212209d38983ce1161bdf9c0b50a9d8e97a718ddfaf9872ee997513ed285f97a65d2d64736f6c634300080d0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000000000000000000000000000000b1a2bc2ec5000000000000000000000000000000000000000000000000000000c7d713b49da000000000000000000000000000000000000000000000000000006f05b59d3b2000000000000000000000000000000000000000000000000000000000000000599a3000000000000000000000000000000000000000000000000000000dd7d86d0190000000000000000000000000000000000000000000000000000000ec41a0de00000000000000000000000000000000000000000000000000000000017a029b00000000000000000000000000000000000000000000000000000fca32dc55c7200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
-----Decoded View---------------
Arg [0] : _config (tuple): System.Collections.Generic.List`1[Nethereum.ABI.FunctionEncoding.ParameterOutput]
-----Encoded View---------------
10 Constructor Arguments found :
Arg [0] : 0000000000000000000000000000000000000000000000000b1a2bc2ec500000
Arg [1] : 0000000000000000000000000000000000000000000000000c7d713b49da0000
Arg [2] : 00000000000000000000000000000000000000000000000006f05b59d3b20000
Arg [3] : 00000000000000000000000000000000000000000000000000000000000599a3
Arg [4] : 000000000000000000000000000000000000000000000000000000dd7d86d019
Arg [5] : 0000000000000000000000000000000000000000000000000000000ec41a0de0
Arg [6] : 0000000000000000000000000000000000000000000000000000000017a029b0
Arg [7] : 0000000000000000000000000000000000000000000000000000fca32dc55c72
Arg [8] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [9] : 0000000000000000000000000000000000000000000000000000000000000000
Loading...
Loading
Loading...
Loading
Make sure to use the "Vote Down" button for any spammy posts, and the "Vote Up" for interesting conversations.
[ 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.