Source Code
Overview
ETH Balance
0 ETH
Eth Value
$0.00Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Latest 1 internal transaction
Advanced mode:
Parent Transaction Hash | Method | Block |
From
|
To
|
|||
---|---|---|---|---|---|---|---|
0x61012060 | 19437228 | 489 days ago | Contract Creation | 0 ETH |
Loading...
Loading
Contract Name:
HintHelpers
Compiler Version
v0.8.17+commit.8df45f5f
Optimization Enabled:
Yes with 200 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT pragma solidity 0.8.17; import "./Interfaces/ICdpManager.sol"; import "./Interfaces/ISortedCdps.sol"; import "./Dependencies/EbtcBase.sol"; /// @title HintHelpers mainly serves to provide handy information to facilitate offchain integration like redemption bots. /// @dev It is strongly recommended to use HintHelper for redemption purpose contract HintHelpers is EbtcBase { string public constant NAME = "HintHelpers"; ISortedCdps public immutable sortedCdps; ICdpManager public immutable cdpManager; // --- Events --- struct LocalVariables_getRedemptionHints { uint256 remainingEbtcToRedeem; uint256 minNetDebtInBTC; bytes32 currentCdpId; address currentCdpUser; } // --- Dependency setters --- constructor( address _sortedCdpsAddress, address _cdpManagerAddress, address _collateralAddress, address _activePoolAddress, address _priceFeedAddress ) EbtcBase(_activePoolAddress, _priceFeedAddress, _collateralAddress) { sortedCdps = ISortedCdps(_sortedCdpsAddress); cdpManager = ICdpManager(_cdpManagerAddress); } // --- Functions --- /// @notice Get the redemption hints for the specified amount of eBTC, price and maximum number of iterations. /// @param _EBTCamount The amount of eBTC to be redeemed. /// @param _price The current price of the stETH:eBTC. /// @param _maxIterations The maximum number of iterations to be performed. /// @return firstRedemptionHint The identifier of the first CDP to be considered for redemption. /// @return partialRedemptionHintNICR The new Nominal Collateral Ratio (NICR) of the CDP after partial redemption. /// @return truncatedEBTCamount The actual amount of eBTC that can be redeemed. /// @return partialRedemptionNewColl The new collateral amount after partial redemption. function getRedemptionHints( uint256 _EBTCamount, uint256 _price, uint256 _maxIterations ) external view returns ( bytes32 firstRedemptionHint, uint256 partialRedemptionHintNICR, uint256 truncatedEBTCamount, uint256 partialRedemptionNewColl ) { LocalVariables_getRedemptionHints memory vars; { vars.remainingEbtcToRedeem = _EBTCamount; vars.currentCdpId = sortedCdps.getLast(); vars.currentCdpUser = sortedCdps.getOwnerAddress(vars.currentCdpId); while ( vars.currentCdpUser != address(0) && cdpManager.getSyncedICR(vars.currentCdpId, _price) < MCR ) { vars.currentCdpId = sortedCdps.getPrev(vars.currentCdpId); vars.currentCdpUser = sortedCdps.getOwnerAddress(vars.currentCdpId); } firstRedemptionHint = vars.currentCdpId; } if (_maxIterations == 0) { _maxIterations = type(uint256).max; } // Underflow is intentionally used in _maxIterations-- > 0 unchecked { while ( vars.currentCdpUser != address(0) && vars.remainingEbtcToRedeem > 0 && _maxIterations-- > 0 ) { // Apply pending debt uint256 currentCdpDebt = cdpManager.getSyncedCdpDebt(vars.currentCdpId); // If this CDP has more debt than the remaining to redeem, attempt a partial redemption if (currentCdpDebt > vars.remainingEbtcToRedeem) { uint256 _cachedEbtcToRedeem = vars.remainingEbtcToRedeem; ( partialRedemptionNewColl, partialRedemptionHintNICR ) = _calculateCdpStateAfterPartialRedemption(vars, currentCdpDebt, _price); // If the partial redemption would leave the CDP with less than the minimum allowed coll, bail out of partial redemption and return only the fully redeemable if ( collateral.getPooledEthByShares(partialRedemptionNewColl) < MIN_NET_STETH_BALANCE ) { partialRedemptionHintNICR = 0; //reset to 0 as there is no partial redemption in this case partialRedemptionNewColl = 0; vars.remainingEbtcToRedeem = _cachedEbtcToRedeem; } else { vars.remainingEbtcToRedeem = 0; } break; } else { vars.remainingEbtcToRedeem = vars.remainingEbtcToRedeem - currentCdpDebt; } vars.currentCdpId = sortedCdps.getPrev(vars.currentCdpId); vars.currentCdpUser = sortedCdps.getOwnerAddress(vars.currentCdpId); } } truncatedEBTCamount = _EBTCamount - vars.remainingEbtcToRedeem; } /** * @notice Calculate the partial redemption information. * @dev This is an internal function used by getRedemptionHints. * @param vars The local variables of the getRedemptionHints function. * @param currentCdpDebt The net eBTC debt of the CDP. * @param _price The current price of the asset. * @return newCollShare The new collateral share amount after partial redemption. * @return newNICR The new Nominal Collateral Ratio (NICR) of the CDP after partial redemption. */ function _calculateCdpStateAfterPartialRedemption( LocalVariables_getRedemptionHints memory vars, uint256 currentCdpDebt, uint256 _price ) internal view returns (uint256, uint256) { // maxReemable = min(remainingToRedeem, currentDebt) uint256 maxRedeemableEBTC = EbtcMath._min(vars.remainingEbtcToRedeem, currentCdpDebt); uint256 newCollShare = cdpManager.getSyncedCdpCollShares(vars.currentCdpId); vars.remainingEbtcToRedeem = vars.remainingEbtcToRedeem - maxRedeemableEBTC; uint256 collShareToReceive = collateral.getSharesByPooledEth( (maxRedeemableEBTC * DECIMAL_PRECISION) / _price ); uint256 _newCollShareAfter = newCollShare - collShareToReceive; return ( _newCollShareAfter, EbtcMath._computeNominalCR(_newCollShareAfter, currentCdpDebt - maxRedeemableEBTC) ); } /* getApproxHint() - return address of a Cdp that is, on average, (length / numTrials) positions away in the sortedCdps list from the correct insert position of the Cdp to be inserted. Note: The output address is worst-case O(n) positions away from the correct insert position, however, the function is probabilistic. Input can be tuned to guarantee results to a high degree of confidence, e.g: Submitting numTrials = k * sqrt(length), with k = 15 makes it very, very likely that the ouput address will be <= sqrt(length) positions away from the correct insert position. */ function getApproxHint( uint256 _CR, uint256 _numTrials, uint256 _inputRandomSeed ) external view returns (bytes32 hint, uint256 diff, uint256 latestRandomSeed) { uint256 arrayLength = cdpManager.getActiveCdpsCount(); if (arrayLength == 0) { return (sortedCdps.nonExistId(), 0, _inputRandomSeed); } hint = sortedCdps.getLast(); diff = EbtcMath._getAbsoluteDifference(_CR, cdpManager.getSyncedNominalICR(hint)); latestRandomSeed = _inputRandomSeed; uint256 i = 1; bytes32[] memory cdpIds = sortedCdpsToArray(); while (i < _numTrials) { latestRandomSeed = uint256(keccak256(abi.encodePacked(latestRandomSeed))); uint256 arrayIndex = latestRandomSeed % arrayLength; bytes32 _cId = cdpIds[arrayIndex]; uint256 currentNICR = cdpManager.getSyncedNominalICR(_cId); // check if abs(current - CR) > abs(closest - CR), and update closest if current is closer uint256 currentDiff = EbtcMath._getAbsoluteDifference(currentNICR, _CR); if (currentDiff < diff) { diff = currentDiff; hint = _cId; } i++; } } function sortedCdpsToArray() public view returns (bytes32[] memory cdpIdArray) { uint256 size = sortedCdps.getSize(); cdpIdArray = new bytes32[](size); if (size == 0) { // If the list is empty, return an empty array return cdpIdArray; } // Initialize the first CDP in the list bytes32 currentCdpId = sortedCdps.getFirst(); for (uint256 i = 0; i < size; ++i) { // Add the current CDP to the array cdpIdArray[i] = currentCdpId; // Move to the next CDP in the list currentCdpId = sortedCdps.getNext(currentCdpId); } return cdpIdArray; } /// @notice Compute nominal CR for a specified collateral and debt amount /// @param _coll The collateral amount, in shares /// @param _debt The debt amount /// @return The computed nominal CR for the given collateral and debt function computeNominalCR(uint256 _coll, uint256 _debt) external pure returns (uint256) { return EbtcMath._computeNominalCR(_coll, _debt); } /// @notice Compute CR for a specified collateral, debt amount, and price /// @param _coll The collateral amount, in shares /// @param _debt The debt amount /// @param _price The current price /// @return The computed CR for the given parameters function computeCR( uint256 _coll, uint256 _debt, uint256 _price ) external pure returns (uint256) { return EbtcMath._computeCR(_coll, _debt, _price); } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.17; contract BaseMath { uint256 public constant DECIMAL_PRECISION = 1e18; }
// SPDX-License-Identifier: MIT pragma solidity 0.8.17; import "./BaseMath.sol"; import "./EbtcMath.sol"; import "../Interfaces/IActivePool.sol"; import "../Interfaces/IPriceFeed.sol"; import "../Interfaces/IEbtcBase.sol"; import "../Dependencies/ICollateralToken.sol"; /* * Base contract for CdpManager, BorrowerOperations. Contains global system constants and * common functions. */ contract EbtcBase is BaseMath, IEbtcBase { // Collateral Ratio applied for Liquidation Incentive // i.e., liquidator repay $1 worth of debt to get back $1.03 worth of collateral uint256 public constant LICR = 1030000000000000000; // 103% // Minimum collateral ratio for individual cdps uint256 public constant MCR = 1100000000000000000; // 110% // Critical system collateral ratio. If the system's total collateral ratio (TCR) falls below the CCR, Recovery Mode is triggered. uint256 public constant CCR = 1250000000000000000; // 125% // Amount of stETH collateral to be locked in active pool on opening cdps uint256 public constant LIQUIDATOR_REWARD = 2e17; // Minimum amount of stETH collateral a CDP must have uint256 public constant MIN_NET_STETH_BALANCE = 2e18; uint256 public constant PERCENT_DIVISOR = 200; // dividing by 200 yields 0.5% uint256 public constant BORROWING_FEE_FLOOR = 0; // 0.5% uint256 public constant STAKING_REWARD_SPLIT = 5_000; // taking 50% cut from staking reward uint256 public constant MAX_REWARD_SPLIT = 10_000; uint256 public constant MIN_CHANGE = 1000; IActivePool public immutable activePool; IPriceFeed public immutable override priceFeed; // the only collateral token allowed in CDP ICollateralToken public immutable collateral; /// @notice Initializes the contract with the provided addresses /// @param _activePoolAddress The address of the ActivePool contract /// @param _priceFeedAddress The address of the PriceFeed contract /// @param _collateralAddress The address of the CollateralToken contract constructor(address _activePoolAddress, address _priceFeedAddress, address _collateralAddress) { activePool = IActivePool(_activePoolAddress); priceFeed = IPriceFeed(_priceFeedAddress); collateral = ICollateralToken(_collateralAddress); } // --- Gas compensation functions --- function _calcNetStEthBalance(uint256 _stEthBalance) internal pure returns (uint256) { return _stEthBalance - LIQUIDATOR_REWARD; } /// @notice Get the entire system collateral /// @notice Entire system collateral = collateral allocated to system in ActivePool, using it's internal accounting /// @dev Collateral tokens stored in ActivePool for liquidator rewards, fees, or coll in CollSurplusPool, are not included function getSystemCollShares() public view returns (uint256 entireSystemColl) { return (activePool.getSystemCollShares()); } /** @notice Get the entire system debt @notice Entire system collateral = collateral stored in ActivePool, using their internal accounting */ function _getSystemDebt() internal view returns (uint256 entireSystemDebt) { return (activePool.getSystemDebt()); } function _getCachedTCR(uint256 _price) internal view returns (uint256 TCR) { (TCR, , ) = _getTCRWithSystemDebtAndCollShares(_price); } function _getTCRWithSystemDebtAndCollShares( uint256 _price ) internal view returns (uint256 TCR, uint256 _coll, uint256 _debt) { uint256 systemCollShares = getSystemCollShares(); uint256 systemDebt = _getSystemDebt(); uint256 _systemStEthBalance = collateral.getPooledEthByShares(systemCollShares); TCR = EbtcMath._computeCR(_systemStEthBalance, systemDebt, _price); return (TCR, systemCollShares, systemDebt); } function _checkRecoveryMode(uint256 _price) internal view returns (bool) { return _checkRecoveryModeForTCR(_getCachedTCR(_price)); } function _checkRecoveryModeForTCR(uint256 _tcr) internal view returns (bool) { return _tcr < CCR; } function _requireUserAcceptsFee( uint256 _fee, uint256 _amount, uint256 _maxFeePercentage ) internal pure { uint256 feePercentage = (_fee * DECIMAL_PRECISION) / _amount; require(feePercentage <= _maxFeePercentage, "Fee exceeded provided maximum"); } // Convert debt denominated in ETH to debt denominated in BTC given that _price is ETH/BTC // _debt is denominated in ETH // _price is ETH/BTC function _convertDebtDenominationToBtc( uint256 _debt, uint256 _price ) internal pure returns (uint256) { return (_debt * _price) / DECIMAL_PRECISION; } /// @dev return true if given ICR is qualified for liquidation compared to configured threshold /// @dev this function ONLY checks numbers not check grace period switch for Recovery Mode function _checkICRAgainstLiqThreshold(uint256 _icr, uint _tcr) internal view returns (bool) { // Either undercollateralized // OR, it's RM AND they meet the requirement // Swapped Requirement && RM to save gas return _checkICRAgainstMCR(_icr) || (_checkICRAgainstTCR(_icr, _tcr) && _checkRecoveryModeForTCR(_tcr)); } /// @dev return true if given ICR is qualified for liquidation compared to MCR function _checkICRAgainstMCR(uint256 _icr) internal view returns (bool) { return _icr < MCR; } /// @dev return true if given ICR is qualified for liquidation compared to TCR /// @dev typically used in Recovery Mode function _checkICRAgainstTCR(uint256 _icr, uint _tcr) internal view returns (bool) { /// @audit is _icr <= _tcr more dangerous for overal system safety? /// @audit Should we use _icr < CCR to allow any risky CDP being liquidated? return _icr <= _tcr; } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.17; library EbtcMath { uint256 internal constant DECIMAL_PRECISION = 1e18; uint256 public constant MAX_TCR = type(uint256).max; /* Precision for Nominal ICR (independent of price). Rationale for the value: * * - Making it “too high” could lead to overflows. * - Making it “too low” could lead to an ICR equal to zero, due to truncation from Solidity floor division. * * This value of 1e20 is chosen for safety: the NICR will only overflow for numerator > ~1e39 ETH, * and will only truncate to 0 if the denominator is at least 1e20 times greater than the numerator. * */ uint256 internal constant NICR_PRECISION = 1e20; function _min(uint256 _a, uint256 _b) internal pure returns (uint256) { return (_a < _b) ? _a : _b; } function _max(uint256 _a, uint256 _b) internal pure returns (uint256) { return (_a >= _b) ? _a : _b; } /** * credit to OpenZeppelin * @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, "EbtcMath: downcast to uint128 will overflow"); return uint128(value); } /* * Multiply two decimal numbers and use normal rounding rules: * -round product up if 19'th mantissa digit >= 5 * -round product down if 19'th mantissa digit < 5 * * Used only inside the exponentiation, _decPow(). */ function decMul(uint256 x, uint256 y) internal pure returns (uint256 decProd) { uint256 prod_xy = x * y; decProd = (prod_xy + (DECIMAL_PRECISION / 2)) / DECIMAL_PRECISION; } /* * _decPow: Exponentiation function for 18-digit decimal base, and integer exponent n. * * Uses the efficient "exponentiation by squaring" algorithm. O(log(n)) complexity. * * Called by two functions that represent time in units of minutes: * 1) CdpManager._calcDecayedBaseRate * 2) CommunityIssuance._getCumulativeIssuanceFraction * * The exponent is capped to avoid reverting due to overflow. The cap 525600000 equals * "minutes in 1000 years": 60 * 24 * 365 * 1000 * * If a period of > 1000 years is ever used as an exponent in either of the above functions, the result will be * negligibly different from just passing the cap, since: * * In function 1), the decayed base rate will be 0 for 1000 years or > 1000 years * In function 2), the difference in tokens issued at 1000 years and any time > 1000 years, will be negligible */ function _decPow(uint256 _base, uint256 _minutes) internal pure returns (uint256) { if (_minutes > 525600000) { _minutes = 525600000; } // cap to avoid overflow if (_minutes == 0) { return DECIMAL_PRECISION; } uint256 y = DECIMAL_PRECISION; uint256 x = _base; uint256 n = _minutes; // Exponentiation-by-squaring while (n > 1) { if (n % 2 == 0) { x = decMul(x, x); n = n / 2; } else { // if (n % 2 != 0) y = decMul(x, y); x = decMul(x, x); n = (n - 1) / 2; } } return decMul(x, y); } function _getAbsoluteDifference(uint256 _a, uint256 _b) internal pure returns (uint256) { return (_a >= _b) ? (_a - _b) : (_b - _a); } function _computeNominalCR(uint256 _collShares, uint256 _debt) internal pure returns (uint256) { if (_debt > 0) { return (_collShares * NICR_PRECISION) / _debt; } // Return the maximal value for uint256 if the Cdp has a debt of 0. Represents "infinite" CR. else { // if (_debt == 0) return MAX_TCR; } } /// @dev Compute collateralization ratio, given stETH balance, price, and debt balance function _computeCR( uint256 _stEthBalance, uint256 _debt, uint256 _price ) internal pure returns (uint256) { if (_debt > 0) { uint256 newCollRatio = (_stEthBalance * _price) / _debt; return newCollRatio; } // Return the maximal value for uint256 if the Cdp has a debt of 0. Represents "infinite" CR. else { // if (_debt == 0) return MAX_TCR; } } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.17; import "./IERC20.sol"; /** * Based on the stETH: * - https://docs.lido.fi/contracts/lido# */ interface ICollateralToken is IERC20 { // Returns the amount of shares that corresponds to _ethAmount protocol-controlled Ether function getSharesByPooledEth(uint256 _ethAmount) external view returns (uint256); // Returns the amount of Ether that corresponds to _sharesAmount token shares function getPooledEthByShares(uint256 _sharesAmount) external view returns (uint256); // Moves `_sharesAmount` token shares from the caller's account to the `_recipient` account. function transferShares(address _recipient, uint256 _sharesAmount) external returns (uint256); // Returns the amount of shares owned by _account function sharesOf(address _account) external view returns (uint256); // Returns authorized oracle address function getOracle() external view returns (address); }
// SPDX-License-Identifier: MIT pragma solidity 0.8.17; /** * Based on the stETH: * - https://docs.lido.fi/contracts/lido# */ interface ICollateralTokenOracle { // Return beacon specification data. function getBeaconSpec() external view returns ( uint64 epochsPerFrame, uint64 slotsPerEpoch, uint64 secondsPerSlot, uint64 genesisTime ); }
// SPDX-License-Identifier: MIT pragma solidity 0.8.17; /** * Based on the OpenZeppelin IER20 interface: * https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/IERC20.sol * * @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); function increaseAllowance(address spender, uint256 addedValue) external returns (bool); function decreaseAllowance(address spender, uint256 subtractedValue) external returns (bool); /** * @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); function name() external view returns (string memory); function symbol() external view returns (string memory); function decimals() external view returns (uint8); /** * @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 pragma solidity 0.8.17; /** * @dev Interface of the ERC2612 standard as defined in the EIP. * * Adds the {permit} method, which can be used to change one's * {IERC20-allowance} without having to send a transaction, by signing a * message. This allows users to spend tokens without having to hold Ether. * * See https://eips.ethereum.org/EIPS/eip-2612. * * Code adapted from https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2237/ */ interface IERC2612 { /** * @dev Sets `amount` as the allowance of `spender` over `owner`'s tokens, * given `owner`'s signed approval. * * IMPORTANT: The same issues {IERC20-approve} has related to transaction * ordering also apply here. * * Emits an {Approval} event. * * Requirements: * * - `owner` cannot be the zero address. * - `spender` cannot be the zero address. * - `deadline` must be a timestamp in the future. * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner` * over the EIP712-formatted function arguments. * - the signature must use ``owner``'s current nonce (see {nonces}). * * For more information on the signature format, see the * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP * section]. */ function permit( address owner, address spender, uint256 amount, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external; /** * @dev Returns the current ERC2612 nonce for `owner`. This value must be * included whenever a signature is generated for {permit}. * * Every successful call to {permit} increases `owner`'s nonce by one. This * prevents a signature from being used multiple times. * * `owner` can limit the time a Permit is valid for by setting `deadline` to * a value in the near future. The deadline argument can be set to uint256(-1) to * create Permits that effectively never expire. */ function nonces(address owner) external view returns (uint256); function version() external view returns (string memory); function permitTypeHash() external view returns (bytes32); function domainSeparator() external view returns (bytes32); }
// SPDX-License-Identifier: MIT pragma solidity 0.8.17; import "./IPool.sol"; import "./ITwapWeightedObserver.sol"; interface IActivePool is IPool, ITwapWeightedObserver { // --- Events --- event ActivePoolEBTCDebtUpdated(uint256 _EBTCDebt); event SystemCollSharesUpdated(uint256 _coll); event FeeRecipientClaimableCollSharesIncreased(uint256 _coll, uint256 _fee); event FeeRecipientClaimableCollSharesDecreased(uint256 _coll, uint256 _fee); event FlashLoanSuccess( address indexed _receiver, address indexed _token, uint256 _amount, uint256 _fee ); event SweepTokenSuccess(address indexed _token, uint256 _amount, address indexed _recipient); // --- Functions --- function transferSystemCollShares(address _account, uint256 _amount) external; function increaseSystemCollShares(uint256 _value) external; function transferSystemCollSharesAndLiquidatorReward( address _account, uint256 _shares, uint256 _liquidatorRewardShares ) external; function allocateSystemCollSharesToFeeRecipient(uint256 _shares) external; function claimFeeRecipientCollShares(uint256 _shares) external; function feeRecipientAddress() external view returns (address); function getFeeRecipientClaimableCollShares() external view returns (uint256); }
// SPDX-License Identifier: MIT pragma solidity 0.8.17; interface IBaseTwapWeightedObserver { // NOTE: Packing manually is cheaper, but this is simpler to understand and follow struct PackedData { // Slot 0 // Seconds in a year: 3.154e+7 /// @dev Accumulator value recorded for TWAP Observer until last update uint128 observerCumuVal; // 3.154e+7 * 80 * 100e27 = 2.5232e+38 | log_2(100e27 * 3.154e+7 * 80) = 127.568522171 /// @dev Accumulator for TWAP globally uint128 accumulator; // 3.154e+7 * 80 * 100e27 = 2.5232e+38 | log_2(100e27 * 3.154e+7 * 80) = 127.568522171 // NOTE: We can further compress this slot but we will not be able to use only one (see u72 impl) /// So what's the point of making the code more complex? // Slot 1 /// @dev last update timestamp for TWAP Observer uint64 lastObserved; // Thousands of Years, if we use relative time we can use u32 | Relative to deploy time (as immutable) /// @dev last update timestamp for TWAP global track(spot) value uint64 lastAccrued; // Thousands of years // Expect eBTC debt to never surpass 100e27, which is 100 BILLION eBTC // log_2(100e27) = 96.3359147517 | log_2(100e27 / 1e18) = 36.5412090438 // We could use a u64 /// @dev average value since last observe uint128 lastObservedAverage; } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.17; import "./IEbtcBase.sol"; import "./ICdpManagerData.sol"; // Common interface for the Cdp Manager. interface ICdpManager is IEbtcBase, ICdpManagerData { // --- Functions --- function liquidate(bytes32 _cdpId) external; function partiallyLiquidate( bytes32 _cdpId, uint256 _partialAmount, bytes32 _upperPartialHint, bytes32 _lowerPartialHint ) external; function batchLiquidateCdps(bytes32[] calldata _cdpArray) external; function redeemCollateral( uint256 _EBTCAmount, bytes32 _firstRedemptionHint, bytes32 _upperPartialRedemptionHint, bytes32 _lowerPartialRedemptionHint, uint256 _partialRedemptionHintNICR, uint256 _maxIterations, uint256 _maxFee ) external; function updateStakeAndTotalStakes(bytes32 _cdpId) external returns (uint256); function syncAccounting(bytes32 _cdpId) external; function closeCdp(bytes32 _cdpId, address _borrower, uint256 _debt, uint256 _coll) external; function getRedemptionRate() external view returns (uint256); function getRedemptionRateWithDecay() external view returns (uint256); function getRedemptionFeeWithDecay(uint256 _stETHToRedeem) external view returns (uint256); function getCdpStatus(bytes32 _cdpId) external view returns (uint256); function getCdpStake(bytes32 _cdpId) external view returns (uint256); function getCdpDebt(bytes32 _cdpId) external view returns (uint256); function getCdpCollShares(bytes32 _cdpId) external view returns (uint256); function getCdpLiquidatorRewardShares(bytes32 _cdpId) external view returns (uint); function initializeCdp( bytes32 _cdpId, uint256 _debt, uint256 _coll, uint256 _liquidatorRewardShares, address _borrower ) external; function updateCdp( bytes32 _cdpId, address _borrower, uint256 _coll, uint256 _debt, uint256 _newColl, uint256 _newDebt ) external; function getCachedTCR(uint256 _price) external view returns (uint256); function checkRecoveryMode(uint256 _price) external view returns (bool); }
// SPDX-License-Identifier: MIT pragma solidity 0.8.17; import "./ICollSurplusPool.sol"; import "./IEBTCToken.sol"; import "./ISortedCdps.sol"; import "./IActivePool.sol"; import "./IRecoveryModeGracePeriod.sol"; import "../Dependencies/ICollateralTokenOracle.sol"; // Common interface for the Cdp Manager. interface ICdpManagerData is IRecoveryModeGracePeriod { // --- Events --- event StakingRewardSplitSet(uint256 _stakingRewardSplit); event RedemptionFeeFloorSet(uint256 _redemptionFeeFloor); event MinuteDecayFactorSet(uint256 _minuteDecayFactor); event BetaSet(uint256 _beta); event RedemptionsPaused(bool _paused); event Liquidation(uint256 _liquidatedDebt, uint256 _liquidatedColl, uint256 _liqReward); event Redemption( uint256 _debtToRedeemExpected, uint256 _debtToRedeemActual, uint256 _collSharesSent, uint256 _feeCollShares, address indexed _redeemer ); event CdpUpdated( bytes32 indexed _cdpId, address indexed _borrower, address indexed _executor, uint256 _oldDebt, uint256 _oldCollShares, uint256 _debt, uint256 _collShares, uint256 _stake, CdpOperation _operation ); event CdpLiquidated( bytes32 indexed _cdpId, address indexed _borrower, uint _debt, uint _collShares, CdpOperation _operation, address indexed _liquidator, uint _premiumToLiquidator ); event CdpPartiallyLiquidated( bytes32 indexed _cdpId, address indexed _borrower, uint256 _debt, uint256 _collShares, CdpOperation operation, address indexed _liquidator, uint _premiumToLiquidator ); event BaseRateUpdated(uint256 _baseRate); event LastRedemptionTimestampUpdated(uint256 _lastFeeOpTime); event TotalStakesUpdated(uint256 _newTotalStakes); event SystemSnapshotsUpdated(uint256 _totalStakesSnapshot, uint256 _totalCollateralSnapshot); event SystemDebtRedistributionIndexUpdated(uint256 _systemDebtRedistributionIndex); event CdpDebtRedistributionIndexUpdated(bytes32 _cdpId, uint256 _cdpDebtRedistributionIndex); event CdpArrayIndexUpdated(bytes32 _cdpId, uint256 _newIndex); event StEthIndexUpdated(uint256 _oldIndex, uint256 _newIndex, uint256 _updTimestamp); event CollateralFeePerUnitUpdated(uint256 _oldPerUnit, uint256 _newPerUnit, uint256 _feeTaken); event CdpFeeSplitApplied( bytes32 _cdpId, uint256 _oldPerUnitCdp, uint256 _newPerUnitCdp, uint256 _collReduced, uint256 _collLeft ); enum CdpOperation { openCdp, closeCdp, adjustCdp, syncAccounting, liquidateInNormalMode, liquidateInRecoveryMode, redeemCollateral, partiallyLiquidate, failedPartialRedemption } enum Status { nonExistent, active, closedByOwner, closedByLiquidation, closedByRedemption } // Store the necessary data for a cdp struct Cdp { uint256 debt; uint256 coll; uint256 stake; uint128 liquidatorRewardShares; Status status; } /* * --- Variable container structs for liquidations --- * * These structs are used to hold, return and assign variables inside the liquidation functions, * in order to avoid the error: "CompilerError: Stack too deep". **/ struct CdpDebtAndCollShares { uint256 debt; uint256 collShares; } struct LiquidationLocals { bytes32 cdpId; uint256 partialAmount; // used only for partial liquidation, default 0 means full liquidation uint256 price; uint256 ICR; bytes32 upperPartialHint; bytes32 lowerPartialHint; bool recoveryModeAtStart; uint256 TCR; uint256 totalSurplusCollShares; uint256 totalCollSharesToSend; uint256 totalDebtToBurn; uint256 totalDebtToRedistribute; uint256 totalLiquidatorRewardCollShares; } struct LiquidationRecoveryModeLocals { uint256 entireSystemDebt; uint256 entireSystemColl; uint256 totalDebtToBurn; uint256 totalCollSharesToSend; uint256 totalSurplusCollShares; bytes32 cdpId; uint256 price; uint256 ICR; uint256 totalDebtToRedistribute; uint256 totalLiquidatorRewardCollShares; } struct LocalVariables_OuterLiquidationFunction { uint256 price; bool recoveryModeAtStart; uint256 liquidatedDebt; uint256 liquidatedColl; } struct LocalVariables_LiquidationSequence { uint256 i; uint256 ICR; bytes32 cdpId; bool backToNormalMode; uint256 entireSystemDebt; uint256 entireSystemColl; uint256 price; uint256 TCR; } struct SingleRedemptionInputs { bytes32 cdpId; uint256 maxEBTCamount; uint256 price; bytes32 upperPartialRedemptionHint; bytes32 lowerPartialRedemptionHint; uint256 partialRedemptionHintNICR; } struct LiquidationValues { uint256 entireCdpDebt; uint256 debtToBurn; uint256 totalCollToSendToLiquidator; uint256 debtToRedistribute; uint256 collSurplus; uint256 liquidatorCollSharesReward; } struct LiquidationTotals { uint256 totalDebtInSequence; uint256 totalDebtToBurn; uint256 totalCollToSendToLiquidator; uint256 totalDebtToRedistribute; uint256 totalCollSurplus; uint256 totalCollReward; } // --- Variable container structs for redemptions --- struct RedemptionTotals { uint256 remainingDebtToRedeem; uint256 debtToRedeem; uint256 collSharesDrawn; uint256 totalCollSharesSurplus; uint256 feeCollShares; uint256 collSharesToRedeemer; uint256 decayedBaseRate; uint256 price; uint256 systemDebtAtStart; uint256 twapSystemDebtAtStart; uint256 systemCollSharesAtStart; uint256 tcrAtStart; } struct SingleRedemptionValues { uint256 debtToRedeem; uint256 collSharesDrawn; uint256 collSurplus; uint256 liquidatorRewardShares; bool cancelledPartial; bool fullRedemption; uint256 newPartialNICR; } function getActiveCdpsCount() external view returns (uint256); function totalStakes() external view returns (uint256); function ebtcToken() external view returns (IEBTCToken); function systemStEthFeePerUnitIndex() external view returns (uint256); function systemStEthFeePerUnitIndexError() external view returns (uint256); function stEthIndex() external view returns (uint256); function calcFeeUponStakingReward( uint256 _newIndex, uint256 _prevIndex ) external view returns (uint256, uint256, uint256); function syncGlobalAccounting() external; // Accrues StEthFeeSplit without influencing Grace Period function syncGlobalAccountingAndGracePeriod() external; // Accrues StEthFeeSplit and influences Grace Period function getAccumulatedFeeSplitApplied( bytes32 _cdpId, uint256 _systemStEthFeePerUnitIndex ) external view returns (uint256, uint256); function getCachedNominalICR(bytes32 _cdpId) external view returns (uint256); function getCachedICR(bytes32 _cdpId, uint256 _price) external view returns (uint256); function getSyncedCdpDebt(bytes32 _cdpId) external view returns (uint256); function getSyncedCdpCollShares(bytes32 _cdpId) external view returns (uint256); function getSyncedICR(bytes32 _cdpId, uint256 _price) external view returns (uint256); function getSyncedTCR(uint256 _price) external view returns (uint256); function getSyncedSystemCollShares() external view returns (uint256); function getSyncedNominalICR(bytes32 _cdpId) external view returns (uint256); function getPendingRedistributedDebt(bytes32 _cdpId) external view returns (uint256); function hasPendingRedistributedDebt(bytes32 _cdpId) external view returns (bool); function getSyncedDebtAndCollShares( bytes32 _cdpId ) external view returns (uint256 debt, uint256 collShares); function canLiquidateRecoveryMode(uint256 icr, uint256 tcr) external view returns (bool); function totalCollateralSnapshot() external view returns (uint256); function totalStakesSnapshot() external view returns (uint256); }
// SPDX-License-Identifier: MIT pragma solidity 0.8.17; interface ICollSurplusPool { // --- Events --- event SurplusCollSharesAdded( bytes32 indexed _cdpId, address indexed _account, uint256 _claimableSurplusCollShares, uint256 _surplusCollSharesAddedFromCollateral, uint256 _surplusCollSharesAddedFromLiquidatorReward ); event CollSharesTransferred(address indexed _to, uint256 _amount); event SweepTokenSuccess(address indexed _token, uint256 _amount, address indexed _recipient); // --- Contract setters --- function getTotalSurplusCollShares() external view returns (uint256); function getSurplusCollShares(address _account) external view returns (uint256); function increaseSurplusCollShares( bytes32 _cdpId, address _account, uint256 _collateralShares, uint256 _liquidatorRewardShares ) external; function claimSurplusCollShares(address _account) external; function increaseTotalSurplusCollShares(uint256 _value) external; }
// SPDX-License-Identifier: MIT pragma solidity 0.8.17; import "./IPriceFeed.sol"; interface IEbtcBase { function priceFeed() external view returns (IPriceFeed); }
// SPDX-License-Identifier: MIT pragma solidity 0.8.17; import "../Dependencies/IERC20.sol"; import "../Dependencies/IERC2612.sol"; interface IEBTCToken is IERC20, IERC2612 { // --- Functions --- function mint(address _account, uint256 _amount) external; function burn(address _account, uint256 _amount) external; }
// SPDX-License-Identifier: MIT pragma solidity 0.8.17; // Common interface for the Pools. interface IPool { // --- Events --- event ETHBalanceUpdated(uint256 _newBalance); event EBTCBalanceUpdated(uint256 _newBalance); event CollSharesTransferred(address indexed _to, uint256 _amount); // --- Functions --- function getSystemCollShares() external view returns (uint256); function getSystemDebt() external view returns (uint256); function increaseSystemDebt(uint256 _amount) external; function decreaseSystemDebt(uint256 _amount) external; }
// SPDX-License-Identifier: MIT pragma solidity 0.8.17; interface IPriceFeed { // --- Events --- event LastGoodPriceUpdated(uint256 _lastGoodPrice); event PriceFeedStatusChanged(Status newStatus); event FallbackCallerChanged( address indexed _oldFallbackCaller, address indexed _newFallbackCaller ); event UnhealthyFallbackCaller(address indexed _fallbackCaller, uint256 timestamp); event CollateralFeedSourceUpdated(address indexed stEthFeed); // --- Structs --- struct ChainlinkResponse { uint80 roundEthBtcId; uint80 roundStEthEthId; uint256 answer; uint256 timestampEthBtc; uint256 timestampStEthEth; bool success; } struct FallbackResponse { uint256 answer; uint256 timestamp; bool success; } // --- Enum --- enum Status { chainlinkWorking, usingFallbackChainlinkUntrusted, bothOraclesUntrusted, usingFallbackChainlinkFrozen, usingChainlinkFallbackUntrusted } // --- Function --- function fetchPrice() external returns (uint256); }
// SPDX-License-Identifier: MIT pragma solidity 0.8.17; // Interface for State Updates that can trigger RM Liquidations interface IRecoveryModeGracePeriod { event TCRNotified(uint256 TCR); /// NOTE: Mostly for debugging to ensure synch // NOTE: Ts is implicit in events (it's added by GETH) event GracePeriodStart(); event GracePeriodEnd(); event GracePeriodDurationSet(uint256 _recoveryModeGracePeriodDuration); function notifyStartGracePeriod(uint256 tcr) external; function notifyEndGracePeriod(uint256 tcr) external; }
// SPDX-License-Identifier: MIT pragma solidity 0.8.17; // Common interface for the SortedCdps Doubly Linked List. interface ISortedCdps { // --- Events --- event NodeAdded(bytes32 _id, uint _NICR); event NodeRemoved(bytes32 _id); // --- Functions --- function remove(bytes32 _id) external; function batchRemove(bytes32[] memory _ids) external; function reInsert(bytes32 _id, uint256 _newICR, bytes32 _prevId, bytes32 _nextId) external; function contains(bytes32 _id) external view returns (bool); function isFull() external view returns (bool); function isEmpty() external view returns (bool); function getSize() external view returns (uint256); function getMaxSize() external view returns (uint256); function getFirst() external view returns (bytes32); function getLast() external view returns (bytes32); function getNext(bytes32 _id) external view returns (bytes32); function getPrev(bytes32 _id) external view returns (bytes32); function validInsertPosition( uint256 _ICR, bytes32 _prevId, bytes32 _nextId ) external view returns (bool); function findInsertPosition( uint256 _ICR, bytes32 _prevId, bytes32 _nextId ) external view returns (bytes32, bytes32); function insert( address owner, uint256 _ICR, bytes32 _prevId, bytes32 _nextId ) external returns (bytes32); function getOwnerAddress(bytes32 _id) external pure returns (address); function nonExistId() external view returns (bytes32); function cdpCountOf(address owner) external view returns (uint256); function getCdpCountOf( address owner, bytes32 startNodeId, uint maxNodes ) external view returns (uint256, bytes32); function getCdpsOf(address owner) external view returns (bytes32[] memory); function getAllCdpsOf( address owner, bytes32 startNodeId, uint maxNodes ) external view returns (bytes32[] memory, uint256, bytes32); function cdpOfOwnerByIndex(address owner, uint256 index) external view returns (bytes32); function cdpOfOwnerByIdx( address owner, uint256 index, bytes32 startNodeId, uint maxNodes ) external view returns (bytes32, bool); function toCdpId( address owner, uint256 blockHeight, uint256 nonce ) external pure returns (bytes32); function nextCdpNonce() external view returns (uint256); }
// SPDX-License Identifier: MIT pragma solidity 0.8.17; import {IBaseTwapWeightedObserver} from "./IBaseTwapWeightedObserver.sol"; interface ITwapWeightedObserver is IBaseTwapWeightedObserver { event TwapDisabled(); function PERIOD() external view returns (uint256); function valueToTrack() external view returns (uint128); function timeToAccrue() external view returns (uint64); function getLatestAccumulator() external view returns (uint128); function observe() external returns (uint256); function update() external; function twapDisabled() external view returns (bool); }
{ "optimizer": { "enabled": true, "runs": 200 }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"_sortedCdpsAddress","type":"address"},{"internalType":"address","name":"_cdpManagerAddress","type":"address"},{"internalType":"address","name":"_collateralAddress","type":"address"},{"internalType":"address","name":"_activePoolAddress","type":"address"},{"internalType":"address","name":"_priceFeedAddress","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"BORROWING_FEE_FLOOR","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"CCR","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DECIMAL_PRECISION","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"LICR","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"LIQUIDATOR_REWARD","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_REWARD_SPLIT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MCR","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_CHANGE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_NET_STETH_BALANCE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"NAME","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PERCENT_DIVISOR","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"STAKING_REWARD_SPLIT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"activePool","outputs":[{"internalType":"contract IActivePool","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"cdpManager","outputs":[{"internalType":"contract ICdpManager","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"collateral","outputs":[{"internalType":"contract ICollateralToken","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_coll","type":"uint256"},{"internalType":"uint256","name":"_debt","type":"uint256"},{"internalType":"uint256","name":"_price","type":"uint256"}],"name":"computeCR","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"_coll","type":"uint256"},{"internalType":"uint256","name":"_debt","type":"uint256"}],"name":"computeNominalCR","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"_CR","type":"uint256"},{"internalType":"uint256","name":"_numTrials","type":"uint256"},{"internalType":"uint256","name":"_inputRandomSeed","type":"uint256"}],"name":"getApproxHint","outputs":[{"internalType":"bytes32","name":"hint","type":"bytes32"},{"internalType":"uint256","name":"diff","type":"uint256"},{"internalType":"uint256","name":"latestRandomSeed","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_EBTCamount","type":"uint256"},{"internalType":"uint256","name":"_price","type":"uint256"},{"internalType":"uint256","name":"_maxIterations","type":"uint256"}],"name":"getRedemptionHints","outputs":[{"internalType":"bytes32","name":"firstRedemptionHint","type":"bytes32"},{"internalType":"uint256","name":"partialRedemptionHintNICR","type":"uint256"},{"internalType":"uint256","name":"truncatedEBTCamount","type":"uint256"},{"internalType":"uint256","name":"partialRedemptionNewColl","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getSystemCollShares","outputs":[{"internalType":"uint256","name":"entireSystemColl","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"priceFeed","outputs":[{"internalType":"contract IPriceFeed","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"sortedCdps","outputs":[{"internalType":"contract ISortedCdps","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"sortedCdpsToArray","outputs":[{"internalType":"bytes32[]","name":"cdpIdArray","type":"bytes32[]"}],"stateMutability":"view","type":"function"}]
Contract Creation Code
6101206040523480156200001257600080fd5b50604051620016533803806200165383398101604081905262000035916200007c565b6001600160a01b03918216608052811660a05290811660c05291821660e0521661010052620000ec565b80516001600160a01b03811681146200007757600080fd5b919050565b600080600080600060a086880312156200009557600080fd5b620000a0866200005f565b9450620000b0602087016200005f565b9350620000c0604087016200005f565b9250620000d0606087016200005f565b9150620000e0608087016200005f565b90509295509295909350565b60805160a05160c05160e05161010051611496620001bd600039600081816102f50152818161052a0152818161074501528181610c2801528181610dcd01528181610ed1015261105701526000818161032f015281816103e60152818161046c015281816105cc0152818161065b015281816108b301528181610942015281816109fd01528181610ad401528181610b9501528181610cb40152610d45015260008181610356015281816107fc0152611106015260006101eb0152600081816102760152610fb901526114966000f3fe608060405234801561001057600080fd5b506004361061014d5760003560e01c80639c77f4cf116100c3578063c526a6b01161007c578063c526a6b01461032a578063d8dfeb4514610351578063d9901b9414610378578063e3f6838814610381578063e825665114610389578063f92d34331461039857600080fd5b80639c77f4cf14610298578063a20baee6146102a1578063a3f4df7e146102b0578063a9beb765146102e7578063bb038e15146102f0578063c394a7fa1461031757600080fd5b80636ee4c8cf116101155780636ee4c8cf146101d7578063741bef1a146101e6578063794e5724146102255780637b41bdbe146102345780637f3020c1146102625780637f7dde4a1461027157600080fd5b806313144dba146101525780634870dd9a1461018a578063525acdbb146101a05780635733d58f146101b35780635dc1eca8146101c2575b600080fd5b61016561016036600461127b565b6103a0565b6040805194855260208501939093529183015260608201526080015b60405180910390f35b61019260c881565b604051908152602001610181565b6101926101ae36600461127b565b6109e0565b610192671158e460913d000081565b6101ca6109f7565b60405161018191906112a7565b610192671bc16d674ec8000081565b61020d7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b039091168152602001610181565b610192670f43fc2c04ee000081565b61024761024236600461127b565b610c20565b60408051938452602084019290925290820152606001610181565b6101926702c68af0bb14000081565b61020d7f000000000000000000000000000000000000000000000000000000000000000081565b61019261138881565b610192670de0b6b3a764000081565b6102da6040518060400160405280600b81526020016a48696e7448656c7065727360a81b81525081565b60405161018191906112eb565b61019261271081565b61020d7f000000000000000000000000000000000000000000000000000000000000000081565b610192610325366004611339565b610fa0565b61020d7f000000000000000000000000000000000000000000000000000000000000000081565b61020d7f000000000000000000000000000000000000000000000000000000000000000081565b6101926103e881565b610192610fb5565b610192670e4b4b8af6a7000081565b610192600081565b6040805160808101825260006020808301829052828401829052606083018290528683528351634d62283160e01b81529351919384938493849391926001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001692634d622831926004808401938290030181865afa15801561042c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610450919061135b565b604082810182905251626a1f6360e11b815260048101919091527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169062d43ec690602401602060405180830381865afa1580156104ba573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104de9190611374565b6001600160a01b031660608201525b60608101516001600160a01b0316158015906105ab5750604080820151905163f869817f60e01b8152670f43fc2c04ee0000916001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169163f869817f91610568918c90600401918252602082015260400190565b602060405180830381865afa158015610585573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105a9919061135b565b105b156106e0576040818101519051630d0117ab60e31b815260048101919091527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690636808bd5890602401602060405180830381865afa15801561061b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061063f919061135b565b604082810182905251626a1f6360e11b815260048101919091527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169062d43ec690602401602060405180830381865afa1580156106a9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106cd9190611374565b6001600160a01b031660608201526104ed565b80604001519450856000036106f55760001995505b60608101516001600160a01b0316158015906107115750805115155b8015610721575060001986019515155b156109c85760408082015190516318cc429f60e11b81526000916001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001691633198853e9161077c9160040190815260200190565b602060405180830381865afa158015610799573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107bd919061135b565b82519091508111156108905781516107d683838b61103e565b604051630f451f7160e31b815260048101839052909750909450671bc16d674ec80000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690637a28fb8890602401602060405180830381865afa15801561084b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061086f919061135b565b10156108845780835260009550859350610889565b600083525b50506109c8565b815181900382526040808301519051630d0117ab60e31b815260048101919091527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690636808bd5890602401602060405180830381865afa158015610902573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610926919061135b565b604083810182905251626a1f6360e11b815260048101919091527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169062d43ec690602401602060405180830381865afa158015610990573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109b49190611374565b6001600160a01b03166060830152506106f5565b80516109d490896113b3565b92505093509350935093565b60006109ed8484846111db565b90505b9392505050565b606060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663de8fa4316040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a59573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a7d919061135b565b90508067ffffffffffffffff811115610a9857610a986113c6565b604051908082528060200260200182016040528015610ac1578160200160208202803683370190505b50915080600003610ad0575090565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316631e2231436040518163ffffffff1660e01b8152600401602060405180830381865afa158015610b30573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b54919061135b565b905060005b82811015610c1a5781848281518110610b7457610b746113dc565b60209081029190910101526040516394dfe33f60e01b8152600481018390527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906394dfe33f90602401602060405180830381865afa158015610be4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c08919061135b565b9150610c13816113f2565b9050610b59565b50505090565b6000806000807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316630c5805bc6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610c84573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ca8919061135b565b905080600003610d43577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663b0faee936040518163ffffffff1660e01b8152600401602060405180830381865afa158015610d10573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d34919061135b565b60008693509350935050610f97565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316634d6228316040518163ffffffff1660e01b8152600401602060405180830381865afa158015610da1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610dc5919061135b565b9350610e5f877f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663db4159ae876040518263ffffffff1660e01b8152600401610e1991815260200190565b602060405180830381865afa158015610e36573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e5a919061135b565b61120c565b925084915060016000610e706109f7565b90505b87821015610f935760408051602081018690520160408051601f19818403018152919052805160209091012093506000610ead8486611421565b90506000828281518110610ec357610ec36113dc565b6020026020010151905060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663db4159ae836040518263ffffffff1660e01b8152600401610f1d91815260200190565b602060405180830381865afa158015610f3a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f5e919061135b565b90506000610f6c828e61120c565b905088811015610f7d578098508299505b85610f87816113f2565b96505050505050610e73565b5050505b93509350939050565b6000610fac838361122f565b90505b92915050565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663e3f683886040518163ffffffff1660e01b8152600401602060405180830381865afa158015611015573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611039919061135b565b905090565b6000806000611051866000015186611265565b905060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316636b4f105b88604001516040518263ffffffff1660e01b81526004016110a791815260200190565b602060405180830381865afa1580156110c4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110e8919061135b565b87519091506110f89083906113b3565b875260006001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001663192084518761113e670de0b6b3a764000087611435565b611148919061144c565b6040518263ffffffff1660e01b815260040161116691815260200190565b602060405180830381865afa158015611183573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111a7919061135b565b905060006111b582846113b3565b9050806111cb816111c6878c6113b3565b61122f565b9550955050505050935093915050565b60008215611203576000836111f08487611435565b6111fa919061144c565b91506109f09050565b506000196109f0565b6000818310156112255761122083836113b3565b610fac565b610fac82846113b3565b6000811561125c578161124b68056bc75e2d6310000085611435565b611255919061144c565b9050610faf565b50600019610faf565b60008183106112745781610fac565b5090919050565b60008060006060848603121561129057600080fd5b505081359360208301359350604090920135919050565b6020808252825182820181905260009190848201906040850190845b818110156112df578351835292840192918401916001016112c3565b50909695505050505050565b600060208083528351808285015260005b81811015611318578581018301518582016040015282016112fc565b506000604082860101526040601f19601f8301168501019250505092915050565b6000806040838503121561134c57600080fd5b50508035926020909101359150565b60006020828403121561136d57600080fd5b5051919050565b60006020828403121561138657600080fd5b81516001600160a01b03811681146109f057600080fd5b634e487b7160e01b600052601160045260246000fd5b81810381811115610faf57610faf61139d565b634e487b7160e01b600052604160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b6000600182016114045761140461139d565b5060010190565b634e487b7160e01b600052601260045260246000fd5b6000826114305761143061140b565b500690565b8082028115828204841417610faf57610faf61139d565b60008261145b5761145b61140b565b50049056fea26469706673582212206b53242751c1ad2817a5149991a5963aec44206a3ee9fba9e364c687c6d08c0764736f6c63430008110033000000000000000000000000591acb5ae192c147948c12651a0a5f24f0529be3000000000000000000000000c4cbae499bb4ca41e78f52f07f5d98c375711774000000000000000000000000ae7ab96520de3a18e5e111b5eaab095312d7fe840000000000000000000000006dbdb6d420c110290431e863a1a978ae53f69ebc000000000000000000000000a9a65b1b1dda8376527e89985b221b6bfca1dc9a
Deployed Bytecode
0x608060405234801561001057600080fd5b506004361061014d5760003560e01c80639c77f4cf116100c3578063c526a6b01161007c578063c526a6b01461032a578063d8dfeb4514610351578063d9901b9414610378578063e3f6838814610381578063e825665114610389578063f92d34331461039857600080fd5b80639c77f4cf14610298578063a20baee6146102a1578063a3f4df7e146102b0578063a9beb765146102e7578063bb038e15146102f0578063c394a7fa1461031757600080fd5b80636ee4c8cf116101155780636ee4c8cf146101d7578063741bef1a146101e6578063794e5724146102255780637b41bdbe146102345780637f3020c1146102625780637f7dde4a1461027157600080fd5b806313144dba146101525780634870dd9a1461018a578063525acdbb146101a05780635733d58f146101b35780635dc1eca8146101c2575b600080fd5b61016561016036600461127b565b6103a0565b6040805194855260208501939093529183015260608201526080015b60405180910390f35b61019260c881565b604051908152602001610181565b6101926101ae36600461127b565b6109e0565b610192671158e460913d000081565b6101ca6109f7565b60405161018191906112a7565b610192671bc16d674ec8000081565b61020d7f000000000000000000000000a9a65b1b1dda8376527e89985b221b6bfca1dc9a81565b6040516001600160a01b039091168152602001610181565b610192670f43fc2c04ee000081565b61024761024236600461127b565b610c20565b60408051938452602084019290925290820152606001610181565b6101926702c68af0bb14000081565b61020d7f0000000000000000000000006dbdb6d420c110290431e863a1a978ae53f69ebc81565b61019261138881565b610192670de0b6b3a764000081565b6102da6040518060400160405280600b81526020016a48696e7448656c7065727360a81b81525081565b60405161018191906112eb565b61019261271081565b61020d7f000000000000000000000000c4cbae499bb4ca41e78f52f07f5d98c37571177481565b610192610325366004611339565b610fa0565b61020d7f000000000000000000000000591acb5ae192c147948c12651a0a5f24f0529be381565b61020d7f000000000000000000000000ae7ab96520de3a18e5e111b5eaab095312d7fe8481565b6101926103e881565b610192610fb5565b610192670e4b4b8af6a7000081565b610192600081565b6040805160808101825260006020808301829052828401829052606083018290528683528351634d62283160e01b81529351919384938493849391926001600160a01b037f000000000000000000000000591acb5ae192c147948c12651a0a5f24f0529be31692634d622831926004808401938290030181865afa15801561042c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610450919061135b565b604082810182905251626a1f6360e11b815260048101919091527f000000000000000000000000591acb5ae192c147948c12651a0a5f24f0529be36001600160a01b03169062d43ec690602401602060405180830381865afa1580156104ba573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104de9190611374565b6001600160a01b031660608201525b60608101516001600160a01b0316158015906105ab5750604080820151905163f869817f60e01b8152670f43fc2c04ee0000916001600160a01b037f000000000000000000000000c4cbae499bb4ca41e78f52f07f5d98c375711774169163f869817f91610568918c90600401918252602082015260400190565b602060405180830381865afa158015610585573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105a9919061135b565b105b156106e0576040818101519051630d0117ab60e31b815260048101919091527f000000000000000000000000591acb5ae192c147948c12651a0a5f24f0529be36001600160a01b031690636808bd5890602401602060405180830381865afa15801561061b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061063f919061135b565b604082810182905251626a1f6360e11b815260048101919091527f000000000000000000000000591acb5ae192c147948c12651a0a5f24f0529be36001600160a01b03169062d43ec690602401602060405180830381865afa1580156106a9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106cd9190611374565b6001600160a01b031660608201526104ed565b80604001519450856000036106f55760001995505b60608101516001600160a01b0316158015906107115750805115155b8015610721575060001986019515155b156109c85760408082015190516318cc429f60e11b81526000916001600160a01b037f000000000000000000000000c4cbae499bb4ca41e78f52f07f5d98c3757117741691633198853e9161077c9160040190815260200190565b602060405180830381865afa158015610799573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107bd919061135b565b82519091508111156108905781516107d683838b61103e565b604051630f451f7160e31b815260048101839052909750909450671bc16d674ec80000907f000000000000000000000000ae7ab96520de3a18e5e111b5eaab095312d7fe846001600160a01b031690637a28fb8890602401602060405180830381865afa15801561084b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061086f919061135b565b10156108845780835260009550859350610889565b600083525b50506109c8565b815181900382526040808301519051630d0117ab60e31b815260048101919091527f000000000000000000000000591acb5ae192c147948c12651a0a5f24f0529be36001600160a01b031690636808bd5890602401602060405180830381865afa158015610902573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610926919061135b565b604083810182905251626a1f6360e11b815260048101919091527f000000000000000000000000591acb5ae192c147948c12651a0a5f24f0529be36001600160a01b03169062d43ec690602401602060405180830381865afa158015610990573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109b49190611374565b6001600160a01b03166060830152506106f5565b80516109d490896113b3565b92505093509350935093565b60006109ed8484846111db565b90505b9392505050565b606060007f000000000000000000000000591acb5ae192c147948c12651a0a5f24f0529be36001600160a01b031663de8fa4316040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a59573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a7d919061135b565b90508067ffffffffffffffff811115610a9857610a986113c6565b604051908082528060200260200182016040528015610ac1578160200160208202803683370190505b50915080600003610ad0575090565b60007f000000000000000000000000591acb5ae192c147948c12651a0a5f24f0529be36001600160a01b0316631e2231436040518163ffffffff1660e01b8152600401602060405180830381865afa158015610b30573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b54919061135b565b905060005b82811015610c1a5781848281518110610b7457610b746113dc565b60209081029190910101526040516394dfe33f60e01b8152600481018390527f000000000000000000000000591acb5ae192c147948c12651a0a5f24f0529be36001600160a01b0316906394dfe33f90602401602060405180830381865afa158015610be4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c08919061135b565b9150610c13816113f2565b9050610b59565b50505090565b6000806000807f000000000000000000000000c4cbae499bb4ca41e78f52f07f5d98c3757117746001600160a01b0316630c5805bc6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610c84573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ca8919061135b565b905080600003610d43577f000000000000000000000000591acb5ae192c147948c12651a0a5f24f0529be36001600160a01b031663b0faee936040518163ffffffff1660e01b8152600401602060405180830381865afa158015610d10573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d34919061135b565b60008693509350935050610f97565b7f000000000000000000000000591acb5ae192c147948c12651a0a5f24f0529be36001600160a01b0316634d6228316040518163ffffffff1660e01b8152600401602060405180830381865afa158015610da1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610dc5919061135b565b9350610e5f877f000000000000000000000000c4cbae499bb4ca41e78f52f07f5d98c3757117746001600160a01b031663db4159ae876040518263ffffffff1660e01b8152600401610e1991815260200190565b602060405180830381865afa158015610e36573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e5a919061135b565b61120c565b925084915060016000610e706109f7565b90505b87821015610f935760408051602081018690520160408051601f19818403018152919052805160209091012093506000610ead8486611421565b90506000828281518110610ec357610ec36113dc565b6020026020010151905060007f000000000000000000000000c4cbae499bb4ca41e78f52f07f5d98c3757117746001600160a01b031663db4159ae836040518263ffffffff1660e01b8152600401610f1d91815260200190565b602060405180830381865afa158015610f3a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f5e919061135b565b90506000610f6c828e61120c565b905088811015610f7d578098508299505b85610f87816113f2565b96505050505050610e73565b5050505b93509350939050565b6000610fac838361122f565b90505b92915050565b60007f0000000000000000000000006dbdb6d420c110290431e863a1a978ae53f69ebc6001600160a01b031663e3f683886040518163ffffffff1660e01b8152600401602060405180830381865afa158015611015573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611039919061135b565b905090565b6000806000611051866000015186611265565b905060007f000000000000000000000000c4cbae499bb4ca41e78f52f07f5d98c3757117746001600160a01b0316636b4f105b88604001516040518263ffffffff1660e01b81526004016110a791815260200190565b602060405180830381865afa1580156110c4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110e8919061135b565b87519091506110f89083906113b3565b875260006001600160a01b037f000000000000000000000000ae7ab96520de3a18e5e111b5eaab095312d7fe841663192084518761113e670de0b6b3a764000087611435565b611148919061144c565b6040518263ffffffff1660e01b815260040161116691815260200190565b602060405180830381865afa158015611183573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111a7919061135b565b905060006111b582846113b3565b9050806111cb816111c6878c6113b3565b61122f565b9550955050505050935093915050565b60008215611203576000836111f08487611435565b6111fa919061144c565b91506109f09050565b506000196109f0565b6000818310156112255761122083836113b3565b610fac565b610fac82846113b3565b6000811561125c578161124b68056bc75e2d6310000085611435565b611255919061144c565b9050610faf565b50600019610faf565b60008183106112745781610fac565b5090919050565b60008060006060848603121561129057600080fd5b505081359360208301359350604090920135919050565b6020808252825182820181905260009190848201906040850190845b818110156112df578351835292840192918401916001016112c3565b50909695505050505050565b600060208083528351808285015260005b81811015611318578581018301518582016040015282016112fc565b506000604082860101526040601f19601f8301168501019250505092915050565b6000806040838503121561134c57600080fd5b50508035926020909101359150565b60006020828403121561136d57600080fd5b5051919050565b60006020828403121561138657600080fd5b81516001600160a01b03811681146109f057600080fd5b634e487b7160e01b600052601160045260246000fd5b81810381811115610faf57610faf61139d565b634e487b7160e01b600052604160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b6000600182016114045761140461139d565b5060010190565b634e487b7160e01b600052601260045260246000fd5b6000826114305761143061140b565b500690565b8082028115828204841417610faf57610faf61139d565b60008261145b5761145b61140b565b50049056fea26469706673582212206b53242751c1ad2817a5149991a5963aec44206a3ee9fba9e364c687c6d08c0764736f6c63430008110033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000591acb5ae192c147948c12651a0a5f24f0529be3000000000000000000000000c4cbae499bb4ca41e78f52f07f5d98c375711774000000000000000000000000ae7ab96520de3a18e5e111b5eaab095312d7fe840000000000000000000000006dbdb6d420c110290431e863a1a978ae53f69ebc000000000000000000000000a9a65b1b1dda8376527e89985b221b6bfca1dc9a
-----Decoded View---------------
Arg [0] : _sortedCdpsAddress (address): 0x591AcB5AE192c147948c12651a0a5f24f0529BE3
Arg [1] : _cdpManagerAddress (address): 0xc4cbaE499bb4Ca41E78f52F07f5d98c375711774
Arg [2] : _collateralAddress (address): 0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84
Arg [3] : _activePoolAddress (address): 0x6dBDB6D420c110290431E863A1A978AE53F69ebC
Arg [4] : _priceFeedAddress (address): 0xa9a65B1B1dDa8376527E89985b221B6bfCA1Dc9a
-----Encoded View---------------
5 Constructor Arguments found :
Arg [0] : 000000000000000000000000591acb5ae192c147948c12651a0a5f24f0529be3
Arg [1] : 000000000000000000000000c4cbae499bb4ca41e78f52f07f5d98c375711774
Arg [2] : 000000000000000000000000ae7ab96520de3a18e5e111b5eaab095312d7fe84
Arg [3] : 0000000000000000000000006dbdb6d420c110290431e863a1a978ae53f69ebc
Arg [4] : 000000000000000000000000a9a65b1b1dda8376527e89985b221b6bfca1dc9a
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 35 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.