Source Code
Overview
ETH Balance
0 ETH
ETH Value
$0.00| Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
Advanced mode: Intended for advanced users or developers and will display all Internal Transactions including zero value transfers.
Latest 4 internal transactions
Advanced mode:
Cross-Chain Transactions
Loading...
Loading
Contract Source Code Verified (Exact Match)
Contract Name:
PermissionedPositionManager
Compiler Version
v0.8.26+commit.8a97fa7a
Optimization Enabled:
Yes with 100 runs
Other Settings:
cancun EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT
pragma solidity 0.8.26;
import {PositionManager} from "../PositionManager.sol";
import {IDebtToken} from "../../interfaces/core/IDebtToken.sol";
import {IPriceFeed} from "../../interfaces/core/IPriceFeed.sol";
import {ISortedPositions} from "../../interfaces/core/ISortedPositions.sol";
/**
@title Permissioned Position Manager
@notice Limits only one arbitrary account to be opened, and redemptions can be toggled on and off
@notice Based on Liquity's `PositionManager`
https://github.com/liquity/dev/blob/main/packages/contracts/contracts/TroveManager.sol
Implementation is modified so that multiple `PositionManager` and `SortedPositions`
contracts are deployed in tandem, with each pair managing positions of a single collateral
type.
Functionality related to liquidations has been moved to `LiquidationManager`. This was
necessary to avoid the restriction on deployed bytecode size.
*/
contract PermissionedPositionManager is PositionManager {
address public permissionedPosition;
address public protocolPosition;
function _isPermissionedCheck(address _borrower) internal view override {
require(_borrower == permissionedPosition || _borrower == protocolPosition, "PermissionedPositionManager: Only the Permissioned/ProtocolPosition can open a position");
}
constructor(
address _core,
address _gasPoolAddress,
address _debtTokenAddress,
address _borrowerOperations,
address _liquidationManager,
uint256 _gasCompensation
) PositionManager(
_core,
_gasPoolAddress,
_debtTokenAddress,
_borrowerOperations,
_liquidationManager,
_gasCompensation
) {}
/// @dev Initialization function
function setPermissionedParameters(address _permissionedPosition, address _protocolPosition) external onlyOwner {
_setPermissionedPosition(_permissionedPosition);
_setProtocolPosition(_protocolPosition);
}
/**
* @dev Has to be set just after PermissionedPositionManager is deployed via the Factory
* @param _permissionedPosition Address of the permissioned position, probably PSM
*/
function setPermissionedPosition(address _permissionedPosition) external onlyOwner {
_setPermissionedPosition(_permissionedPosition);
}
/**
* @notice To enable liquidations on permissioned position (BoycoVault), since a minimum of 2 positions are required
* @dev Has a higher CR than the permissioned position
* @param _protocolPosition Address of the protocol position, apart from BoycoVault
*/
function setProtocolPosition(address _protocolPosition) external onlyOwner {
_setProtocolPosition(_protocolPosition);
}
function _setPermissionedPosition(address _permissionedPosition) private {
permissionedPosition = _permissionedPosition;
}
function _setProtocolPosition(address _protocolPosition) private {
protocolPosition = _protocolPosition;
}
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.26;
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/utils/math/Math.sol";
import { IERC3156FlashBorrower } from "@openzeppelin/contracts/interfaces/IERC3156FlashBorrower.sol";
import "../interfaces/core/IBorrowerOperations.sol";
import "../interfaces/core/IDebtToken.sol";
import "../interfaces/core/ISortedPositions.sol";
import "../interfaces/core/IPriceFeed.sol";
import "../interfaces/core/IFactory.sol";
import "../interfaces/core/ILiquidationManager.sol";
import "../dependencies/SystemStart.sol";
import "../dependencies/PropBase.sol";
import "../dependencies/PropMath.sol";
import "../dependencies/PropOwnable.sol";
/**
@title Position Manager
@notice Based on Liquity's `TroveManager`
https://github.com/liquity/dev/blob/main/packages/contracts/contracts/TroveManager.sol
Implementation is modified so that multiple `PositionManager` and `SortedPositions`
contracts are deployed in tandem, with each pair managing positions of a single collateral
type.
Functionality related to liquidations has been moved to `LiquidationManager`. This was
necessary to avoid the restriction on deployed bytecode size.
*/
contract PositionManager is PropBase, PropOwnable, SystemStart {
using SafeERC20 for IERC20;
address public immutable borrowerOperations;
address public immutable liquidationManager;
address immutable gasPoolAddress;
IDebtToken public immutable debtToken;
address public collVaultRouter;
IPriceFeed public priceFeed;
IERC20 public collateralToken;
// A doubly linked list of Positions, sorted by their collateral ratios
ISortedPositions public sortedPositions;
// Minimum collateral ratio for individual positions
uint256 public MCR;
uint256 constant SECONDS_IN_ONE_MINUTE = 60;
uint256 constant INTEREST_PRECISION = 1e27;
uint256 constant SECONDS_IN_YEAR = 365 days;
uint256 public constant SUNSETTING_INTEREST_RATE = (INTEREST_PRECISION * 5000) / (BP * SECONDS_IN_YEAR); // 50%
uint256 constant _100pct = 1000000000000000000; // 1e18 == 100%, below this CR it's considered undercollateralized
/*
* BETA: 18 digit decimal. Parameter by which to divide the redeemed fraction, in order to calc the new base rate from a redemption.
* Corresponds to (1 / ALPHA) in the white paper.
*/
uint256 constant BETA = 2;
uint16 constant BP = 1e4;
// --- ERC 3156 Data ---
bytes32 private constant _RETURN_VALUE = keccak256("ERC3156FlashBorrower.onFlashLoan");
// commented values are Liquity's fixed settings for each parameter
uint256 public minuteDecayFactor; // 999037758833783000 (half-life of 12 hours)
/// @dev Redemption fee floor should be higher than deviation threshold of oracle supporting this collateral
uint256 public redemptionFeeFloor; // DECIMAL_PRECISION / 1000 * 5 (0.5%)
uint256 public maxRedemptionFee; // DECIMAL_PRECISION (100%)
uint256 public borrowingFeeFloor; // DECIMAL_PRECISION / 1000 * 5 (0.5%)
uint256 public maxBorrowingFee; // DECIMAL_PRECISION / 100 * 5 (5%)
uint256 public maxSystemDebt;
uint256 public interestRate;
uint256 public activeInterestIndex;
uint256 public lastActiveIndexUpdate;
uint256 public systemDeploymentTime;
bool public sunsetting;
bool public paused;
uint256 public baseRate;
// The timestamp of the latest fee operation (redemption or new debt issuance)
uint256 public lastFeeOperationTime;
uint256 public totalStakes;
// Snapshot of the value of totalStakes, taken immediately after the latest liquidation
uint256 public totalStakesSnapshot;
// Snapshot of the total collateral taken immediately after the latest liquidation.
uint256 public totalCollateralSnapshot;
/*
* L_collateral and L_debt track the sums of accumulated liquidation rewards per unit staked. During its lifetime, each stake earns:
*
* An collateral gain of ( stake * [L_collateral - L_collateral(0)] )
* A debt increase of ( stake * [L_debt - L_debt(0)] )
*
* Where L_collateral(0) and L_debt(0) are snapshots of L_collateral and L_debt for the active Position taken at the instant the stake was made
*/
uint256 public L_collateral;
uint256 public L_debt;
// Error trackers for the position redistribution calculation
uint256 public lastCollateralError_Redistribution;
uint256 public lastDebtError_Redistribution;
uint256 internal totalActiveCollateral;
uint256 internal totalActiveDebt;
uint256 public interestPayable;
address public interestReceiver;
uint256 public defaultedCollateral;
uint256 public defaultedDebt;
mapping(address => Position) public Positions;
mapping(address => uint256) public surplusBalances;
// Map addresses with active positions to their RewardSnapshot
mapping(address => RewardSnapshot) public rewardSnapshots;
// Array of all active position addresses - used to to compute an approximate hint off-chain, for the sorted list insertion
address[] PositionOwners;
// Store the necessary data for a position
struct Position {
uint256 debt;
uint256 coll;
uint256 stake;
Status status;
uint128 arrayIndex;
uint256 activeInterestIndex;
}
struct RedemptionTotals {
uint256 remainingDebt;
uint256 totalDebtToRedeem;
uint256 totalCollateralDrawn;
uint256 collateralFee;
uint256 collateralToSendToRedeemer;
uint256 decayedBaseRate;
uint256 price;
uint256 totalDebtSupplyAtStart;
}
struct SingleRedemptionValues {
uint256 debtLot;
uint256 collateralLot;
bool cancelledPartial;
}
// Object containing the collateral and debt snapshots for a given active position
struct RewardSnapshot {
uint256 collateral;
uint256 debt;
}
enum PositionManagerOperation {
applyPendingRewards,
liquidateInNormalMode,
liquidateInRecoveryMode,
redeemCollateral
}
enum Status {
nonExistent,
active,
closedByOwner,
closedByLiquidation,
closedByRedemption
}
event NewParameters(IFactory.DeploymentParams params);
event PriceFeedUpdated(address _priceFeed);
event PositionUpdated(
address indexed _borrower,
uint256 _debt,
uint256 _coll,
uint256 _stake,
PositionManagerOperation _operation
);
event Redemption(
address indexed _redeemer,
uint256 _attemptedDebtAmount,
uint256 _actualDebtAmount,
uint256 _collateralSent,
uint256 _collateralFee
);
event BaseRateUpdated(uint256 _baseRate);
event LastFeeOpTimeUpdated(uint256 _lastFeeOpTime);
event TotalStakesUpdated(uint256 _newTotalStakes);
event SystemSnapshotsUpdated(uint256 _totalStakesSnapshot, uint256 _totalCollateralSnapshot);
event LTermsUpdated(uint256 _L_collateral, uint256 _L_debt);
event PositionSnapshotsUpdated(uint256 _L_collateral, uint256 _L_debt);
event PositionIndexUpdated(address _borrower, uint256 _newIndex);
event CollateralSent(address _to, uint256 _amount);
event InterestReceiverSet(address indexed _interestReceiver);
modifier whenNotPaused() {
require(!paused, "Collateral Paused");
_;
}
/// @dev Overrided by PermissionedPositionManager to enforce only one position
function _isPermissionedCheck(address _borrower) internal virtual {}
constructor(
address _core,
address _gasPoolAddress,
address _debtTokenAddress,
address _borrowerOperations,
address _liquidationManager,
uint256 _gasCompensation
) PropOwnable(_core) PropBase(_gasCompensation) SystemStart(_core) {
if (_core == address(0) || _gasPoolAddress == address(0) || _debtTokenAddress == address(0) || _borrowerOperations == address(0) || _liquidationManager == address(0)) {
revert("PositionManager: 0 address");
}
gasPoolAddress = _gasPoolAddress;
debtToken = IDebtToken(_debtTokenAddress);
borrowerOperations = _borrowerOperations;
liquidationManager = _liquidationManager;
}
function setAddresses(address _priceFeedAddress, address _sortedPositionsAddress, address _collateralToken) external {
require(address(sortedPositions) == address(0));
priceFeed = IPriceFeed(_priceFeedAddress);
sortedPositions = ISortedPositions(_sortedPositionsAddress);
collateralToken = IERC20(_collateralToken);
systemDeploymentTime = block.timestamp;
sunsetting = false;
activeInterestIndex = INTEREST_PRECISION;
lastActiveIndexUpdate = block.timestamp;
}
/**
* @notice Sets the pause state for this position manager
* Pausing is used to mitigate risks in exceptional circumstances
* Functionalities affected by pausing are:
* - New borrowing is not possible
* - New collateral deposits are not possible
* @param _paused If true the protocol is paused
*/
function setPaused(bool _paused) external {
require((_paused && msg.sender == guardian()) || msg.sender == owner(), "Unauthorized");
paused = _paused;
}
/**
* @notice Sets a custom price feed for this position manager
* @param _priceFeedAddress Price feed address
*/
function setPriceFeed(address _priceFeedAddress) external onlyOwner {
priceFeed = IPriceFeed(_priceFeedAddress);
emit PriceFeedUpdated(_priceFeedAddress);
}
function setCollVaultRouter(address _collVaultRouter) external onlyOwner {
collVaultRouter = _collVaultRouter;
}
function setInterestReceiver(address _interestReceiver) external onlyOwner {
interestReceiver = _interestReceiver;
emit InterestReceiverSet(_interestReceiver);
}
/**
* @notice Starts sunsetting a collateral
* During sunsetting only the following are possible:
1) Disable collateral handoff to SP
2) Greatly Increase interest rate to incentivize redemptions
3) Remove redemptions fees
4) Disable new loans
@dev IMPORTANT: When sunsetting a collateral altogether this function should be called on
all PM linked to that collateral as well as `StabilityPool.startCollateralSunset`
@dev IMPORTANT: A peripheral system will ensure users aren't MEVed due to redemptions fees being removed
*/
function startSunset() external onlyOwner {
sunsetting = true;
_accrueActiveInterests();
interestRate = SUNSETTING_INTEREST_RATE;
// accrual function doesn't update timestamp if interest was 0
lastActiveIndexUpdate = block.timestamp;
redemptionFeeFloor = 0;
maxSystemDebt = 0;
baseRate = 0;
maxRedemptionFee = 0;
}
/*
_minuteDecayFactor is calculated as
10**18 * (1/2)**(1/n)
where n = the half-life in minutes
*/
function setParameters(IFactory.DeploymentParams calldata params) public {
require(!sunsetting, "Cannot change after sunset");
require(params.MCR >= 1e18, "MCR cannot < 100%");
if (minuteDecayFactor != 0) {
require(msg.sender == owner(), "Only owner");
}
require(
params.minuteDecayFactor >= 977159968434245900 && // half-life of 30 minutes
params.minuteDecayFactor <= 999931237762985000 // half-life of 1 week
);
require(params.redemptionFeeFloor <= params.maxRedemptionFee && params.maxRedemptionFee <= DECIMAL_PRECISION);
require(params.borrowingFeeFloor <= params.maxBorrowingFee && params.maxBorrowingFee <= DECIMAL_PRECISION);
_decayBaseRate();
minuteDecayFactor = params.minuteDecayFactor;
redemptionFeeFloor = params.redemptionFeeFloor;
maxRedemptionFee = params.maxRedemptionFee;
borrowingFeeFloor = params.borrowingFeeFloor;
maxBorrowingFee = params.maxBorrowingFee;
maxSystemDebt = params.maxDebt;
collVaultRouter = params.collVaultRouter;
uint256 newInterestRate = (INTEREST_PRECISION * params.interestRateInBps) / (BP * SECONDS_IN_YEAR);
if (newInterestRate != interestRate) {
_accrueActiveInterests();
// accrual function doesn't update timestamp if interest was 0
lastActiveIndexUpdate = block.timestamp;
interestRate = newInterestRate;
}
MCR = params.MCR;
emit NewParameters(params);
}
function collectInterests() external {
_accrueActiveInterests();
uint256 interestPayableCached = interestPayable;
require(interestPayableCached > 0, "Nothing to collect");
uint256 interestPayableToTreasury = Math.mulDiv(interestPayableCached, CORE.interestProtocolShare(), BP);
uint256 interestPayableToProtocol = interestPayableCached - interestPayableToTreasury;
address protocolReceiver = interestReceiver != address(0) ? interestReceiver : CORE.defaultInterestReceiver();
if (interestPayableToTreasury != 0) debtToken.mint(CORE.feeReceiver(), interestPayableToTreasury);
if (interestPayableToProtocol != 0) debtToken.mint(protocolReceiver, interestPayableToProtocol);
interestPayable = 0;
}
// --- Getters ---
function fetchPrice() public view returns (uint256) {
IPriceFeed _priceFeed = priceFeed;
if (address(_priceFeed) == address(0)) {
_priceFeed = IPriceFeed(CORE.priceFeed());
}
return _priceFeed.fetchPrice(address(collateralToken));
}
function getPositionOwnersCount() external view returns (uint256) {
return PositionOwners.length;
}
function getPositionFromPositionOwnersArray(uint256 _index) external view returns (address) {
return PositionOwners[_index];
}
function getPositionStatus(address _borrower) external view returns (uint256) {
return uint256(Positions[_borrower].status);
}
function getPositionStake(address _borrower) external view returns (uint256) {
return Positions[_borrower].stake;
}
/**
@notice Get the current total collateral and debt amounts for a position
@dev Also includes pending rewards from redistribution
*/
function getPositionCollAndDebt(address _borrower) public view returns (uint256 coll, uint256 debt) {
(debt, coll, , ) = getEntireDebtAndColl(_borrower);
return (coll, debt);
}
/**
@notice Get the total and pending collateral and debt amounts for a position
@dev Used by the liquidation manager
*/
function getEntireDebtAndColl(
address _borrower
) public view returns (uint256 debt, uint256 coll, uint256 pendingDebtReward, uint256 pendingCollateralReward) {
Position storage t = Positions[_borrower];
debt = t.debt;
coll = t.coll;
(pendingCollateralReward, pendingDebtReward) = getPendingCollAndDebtRewards(_borrower);
// Accrued position interest for correct liquidation values. This assumes the index to be updated.
uint256 positionInterestIndex = t.activeInterestIndex;
if (positionInterestIndex > 0) {
(uint256 currentIndex, ) = _calculateInterestIndex();
debt = (debt * currentIndex) / positionInterestIndex;
}
debt = debt + pendingDebtReward;
coll = coll + pendingCollateralReward;
}
function getEntireSystemColl() public view returns (uint256) {
return totalActiveCollateral + defaultedCollateral;
}
function getEntireSystemDebt() public view returns (uint256) {
uint256 currentActiveDebt = totalActiveDebt;
(, uint256 interestFactor) = _calculateInterestIndex();
if (interestFactor > 0) {
uint256 activeInterests = Math.mulDiv(currentActiveDebt, interestFactor, INTEREST_PRECISION);
currentActiveDebt = currentActiveDebt + activeInterests;
}
return currentActiveDebt + defaultedDebt;
}
function getEntireSystemBalances() external view returns (uint256, uint256, uint256) {
return (getEntireSystemColl(), getEntireSystemDebt(), fetchPrice());
}
// --- Helper functions ---
// Return the nominal collateral ratio (ICR) of a given Position, without the price. Takes a positions pending coll and debt rewards from redistributions into account.
function getNominalICR(address _borrower) public view returns (uint256) {
(uint256 currentCollateral, uint256 currentDebt) = getPositionCollAndDebt(_borrower);
uint256 NICR = PropMath._computeNominalCR(currentCollateral, currentDebt);
return NICR;
}
// Return the current collateral ratio (ICR) of a given Position. Takes a positions pending coll and debt rewards from redistributions into account.
function getCurrentICR(address _borrower, uint256 _price) public view returns (uint256) {
(uint256 currentCollateral, uint256 currentDebt) = getPositionCollAndDebt(_borrower);
uint256 ICR = PropMath._computeCR(currentCollateral, currentDebt, _price);
return ICR;
}
function getTotalActiveCollateral() public view returns (uint256) {
return totalActiveCollateral;
}
function getTotalActiveDebt() public view returns (uint256) {
uint256 currentActiveDebt = totalActiveDebt;
(, uint256 interestFactor) = _calculateInterestIndex();
if (interestFactor > 0) {
uint256 activeInterests = Math.mulDiv(currentActiveDebt, interestFactor, INTEREST_PRECISION);
currentActiveDebt = currentActiveDebt + activeInterests;
}
return currentActiveDebt;
}
// Get the borrower's pending accumulated collateral and debt rewards, earned by their stake
function getPendingCollAndDebtRewards(address _borrower) public view returns (uint256, uint256) {
RewardSnapshot memory snapshot = rewardSnapshots[_borrower];
uint256 coll = L_collateral - snapshot.collateral;
uint256 debt = L_debt - snapshot.debt;
if (coll + debt == 0 || Positions[_borrower].status != Status.active) return (0, 0);
uint256 stake = Positions[_borrower].stake;
return ((stake * coll) / DECIMAL_PRECISION, (stake * debt) / DECIMAL_PRECISION);
}
function hasPendingRewards(address _borrower) public view returns (bool) {
/*
* A Position has pending rewards if its snapshot is less than the current rewards per-unit-staked sum:
* this indicates that rewards have occured since the snapshot was made, and the user therefore has
* pending rewards
*/
if (Positions[_borrower].status != Status.active) {
return false;
}
return (rewardSnapshots[_borrower].collateral < L_collateral);
}
// --- Redemption fee functions ---
/*
* This function has two impacts on the baseRate state variable:
* 1) decays the baseRate based on time passed since last redemption or debt borrowing operation.
* then,
* 2) increases the baseRate based on the amount redeemed, as a proportion of total supply
*/
function _updateBaseRateFromRedemption(
uint256 _collateralDrawn,
uint256 _price,
uint256 _totalDebtSupply
) internal returns (uint256) {
uint256 decayedBaseRate = _calcDecayedBaseRate();
/* Convert the drawn collateral back to debt at face value rate (1 debt:1 USD), in order to get
* the fraction of total supply that was redeemed at face value. */
uint256 redeemedDebtFraction = (_collateralDrawn * _price) / _totalDebtSupply;
uint256 newBaseRate = decayedBaseRate + (redeemedDebtFraction / BETA);
newBaseRate = PropMath._min(newBaseRate, DECIMAL_PRECISION); // cap baseRate at a maximum of 100%
// Update the baseRate state variable
baseRate = newBaseRate;
emit BaseRateUpdated(newBaseRate);
_updateLastFeeOpTime();
return newBaseRate;
}
function getRedemptionRate() public view returns (uint256) {
return _calcRedemptionRate(baseRate);
}
function getRedemptionRateWithDecay() public view returns (uint256) {
return _calcRedemptionRate(_calcDecayedBaseRate());
}
function _calcRedemptionRate(uint256 _baseRate) internal view returns (uint256) {
return
PropMath._min(
redemptionFeeFloor + _baseRate,
maxRedemptionFee
);
}
function getRedemptionFeeWithDecay(uint256 _collateralDrawn) external view returns (uint256) {
return _calcRedemptionFee(getRedemptionRateWithDecay(), _collateralDrawn);
}
function _calcRedemptionFee(uint256 _redemptionRate, uint256 _collateralDrawn) internal pure returns (uint256) {
uint256 redemptionFee = (_redemptionRate * _collateralDrawn) / DECIMAL_PRECISION;
require(redemptionFee < _collateralDrawn, "Fee exceeds returned collateral");
return redemptionFee;
}
// --- Borrowing fee functions ---
function getBorrowingRate() public view returns (uint256) {
return _calcBorrowingRate(baseRate);
}
function getBorrowingRateWithDecay() public view returns (uint256) {
return _calcBorrowingRate(_calcDecayedBaseRate());
}
function _calcBorrowingRate(uint256 _baseRate) internal view returns (uint256) {
return PropMath._min(borrowingFeeFloor + _baseRate, maxBorrowingFee);
}
function getBorrowingFee(uint256 _debt) external view returns (uint256) {
return _calcBorrowingFee(getBorrowingRate(), _debt);
}
function getBorrowingFeeWithDecay(uint256 _debt) external view returns (uint256) {
return _calcBorrowingFee(getBorrowingRateWithDecay(), _debt);
}
function _calcBorrowingFee(uint256 _borrowingRate, uint256 _debt) internal pure returns (uint256) {
return (_borrowingRate * _debt) / DECIMAL_PRECISION;
}
// --- Internal fee functions ---
// Update the last fee operation time only if time passed >= decay interval. This prevents base rate griefing.
function _updateLastFeeOpTime() internal {
uint256 timePassed = block.timestamp - lastFeeOperationTime;
if (timePassed >= SECONDS_IN_ONE_MINUTE) {
lastFeeOperationTime += _minutesPassedSinceLastFeeOp() * SECONDS_IN_ONE_MINUTE;
emit LastFeeOpTimeUpdated(block.timestamp);
}
}
function _calcDecayedBaseRate() internal view returns (uint256) {
uint256 minutesPassed = _minutesPassedSinceLastFeeOp();
uint256 decayFactor = PropMath._decPow(minuteDecayFactor, minutesPassed);
return (baseRate * decayFactor) / DECIMAL_PRECISION;
}
function _minutesPassedSinceLastFeeOp() internal view returns (uint256) {
return (block.timestamp - lastFeeOperationTime) / SECONDS_IN_ONE_MINUTE;
}
// --- Redemption functions ---
/* Send _debtAmount debt to the system and redeem the corresponding amount of collateral from as many Positions as are needed to fill the redemption
* request. Applies pending rewards to a Position before reducing its debt and coll.
*
* Note that if _amount is very large, this function can run out of gas, specially if traversed positions are small. This can be easily avoided by
* splitting the total _amount in appropriate chunks and calling the function multiple times.
*
* Param `_maxIterations` can also be provided, so the loop through Positions is capped (if it’s zero, it will be ignored).This makes it easier to
* avoid OOG for the frontend, as only knowing approximately the average cost of an iteration is enough, without needing to know the “topology”
* of the position list. It also avoids the need to set the cap in stone in the contract, nor doing gas calculations, as both gas price and opcode
* costs can vary.
*
* All Positions that are redeemed from -- with the likely exception of the last one -- will end up with no debt left, therefore they will be closed.
* If the last Position does have some remaining debt, it has a finite ICR, and the reinsertion could be anywhere in the list, therefore it requires a hint.
* A frontend should use getRedemptionHints() to calculate what the ICR of this Position will be after redemption, and pass a hint for its position
* in the sortedPositions list along with the ICR value that the hint was found for.
*
* If another transaction modifies the list between calling getRedemptionHints() and passing the hints to redeemCollateral(), it
* is very likely that the last (partially) redeemed Position would end up with a different ICR than what the hint is for. In this case the
* redemption will stop after the last completely redeemed Position and the sender will keep the remaining debt amount, which they can attempt
* to redeem later.
*/
function redeemCollateral(
uint256 _debtAmount,
address _firstRedemptionHint,
address _upperPartialRedemptionHint,
address _lowerPartialRedemptionHint,
uint256 _partialRedemptionHintNICR,
uint256 _maxIterations,
uint256 _maxFeePercentage
) external {
ISortedPositions _sortedPositionsCached = sortedPositions;
RedemptionTotals memory totals;
require(
_maxFeePercentage >= redemptionFeeFloor && _maxFeePercentage <= maxRedemptionFee,
"Max fee not in bounds"
);
require(block.timestamp >= systemDeploymentTime + CORE.dmBootstrapPeriod(), "BOOTSTRAP_PERIOD");
totals.price = fetchPrice();
require(IBorrowerOperations(borrowerOperations).getTCR() >= MCR, "Cannot redeem when TCR < MCR");
require(_debtAmount > 0, "Amount must be greater than zero");
require(debtToken.balanceOf(msg.sender) >= _debtAmount, "Insufficient balance");
_updateBalances();
totals.totalDebtSupplyAtStart = getEntireSystemDebt();
totals.remainingDebt = _debtAmount;
address currentBorrower;
if (_isValidFirstRedemptionHint(_sortedPositionsCached, _firstRedemptionHint, totals.price)) {
currentBorrower = _firstRedemptionHint;
} else {
currentBorrower = _sortedPositionsCached.getLast();
// Find the first position with ICR >= MCR
while (currentBorrower != address(0) && getCurrentICR(currentBorrower, totals.price) < _100pct) {
currentBorrower = _sortedPositionsCached.getPrev(currentBorrower);
}
}
// Loop through the Positions starting from the one with lowest collateral ratio until _amount of debt is exchanged for collateral
if (_maxIterations == 0) {
_maxIterations = 100;
}
while (currentBorrower != address(0) && totals.remainingDebt > 0 && _maxIterations > 0) {
_maxIterations--;
// Save the address of the Position preceding the current one, before potentially modifying the list
address nextUserToCheck = _sortedPositionsCached.getPrev(currentBorrower);
_applyPendingRewards(currentBorrower);
SingleRedemptionValues memory singleRedemption = _redeemCollateralFromPosition(
_sortedPositionsCached,
currentBorrower,
totals.remainingDebt,
totals.price,
_upperPartialRedemptionHint,
_lowerPartialRedemptionHint,
_partialRedemptionHintNICR
);
if (singleRedemption.cancelledPartial) break; // Partial redemption was cancelled (out-of-date hint, or new net debt < minimum), therefore we could not redeem from the last Position
totals.totalDebtToRedeem = totals.totalDebtToRedeem + singleRedemption.debtLot;
totals.totalCollateralDrawn = totals.totalCollateralDrawn + singleRedemption.collateralLot;
totals.remainingDebt = totals.remainingDebt - singleRedemption.debtLot;
currentBorrower = nextUserToCheck;
}
require(totals.totalCollateralDrawn > 0, "Unable to redeem any amount");
// Decay the baseRate due to time passed, and then increase it according to the size of this redemption.
// Use the saved total debt supply value, from before it was reduced by the redemption.
// only callabe when not sunsetting
if (!sunsetting) {
_updateBaseRateFromRedemption(totals.totalCollateralDrawn, totals.price, totals.totalDebtSupplyAtStart);
}
// Calculate the collateral fee
totals.collateralFee = sunsetting ? 0 : _calcRedemptionFee(getRedemptionRate(), totals.totalCollateralDrawn);
_requireUserAcceptsFee(totals.collateralFee, totals.totalCollateralDrawn, _maxFeePercentage);
_sendCollateral(CORE.feeReceiver(), totals.collateralFee);
totals.collateralToSendToRedeemer = totals.totalCollateralDrawn - totals.collateralFee;
emit Redemption(msg.sender, _debtAmount, totals.totalDebtToRedeem, totals.totalCollateralDrawn, totals.collateralFee);
// Burn the total debt that is cancelled with debt, and send the redeemed collateral to msg.sender
debtToken.burn(msg.sender, totals.totalDebtToRedeem);
// Update Position Manager debt, and send collateral to account
totalActiveDebt = totalActiveDebt - totals.totalDebtToRedeem;
_sendCollateral(msg.sender, totals.collateralToSendToRedeemer);
_resetState();
}
// Redeem as much collateral as possible from _borrower's Position in exchange for debt up to _maxDebtAmount
function _redeemCollateralFromPosition(
ISortedPositions _sortedPositionsCached,
address _borrower,
uint256 _maxDebtAmount,
uint256 _price,
address _upperPartialRedemptionHint,
address _lowerPartialRedemptionHint,
uint256 _partialRedemptionHintNICR
) internal returns (SingleRedemptionValues memory singleRedemption) {
Position storage t = Positions[_borrower];
// Determine the remaining amount (lot) to be redeemed, capped by the entire debt of the Position minus the liquidation reserve
singleRedemption.debtLot = PropMath._min(_maxDebtAmount, t.debt - DEBT_GAS_COMPENSATION);
// Get the CollateralLot of equivalent value in USD
singleRedemption.collateralLot = (singleRedemption.debtLot * DECIMAL_PRECISION) / _price;
// Decrease the debt and collateral of the current Position according to the debt lot and corresponding collateral to send
uint256 newDebt = (t.debt) - singleRedemption.debtLot;
uint256 newColl = (t.coll) - singleRedemption.collateralLot;
if (newDebt == DEBT_GAS_COMPENSATION) {
// No debt left in the Position (except for the liquidation reserve), therefore the position gets closed
_removeStake(_borrower);
_closePosition(_borrower, Status.closedByRedemption);
_redeemClosePosition(_borrower, DEBT_GAS_COMPENSATION, newColl);
emit PositionUpdated(_borrower, 0, 0, 0, PositionManagerOperation.redeemCollateral);
} else {
uint256 newNICR = PropMath._computeNominalCR(newColl, newDebt);
/*
* If the provided hint is out of date, we bail since trying to reinsert without a good hint will almost
* certainly result in running out of gas.
*
* If the resultant net debt of the partial is less than the minimum, net debt we bail.
*/
{
// We check if the ICR hint is reasonable up to date, with continuous interest there might be slight differences (<1bps)
uint256 icrError = _partialRedemptionHintNICR > newNICR
? _partialRedemptionHintNICR - newNICR
: newNICR - _partialRedemptionHintNICR;
if (
icrError > 5e14 ||
_getNetDebt(newDebt) < IBorrowerOperations(borrowerOperations).minNetDebt()
) {
singleRedemption.cancelledPartial = true;
return singleRedemption;
}
}
_sortedPositionsCached.reInsert(_borrower, newNICR, _upperPartialRedemptionHint, _lowerPartialRedemptionHint);
t.debt = newDebt;
t.coll = newColl;
_updateStakeAndTotalStakes(t);
emit PositionUpdated(_borrower, newDebt, newColl, t.stake, PositionManagerOperation.redeemCollateral);
}
return singleRedemption;
}
/*
* Called when a full redemption occurs, and closes the position.
* The redeemer swaps (debt - liquidation reserve) debt for (debt - liquidation reserve) worth of collateral, so the debt liquidation reserve left corresponds to the remaining debt.
* In order to close the position, the debt liquidation reserve is burned, and the corresponding debt is removed.
* The debt recorded on the positions struct is zero'd elswhere, in _closePosition.
* Any surplus collateral left in the position can be later claimed by the borrower.
*/
function _redeemClosePosition(address _borrower, uint256 _debt, uint256 _collateral) internal {
debtToken.burn(gasPoolAddress, _debt);
totalActiveDebt = totalActiveDebt - _debt;
surplusBalances[_borrower] += _collateral;
totalActiveCollateral -= _collateral;
}
function _isValidFirstRedemptionHint(
ISortedPositions _sortedPositions,
address _firstRedemptionHint,
uint256 _price
) internal view returns (bool) {
if (
_firstRedemptionHint == address(0) ||
!_sortedPositions.contains(_firstRedemptionHint) ||
getCurrentICR(_firstRedemptionHint, _price) < _100pct
) {
return false;
}
address nextPosition = _sortedPositions.getNext(_firstRedemptionHint);
return nextPosition == address(0) || getCurrentICR(nextPosition, _price) < _100pct;
}
/**
* Claim remaining collateral from a redemption or from a liquidation with ICR > MCR in Recovery Mode
*/
function claimCollateral(address borrower, address _receiver) external {
if (msg.sender != collVaultRouter) {
borrower = msg.sender;
}
uint256 claimableColl = surplusBalances[borrower];
require(claimableColl > 0, "No collateral available to claim");
surplusBalances[borrower] = 0;
collateralToken.safeTransfer(_receiver, claimableColl);
}
// --- Position Adjustment functions ---
function openPosition(
address _borrower,
uint256 _collateralAmount,
uint256 _compositeDebt,
uint256 NICR,
address _upperHint,
address _lowerHint
) external whenNotPaused returns (uint256 stake, uint256 arrayIndex) {
_requireCallerIsBO();
require(!sunsetting, "Cannot open while sunsetting");
_isPermissionedCheck(_borrower);
Position storage t = Positions[_borrower];
require(t.status != Status.active, "BorrowerOps: Position is active");
t.status = Status.active;
t.coll = _collateralAmount;
t.debt = _compositeDebt;
uint256 currentInterestIndex = _accrueActiveInterests();
t.activeInterestIndex = currentInterestIndex;
_updatePositionRewardSnapshots(_borrower);
stake = _updateStakeAndTotalStakes(t);
sortedPositions.insert(_borrower, NICR, _upperHint, _lowerHint);
PositionOwners.push(_borrower);
arrayIndex = PositionOwners.length - 1;
t.arrayIndex = uint128(arrayIndex);
totalActiveCollateral = totalActiveCollateral + _collateralAmount;
uint256 _newTotalDebt = totalActiveDebt + _compositeDebt;
require(_newTotalDebt + defaultedDebt <= maxSystemDebt, "Collateral debt limit reached");
totalActiveDebt = _newTotalDebt;
}
function updatePositionFromAdjustment(
bool _isDebtIncrease,
uint256 _debtChange,
uint256 _netDebtChange,
bool _isCollIncrease,
uint256 _collChange,
address _upperHint,
address _lowerHint,
address _borrower,
address _receiver
) external returns (uint256, uint256, uint256) {
_requireCallerIsBO();
if (_isCollIncrease || _isDebtIncrease) {
require(!paused, "Collateral Paused");
require(!sunsetting, "Cannot increase while sunsetting");
}
Position storage t = Positions[_borrower];
require(t.status == Status.active, "Position closed or does not exist");
uint256 newDebt = t.debt;
if (_debtChange > 0) {
if (_isDebtIncrease) {
newDebt = newDebt + _netDebtChange;
_increaseDebt(_receiver, _netDebtChange, _debtChange);
} else {
newDebt = newDebt - _netDebtChange;
_decreaseDebt(_receiver, _debtChange);
}
t.debt = newDebt;
}
uint256 newColl = t.coll;
if (_collChange > 0) {
if (_isCollIncrease) {
newColl = newColl + _collChange;
totalActiveCollateral = totalActiveCollateral + _collChange;
// trust that BorrowerOperations sent the collateral
} else {
newColl = newColl - _collChange;
_sendCollateral(_receiver, _collChange);
}
t.coll = newColl;
}
uint256 newNICR = PropMath._computeNominalCR(newColl, newDebt);
sortedPositions.reInsert(_borrower, newNICR, _upperHint, _lowerHint);
return (newColl, newDebt, _updateStakeAndTotalStakes(t));
}
function closePosition(address _borrower, address _receiver, uint256 collAmount, uint256 debtAmount) external {
_requireCallerIsBO();
require(Positions[_borrower].status == Status.active, "Position closed or does not exist");
_removeStake(_borrower);
_closePosition(_borrower, Status.closedByOwner);
totalActiveDebt = totalActiveDebt - debtAmount;
_sendCollateral(_receiver, collAmount);
_resetState();
}
/**
@dev Only called from `closePosition` because liquidating the final position is blocked in
`LiquidationManager`. Many liquidation paths involve redistributing debt and
collateral to existing positions. If the collateral is being sunset, the final position
must be closed by repaying the debt or via a redemption.
*/
function _resetState() private {
if (PositionOwners.length == 0) {
activeInterestIndex = INTEREST_PRECISION;
lastActiveIndexUpdate = block.timestamp;
totalStakes = 0;
totalStakesSnapshot = 0;
totalCollateralSnapshot = 0;
L_collateral = 0;
L_debt = 0;
lastCollateralError_Redistribution = 0;
lastDebtError_Redistribution = 0;
totalActiveCollateral = 0;
totalActiveDebt = 0;
defaultedCollateral = 0;
defaultedDebt = 0;
}
}
function _closePosition(address _borrower, Status closedStatus) internal {
uint256 PositionOwnersArrayLength = PositionOwners.length;
Position storage t = Positions[_borrower];
t.status = closedStatus;
t.coll = 0;
t.debt = 0;
t.activeInterestIndex = 0;
ISortedPositions sortedPositionsCached = sortedPositions;
rewardSnapshots[_borrower].collateral = 0;
rewardSnapshots[_borrower].debt = 0;
if (PositionOwnersArrayLength > 1 && sortedPositionsCached.getSize() > 1) {
// remove position owner from the PositionOwners array, not preserving array order
uint128 index = t.arrayIndex;
address addressToMove = PositionOwners[PositionOwnersArrayLength - 1];
PositionOwners[index] = addressToMove;
Positions[addressToMove].arrayIndex = index;
emit PositionIndexUpdated(addressToMove, index);
}
PositionOwners.pop();
sortedPositionsCached.remove(_borrower);
t.arrayIndex = 0;
}
// Updates the baseRate state variable based on time elapsed since the last redemption or debt borrowing operation.
function decayBaseRateAndGetBorrowingFee(uint256 _debt) external returns (uint256) {
_requireCallerIsBO();
uint256 rate = _decayBaseRate();
return _calcBorrowingFee(_calcBorrowingRate(rate), _debt);
}
function _decayBaseRate() internal returns (uint256) {
uint256 decayedBaseRate = _calcDecayedBaseRate();
baseRate = decayedBaseRate;
emit BaseRateUpdated(decayedBaseRate);
_updateLastFeeOpTime();
return decayedBaseRate;
}
function applyPendingRewards(address _borrower) external returns (uint256 coll, uint256 debt) {
_requireCallerIsBO();
return _applyPendingRewards(_borrower);
}
// Add the borrowers's coll and debt rewards earned from redistributions, to their Position
function _applyPendingRewards(address _borrower) internal returns (uint256 coll, uint256 debt) {
Position storage t = Positions[_borrower];
if (t.status == Status.active) {
uint256 positionInterestIndex = t.activeInterestIndex;
uint256 currentInterestIndex = _accrueActiveInterests();
debt = t.debt;
uint256 prevDebt = debt;
coll = t.coll;
// We accrue interests for this position if not already updated
if (positionInterestIndex < currentInterestIndex) {
debt = (debt * currentInterestIndex) / positionInterestIndex;
t.activeInterestIndex = currentInterestIndex;
}
if (rewardSnapshots[_borrower].collateral < L_collateral) {
// Compute pending rewards
(uint256 pendingCollateralReward, uint256 pendingDebtReward) = getPendingCollAndDebtRewards(_borrower);
// Apply pending rewards to positions state
coll = coll + pendingCollateralReward;
t.coll = coll;
debt = debt + pendingDebtReward;
_updatePositionRewardSnapshots(_borrower);
_movePendingPositionRewardsToActiveBalance(pendingDebtReward, pendingCollateralReward);
emit PositionUpdated(_borrower, debt, coll, t.stake, PositionManagerOperation.applyPendingRewards);
}
if (prevDebt != debt) {
t.debt = debt;
}
}
return (coll, debt);
}
function _updatePositionRewardSnapshots(address _borrower) internal {
uint256 L_collateralCached = L_collateral;
uint256 L_debtCached = L_debt;
rewardSnapshots[_borrower] = RewardSnapshot(L_collateralCached, L_debtCached);
emit PositionSnapshotsUpdated(L_collateralCached, L_debtCached);
}
// Remove borrower's stake from the totalStakes sum, and set their stake to 0
function _removeStake(address _borrower) internal {
uint256 stake = Positions[_borrower].stake;
totalStakes = totalStakes - stake;
Positions[_borrower].stake = 0;
}
// Update borrower's stake based on their latest collateral value
function _updateStakeAndTotalStakes(Position storage t) internal returns (uint256) {
uint256 newStake = _computeNewStake(t.coll);
uint256 oldStake = t.stake;
t.stake = newStake;
uint256 newTotalStakes = totalStakes - oldStake + newStake;
totalStakes = newTotalStakes;
emit TotalStakesUpdated(newTotalStakes);
return newStake;
}
// Calculate a new stake based on the snapshots of the totalStakes and totalCollateral taken at the last liquidation
function _computeNewStake(uint256 _coll) internal view returns (uint256) {
uint256 stake;
uint256 totalCollateralSnapshotCached = totalCollateralSnapshot;
if (totalCollateralSnapshotCached == 0) {
stake = _coll;
} else {
/*
* The following assert() holds true because:
* - The system always contains >= 1 position
* - When we close or liquidate a position, we redistribute the pending rewards, so if all positions were closed/liquidated,
* rewards would’ve been emptied and totalCollateralSnapshot would be zero too.
*/
uint256 totalStakesSnapshotCached = totalStakesSnapshot;
assert(totalStakesSnapshotCached > 0);
stake = (_coll * totalStakesSnapshotCached) / totalCollateralSnapshotCached;
}
return stake;
}
// --- Liquidation Functions ---
function closePositionByLiquidation(address _borrower) external {
_requireCallerIsLM();
_removeStake(_borrower);
_closePosition(_borrower, Status.closedByLiquidation);
}
function movePendingPositionRewardsToActiveBalances(uint256 _debt, uint256 _collateral) external {
_requireCallerIsLM();
_movePendingPositionRewardsToActiveBalance(_debt, _collateral);
}
function _movePendingPositionRewardsToActiveBalance(uint256 _debt, uint256 _collateral) internal {
defaultedDebt -= _debt;
totalActiveDebt += _debt;
defaultedCollateral -= _collateral;
totalActiveCollateral += _collateral;
}
function addCollateralSurplus(address borrower, uint256 collSurplus) external {
_requireCallerIsLM();
surplusBalances[borrower] += collSurplus;
}
function finalizeLiquidation(
address _liquidator,
uint256 _debt,
uint256 _coll,
uint256 _collSurplus,
uint256 _debtGasComp,
uint256 _collGasComp
) external {
_requireCallerIsLM();
// redistribute debt and collateral
_redistributeDebtAndColl(_debt, _coll);
uint256 _activeColl = totalActiveCollateral;
if (_collSurplus > 0) {
_activeColl -= _collSurplus;
totalActiveCollateral = _activeColl;
}
// update system snapshot
totalStakesSnapshot = totalStakes;
totalCollateralSnapshot = _activeColl + defaultedCollateral - _collGasComp;
emit SystemSnapshotsUpdated(totalStakesSnapshot, totalCollateralSnapshot);
// Send collateral and debt compensation to liquidator
debtToken.returnFromPool(gasPoolAddress, _liquidator, _debtGasComp);
_sendCollateral(_liquidator, _collGasComp);
}
function _redistributeDebtAndColl(uint256 _debt, uint256 _coll) internal {
if (_debt == 0) {
return;
}
/*
* Add distributed coll and debt rewards-per-unit-staked to the running totals. Division uses a "feedback"
* error correction, to keep the cumulative error low in the running totals L_collateral and L_debt:
*
* 1) Form numerators which compensate for the floor division errors that occurred the last time this
* function was called.
* 2) Calculate "per-unit-staked" ratios.
* 3) Multiply each ratio back by its positionominator, to reveal the current floor division error.
* 4) Store these errors for use in the next correction when this function is called.
* 5) Note: static analysis tools complain about this "division before multiplication", however, it is intended.
*/
uint256 collateralNumerator = (_coll * DECIMAL_PRECISION) + lastCollateralError_Redistribution;
uint256 debtNumerator = (_debt * DECIMAL_PRECISION) + lastDebtError_Redistribution;
uint256 totalStakesCached = totalStakes;
// Get the per-unit-staked terms
uint256 collateralRewardPerUnitStaked = collateralNumerator / totalStakesCached;
uint256 debtRewardPerUnitStaked = debtNumerator / totalStakesCached;
lastCollateralError_Redistribution = collateralNumerator - (collateralRewardPerUnitStaked * totalStakesCached);
lastDebtError_Redistribution = debtNumerator - (debtRewardPerUnitStaked * totalStakesCached);
// Add per-unit-staked terms to the running totals
uint256 new_L_collateral = L_collateral + collateralRewardPerUnitStaked;
uint256 new_L_debt = L_debt + debtRewardPerUnitStaked;
L_collateral = new_L_collateral;
L_debt = new_L_debt;
emit LTermsUpdated(new_L_collateral, new_L_debt);
totalActiveDebt -= _debt;
defaultedDebt += _debt;
defaultedCollateral += _coll;
totalActiveCollateral -= _coll;
}
// --- Position property setters ---
function _sendCollateral(address _account, uint256 _amount) private {
if (_amount > 0) {
totalActiveCollateral = totalActiveCollateral - _amount;
emit CollateralSent(_account, _amount);
collateralToken.safeTransfer(_account, _amount);
}
}
function _increaseDebt(address account, uint256 netDebtAmount, uint256 debtAmount) internal {
uint256 _newTotalDebt = totalActiveDebt + netDebtAmount;
require(_newTotalDebt + defaultedDebt <= maxSystemDebt, "Collateral debt limit reached");
totalActiveDebt = _newTotalDebt;
debtToken.mint(account, debtAmount);
}
function decreaseDebtAndSendCollateral(address account, uint256 debt, uint256 coll) external {
_requireCallerIsLM();
_decreaseDebt(account, debt);
_sendCollateral(account, coll);
}
function _decreaseDebt(address account, uint256 amount) internal {
debtToken.burn(account, amount);
totalActiveDebt = totalActiveDebt - amount;
}
// --- Balances and interest ---
function updateBalances() external {
_requireCallerIsLM();
_updateBalances();
}
function _updateBalances() private {
_accrueActiveInterests();
}
// This function must be called any time the debt or the interest changes
function _accrueActiveInterests() internal returns (uint256) {
(uint256 currentInterestIndex, uint256 interestFactor) = _calculateInterestIndex();
if (interestFactor > 0) {
uint256 currentDebt = totalActiveDebt;
uint256 activeInterests = Math.mulDiv(currentDebt, interestFactor, INTEREST_PRECISION);
totalActiveDebt = currentDebt + activeInterests;
interestPayable = interestPayable + activeInterests;
activeInterestIndex = currentInterestIndex;
lastActiveIndexUpdate = block.timestamp;
}
return currentInterestIndex;
}
function _calculateInterestIndex() internal view returns (uint256 currentInterestIndex, uint256 interestFactor) {
uint256 lastIndexUpdateCached = lastActiveIndexUpdate;
// Short circuit if we updated in the current block
if (lastIndexUpdateCached == block.timestamp) return (activeInterestIndex, 0);
uint256 currentInterest = interestRate;
currentInterestIndex = activeInterestIndex; // we need to return this if it's already up to date
if (currentInterest > 0) {
/*
* Calculate the interest accumulated and the new index:
* We compound the index and increase the debt accordingly
*/
uint256 deltaT = block.timestamp - lastIndexUpdateCached;
interestFactor = deltaT * currentInterest;
currentInterestIndex =
currentInterestIndex +
Math.mulDiv(currentInterestIndex, interestFactor, INTEREST_PRECISION);
}
}
// --- Requires ---
function _requireCallerIsBO() internal view {
require(msg.sender == borrowerOperations, "Caller not BO");
}
function _requireCallerIsLM() internal view {
require(msg.sender == liquidationManager, "Not Liquidation Manager");
}
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.26;
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import { IERC3156FlashBorrower } from "@openzeppelin/contracts/interfaces/IERC3156FlashBorrower.sol";
import "./ICore.sol";
interface IDebtToken is IERC20 {
// --- Events ---
event FlashLoanFeeUpdated(uint256 newFee);
// --- Public constants ---
function version() external view returns (string memory);
function permitTypeHash() external view returns (bytes32);
// --- Public immutables ---
function gasPool() external view returns (address);
function DEBT_GAS_COMPENSATION() external view returns (uint256);
// --- Public mappings ---
function liquidStabilityPools(address) external view returns (bool);
function borrowerOperations(address) external view returns (bool);
function factories(address) external view returns (bool);
function peripheries(address) external view returns (bool);
function positionManagers(address) external view returns (bool);
// --- External functions ---
function enablePositionManager(address _positionManager) external;
function mintWithGasCompensation(address _account, uint256 _amount) external returns (bool);
function burnWithGasCompensation(address _account, uint256 _amount) external returns (bool);
function mint(address _account, uint256 _amount) external;
function burn(address _account, uint256 _amount) external;
function decimals() external view returns (uint8);
function sendToPeriphery(address _sender, uint256 _amount) external;
function sendToSP(address _sender, uint256 _amount) external;
function returnFromPool(address _poolAddress, address _receiver, uint256 _amount) external;
function transfer(address recipient, uint256 amount) external returns (bool);
function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
function maxFlashLoan(address token) external view returns (uint256);
function flashFee(address token, uint256 amount) external view returns (uint256);
function flashLoan(
IERC3156FlashBorrower receiver,
address token,
uint256 amount,
bytes calldata data
) external returns (bool);
function whitelistLiquidStabilityPoolAddress(address _liquidStabilityPool, bool active) external;
function whitelistBorrowerOperationsAddress(address _borrowerOperations, bool active) external;
function whitelistFactoryAddress(address _factory, bool active) external;
function whitelistPeripheryAddress(address _periphery, bool active) external;
function whitelistPSM(address, bool) external;
function setDebtGasCompensation(uint256 _gasCompensation, bool _isFinalValue) external;
function setFlashLoanFee(uint256 _fee) external;
function DOMAIN_SEPARATOR() external view returns (bytes32);
function permit(
address owner,
address spender,
uint256 amount,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
function nonces(address owner) external view returns (uint256);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface IPriceFeed {
struct FeedType {
address spotOracle;
bool isCollVault;
}
event NewOracleRegistered(address token, address chainlinkAggregator, address underlyingDerivative);
event PriceFeedStatusUpdated(address token, address oracle, bool isWorking);
event PriceRecordUpdated(address indexed token, uint256 _price);
event NewCollVaultRegistered(address collVault, bool enable);
event NewSpotOracleRegistered(address token, address spotOracle);
function fetchPrice(address _token) external view returns (uint256);
function getMultiplePrices(address[] memory _tokens) external view returns (uint256[] memory prices);
function setOracle(
address _token,
address _chainlinkOracle,
uint32 _heartbeat,
uint16 _staleThreshold,
address underlyingDerivative
) external;
function whitelistCollateralVault(address _collateralVaultShareToken, bool enable) external;
function setSpotOracle(address _token, address _spotOracle) external;
function MAX_PRICE_DEVIATION_FROM_PREVIOUS_ROUND() external view returns (uint256);
function CORE() external view returns (address);
function RESPONSE_TIMEOUT() external view returns (uint256);
function TARGET_DIGITS() external view returns (uint256);
function guardian() external view returns (address);
function oracleRecords(
address
)
external
view
returns (
address chainLinkOracle,
uint8 decimals,
uint32 heartbeat,
uint16 staleThreshold,
address underlyingDerivative
);
function isCollVault(address _collateralVaultShareToken) external view returns (bool);
function isStableBPT(address _oracle) external view returns (bool);
function isWeightedBPT(address _oracle) external view returns (bool);
function getSpotOracle(address _token) external view returns (address);
function feedType(address _token) external view returns (FeedType memory);
function owner() external view returns (address);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface ISortedPositions {
event NodeAdded(address _id, uint256 _NICR);
event NodeRemoved(address _id);
function insert(address _id, uint256 _NICR, address _prevId, address _nextId) external;
function reInsert(address _id, uint256 _newNICR, address _prevId, address _nextId) external;
function remove(address _id) external;
function setAddresses(address _positionManagerAddress) external;
function contains(address _id) external view returns (bool);
function data() external view returns (address head, address tail, uint256 size);
function findInsertPosition(
uint256 _NICR,
address _prevId,
address _nextId
) external view returns (address, address);
function getFirst() external view returns (address);
function getLast() external view returns (address);
function getNext(address _id) external view returns (address);
function getPrev(address _id) external view returns (address);
function getSize() external view returns (uint256);
function isEmpty() external view returns (bool);
function positionManager() external view returns (address);
function validInsertPosition(uint256 _NICR, address _prevId, address _nextId) external view returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/utils/SafeERC20.sol)
pragma solidity ^0.8.0;
import "../IERC20.sol";
import "../extensions/draft-IERC20Permit.sol";
import "../../../utils/Address.sol";
/**
* @title SafeERC20
* @dev Wrappers around ERC20 operations that throw on failure (when the token
* contract returns false). Tokens that return no value (and instead revert or
* throw on failure) are also supported, non-reverting calls are assumed to be
* successful.
* To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
* which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
*/
library SafeERC20 {
using Address for address;
function safeTransfer(
IERC20 token,
address to,
uint256 value
) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
}
function safeTransferFrom(
IERC20 token,
address from,
address to,
uint256 value
) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
}
/**
* @dev Deprecated. This function has issues similar to the ones found in
* {IERC20-approve}, and its usage is discouraged.
*
* Whenever possible, use {safeIncreaseAllowance} and
* {safeDecreaseAllowance} instead.
*/
function safeApprove(
IERC20 token,
address spender,
uint256 value
) internal {
// safeApprove should only be called when setting an initial allowance,
// or when resetting it to zero. To increase and decrease it, use
// 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
require(
(value == 0) || (token.allowance(address(this), spender) == 0),
"SafeERC20: approve from non-zero to non-zero allowance"
);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
}
function safeIncreaseAllowance(
IERC20 token,
address spender,
uint256 value
) internal {
uint256 newAllowance = token.allowance(address(this), spender) + value;
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
function safeDecreaseAllowance(
IERC20 token,
address spender,
uint256 value
) internal {
unchecked {
uint256 oldAllowance = token.allowance(address(this), spender);
require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
uint256 newAllowance = oldAllowance - value;
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
}
function safePermit(
IERC20Permit token,
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) internal {
uint256 nonceBefore = token.nonces(owner);
token.permit(owner, spender, value, deadline, v, r, s);
uint256 nonceAfter = token.nonces(owner);
require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed");
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*/
function _callOptionalReturn(IERC20 token, bytes memory data) private {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that
// the target address contains contract code and also asserts for success in the low-level call.
bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
if (returndata.length > 0) {
// Return data is optional
require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @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);
/**
* @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 `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, 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 `from` to `to` 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 from,
address to,
uint256 amount
) external returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/Math.sol)
pragma solidity ^0.8.0;
/**
* @dev Standard math utilities missing in the Solidity language.
*/
library Math {
enum Rounding {
Down, // Toward negative infinity
Up, // Toward infinity
Zero // Toward zero
}
/**
* @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 == 0 ? 0 : (a - 1) / b + 1;
}
/**
* @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
* @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)
* with further edits by Uniswap Labs also under MIT license.
*/
function mulDiv(
uint256 x,
uint256 y,
uint256 denominator
) internal pure returns (uint256 result) {
unchecked {
// 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) {
return prod0 / denominator;
}
// 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.
// Does not overflow because the denominator cannot be zero at this stage in the function.
uint256 twos = denominator & (~denominator + 1);
assembly {
// Divide denominator by twos.
denominator := div(denominator, twos)
// Divide [prod1 prod0] by twos.
prod0 := div(prod0, twos)
// Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
twos := add(div(sub(0, twos), twos), 1)
}
// Shift in bits from prod1 into prod0.
prod0 |= prod1 * twos;
// 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;
// Use the 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 preconditions 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;
}
}
/**
* @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
*/
function mulDiv(
uint256 x,
uint256 y,
uint256 denominator,
Rounding rounding
) internal pure returns (uint256) {
uint256 result = mulDiv(x, y, denominator);
if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {
result += 1;
}
return result;
}
/**
* @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.
*
* Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
*/
function sqrt(uint256 a) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
// For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
//
// We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
// `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
//
// This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
// → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
// → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
//
// Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
uint256 result = 1 << (log2(a) >> 1);
// At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
// since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
// every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
// into the expected uint128 result.
unchecked {
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
return min(result, a / result);
}
}
/**
* @notice Calculates sqrt(a), following the selected rounding direction.
*/
function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = sqrt(a);
return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);
}
}
/**
* @dev Return the log in base 2, rounded down, of a positive value.
* Returns 0 if given 0.
*/
function log2(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 128;
}
if (value >> 64 > 0) {
value >>= 64;
result += 64;
}
if (value >> 32 > 0) {
value >>= 32;
result += 32;
}
if (value >> 16 > 0) {
value >>= 16;
result += 16;
}
if (value >> 8 > 0) {
value >>= 8;
result += 8;
}
if (value >> 4 > 0) {
value >>= 4;
result += 4;
}
if (value >> 2 > 0) {
value >>= 2;
result += 2;
}
if (value >> 1 > 0) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 2, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log2(value);
return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 10, rounded down, of a positive value.
* Returns 0 if given 0.
*/
function log10(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >= 10**64) {
value /= 10**64;
result += 64;
}
if (value >= 10**32) {
value /= 10**32;
result += 32;
}
if (value >= 10**16) {
value /= 10**16;
result += 16;
}
if (value >= 10**8) {
value /= 10**8;
result += 8;
}
if (value >= 10**4) {
value /= 10**4;
result += 4;
}
if (value >= 10**2) {
value /= 10**2;
result += 2;
}
if (value >= 10**1) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 10, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log10(value);
return result + (rounding == Rounding.Up && 10**result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 256, rounded down, of a positive value.
* Returns 0 if given 0.
*
* Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
*/
function log256(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 16;
}
if (value >> 64 > 0) {
value >>= 64;
result += 8;
}
if (value >> 32 > 0) {
value >>= 32;
result += 4;
}
if (value >> 16 > 0) {
value >>= 16;
result += 2;
}
if (value >> 8 > 0) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 10, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log256(value);
return result + (rounding == Rounding.Up && 1 << (result * 8) < value ? 1 : 0);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (interfaces/IERC3156FlashBorrower.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC3156 FlashBorrower, as defined in
* https://eips.ethereum.org/EIPS/eip-3156[ERC-3156].
*
* _Available since v4.1._
*/
interface IERC3156FlashBorrower {
/**
* @dev Receive a flash loan.
* @param initiator The initiator of the loan.
* @param token The loan currency.
* @param amount The amount of tokens lent.
* @param fee The additional amount of tokens to repay.
* @param data Arbitrary data structure, intended to contain user-defined parameters.
* @return The keccak256 hash of "IERC3156FlashBorrower.onFlashLoan"
*/
function onFlashLoan(
address initiator,
address token,
uint256 amount,
uint256 fee,
bytes calldata data
) external returns (bytes32);
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.26;
import {ICore} from "./ICore.sol";
interface IBorrowerOperations {
struct Balances {
uint256[] collaterals;
uint256[] debts;
uint256[] prices;
}
event BorrowingFeePaid(address indexed borrower, uint256 amount);
event CollateralConfigured(address positionManager, address collateralToken);
event PositionCreated(address indexed _borrower, uint256 arrayIndex);
event PositionManagerRemoved(address positionManager);
event PositionUpdated(address indexed _borrower, uint256 _debt, uint256 _coll, uint256 stake, uint8 operation);
function addColl(
address positionManager,
address account,
uint256 _collateralAmount,
address _upperHint,
address _lowerHint
) external;
function adjustPosition(
address positionManager,
address account,
uint256 _maxFeePercentage,
uint256 _collDeposit,
uint256 _collWithdrawal,
uint256 _debtChange,
bool _isDebtIncrease,
address _upperHint,
address _lowerHint
) external;
function closePosition(address positionManager, address account) external;
function configureCollateral(address positionManager, address collateralToken) external;
function fetchBalances() external view returns (Balances memory balances);
function getGlobalSystemBalances() external view returns (uint256 totalPricedCollateral, uint256 totalDebt);
function getTCR() external view returns (uint256 globalTotalCollateralRatio);
function openPosition(
address positionManager,
address account,
uint256 _maxFeePercentage,
uint256 _collateralAmount,
uint256 _debtAmount,
address _upperHint,
address _lowerHint
) external;
function removePositionManager(address positionManager) external;
function repayDebt(
address positionManager,
address account,
uint256 _debtAmount,
address _upperHint,
address _lowerHint
) external;
function setDelegateApproval(address _delegate, bool _isApproved) external;
function setMinNetDebt(uint256 _minNetDebt) external;
function withdrawColl(
address positionManager,
address account,
uint256 _collWithdrawal,
address _upperHint,
address _lowerHint
) external;
function withdrawDebt(
address positionManager,
address account,
uint256 _maxFeePercentage,
uint256 _debtAmount,
address _upperHint,
address _lowerHint
) external;
function positionManagers(uint256) external view returns (address);
function checkRecoveryMode(uint256 TCR) external view returns (bool);
function DEBT_GAS_COMPENSATION() external view returns (uint256);
function DECIMAL_PRECISION() external view returns (uint256);
function PERCENT_DIVISOR() external view returns (uint256);
function CORE() external view returns (ICore);
function debtToken() external view returns (address);
function factory() external view returns (address);
function getCompositeDebt(uint256 _debt) external view returns (uint256);
function guardian() external view returns (address);
function isApprovedDelegate(address owner, address caller) external view returns (bool isApproved);
function minNetDebt() external view returns (uint256);
function owner() external view returns (address);
function positionManagersData(address) external view returns (address collateralToken, uint16 index);
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.26;
interface IFactory {
// commented values are suggested default parameters
struct DeploymentParams {
uint256 minuteDecayFactor; // 999037758833783000 (half life of 12 hours)
uint256 redemptionFeeFloor; // 1e18 / 1000 * 5 (0.5%)
uint256 maxRedemptionFee; // 1e18 (100%)
uint256 borrowingFeeFloor; // 1e18 / 1000 * 5 (0.5%)
uint256 maxBorrowingFee; // 1e18 / 100 * 5 (5%)
uint256 interestRateInBps; // 100 (1%)
uint256 maxDebt;
uint256 MCR; // 12 * 1e17 (120%)
address collVaultRouter; // set to address(0) if PositionManager coll is not CollateralVault
}
event NewDeployment(address collateral, address priceFeed, address positionManager, address sortedPositions);
function deployNewInstance(
address collateral,
address priceFeed,
address customPositionManagerImpl,
address customSortedPositionsImpl,
DeploymentParams calldata params,
uint64 unlockRatePerSecond,
bool forceThroughLspBalanceCheck
) external;
function setImplementations(address _positionManagerImpl, address _sortedPositionsImpl) external;
function CORE() external view returns (address);
function borrowerOperations() external view returns (address);
function debtToken() external view returns (address);
function guardian() external view returns (address);
function liquidationManager() external view returns (address);
function owner() external view returns (address);
function sortedPositionsImpl() external view returns (address);
function liquidStabilityPool() external view returns (address);
function positionManagerCount() external view returns (uint256);
function positionManagerImpl() external view returns (address);
function positionManagers(uint256) external view returns (address);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface ILiquidationManager {
function batchLiquidatePositions(address positionManager, address[] calldata _positionArray, address liquidator) external;
function enablePositionManager(address _positionManager) external;
function liquidate(address positionManager, address borrower, address liquidator) external;
function liquidatePositions(address positionManager, uint256 maxPositionsToLiquidate, uint256 maxICR, address liquidator) external;
function DEBT_GAS_COMPENSATION() external view returns (uint256);
function DECIMAL_PRECISION() external view returns (uint256);
function PERCENT_DIVISOR() external view returns (uint256);
function borrowerOperations() external view returns (address);
function factory() external view returns (address);
function liquidStabilityPool() external view returns (address);
function DOMAIN_SEPARATOR() external view returns (bytes32);
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.26;
import "../interfaces/core/ICore.sol";
/**
@title System Start Time
@dev Provides a unified `startTime` and `getWeek`, used for emissions.
*/
contract SystemStart {
uint256 immutable startTime;
constructor(address core) {
startTime = ICore(core).startTime();
}
function getWeek() public view returns (uint256 week) {
return (block.timestamp - startTime) / 1 weeks;
}
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.26;
/*
* Base contract for PositionManager, BorrowerOperations and StabilityPool. Contains global system constants and
* common functions.
*/
contract PropBase {
uint256 public constant DECIMAL_PRECISION = 1e18;
// Amount of debt to be locked in gas pool on opening positions
uint256 public immutable DEBT_GAS_COMPENSATION;
uint256 public constant PERCENT_DIVISOR = 1000; // dividing by 1000 yields 0.1%
constructor(uint256 _gasCompensation) {
DEBT_GAS_COMPENSATION = _gasCompensation;
}
// --- Gas compensation functions ---
// Returns the composite debt (drawn debt + gas compensation) of a position, for the purpose of ICR calculation
function _getCompositeDebt(uint256 _debt) internal view returns (uint256) {
return _debt + DEBT_GAS_COMPENSATION;
}
function _getNetDebt(uint256 _debt) internal view returns (uint256) {
return _debt - DEBT_GAS_COMPENSATION;
}
// Return the amount of collateral to be drawn from a position's collateral and sent as gas compensation.
function _getCollGasCompensation(uint256 _entireColl) internal pure returns (uint256) {
return _entireColl / PERCENT_DIVISOR;
}
function _requireUserAcceptsFee(uint256 _fee, uint256 _amount, uint256 _maxFeePercentage) internal pure {
uint256 feePercentage = _amount != 0 ? (_fee * DECIMAL_PRECISION) / _amount : 0;
require(feePercentage <= _maxFeePercentage, "Fee exceeded provided maximum");
}
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.26;
library PropMath {
uint256 internal constant DECIMAL_PRECISION = 1e18;
/* 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,
* 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;
}
/*
* 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) PositionManager._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 _coll, uint256 _debt) internal pure returns (uint256) {
if (_debt > 0) {
return (_coll * NICR_PRECISION) / _debt;
}
// Return the maximal value for uint256 if the Position has a debt of 0. Represents "infinite" CR.
else {
// if (_debt == 0)
return 2 ** 256 - 1;
}
}
function _computeCR(uint256 _coll, uint256 _debt, uint256 _price) internal pure returns (uint256) {
if (_debt > 0) {
uint256 newCollRatio = (_coll * _price) / _debt;
return newCollRatio;
}
// Return the maximal value for uint256 if the Position has a debt of 0. Represents "infinite" CR.
else {
// if (_debt == 0)
return 2 ** 256 - 1;
}
}
function _computeCR(uint256 _coll, uint256 _debt) internal pure returns (uint256) {
if (_debt > 0) {
uint256 newCollRatio = (_coll) / _debt;
return newCollRatio;
}
// Return the maximal value for uint256 if the Position has a debt of 0. Represents "infinite" CR.
else {
// if (_debt == 0)
return 2 ** 256 - 1;
}
}
function _isApproxEqAbs(uint256 a, uint256 b, uint256 tolerance) internal pure returns (bool) {
return a > b ? (a - b) <= tolerance : (b - a) <= tolerance;
}
function _isWithinToleranceAbove(
uint256 a,
uint256 b,
uint256 tolerance
) internal pure returns (bool) {
if (a < b) return false;
return (a - b) <= tolerance;
}
function _isWithinToleranceBelow(
uint256 a,
uint256 b,
uint256 tolerance
) internal pure returns (bool) {
if (a > b) return false;
return (b - a) <= tolerance;
}
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.26;
import "../interfaces/core/ICore.sol";
/**
@title Prop Ownable
@notice Contracts inheriting `PropOwnable` have the same owner as `PropCore`.
The ownership cannot be independently modified or renounced.
@dev In the contracts that use CORE to interact with protocol instance specific parameters,
the immutable will be instanced with PropCore.sol, eitherway, it will be MetaCore.sol
*/
contract PropOwnable {
ICore public immutable CORE;
constructor(address _core) {
CORE = ICore(_core);
}
modifier onlyOwner() {
require(msg.sender == CORE.owner(), "Only owner");
_;
}
function owner() public view returns (address) {
return CORE.owner();
}
function guardian() public view returns (address) {
return CORE.guardian();
}
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.26;
import {IMetaCore} from "src/interfaces/core/IMetaCore.sol";
interface ICore {
// --- Public variables ---
function metaCore() external view returns (IMetaCore);
function startTime() external view returns (uint256);
function CCR() external view returns (uint256);
function dmBootstrapPeriod() external view returns (uint64);
function isPeriphery(address peripheryContract) external view returns (bool);
// --- External functions ---
function setPeripheryEnabled(address _periphery, bool _enabled) external;
function setPMBootstrapPeriod(address dm, uint64 _bootstrapPeriod) external;
function setNewCCR(uint256 _CCR) external;
function priceFeed() external view returns (address);
function owner() external view returns (address);
function pendingOwner() external view returns (address);
function guardian() external view returns (address);
function feeReceiver() external view returns (address);
function paused() external view returns (bool);
function lspBootstrapPeriod() external view returns (uint64);
function getLspEntryFee(address rebalancer) external view returns (uint16);
function getLspExitFee(address rebalancer) external view returns (uint16);
function interestProtocolShare() external view returns (uint16);
function defaultInterestReceiver() external view returns (address);
// --- Events ---
event CCRSet(uint256 initialCCR);
event PMBootstrapPeriodSet(address dm, uint64 bootstrapPeriod);
event PeripheryEnabled(address indexed periphery, bool enabled);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
* https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
*
* Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
* presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
* need to send a transaction, and thus is not required to hold Ether at all.
*/
interface IERC20Permit {
/**
* @dev Sets `value` 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:
*
* - `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 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
/**
* @dev Returns the current 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.
*/
function nonces(address owner) external view returns (uint256);
/**
* @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
*/
// solhint-disable-next-line func-name-mixedcase
function DOMAIN_SEPARATOR() external view returns (bytes32);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol)
pragma solidity ^0.8.1;
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
* ====
*
* [IMPORTANT]
* ====
* You shouldn't rely on `isContract` to protect against flash loan attacks!
*
* Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
* like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
* constructor.
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies on extcodesize/address.code.length, which returns 0
// for contracts in construction, since the code is only stored at the end
// of the constructor execution.
return account.code.length > 0;
}
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason, it is bubbled up by this
* function (like regular Solidity function calls).
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value
) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
* the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
*
* _Available since v4.8._
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata,
string memory errorMessage
) internal view returns (bytes memory) {
if (success) {
if (returndata.length == 0) {
// only check isContract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
require(isContract(target), "Address: call to non-contract");
}
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
/**
* @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason or using the provided one.
*
* _Available since v4.3._
*/
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
function _revert(bytes memory returndata, string memory errorMessage) private pure {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.26;
interface IMetaCore {
// ---------------------------------
// Structures
// ---------------------------------
struct FeeInfo {
bool existsForDebtToken;
uint16 debtTokenFee;
}
struct RebalancerFeeInfo {
bool exists;
uint16 entryFee;
uint16 exitFee;
}
// ---------------------------------
// Public constants
// ---------------------------------
function OWNERSHIP_TRANSFER_DELAY() external view returns (uint256);
function DEFAULT_FLASH_LOAN_FEE() external view returns (uint16);
// ---------------------------------
// Public state variables
// ---------------------------------
function debtToken() external view returns (address);
function lspEntryFee() external view returns (uint16);
function lspExitFee() external view returns (uint16);
function interestProtocolShare() external view returns (uint16);
/// @dev Default interest receiver for all PositionManagers, unless overriden in the respective PM
function defaultInterestReceiver() external view returns (address);
function feeReceiver() external view returns (address);
function priceFeed() external view returns (address);
function owner() external view returns (address);
function pendingOwner() external view returns (address);
function ownershipTransferDeadline() external view returns (uint256);
function guardian() external view returns (address);
function paused() external view returns (bool);
function lspBootstrapPeriod() external view returns (uint64);
// ---------------------------------
// External functions
// ---------------------------------
function setFeeReceiver(address _feeReceiver) external;
function setPriceFeed(address _priceFeed) external;
function setGuardian(address _guardian) external;
/**
* @notice Global pause/unpause
* Pausing halts new deposits/borrowing across the protocol
*/
function setPaused(bool _paused) external;
/**
* @notice Extend or change the LSP bootstrap period,
* after which certain protocol mechanics change
*/
function setLspBootstrapPeriod(uint64 _bootstrapPeriod) external;
/**
* @notice Set a custom flash-loan fee for a given periphery contract
* @param _periphery Target contract that will get this custom fee
* @param _debtTokenFee Fee in basis points (bp)
* @param _existsForDebtToken Whether this custom fee is used when the caller = `debtToken`
*/
function setPeripheryFlashLoanFee(address _periphery, uint16 _debtTokenFee, bool _existsForDebtToken) external;
/**
* @notice Begin the ownership transfer process
* @param newOwner The address proposed to be the new owner
*/
function commitTransferOwnership(address newOwner) external;
/**
* @notice Finish the ownership transfer, after the mandatory delay
*/
function acceptTransferOwnership() external;
/**
* @notice Revoke a pending ownership transfer
*/
function revokeTransferOwnership() external;
/**
* @notice Look up a custom flash-loan fee for a specific periphery contract
* @param peripheryContract The contract that might have a custom fee
* @return The flash-loan fee in basis points
*/
function getPeripheryFlashLoanFee(address peripheryContract) external view returns (uint16);
/**
* @notice Set / override entry & exit fees for a special rebalancer contract
*/
function setRebalancerFee(address _rebalancer, uint16 _entryFee, uint16 _exitFee) external;
/**
* @notice Set the LSP entry fee globally
* @param _fee Fee in basis points
*/
function setEntryFee(uint16 _fee) external;
/**
* @notice Set the LSP exit fee globally
* @param _fee Fee in basis points
*/
function setExitFee(uint16 _fee) external;
/**
* @notice Set the interest protocol share globally to all PositionManagers
* @param _interestProtocolShare Share in basis points
*/
function setInterestProtocolShare(uint16 _interestProtocolShare) external;
/**
* @notice Look up the LSP entry fee for a rebalancer
* @param rebalancer Possibly has a special fee
* @return The entry fee in basis points
*/
function getLspEntryFee(address rebalancer) external view returns (uint16);
/**
* @notice Look up the LSP exit fee for a rebalancer
* @param rebalancer Possibly has a special fee
* @return The exit fee in basis points
*/
function getLspExitFee(address rebalancer) external view returns (uint16);
// ---------------------------------
// Events
// ---------------------------------
event NewOwnerCommitted(address indexed owner, address indexed pendingOwner, uint256 deadline);
event NewOwnerAccepted(address indexed oldOwner, address indexed newOwner);
event NewOwnerRevoked(address indexed owner, address indexed revokedOwner);
event FeeReceiverSet(address indexed feeReceiver);
event PriceFeedSet(address indexed priceFeed);
event GuardianSet(address indexed guardian);
event PeripheryFlashLoanFee(address indexed periphery, uint16 debtTokenFee);
event LSPBootstrapPeriodSet(uint64 bootstrapPeriod);
event RebalancerFees(address indexed rebalancer, uint16 entryFee, uint16 exitFee);
event EntryFeeSet(uint16 fee);
event ExitFeeSet(uint16 fee);
event InterestProtocolShareSet(uint16 interestProtocolShare);
event DefaultInterestReceiverSet(address indexed defaultInterestReceiver);
event Paused();
event Unpaused();
}{
"remappings": [
"@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/",
"@openzeppelin-upgradeable/contracts/=lib/openzeppelin-contracts-upgradeable/contracts/",
"solady/=lib/solady/src/",
"@solmate/=lib/solmate/src/",
"@chimera/=lib/chimera/src/",
"forge-std/=lib/forge-std/src/",
"@uniswap/v3-core/=lib/v3-core/",
"@uniswap/v3-periphery/=lib/v3-periphery/",
"@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/",
"chimera/=lib/chimera/src/",
"ds-test/=lib/solmate/lib/ds-test/src/",
"erc4626-tests/=lib/openzeppelin-contracts-upgradeable/lib/erc4626-tests/",
"halmos-cheatcodes/=lib/openzeppelin-contracts-upgradeable/lib/halmos-cheatcodes/src/",
"openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/",
"openzeppelin-contracts/=lib/openzeppelin-contracts/",
"rewards/=lib/rewards/",
"solmate/=lib/solmate/src/",
"v3-core/=lib/v3-core/contracts/",
"v3-periphery/=lib/v3-periphery/contracts/"
],
"optimizer": {
"enabled": true,
"runs": 100
},
"metadata": {
"useLiteralContent": false,
"bytecodeHash": "ipfs",
"appendCBOR": true
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"evmVersion": "cancun",
"viaIR": false
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"_core","type":"address"},{"internalType":"address","name":"_gasPoolAddress","type":"address"},{"internalType":"address","name":"_debtTokenAddress","type":"address"},{"internalType":"address","name":"_borrowerOperations","type":"address"},{"internalType":"address","name":"_liquidationManager","type":"address"},{"internalType":"uint256","name":"_gasCompensation","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_baseRate","type":"uint256"}],"name":"BaseRateUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_to","type":"address"},{"indexed":false,"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"CollateralSent","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_interestReceiver","type":"address"}],"name":"InterestReceiverSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_L_collateral","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_L_debt","type":"uint256"}],"name":"LTermsUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_lastFeeOpTime","type":"uint256"}],"name":"LastFeeOpTimeUpdated","type":"event"},{"anonymous":false,"inputs":[{"components":[{"internalType":"uint256","name":"minuteDecayFactor","type":"uint256"},{"internalType":"uint256","name":"redemptionFeeFloor","type":"uint256"},{"internalType":"uint256","name":"maxRedemptionFee","type":"uint256"},{"internalType":"uint256","name":"borrowingFeeFloor","type":"uint256"},{"internalType":"uint256","name":"maxBorrowingFee","type":"uint256"},{"internalType":"uint256","name":"interestRateInBps","type":"uint256"},{"internalType":"uint256","name":"maxDebt","type":"uint256"},{"internalType":"uint256","name":"MCR","type":"uint256"},{"internalType":"address","name":"collVaultRouter","type":"address"}],"indexed":false,"internalType":"struct IFactory.DeploymentParams","name":"params","type":"tuple"}],"name":"NewParameters","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_borrower","type":"address"},{"indexed":false,"internalType":"uint256","name":"_newIndex","type":"uint256"}],"name":"PositionIndexUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_L_collateral","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_L_debt","type":"uint256"}],"name":"PositionSnapshotsUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_borrower","type":"address"},{"indexed":false,"internalType":"uint256","name":"_debt","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_coll","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_stake","type":"uint256"},{"indexed":false,"internalType":"enum PositionManager.PositionManagerOperation","name":"_operation","type":"uint8"}],"name":"PositionUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_priceFeed","type":"address"}],"name":"PriceFeedUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_redeemer","type":"address"},{"indexed":false,"internalType":"uint256","name":"_attemptedDebtAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_actualDebtAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_collateralSent","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_collateralFee","type":"uint256"}],"name":"Redemption","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_totalStakesSnapshot","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_totalCollateralSnapshot","type":"uint256"}],"name":"SystemSnapshotsUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_newTotalStakes","type":"uint256"}],"name":"TotalStakesUpdated","type":"event"},{"inputs":[],"name":"CORE","outputs":[{"internalType":"contract ICore","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DEBT_GAS_COMPENSATION","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":"L_collateral","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"L_debt","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":"PERCENT_DIVISOR","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"Positions","outputs":[{"internalType":"uint256","name":"debt","type":"uint256"},{"internalType":"uint256","name":"coll","type":"uint256"},{"internalType":"uint256","name":"stake","type":"uint256"},{"internalType":"enum PositionManager.Status","name":"status","type":"uint8"},{"internalType":"uint128","name":"arrayIndex","type":"uint128"},{"internalType":"uint256","name":"activeInterestIndex","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SUNSETTING_INTEREST_RATE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"activeInterestIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"borrower","type":"address"},{"internalType":"uint256","name":"collSurplus","type":"uint256"}],"name":"addCollateralSurplus","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_borrower","type":"address"}],"name":"applyPendingRewards","outputs":[{"internalType":"uint256","name":"coll","type":"uint256"},{"internalType":"uint256","name":"debt","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"baseRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"borrowerOperations","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"borrowingFeeFloor","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"borrower","type":"address"},{"internalType":"address","name":"_receiver","type":"address"}],"name":"claimCollateral","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_borrower","type":"address"},{"internalType":"address","name":"_receiver","type":"address"},{"internalType":"uint256","name":"collAmount","type":"uint256"},{"internalType":"uint256","name":"debtAmount","type":"uint256"}],"name":"closePosition","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_borrower","type":"address"}],"name":"closePositionByLiquidation","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"collVaultRouter","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"collateralToken","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"collectInterests","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"debtToken","outputs":[{"internalType":"contract IDebtToken","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_debt","type":"uint256"}],"name":"decayBaseRateAndGetBorrowingFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"debt","type":"uint256"},{"internalType":"uint256","name":"coll","type":"uint256"}],"name":"decreaseDebtAndSendCollateral","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"defaultedCollateral","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"defaultedDebt","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"fetchPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_liquidator","type":"address"},{"internalType":"uint256","name":"_debt","type":"uint256"},{"internalType":"uint256","name":"_coll","type":"uint256"},{"internalType":"uint256","name":"_collSurplus","type":"uint256"},{"internalType":"uint256","name":"_debtGasComp","type":"uint256"},{"internalType":"uint256","name":"_collGasComp","type":"uint256"}],"name":"finalizeLiquidation","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_debt","type":"uint256"}],"name":"getBorrowingFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_debt","type":"uint256"}],"name":"getBorrowingFeeWithDecay","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getBorrowingRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getBorrowingRateWithDecay","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_borrower","type":"address"},{"internalType":"uint256","name":"_price","type":"uint256"}],"name":"getCurrentICR","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_borrower","type":"address"}],"name":"getEntireDebtAndColl","outputs":[{"internalType":"uint256","name":"debt","type":"uint256"},{"internalType":"uint256","name":"coll","type":"uint256"},{"internalType":"uint256","name":"pendingDebtReward","type":"uint256"},{"internalType":"uint256","name":"pendingCollateralReward","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getEntireSystemBalances","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getEntireSystemColl","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getEntireSystemDebt","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_borrower","type":"address"}],"name":"getNominalICR","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_borrower","type":"address"}],"name":"getPendingCollAndDebtRewards","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_borrower","type":"address"}],"name":"getPositionCollAndDebt","outputs":[{"internalType":"uint256","name":"coll","type":"uint256"},{"internalType":"uint256","name":"debt","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_index","type":"uint256"}],"name":"getPositionFromPositionOwnersArray","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getPositionOwnersCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_borrower","type":"address"}],"name":"getPositionStake","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_borrower","type":"address"}],"name":"getPositionStatus","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_collateralDrawn","type":"uint256"}],"name":"getRedemptionFeeWithDecay","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getRedemptionRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getRedemptionRateWithDecay","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTotalActiveCollateral","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTotalActiveDebt","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getWeek","outputs":[{"internalType":"uint256","name":"week","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"guardian","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_borrower","type":"address"}],"name":"hasPendingRewards","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"interestPayable","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"interestRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"interestReceiver","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastActiveIndexUpdate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastCollateralError_Redistribution","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastDebtError_Redistribution","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastFeeOperationTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"liquidationManager","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxBorrowingFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxRedemptionFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxSystemDebt","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minuteDecayFactor","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_debt","type":"uint256"},{"internalType":"uint256","name":"_collateral","type":"uint256"}],"name":"movePendingPositionRewardsToActiveBalances","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_borrower","type":"address"},{"internalType":"uint256","name":"_collateralAmount","type":"uint256"},{"internalType":"uint256","name":"_compositeDebt","type":"uint256"},{"internalType":"uint256","name":"NICR","type":"uint256"},{"internalType":"address","name":"_upperHint","type":"address"},{"internalType":"address","name":"_lowerHint","type":"address"}],"name":"openPosition","outputs":[{"internalType":"uint256","name":"stake","type":"uint256"},{"internalType":"uint256","name":"arrayIndex","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"permissionedPosition","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"priceFeed","outputs":[{"internalType":"contract IPriceFeed","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"protocolPosition","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_debtAmount","type":"uint256"},{"internalType":"address","name":"_firstRedemptionHint","type":"address"},{"internalType":"address","name":"_upperPartialRedemptionHint","type":"address"},{"internalType":"address","name":"_lowerPartialRedemptionHint","type":"address"},{"internalType":"uint256","name":"_partialRedemptionHintNICR","type":"uint256"},{"internalType":"uint256","name":"_maxIterations","type":"uint256"},{"internalType":"uint256","name":"_maxFeePercentage","type":"uint256"}],"name":"redeemCollateral","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"redemptionFeeFloor","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"rewardSnapshots","outputs":[{"internalType":"uint256","name":"collateral","type":"uint256"},{"internalType":"uint256","name":"debt","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_priceFeedAddress","type":"address"},{"internalType":"address","name":"_sortedPositionsAddress","type":"address"},{"internalType":"address","name":"_collateralToken","type":"address"}],"name":"setAddresses","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_collVaultRouter","type":"address"}],"name":"setCollVaultRouter","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_interestReceiver","type":"address"}],"name":"setInterestReceiver","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"minuteDecayFactor","type":"uint256"},{"internalType":"uint256","name":"redemptionFeeFloor","type":"uint256"},{"internalType":"uint256","name":"maxRedemptionFee","type":"uint256"},{"internalType":"uint256","name":"borrowingFeeFloor","type":"uint256"},{"internalType":"uint256","name":"maxBorrowingFee","type":"uint256"},{"internalType":"uint256","name":"interestRateInBps","type":"uint256"},{"internalType":"uint256","name":"maxDebt","type":"uint256"},{"internalType":"uint256","name":"MCR","type":"uint256"},{"internalType":"address","name":"collVaultRouter","type":"address"}],"internalType":"struct IFactory.DeploymentParams","name":"params","type":"tuple"}],"name":"setParameters","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_paused","type":"bool"}],"name":"setPaused","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_permissionedPosition","type":"address"},{"internalType":"address","name":"_protocolPosition","type":"address"}],"name":"setPermissionedParameters","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_permissionedPosition","type":"address"}],"name":"setPermissionedPosition","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_priceFeedAddress","type":"address"}],"name":"setPriceFeed","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_protocolPosition","type":"address"}],"name":"setProtocolPosition","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"sortedPositions","outputs":[{"internalType":"contract ISortedPositions","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"startSunset","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"sunsetting","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"surplusBalances","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"systemDeploymentTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalCollateralSnapshot","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalStakes","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalStakesSnapshot","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"updateBalances","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_isDebtIncrease","type":"bool"},{"internalType":"uint256","name":"_debtChange","type":"uint256"},{"internalType":"uint256","name":"_netDebtChange","type":"uint256"},{"internalType":"bool","name":"_isCollIncrease","type":"bool"},{"internalType":"uint256","name":"_collChange","type":"uint256"},{"internalType":"address","name":"_upperHint","type":"address"},{"internalType":"address","name":"_lowerHint","type":"address"},{"internalType":"address","name":"_borrower","type":"address"},{"internalType":"address","name":"_receiver","type":"address"}],"name":"updatePositionFromAdjustment","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"}]Contract Creation Code
610160604052348015610010575f80fd5b506040516152cc3803806152cc83398101604081905261002f9161019f565b60808190526001600160a01b03861660a0819052604080516378e9792560e01b815290518892889288928892889288928892916378e979259160048083019260209291908290030181865afa15801561008a573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906100ae919061020d565b60c052506001600160a01b03861615806100cf57506001600160a01b038516155b806100e157506001600160a01b038416155b806100f357506001600160a01b038316155b8061010557506001600160a01b038216155b156101565760405162461bcd60e51b815260206004820152601a60248201527f506f736974696f6e4d616e616765723a20302061646472657373000000000000604482015260640160405180910390fd5b506001600160a01b039384166101205291831661014052821660e05216610100525061022495505050505050565b80516001600160a01b038116811461019a575f80fd5b919050565b5f805f805f8060c087890312156101b4575f80fd5b6101bd87610184565b95506101cb60208801610184565b94506101d960408801610184565b93506101e760608801610184565b92506101f560808801610184565b91505f60a08801519050809150509295509295509295565b5f6020828403121561021d575f80fd5b5051919050565b60805160a05160c05160e051610100516101205161014051614f776103555f395f8181610b7001528181611a1301528181611b29015281816123a0015281816128a601528181612e8d015281816140090152818161408a015261450d01525f8181612e56015261453a01525f81816105d6015261356301525f81816107f20152818161226c01528181612f260152613cd101525f611ba201525f818161078101528181610e4f01528181610f49015281816111d20152818161132d015281816113e701528181611479015281816115ef015281816116e9015281816118cb0152818161197901528181611a4201528181611be501528181611c410152818161217f015261277c01525f81816106f701528181613b7601528181613bf101528181613c3001526145f00152614f775ff3fe608060405234801561000f575f80fd5b50600436106104fe575f3560e01c80637e95d6641161029a578063bcd375261161016c578063d30612e1116100d5578063e9186c941161008f578063e9186c9414610b0c578063ea23a27a14610b1f578063eb7a7f7e14610b32578063ec38a05d14610b45578063f36b242514610b63578063f8d8989814610b6b575f80fd5b8063d30612e114610ac3578063d380a37c14610acb578063d38b055814610ad4578063d5b3563514610add578063e2ac77b014610af0578063e47cf0c314610b03575f80fd5b8063c77cf61511610126578063c77cf61514610a44578063c98eef6214610a57578063d128080c14610a82578063d12ae84114610a8a578063d23ab46114610a9d578063d293c71014610ab0575f80fd5b8063bcd37526146109a2578063be2c377b146109b5578063bf88dd71146109be578063bf9befb114610a20578063c045e47d14610a29578063c52861f214610a3c575f80fd5b80639bf9b9611161020e578063b0d8e181116101c8578063b0d8e1811461091a578063b2016bd41461092d578063b279906e14610940578063b2f29d7b14610953578063b91af97c14610966578063bc006c3814610999575f80fd5b80639bf9b961146108b75780639e994ca8146108c95780639ed72542146108dc578063a20baee6146108e5578063a223ce37146108f4578063a27bcdaa14610907575f80fd5b80638da5cb5b1161025f5780638da5cb5b1461087457806391245f9f1461087c5780639484fb8e1461088557806396660b181461089257806396d711ff1461089b5780639bf60244146108a4575f80fd5b80637e95d66414610849578063807d138d14610852578063874d6d811461085b578063887105d3146108635780638bbb1de81461086b575f80fd5b8063452a9320116103d35780636b6c07741161034757806377553ad41161030157806377553ad4146107ed578063789c6b9314610814578063794e572414610827578063795d26c3146108305780637a83a34e146108385780637c3a00fd14610840575f80fd5b80636b6c07741461077c5780636c302c76146107a35780636f3fe404146107b6578063720fbe2c146107be578063724e78da146107c7578063741bef1a146107da575f80fd5b80634ba4a28b116103985780634ba4a28b146106f25780635728ddda146107195780635c975abb1461072c5780635cef58f91461074e578063631203b01461076157806366ca4a2114610774575f80fd5b8063452a9320146106b3578063477d66cf146106bb5780634820fe56146106ce5780634870dd9a146106d65780634af79734146106df575f80fd5b8063219efc461161047557806331c7a2611161042f57806331c7a2611461066a57806333d53b5914610673578063363bf9641461067c5780633cf1b05b1461068f5780633d397f99146106975780634056d9fc146106aa575f80fd5b8063219efc46146106175780632b11551a1461062a5780632d1c477e146106325780632d587e10146106455780632f41d9e11461064e5780632f5c83a814610661575f80fd5b80631673c79a116104c65780631673c79a1461058557806316c38b3c146105ab5780631983fb40146105be5780631ef3a04c146105d15780631f68f20a1461060557806320d17d7b1461060e575f80fd5b806301c799fc146105025780630b0765571461052a5780630b216022146105525780630fdb11cf146105675780631289fefb1461057d575b5f80fd5b61050a610b92565b604080519384526020840192909252908201526060015b60405180910390f35b61053d6105383660046147d9565b610bb8565b60408051928352602083019190915201610521565b6105656105603660046147f4565b610bd4565b005b61056f610e3a565b604051908152602001610521565b610565610f47565b61053d6105933660046147d9565b60216020525f90815260409020805460019091015482565b6105656105b936600461481b565b61105a565b61056f6105cc3660046147d9565b6110f7565b6105f87f000000000000000000000000000000000000000000000000000000000000000081565b6040516105219190614836565b61056f60105481565b61056f601e5481565b61056561062536600461484a565b61112c565b61056f6111bf565b61056561064036600461488d565b6111d0565b61056f600d5481565b61056561065c3660046147d9565b611296565b61056f600a5481565b61056f60085481565b61056f60155481565b61056561068a3660046148c4565b6112b5565b60225461056f565b6105656106a53660046147d9565b61132b565b61056f60095481565b6105f86113e4565b61056f6106c936600461490c565b611465565b60195461056f565b61056f6103e881565b6105656106ed3660046147d9565b611477565b61056f7f000000000000000000000000000000000000000000000000000000000000000081565b61056561072736600461488d565b611548565b600f5461073e90610100900460ff1681565b6040519015158152602001610521565b61056561075c3660046147d9565b6115ed565b61056f61076f36600461490c565b6116a6565b61056f6116b2565b6105f87f000000000000000000000000000000000000000000000000000000000000000081565b6105656107b1366004614923565b6116c3565b6105656116d5565b61056f600e5481565b6105656107d53660046147d9565b6116e7565b6001546105f8906001600160a01b031681565b6105f87f000000000000000000000000000000000000000000000000000000000000000081565b610565610822366004614943565b6117ed565b61056f60045481565b61056f611824565b610565611876565b61056f600b5481565b61056f60065481565b61056f60135481565b61056f611b98565b61056f611bd1565b61056f600c5481565b6105f8611be2565b61056f60075481565b600f5461073e9060ff1681565b61056f601b5481565b61056f60145481565b6023546105f8906001600160a01b031681565b5f546105f8906001600160a01b031681565b6105656108d73660046147d9565b611c3f565b61056f60185481565b61056f670de0b6b3a764000081565b6024546105f8906001600160a01b031681565b61053d61091536600461496d565b611d38565b61056f6109283660046147d9565b611fca565b6002546105f8906001600160a01b031681565b6105f861094e36600461490c565b611fee565b61056f61096136600461490c565b61201c565b6109796109743660046147d9565b612049565b604080519485526020850193909352918301526060820152608001610521565b61056f60055481565b6105656109b03660046149d0565b6120cd565b61056f601d5481565b610a0e6109cc3660046147d9565b601f6020525f90815260409020805460018201546002830154600384015460049094015492939192909160ff8116916101009091046001600160801b03169086565b60405161052196959493929190614a4d565b61056f60125481565b6003546105f8906001600160a01b031681565b61056f612940565b601c546105f8906001600160a01b031681565b61056f610a653660046147d9565b6001600160a01b03165f908152601f602052604090206002015490565b61056f612951565b61053d610a983660046147d9565b612995565b61050a610aab366004614a98565b612aaa565b61056f610abe366004614943565b612cc6565b61056f612cec565b61056f60115481565b61056f60175481565b61056f610aeb36600461490c565b612d20565b61073e610afe3660046147d9565b612d32565b61056f60165481565b610565610b1a366004614b33565b612d91565b610565610b2d366004614b65565b612dad565b61053d610b403660046147d9565b612ef7565b61056f610b533660046147d9565b602080525f908152604090205481565b61056f612f0f565b6105f87f000000000000000000000000000000000000000000000000000000000000000081565b5f805f610b9d611bd1565b610ba5611824565b610bad610e3a565b925092509250909192565b5f80610bc2612f1b565b610bcb83612f83565b91509150915091565b600f5460ff1615610c2c5760405162461bcd60e51b815260206004820152601a60248201527f43616e6e6f74206368616e67652061667465722073756e73657400000000000060448201526064015b60405180910390fd5b670de0b6b3a76400008160e001351015610c7c5760405162461bcd60e51b81526020600482015260116024820152704d43522063616e6e6f74203c203130302560781b6044820152606401610c23565b60055415610cbc57610c8c611be2565b6001600160a01b0316336001600160a01b031614610cbc5760405162461bcd60e51b8152600401610c2390614bad565b670d8f91d06741510c813510801590610cde5750670de07829b2adec28813511155b610ce6575f80fd5b8060400135816020013511158015610d0a5750670de0b6b3a7640000816040013511155b610d12575f80fd5b8060800135816060013511158015610d365750670de0b6b3a7640000816080013511155b610d3e575f80fd5b610d466130b2565b508035600555602081013560065560408101356007556060810135600855608081013560095560c0810135600a55610d86610120820161010083016147d9565b5f80546001600160a01b0319166001600160a01b0392909216919091178155610db56301e13380612710614be5565b610dce60a0840135676765c793fa10079d601b1b614be5565b610dd89190614c10565b9050600b548114610df657610deb613104565b5042600d55600b8190555b60e08201356004556040517fdba82a425948402262be7f293af6e198241329ec2ff19e69724a0bcdcda31f4d90610e2e908490614c23565b60405180910390a15050565b6001545f906001600160a01b031680610ed0577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663741bef1a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610ea9573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610ecd9190614c9a565b90505b600254604051635670bcc760e11b81526001600160a01b038381169263ace1798e92610f029290911690600401614836565b602060405180830381865afa158015610f1d573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610f419190614cb5565b91505090565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610fa3573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610fc79190614c9a565b6001600160a01b0316336001600160a01b031614610ff75760405162461bcd60e51b8152600401610c2390614bad565b600f805460ff1916600117905561100c613104565b5061101d6301e13380612710614be5565b611034676765c793fa10079d601b1b611388614be5565b61103e9190614c10565b600b5542600d555f6006819055600a8190556010819055600755565b80801561107f575061106a6113e4565b6001600160a01b0316336001600160a01b0316145b806110a2575061108d611be2565b6001600160a01b0316336001600160a01b0316145b6110dd5760405162461bcd60e51b815260206004820152600c60248201526b155b985d5d1a1bdc9a5e995960a21b6044820152606401610c23565b600f80549115156101000261ff0019909216919091179055565b6001600160a01b0381165f908152601f602052604081206003015460ff16600481111561112657611126614a39565b92915050565b611134612f1b565b60016001600160a01b0385165f908152601f602052604090206003015460ff16600481111561116557611165614a39565b146111825760405162461bcd60e51b8152600401610c2390614ccc565b61118b84613165565b6111968460026131ae565b80601a546111a49190614d0d565b601a556111b1838361343e565b6111b96134a6565b50505050565b5f6111cb6010546134fa565b905090565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561122c573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906112509190614c9a565b6001600160a01b0316336001600160a01b0316146112805760405162461bcd60e51b8152600401610c2390614bad565b61128982613514565b61129281613536565b5050565b61129e613558565b6112a781613165565b6112b28160036131ae565b50565b6003546001600160a01b0316156112ca575f80fd5b600180546001600160a01b039485166001600160a01b03199182161790915560038054938516938216939093179092556002805491909316911617905542600e819055600f805460ff19169055676765c793fa10079d601b1b600c55600d55565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611387573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906113ab9190614c9a565b6001600160a01b0316336001600160a01b0316146113db5760405162461bcd60e51b8152600401610c2390614bad565b6112b281613514565b5f7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663452a93206040518163ffffffff1660e01b8152600401602060405180830381865afa158015611441573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906111cb9190614c9a565b5f6111266114716116b2565b836135ca565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156114d3573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906114f79190614c9a565b6001600160a01b0316336001600160a01b0316146115275760405162461bcd60e51b8152600401610c2390614bad565b5f80546001600160a01b0319166001600160a01b0392909216919091179055565b5f546001600160a01b0316331461155d573391505b6001600160a01b0382165f908152602080526040902054806115c15760405162461bcd60e51b815260206004820181905260248201527f4e6f20636f6c6c61746572616c20617661696c61626c6520746f20636c61696d6044820152606401610c23565b6001600160a01b038084165f9081526020805260408120556002546115e8911683836135e8565b505050565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611649573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061166d9190614c9a565b6001600160a01b0316336001600160a01b03161461169d5760405162461bcd60e51b8152600401610c2390614bad565b6112b281613536565b5f611126611471612f0f565b5f6111cb6116be61363e565b61367a565b6116cb613558565b6112928282613694565b6116dd613558565b6116e56136ed565b565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611743573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906117679190614c9a565b6001600160a01b0316336001600160a01b0316146117975760405162461bcd60e51b8152600401610c2390614bad565b600180546001600160a01b0319166001600160a01b0383161790556040517fe5b20b8497e4f3e2435ef9c20e2e26b47497ee13745ce1c681ad6640653119e6906117e2908390614836565b60405180910390a150565b6117f5613558565b6001600160a01b0382165f9081526020805260408120805483929061181b908490614d20565b90915550505050565b601a545f90816118326136f5565b9150508015611862575f6118528383676765c793fa10079d601b1b61375f565b905061185e8184614d20565b9250505b601e5461186f9083614d20565b9250505090565b61187e613104565b50601b54806118c45760405162461bcd60e51b8152602060048201526012602482015271139bdd1a1a5b99c81d1bc818dbdb1b1958dd60721b6044820152606401610c23565b5f611955827f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316636d52dffd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611925573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906119499190614d33565b61ffff1661271061375f565b90505f6119628284614d0d565b601c549091505f906001600160a01b03166119fc577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166371f8424f6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156119d3573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906119f79190614c9a565b611a09565b601c546001600160a01b03165b90508215611b0c577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166340c10f197f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663b3f006746040518163ffffffff1660e01b8152600401602060405180830381865afa158015611a9c573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611ac09190614c9a565b856040518363ffffffff1660e01b8152600401611ade929190614d54565b5f604051808303815f87803b158015611af5575f80fd5b505af1158015611b07573d5f803e3d5ffd5b505050505b8115611b8e576040516340c10f1960e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906340c10f1990611b609084908690600401614d54565b5f604051808303815f87803b158015611b77575f80fd5b505af1158015611b89573d5f803e3d5ffd5b505050505b50505f601b555050565b5f62093a80611bc77f000000000000000000000000000000000000000000000000000000000000000042614d0d565b6111cb9190614c10565b5f601d546019546111cb9190614d20565b5f7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611441573d5f803e3d5ffd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611c9b573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611cbf9190614c9a565b6001600160a01b0316336001600160a01b031614611cef5760405162461bcd60e51b8152600401610c2390614bad565b601c80546001600160a01b0319166001600160a01b0383169081179091556040517f085af60e444f2bfe4e6ad75d3227d2a8702123a3d663597ed1ca90a5f0c2c89c905f90a250565b600f545f908190610100900460ff1615611d645760405162461bcd60e51b8152600401610c2390614d6d565b611d6c612f1b565b600f5460ff1615611dbf5760405162461bcd60e51b815260206004820152601c60248201527f43616e6e6f74206f70656e207768696c652073756e73657474696e67000000006044820152606401610c23565b611dc888613807565b6001600160a01b0388165f908152601f602052604090206001600382015460ff166004811115611dfa57611dfa614a39565b03611e475760405162461bcd60e51b815260206004820152601f60248201527f426f72726f7765724f70733a20506f736974696f6e20697320616374697665006044820152606401610c23565b60038101805460ff1916600190811790915581018890558681555f611e6a613104565b600483018190559050611e7c8a6138c2565b611e858261393a565b6003546040516346f7cf8760e01b81529195506001600160a01b0316906346f7cf8790611ebc908d908b908b908b90600401614d98565b5f604051808303815f87803b158015611ed3575f80fd5b505af1158015611ee5573d5f803e3d5ffd5b5050505060228a908060018154018082558091505060019003905f5260205f20015f9091909190916101000a8154816001600160a01b0302191690836001600160a01b031602179055506001602280549050611f419190614d0d565b600383018054610100600160881b0319166101006001600160801b03841602179055601954909350611f74908a90614d20565b601955601a545f90611f87908a90614d20565b9050600a54601e5482611f9a9190614d20565b1115611fb85760405162461bcd60e51b8152600401610c2390614dc3565b601a5550919890975095505050505050565b5f805f611fd684612ef7565b915091505f611fe583836139b7565b95945050505050565b5f6022828154811061200257612002614dfa565b5f918252602090912001546001600160a01b031692915050565b5f612025612f1b565b5f61202e6130b2565b905061204261203c8261367a565b846135ca565b9392505050565b6001600160a01b0381165f908152601f602052604081208054600182015490929091819061207686612995565b600483015490945090925080156120ac575f6120906136f5565b5090508161209e8289614be5565b6120a89190614c10565b9650505b6120b68487614d20565b95506120c28386614d20565b945050509193509193565b5f60035f9054906101000a90046001600160a01b031690506121256040518061010001604052805f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81525090565b600654831015801561213957506007548311155b61217d5760405162461bcd60e51b81526020600482015260156024820152744d617820666565206e6f7420696e20626f756e647360581b6044820152606401610c23565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663c0c39a6f6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156121d9573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906121fd9190614e0e565b67ffffffffffffffff16600e546122149190614d20565b4210156122565760405162461bcd60e51b815260206004820152601060248201526f1093d3d514d514905417d411549253d160821b6044820152606401610c23565b61225e610e3a565b8160c00181815250506004547f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663b620115d6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156122c6573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906122ea9190614cb5565b10156123385760405162461bcd60e51b815260206004820152601c60248201527f43616e6e6f742072656465656d207768656e20544352203c204d4352000000006044820152606401610c23565b5f89116123875760405162461bcd60e51b815260206004820181905260248201527f416d6f756e74206d7573742062652067726561746572207468616e207a65726f6044820152606401610c23565b6040516370a0823160e01b815289906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906370a08231906123d5903390600401614836565b602060405180830381865afa1580156123f0573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906124149190614cb5565b10156124595760405162461bcd60e51b8152602060048201526014602482015273496e73756666696369656e742062616c616e636560601b6044820152606401610c23565b6124616136ed565b612469611824565b60e082015288815260c08101515f906124859084908b906139eb565b15612491575087612597565b826001600160a01b0316634d6228316040518163ffffffff1660e01b8152600401602060405180830381865afa1580156124cd573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906124f19190614c9a565b90505b6001600160a01b038116158015906125205750670de0b6b3a764000061251e828460c00151612cc6565b105b1561259757604051632dc9c0eb60e21b81526001600160a01b0384169063b72703ac90612551908490600401614836565b602060405180830381865afa15801561256c573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906125909190614c9a565b90506124f4565b845f036125a357606494505b6001600160a01b038116158015906125bb5750815115155b80156125c657505f85115b156126c457846125d581614e35565b9550505f836001600160a01b031663b72703ac836040518263ffffffff1660e01b81526004016126059190614836565b602060405180830381865afa158015612620573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906126449190614c9a565b905061264f82612f83565b50505f6126688584865f01518760c001518e8e8e613b2e565b905080604001511561267b5750506126c4565b8051602085015161268c9190614d20565b60208086019190915281015160408501516126a79190614d20565b6040850152805184516126ba9190614d0d565b84525090506125a3565b5f8260400151116127175760405162461bcd60e51b815260206004820152601b60248201527f556e61626c6520746f2072656465656d20616e7920616d6f756e7400000000006044820152606401610c23565b600f5460ff1661273a5761273882604001518360c001518460e00151613e2f565b505b600f5460ff1661275e5761275961274f6111bf565b8360400151613ec0565b612760565b5f5b606083018190526040830151612777919086613f30565b6128047f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663b3f006746040518163ffffffff1660e01b8152600401602060405180830381865afa1580156127d6573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906127fa9190614c9a565b836060015161343e565b816060015182604001516128189190614d0d565b826080018181525050336001600160a01b03167f08b6f1ce3f9ab2722e8ea40c31a3e3a806a41702c5994f29af43dc0c1f2837df8b846020015185604001518660600151604051612882949392919093845260208401929092526040830152606082015260800190565b60405180910390a26020820151604051632770a7eb60e21b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001691639dc29fac916128db913391600401614d54565b5f604051808303815f87803b1580156128f2575f80fd5b505af1158015612904573d5f803e3d5ffd5b5050506020830151601a546129199250614d0d565b601a55608082015161292c90339061343e565b6129346134a6565b50505050505050505050565b5f6111cb61294c61363e565b6134fa565b601a545f908161295f6136f5565b915050801561298f575f61297f8383676765c793fa10079d601b1b61375f565b905061298b8184614d20565b9250505b50919050565b6001600160a01b0381165f9081526021602090815260408083208151808301909252805480835260019091015492820192909252601554839283916129da9190614d0d565b90505f82602001516016546129ef9190614d0d565b90506129fb8183614d20565b1580612a36575060016001600160a01b0387165f908152601f602052604090206003015460ff166004811115612a3357612a33614a39565b14155b15612a4857505f958695509350505050565b6001600160a01b0386165f908152601f6020526040902060020154670de0b6b3a7640000612a768483614be5565b612a809190614c10565b670de0b6b3a7640000612a938484614be5565b612a9d9190614c10565b9550955050505050915091565b5f805f612ab5612f1b565b8880612abe57508b5b15612b3e57600f54610100900460ff1615612aeb5760405162461bcd60e51b8152600401610c2390614d6d565b600f5460ff1615612b3e5760405162461bcd60e51b815260206004820181905260248201527f43616e6e6f7420696e637265617365207768696c652073756e73657474696e676044820152606401610c23565b6001600160a01b0385165f908152601f602052604090206001600382015460ff166004811115612b7057612b70614a39565b14612b8d5760405162461bcd60e51b8152600401610c2390614ccc565b80548c15612bd1578d15612bb757612ba58c82614d20565b9050612bb2868d8f613fad565b612bcd565b612bc18c82614d0d565b9050612bcd868e614073565b8082555b60018201548a15612c22578b15612c0457612bec8b82614d20565b90508a601954612bfc9190614d20565b601955612c1a565b612c0e8b82614d0d565b9050612c1a878c61343e565b600183018190555b5f612c2d82846139b7565b905060035f9054906101000a90046001600160a01b03166001600160a01b0316632be212608a838e8e6040518563ffffffff1660e01b8152600401612c759493929190614d98565b5f604051808303815f87803b158015612c8c575f80fd5b505af1158015612c9e573d5f803e3d5ffd5b505050508183612cad8661393a565b9650965096505050505099509950999650505050505050565b5f805f612cd285612ef7565b915091505f612ce2838387614103565b9695505050505050565b612cfc6301e13380612710614be5565b612d13676765c793fa10079d601b1b611388614be5565b612d1d9190614c10565b81565b5f611126612d2c612940565b83613ec0565b5f60016001600160a01b0383165f908152601f602052604090206003015460ff166004811115612d6457612d64614a39565b14612d7057505f919050565b506015546001600160a01b039091165f908152602160205260409020541090565b612d99613558565b612da38383614073565b6115e8838261343e565b612db5613558565b612dbf8585614131565b6019548315612dda57612dd28482614d0d565b601981905590505b601254601355601d548290612def9083614d20565b612df99190614d0d565b60148190556013546040517f51bf4c63ec3cba9d03d43238abbdd979dd91bd16d9895c74ceea9118c7baaf6092612e37928252602082015260400190565b60405180910390a1604051631062c15f60e11b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811660048301528881166024830152604482018590527f000000000000000000000000000000000000000000000000000000000000000016906320c582be906064015f604051808303815f87803b158015612ece575f80fd5b505af1158015612ee0573d5f803e3d5ffd5b50505050612eee878361343e565b50505050505050565b5f80612f0283612049565b5090959194509092505050565b5f6111cb60105461367a565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146116e55760405162461bcd60e51b815260206004820152600d60248201526c43616c6c6572206e6f7420424f60981b6044820152606401610c23565b6001600160a01b0381165f908152601f6020526040812081906001600382015460ff166004811115612fb757612fb7614a39565b036130ac5760048101545f612fca613104565b835460018501549650945090508381831015612fff5782612feb8387614be5565b612ff59190614c10565b6004850183905594505b6015546001600160a01b0388165f90815260216020526040902054101561309d575f8061302b89612995565b909250905061303a8289614d20565b60018701819055975061304d8188614d20565b9650613058896138c2565b6130628183613694565b886001600160a01b03165f80516020614f22833981519152888a89600201545f6040516130929493929190614e5e565b60405180910390a250505b8481146130a8578484555b5050505b50915091565b5f806130bc61363e565b60108190556040518181529091507fc454ee9b76c52f782a256af821b857ca6e125d1e3333bcede402fec2bed9600c9060200160405180910390a16130ff61429f565b919050565b5f805f61310f6136f5565b9092509050801561298f57601a545f6131348284676765c793fa10079d601b1b61375f565b90506131408183614d20565b601a55601b54613151908290614d20565b601b555050600c82905542600d5550919050565b6001600160a01b0381165f908152601f602052604090206002015460125461318e908290614d0d565b601255506001600160a01b03165f908152601f6020526040812060020155565b6022546001600160a01b0383165f908152601f6020526040902060038101805484919060ff191660018360048111156131e9576131e9614a39565b02179055505f6001808301829055818355600483018290556003546001600160a01b03878116845260216020526040842084815583019390935591909116908311801561329557506001816001600160a01b031663de8fa4316040518163ffffffff1660e01b8152600401602060405180830381865afa15801561326f573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906132939190614cb5565b115b1561339a57600382015461010090046001600160801b03165f60226132bb600187614d0d565b815481106132cb576132cb614dfa565b5f91825260209091200154602280546001600160a01b03909216925082916001600160801b03851690811061330257613302614dfa565b5f91825260208083209190910180546001600160a01b0319166001600160a01b03948516179055918316808252601f83526040918290206003018054610100600160881b0319166101006001600160801b038816908102919091179091558251918252928101929092527f2391d278b0562640dd6add67aa715b4dab2327f1ec896819ff2a809adea29a36910160405180910390a150505b60228054806133ab576133ab614e80565b5f8281526020902081015f1990810180546001600160a01b0319169055019055604051631484968760e11b81526001600160a01b038216906329092d0e906133f7908890600401614836565b5f604051808303815f87803b15801561340e575f80fd5b505af1158015613420573d5f803e3d5ffd5b50505060039092018054610100600160881b03191690555050505050565b801561129257806019546134529190614d0d565b6019556040517f342693d2465f6f44931e41128424a0227e0cbc69d1c3917a839e6de71696d44c906134879084908490614d54565b60405180910390a1600254611292906001600160a01b031683836135e8565b6022545f036116e557676765c793fa10079d601b1b600c5542600d555f60128190556013819055601481905560158190556016819055601781905560188190556019819055601a819055601d819055601e55565b5f6111268260065461350c9190614d20565b600754614311565b602380546001600160a01b0319166001600160a01b0392909216919091179055565b602480546001600160a01b0319166001600160a01b0392909216919091179055565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146116e55760405162461bcd60e51b81526020600482015260176024820152762737ba102634b8bab4b230ba34b7b71026b0b730b3b2b960491b6044820152606401610c23565b5f670de0b6b3a76400006135de8385614be5565b6120429190614c10565b6115e88363a9059cbb60e01b8484604051602401613607929190614d54565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152614326565b5f806136486143f7565b90505f61365760055483614408565b9050670de0b6b3a7640000816010546136709190614be5565b61186f9190614c10565b5f6111268260085461368c9190614d20565b600954614311565b81601e5f8282546136a59190614d0d565b9250508190555081601a5f8282546136bd9190614d20565b9250508190555080601d5f8282546136d59190614d0d565b925050819055508060195f82825461181b9190614d20565b6112b2613104565b600d545f90819042810361370e575050600c54915f9150565b600b54600c5493508015613759575f6137278342614d0d565b90506137338282614be5565b935061374b8585676765c793fa10079d601b1b61375f565b6137559086614d20565b9450505b50509091565b5f80805f19858709858702925082811083820303915050805f036137965783828161378c5761378c614bfc565b0492505050612042565b8084116137a1575f80fd5b5f84868809600260036001881981018916988990049182028318808302840302808302840302808302840302808302840302808302840302918202909203025f889003889004909101858311909403939093029303949094049190911702949350505050565b6023546001600160a01b038281169116148061383057506024546001600160a01b038281169116145b6112b25760405162461bcd60e51b815260206004820152605760248201527f5065726d697373696f6e6564506f736974696f6e4d616e616765723a204f6e6c60448201527f7920746865205065726d697373696f6e65642f50726f746f636f6c506f73697460648201527634b7b71031b0b71037b832b71030903837b9b4ba34b7b760491b608482015260a401610c23565b60155460165460408051808201825283815260208082018481526001600160a01b0387165f90815260218352849020925183555160019092019190915581518481529081018390527fc2910901d6342262f6857ac83c05564d215eef237fb5bcdf69013b47bbf4b8a8910160405180910390a1505050565b5f8061394983600101546144b0565b60028401805490829055601254919250905f908390613969908490614d0d565b6139739190614d20565b60128190556040518181529091507f6bac5e0eb3c44eb03a60ab11ec3a2c051771616aecadbcfff2630aabae5203829060200160405180910390a150909392505050565b5f81156139e357816139d268056bc75e2d6310000085614be5565b6139dc9190614c10565b9050611126565b505f19611126565b5f6001600160a01b0383161580613a6a5750604051630bb7c8fd60e31b81526001600160a01b03851690635dbe47e890613a29908690600401614836565b602060405180830381865afa158015613a44573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613a689190614e94565b155b80613a855750670de0b6b3a7640000613a838484612cc6565b105b15613a9157505f612042565b60405163765e015960e01b81525f906001600160a01b0386169063765e015990613abf908790600401614836565b602060405180830381865afa158015613ada573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613afe9190614c9a565b90506001600160a01b0381161580611fe55750670de0b6b3a7640000613b248285612cc6565b1095945050505050565b613b5160405180606001604052805f81526020015f81526020015f151581525090565b6001600160a01b0387165f908152601f602052604090208054613ba0908890613b9b907f000000000000000000000000000000000000000000000000000000000000000090614d0d565b614311565b8083528690613bb890670de0b6b3a764000090614be5565b613bc29190614c10565b6020830152815181545f91613bd691614d0d565b90505f83602001518360010154613bed9190614d0d565b90507f00000000000000000000000000000000000000000000000000000000000000008203613c8f57613c1f8a613165565b613c2a8a60046131ae565b613c558a7f0000000000000000000000000000000000000000000000000000000000000000836144f6565b896001600160a01b03165f80516020614f228339815191525f805f6003604051613c829493929190614e5e565b60405180910390a2613e20565b5f613c9a82846139b7565b90505f818711613cb357613cae8783614d0d565b613cbd565b613cbd8288614d0d565b90506601c6bf52634000811180613d5a57507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663969c24526040518163ffffffff1660e01b8152600401602060405180830381865afa158015613d2b573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613d4f9190614cb5565b613d58856145ea565b105b15613d715750506001604085015250613e24915050565b5060405163015f109360e51b81526001600160a01b038d1690632be2126090613da4908e9085908d908d90600401614d98565b5f604051808303815f87803b158015613dbb575f80fd5b505af1158015613dcd573d5f803e3d5ffd5b5050508385555060018401829055613de48461393a565b508a6001600160a01b03165f80516020614f22833981519152848487600201546003604051613e169493929190614e5e565b60405180910390a2505b5050505b979650505050505050565b5f80613e3961363e565b90505f83613e478688614be5565b613e519190614c10565b90505f613e5f600283614c10565b613e699084614d20565b9050613e7d81670de0b6b3a7640000614311565b60108190556040518181529091507fc454ee9b76c52f782a256af821b857ca6e125d1e3333bcede402fec2bed9600c9060200160405180910390a1612ce261429f565b5f80670de0b6b3a7640000613ed58486614be5565b613edf9190614c10565b90508281106120425760405162461bcd60e51b815260206004820152601f60248201527f46656520657863656564732072657475726e656420636f6c6c61746572616c006044820152606401610c23565b5f825f03613f3e575f613f5b565b82613f51670de0b6b3a764000086614be5565b613f5b9190614c10565b9050818111156111b95760405162461bcd60e51b815260206004820152601d60248201527f4665652065786365656465642070726f7669646564206d6178696d756d0000006044820152606401610c23565b5f82601a54613fbc9190614d20565b9050600a54601e5482613fcf9190614d20565b1115613fed5760405162461bcd60e51b8152600401610c2390614dc3565b601a8190556040516340c10f1960e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906340c10f19906140409087908690600401614d54565b5f604051808303815f87803b158015614057575f80fd5b505af1158015614069573d5f803e3d5ffd5b5050505050505050565b604051632770a7eb60e21b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690639dc29fac906140c19085908590600401614d54565b5f604051808303815f87803b1580156140d8575f80fd5b505af11580156140ea573d5f803e3d5ffd5b5050505080601a546140fc9190614d0d565b601a555050565b5f8215614129575f836141168487614be5565b6141209190614c10565b91506120429050565b505f19612042565b815f0361413c575050565b6017545f90614153670de0b6b3a764000084614be5565b61415d9190614d20565b90505f601854670de0b6b3a7640000856141779190614be5565b6141819190614d20565b6012549091505f6141928285614c10565b90505f61419f8385614c10565b90506141ab8383614be5565b6141b59086614d0d565b6017556141c28382614be5565b6141cc9085614d0d565b6018556015545f906141df908490614d20565b90505f826016546141f09190614d20565b6015839055601681905560408051848152602081018390529192507f9f8bc8ab0daf5bceef75ecfd2085d1fcc6548c657ea970d9a23a60610d0737e3910160405180910390a188601a5f8282546142479190614d0d565b9250508190555088601e5f82825461425f9190614d20565b9250508190555087601d5f8282546142779190614d20565b925050819055508760195f82825461428f9190614d0d565b9091555050505050505050505050565b5f601154426142ae9190614d0d565b9050603c81106112b257603c6142c26143f7565b6142cc9190614be5565b60115f8282546142dc9190614d20565b90915550506040514281527f860f8d2f0c74dd487e89e2883e3b25b8159ce1e1b3433a291cba7b82c508f3bc906020016117e2565b5f81831061431f5781612042565b5090919050565b5f61437a826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166146159092919063ffffffff16565b8051909150156115e857808060200190518101906143989190614e94565b6115e85760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610c23565b5f603c60115442611bc79190614d0d565b5f631f54050082111561441d57631f54050091505b815f036144335750670de0b6b3a7640000611126565b670de0b6b3a764000083835b60018111156144a657614453600282614eaf565b5f0361447757614463828361462b565b9150614470600282614c10565b905061443f565b614481828461462b565b925061448d828361462b565b9150600261449c600183614d0d565b6144709190614c10565b612ce2828461462b565b6014545f9081908082036144c6578391506144ef565b601354806144d6576144d6614ec2565b816144e18287614be5565b6144eb9190614c10565b9250505b5092915050565b604051632770a7eb60e21b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690639dc29fac90614564907f0000000000000000000000000000000000000000000000000000000000000000908690600401614d54565b5f604051808303815f87803b15801561457b575f80fd5b505af115801561458d573d5f803e3d5ffd5b5050505081601a5461459f9190614d0d565b601a556001600160a01b0383165f908152602080526040812080548392906145c8908490614d20565b925050819055508060195f8282546145e09190614d0d565b9091555050505050565b5f6111267f000000000000000000000000000000000000000000000000000000000000000083614d0d565b606061462384845f85614661565b949350505050565b5f806146378385614be5565b9050670de0b6b3a764000061464d600282614c10565b6146579083614d20565b6146239190614c10565b6060824710156146c25760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401610c23565b5f80866001600160a01b031685876040516146dd9190614ed6565b5f6040518083038185875af1925050503d805f8114614717576040519150601f19603f3d011682016040523d82523d5f602084013e61471c565b606091505b5091509150613e2487838387606083156147965782515f0361478f576001600160a01b0385163b61478f5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610c23565b5081614623565b61462383838151156147ab5781518083602001fd5b8060405162461bcd60e51b8152600401610c239190614eec565b6001600160a01b03811681146112b2575f80fd5b5f602082840312156147e9575f80fd5b8135612042816147c5565b5f610120828403128015614806575f80fd5b509092915050565b80151581146112b2575f80fd5b5f6020828403121561482b575f80fd5b81356120428161480e565b6001600160a01b0391909116815260200190565b5f805f806080858703121561485d575f80fd5b8435614868816147c5565b93506020850135614878816147c5565b93969395505050506040820135916060013590565b5f806040838503121561489e575f80fd5b82356148a9816147c5565b915060208301356148b9816147c5565b809150509250929050565b5f805f606084860312156148d6575f80fd5b83356148e1816147c5565b925060208401356148f1816147c5565b91506040840135614901816147c5565b809150509250925092565b5f6020828403121561491c575f80fd5b5035919050565b5f8060408385031215614934575f80fd5b50508035926020909101359150565b5f8060408385031215614954575f80fd5b823561495f816147c5565b946020939093013593505050565b5f805f805f8060c08789031215614982575f80fd5b863561498d816147c5565b955060208701359450604087013593506060870135925060808701356149b2816147c5565b915060a08701356149c2816147c5565b809150509295509295509295565b5f805f805f805f60e0888a0312156149e6575f80fd5b8735965060208801356149f8816147c5565b95506040880135614a08816147c5565b94506060880135614a18816147c5565b9699959850939660808101359560a0820135955060c0909101359350915050565b634e487b7160e01b5f52602160045260245ffd5b868152602081018690526040810185905260c0810160058510614a7257614a72614a39565b60608201949094526001600160801b0392909216608083015260a0909101529392505050565b5f805f805f805f805f6101208a8c031215614ab1575f80fd5b8935614abc8161480e565b985060208a0135975060408a0135965060608a0135614ada8161480e565b955060808a0135945060a08a0135614af1816147c5565b935060c08a0135614b01816147c5565b925060e08a0135614b11816147c5565b91506101008a0135614b22816147c5565b809150509295985092959850929598565b5f805f60608486031215614b45575f80fd5b8335614b50816147c5565b95602085013595506040909401359392505050565b5f805f805f8060c08789031215614b7a575f80fd5b8635614b85816147c5565b9860208801359850604088013597606081013597506080810135965060a00135945092505050565b6020808252600a908201526927b7363c9037bbb732b960b11b604082015260600190565b634e487b7160e01b5f52601160045260245ffd5b808202811582820484141761112657611126614bd1565b634e487b7160e01b5f52601260045260245ffd5b5f82614c1e57614c1e614bfc565b500490565b813581526020808301359082015260408083013590820152606080830135908201526080808301359082015260a0808301359082015260c0808301359082015260e080830135908201526101208101610100830135614c81816147c5565b6001600160a01b03166101009290920191909152919050565b5f60208284031215614caa575f80fd5b8151612042816147c5565b5f60208284031215614cc5575f80fd5b5051919050565b60208082526021908201527f506f736974696f6e20636c6f736564206f7220646f6573206e6f7420657869736040820152601d60fa1b606082015260800190565b8181038181111561112657611126614bd1565b8082018082111561112657611126614bd1565b5f60208284031215614d43575f80fd5b815161ffff81168114612042575f80fd5b6001600160a01b03929092168252602082015260400190565b60208082526011908201527010dbdb1b185d195c985b0814185d5cd959607a1b604082015260600190565b6001600160a01b03948516815260208101939093529083166040830152909116606082015260800190565b6020808252601d908201527f436f6c6c61746572616c2064656274206c696d69742072656163686564000000604082015260600190565b634e487b7160e01b5f52603260045260245ffd5b5f60208284031215614e1e575f80fd5b815167ffffffffffffffff81168114612042575f80fd5b5f81614e4357614e43614bd1565b505f190190565b60048110614e5a57614e5a614a39565b9052565b848152602081018490526040810183905260808101611fe56060830184614e4a565b634e487b7160e01b5f52603160045260245ffd5b5f60208284031215614ea4575f80fd5b81516120428161480e565b5f82614ebd57614ebd614bfc565b500690565b634e487b7160e01b5f52600160045260245ffd5b5f82518060208501845e5f920191825250919050565b602081525f82518060208401528060208501604085015e5f604082850101526040601f19601f8301168401019150509291505056fe4fe7fb62190647b8a7596709832f68a365082b18206e55ae330b95593c369affa2646970667358221220195e3f78c14044321bcd2e37d0d99b55a0b623110838e1bb64abb1b416068d4a64736f6c634300081a0033000000000000000000000000f6ec524105548c37d3c2eb482ba197ae19740d57000000000000000000000000130541a39cfaa89c9ed8f387d479b277321d1ad40000000000000000000000000f26bbb8962d73bc891327f14db5162d5279899f00000000000000000000000049fd0c4fb5172b20b7636b13c49fb15da52d5bd4000000000000000000000000fa2de0dcaa6dfdc0d01ad2677258a641bdae08400000000000000000000000000000000000000000000000000de0b6b3a7640000
Deployed Bytecode
0x608060405234801561000f575f80fd5b50600436106104fe575f3560e01c80637e95d6641161029a578063bcd375261161016c578063d30612e1116100d5578063e9186c941161008f578063e9186c9414610b0c578063ea23a27a14610b1f578063eb7a7f7e14610b32578063ec38a05d14610b45578063f36b242514610b63578063f8d8989814610b6b575f80fd5b8063d30612e114610ac3578063d380a37c14610acb578063d38b055814610ad4578063d5b3563514610add578063e2ac77b014610af0578063e47cf0c314610b03575f80fd5b8063c77cf61511610126578063c77cf61514610a44578063c98eef6214610a57578063d128080c14610a82578063d12ae84114610a8a578063d23ab46114610a9d578063d293c71014610ab0575f80fd5b8063bcd37526146109a2578063be2c377b146109b5578063bf88dd71146109be578063bf9befb114610a20578063c045e47d14610a29578063c52861f214610a3c575f80fd5b80639bf9b9611161020e578063b0d8e181116101c8578063b0d8e1811461091a578063b2016bd41461092d578063b279906e14610940578063b2f29d7b14610953578063b91af97c14610966578063bc006c3814610999575f80fd5b80639bf9b961146108b75780639e994ca8146108c95780639ed72542146108dc578063a20baee6146108e5578063a223ce37146108f4578063a27bcdaa14610907575f80fd5b80638da5cb5b1161025f5780638da5cb5b1461087457806391245f9f1461087c5780639484fb8e1461088557806396660b181461089257806396d711ff1461089b5780639bf60244146108a4575f80fd5b80637e95d66414610849578063807d138d14610852578063874d6d811461085b578063887105d3146108635780638bbb1de81461086b575f80fd5b8063452a9320116103d35780636b6c07741161034757806377553ad41161030157806377553ad4146107ed578063789c6b9314610814578063794e572414610827578063795d26c3146108305780637a83a34e146108385780637c3a00fd14610840575f80fd5b80636b6c07741461077c5780636c302c76146107a35780636f3fe404146107b6578063720fbe2c146107be578063724e78da146107c7578063741bef1a146107da575f80fd5b80634ba4a28b116103985780634ba4a28b146106f25780635728ddda146107195780635c975abb1461072c5780635cef58f91461074e578063631203b01461076157806366ca4a2114610774575f80fd5b8063452a9320146106b3578063477d66cf146106bb5780634820fe56146106ce5780634870dd9a146106d65780634af79734146106df575f80fd5b8063219efc461161047557806331c7a2611161042f57806331c7a2611461066a57806333d53b5914610673578063363bf9641461067c5780633cf1b05b1461068f5780633d397f99146106975780634056d9fc146106aa575f80fd5b8063219efc46146106175780632b11551a1461062a5780632d1c477e146106325780632d587e10146106455780632f41d9e11461064e5780632f5c83a814610661575f80fd5b80631673c79a116104c65780631673c79a1461058557806316c38b3c146105ab5780631983fb40146105be5780631ef3a04c146105d15780631f68f20a1461060557806320d17d7b1461060e575f80fd5b806301c799fc146105025780630b0765571461052a5780630b216022146105525780630fdb11cf146105675780631289fefb1461057d575b5f80fd5b61050a610b92565b604080519384526020840192909252908201526060015b60405180910390f35b61053d6105383660046147d9565b610bb8565b60408051928352602083019190915201610521565b6105656105603660046147f4565b610bd4565b005b61056f610e3a565b604051908152602001610521565b610565610f47565b61053d6105933660046147d9565b60216020525f90815260409020805460019091015482565b6105656105b936600461481b565b61105a565b61056f6105cc3660046147d9565b6110f7565b6105f87f000000000000000000000000fa2de0dcaa6dfdc0d01ad2677258a641bdae084081565b6040516105219190614836565b61056f60105481565b61056f601e5481565b61056561062536600461484a565b61112c565b61056f6111bf565b61056561064036600461488d565b6111d0565b61056f600d5481565b61056561065c3660046147d9565b611296565b61056f600a5481565b61056f60085481565b61056f60155481565b61056561068a3660046148c4565b6112b5565b60225461056f565b6105656106a53660046147d9565b61132b565b61056f60095481565b6105f86113e4565b61056f6106c936600461490c565b611465565b60195461056f565b61056f6103e881565b6105656106ed3660046147d9565b611477565b61056f7f0000000000000000000000000000000000000000000000000de0b6b3a764000081565b61056561072736600461488d565b611548565b600f5461073e90610100900460ff1681565b6040519015158152602001610521565b61056561075c3660046147d9565b6115ed565b61056f61076f36600461490c565b6116a6565b61056f6116b2565b6105f87f000000000000000000000000f6ec524105548c37d3c2eb482ba197ae19740d5781565b6105656107b1366004614923565b6116c3565b6105656116d5565b61056f600e5481565b6105656107d53660046147d9565b6116e7565b6001546105f8906001600160a01b031681565b6105f87f00000000000000000000000049fd0c4fb5172b20b7636b13c49fb15da52d5bd481565b610565610822366004614943565b6117ed565b61056f60045481565b61056f611824565b610565611876565b61056f600b5481565b61056f60065481565b61056f60135481565b61056f611b98565b61056f611bd1565b61056f600c5481565b6105f8611be2565b61056f60075481565b600f5461073e9060ff1681565b61056f601b5481565b61056f60145481565b6023546105f8906001600160a01b031681565b5f546105f8906001600160a01b031681565b6105656108d73660046147d9565b611c3f565b61056f60185481565b61056f670de0b6b3a764000081565b6024546105f8906001600160a01b031681565b61053d61091536600461496d565b611d38565b61056f6109283660046147d9565b611fca565b6002546105f8906001600160a01b031681565b6105f861094e36600461490c565b611fee565b61056f61096136600461490c565b61201c565b6109796109743660046147d9565b612049565b604080519485526020850193909352918301526060820152608001610521565b61056f60055481565b6105656109b03660046149d0565b6120cd565b61056f601d5481565b610a0e6109cc3660046147d9565b601f6020525f90815260409020805460018201546002830154600384015460049094015492939192909160ff8116916101009091046001600160801b03169086565b60405161052196959493929190614a4d565b61056f60125481565b6003546105f8906001600160a01b031681565b61056f612940565b601c546105f8906001600160a01b031681565b61056f610a653660046147d9565b6001600160a01b03165f908152601f602052604090206002015490565b61056f612951565b61053d610a983660046147d9565b612995565b61050a610aab366004614a98565b612aaa565b61056f610abe366004614943565b612cc6565b61056f612cec565b61056f60115481565b61056f60175481565b61056f610aeb36600461490c565b612d20565b61073e610afe3660046147d9565b612d32565b61056f60165481565b610565610b1a366004614b33565b612d91565b610565610b2d366004614b65565b612dad565b61053d610b403660046147d9565b612ef7565b61056f610b533660046147d9565b602080525f908152604090205481565b61056f612f0f565b6105f87f0000000000000000000000000f26bbb8962d73bc891327f14db5162d5279899f81565b5f805f610b9d611bd1565b610ba5611824565b610bad610e3a565b925092509250909192565b5f80610bc2612f1b565b610bcb83612f83565b91509150915091565b600f5460ff1615610c2c5760405162461bcd60e51b815260206004820152601a60248201527f43616e6e6f74206368616e67652061667465722073756e73657400000000000060448201526064015b60405180910390fd5b670de0b6b3a76400008160e001351015610c7c5760405162461bcd60e51b81526020600482015260116024820152704d43522063616e6e6f74203c203130302560781b6044820152606401610c23565b60055415610cbc57610c8c611be2565b6001600160a01b0316336001600160a01b031614610cbc5760405162461bcd60e51b8152600401610c2390614bad565b670d8f91d06741510c813510801590610cde5750670de07829b2adec28813511155b610ce6575f80fd5b8060400135816020013511158015610d0a5750670de0b6b3a7640000816040013511155b610d12575f80fd5b8060800135816060013511158015610d365750670de0b6b3a7640000816080013511155b610d3e575f80fd5b610d466130b2565b508035600555602081013560065560408101356007556060810135600855608081013560095560c0810135600a55610d86610120820161010083016147d9565b5f80546001600160a01b0319166001600160a01b0392909216919091178155610db56301e13380612710614be5565b610dce60a0840135676765c793fa10079d601b1b614be5565b610dd89190614c10565b9050600b548114610df657610deb613104565b5042600d55600b8190555b60e08201356004556040517fdba82a425948402262be7f293af6e198241329ec2ff19e69724a0bcdcda31f4d90610e2e908490614c23565b60405180910390a15050565b6001545f906001600160a01b031680610ed0577f000000000000000000000000f6ec524105548c37d3c2eb482ba197ae19740d576001600160a01b031663741bef1a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610ea9573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610ecd9190614c9a565b90505b600254604051635670bcc760e11b81526001600160a01b038381169263ace1798e92610f029290911690600401614836565b602060405180830381865afa158015610f1d573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610f419190614cb5565b91505090565b7f000000000000000000000000f6ec524105548c37d3c2eb482ba197ae19740d576001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610fa3573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610fc79190614c9a565b6001600160a01b0316336001600160a01b031614610ff75760405162461bcd60e51b8152600401610c2390614bad565b600f805460ff1916600117905561100c613104565b5061101d6301e13380612710614be5565b611034676765c793fa10079d601b1b611388614be5565b61103e9190614c10565b600b5542600d555f6006819055600a8190556010819055600755565b80801561107f575061106a6113e4565b6001600160a01b0316336001600160a01b0316145b806110a2575061108d611be2565b6001600160a01b0316336001600160a01b0316145b6110dd5760405162461bcd60e51b815260206004820152600c60248201526b155b985d5d1a1bdc9a5e995960a21b6044820152606401610c23565b600f80549115156101000261ff0019909216919091179055565b6001600160a01b0381165f908152601f602052604081206003015460ff16600481111561112657611126614a39565b92915050565b611134612f1b565b60016001600160a01b0385165f908152601f602052604090206003015460ff16600481111561116557611165614a39565b146111825760405162461bcd60e51b8152600401610c2390614ccc565b61118b84613165565b6111968460026131ae565b80601a546111a49190614d0d565b601a556111b1838361343e565b6111b96134a6565b50505050565b5f6111cb6010546134fa565b905090565b7f000000000000000000000000f6ec524105548c37d3c2eb482ba197ae19740d576001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561122c573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906112509190614c9a565b6001600160a01b0316336001600160a01b0316146112805760405162461bcd60e51b8152600401610c2390614bad565b61128982613514565b61129281613536565b5050565b61129e613558565b6112a781613165565b6112b28160036131ae565b50565b6003546001600160a01b0316156112ca575f80fd5b600180546001600160a01b039485166001600160a01b03199182161790915560038054938516938216939093179092556002805491909316911617905542600e819055600f805460ff19169055676765c793fa10079d601b1b600c55600d55565b7f000000000000000000000000f6ec524105548c37d3c2eb482ba197ae19740d576001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611387573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906113ab9190614c9a565b6001600160a01b0316336001600160a01b0316146113db5760405162461bcd60e51b8152600401610c2390614bad565b6112b281613514565b5f7f000000000000000000000000f6ec524105548c37d3c2eb482ba197ae19740d576001600160a01b031663452a93206040518163ffffffff1660e01b8152600401602060405180830381865afa158015611441573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906111cb9190614c9a565b5f6111266114716116b2565b836135ca565b7f000000000000000000000000f6ec524105548c37d3c2eb482ba197ae19740d576001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156114d3573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906114f79190614c9a565b6001600160a01b0316336001600160a01b0316146115275760405162461bcd60e51b8152600401610c2390614bad565b5f80546001600160a01b0319166001600160a01b0392909216919091179055565b5f546001600160a01b0316331461155d573391505b6001600160a01b0382165f908152602080526040902054806115c15760405162461bcd60e51b815260206004820181905260248201527f4e6f20636f6c6c61746572616c20617661696c61626c6520746f20636c61696d6044820152606401610c23565b6001600160a01b038084165f9081526020805260408120556002546115e8911683836135e8565b505050565b7f000000000000000000000000f6ec524105548c37d3c2eb482ba197ae19740d576001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611649573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061166d9190614c9a565b6001600160a01b0316336001600160a01b03161461169d5760405162461bcd60e51b8152600401610c2390614bad565b6112b281613536565b5f611126611471612f0f565b5f6111cb6116be61363e565b61367a565b6116cb613558565b6112928282613694565b6116dd613558565b6116e56136ed565b565b7f000000000000000000000000f6ec524105548c37d3c2eb482ba197ae19740d576001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611743573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906117679190614c9a565b6001600160a01b0316336001600160a01b0316146117975760405162461bcd60e51b8152600401610c2390614bad565b600180546001600160a01b0319166001600160a01b0383161790556040517fe5b20b8497e4f3e2435ef9c20e2e26b47497ee13745ce1c681ad6640653119e6906117e2908390614836565b60405180910390a150565b6117f5613558565b6001600160a01b0382165f9081526020805260408120805483929061181b908490614d20565b90915550505050565b601a545f90816118326136f5565b9150508015611862575f6118528383676765c793fa10079d601b1b61375f565b905061185e8184614d20565b9250505b601e5461186f9083614d20565b9250505090565b61187e613104565b50601b54806118c45760405162461bcd60e51b8152602060048201526012602482015271139bdd1a1a5b99c81d1bc818dbdb1b1958dd60721b6044820152606401610c23565b5f611955827f000000000000000000000000f6ec524105548c37d3c2eb482ba197ae19740d576001600160a01b0316636d52dffd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611925573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906119499190614d33565b61ffff1661271061375f565b90505f6119628284614d0d565b601c549091505f906001600160a01b03166119fc577f000000000000000000000000f6ec524105548c37d3c2eb482ba197ae19740d576001600160a01b03166371f8424f6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156119d3573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906119f79190614c9a565b611a09565b601c546001600160a01b03165b90508215611b0c577f0000000000000000000000000f26bbb8962d73bc891327f14db5162d5279899f6001600160a01b03166340c10f197f000000000000000000000000f6ec524105548c37d3c2eb482ba197ae19740d576001600160a01b031663b3f006746040518163ffffffff1660e01b8152600401602060405180830381865afa158015611a9c573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611ac09190614c9a565b856040518363ffffffff1660e01b8152600401611ade929190614d54565b5f604051808303815f87803b158015611af5575f80fd5b505af1158015611b07573d5f803e3d5ffd5b505050505b8115611b8e576040516340c10f1960e01b81526001600160a01b037f0000000000000000000000000f26bbb8962d73bc891327f14db5162d5279899f16906340c10f1990611b609084908690600401614d54565b5f604051808303815f87803b158015611b77575f80fd5b505af1158015611b89573d5f803e3d5ffd5b505050505b50505f601b555050565b5f62093a80611bc77f0000000000000000000000000000000000000000000000000000000069151f8042614d0d565b6111cb9190614c10565b5f601d546019546111cb9190614d20565b5f7f000000000000000000000000f6ec524105548c37d3c2eb482ba197ae19740d576001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611441573d5f803e3d5ffd5b7f000000000000000000000000f6ec524105548c37d3c2eb482ba197ae19740d576001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611c9b573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611cbf9190614c9a565b6001600160a01b0316336001600160a01b031614611cef5760405162461bcd60e51b8152600401610c2390614bad565b601c80546001600160a01b0319166001600160a01b0383169081179091556040517f085af60e444f2bfe4e6ad75d3227d2a8702123a3d663597ed1ca90a5f0c2c89c905f90a250565b600f545f908190610100900460ff1615611d645760405162461bcd60e51b8152600401610c2390614d6d565b611d6c612f1b565b600f5460ff1615611dbf5760405162461bcd60e51b815260206004820152601c60248201527f43616e6e6f74206f70656e207768696c652073756e73657474696e67000000006044820152606401610c23565b611dc888613807565b6001600160a01b0388165f908152601f602052604090206001600382015460ff166004811115611dfa57611dfa614a39565b03611e475760405162461bcd60e51b815260206004820152601f60248201527f426f72726f7765724f70733a20506f736974696f6e20697320616374697665006044820152606401610c23565b60038101805460ff1916600190811790915581018890558681555f611e6a613104565b600483018190559050611e7c8a6138c2565b611e858261393a565b6003546040516346f7cf8760e01b81529195506001600160a01b0316906346f7cf8790611ebc908d908b908b908b90600401614d98565b5f604051808303815f87803b158015611ed3575f80fd5b505af1158015611ee5573d5f803e3d5ffd5b5050505060228a908060018154018082558091505060019003905f5260205f20015f9091909190916101000a8154816001600160a01b0302191690836001600160a01b031602179055506001602280549050611f419190614d0d565b600383018054610100600160881b0319166101006001600160801b03841602179055601954909350611f74908a90614d20565b601955601a545f90611f87908a90614d20565b9050600a54601e5482611f9a9190614d20565b1115611fb85760405162461bcd60e51b8152600401610c2390614dc3565b601a5550919890975095505050505050565b5f805f611fd684612ef7565b915091505f611fe583836139b7565b95945050505050565b5f6022828154811061200257612002614dfa565b5f918252602090912001546001600160a01b031692915050565b5f612025612f1b565b5f61202e6130b2565b905061204261203c8261367a565b846135ca565b9392505050565b6001600160a01b0381165f908152601f602052604081208054600182015490929091819061207686612995565b600483015490945090925080156120ac575f6120906136f5565b5090508161209e8289614be5565b6120a89190614c10565b9650505b6120b68487614d20565b95506120c28386614d20565b945050509193509193565b5f60035f9054906101000a90046001600160a01b031690506121256040518061010001604052805f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81525090565b600654831015801561213957506007548311155b61217d5760405162461bcd60e51b81526020600482015260156024820152744d617820666565206e6f7420696e20626f756e647360581b6044820152606401610c23565b7f000000000000000000000000f6ec524105548c37d3c2eb482ba197ae19740d576001600160a01b031663c0c39a6f6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156121d9573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906121fd9190614e0e565b67ffffffffffffffff16600e546122149190614d20565b4210156122565760405162461bcd60e51b815260206004820152601060248201526f1093d3d514d514905417d411549253d160821b6044820152606401610c23565b61225e610e3a565b8160c00181815250506004547f00000000000000000000000049fd0c4fb5172b20b7636b13c49fb15da52d5bd46001600160a01b031663b620115d6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156122c6573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906122ea9190614cb5565b10156123385760405162461bcd60e51b815260206004820152601c60248201527f43616e6e6f742072656465656d207768656e20544352203c204d4352000000006044820152606401610c23565b5f89116123875760405162461bcd60e51b815260206004820181905260248201527f416d6f756e74206d7573742062652067726561746572207468616e207a65726f6044820152606401610c23565b6040516370a0823160e01b815289906001600160a01b037f0000000000000000000000000f26bbb8962d73bc891327f14db5162d5279899f16906370a08231906123d5903390600401614836565b602060405180830381865afa1580156123f0573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906124149190614cb5565b10156124595760405162461bcd60e51b8152602060048201526014602482015273496e73756666696369656e742062616c616e636560601b6044820152606401610c23565b6124616136ed565b612469611824565b60e082015288815260c08101515f906124859084908b906139eb565b15612491575087612597565b826001600160a01b0316634d6228316040518163ffffffff1660e01b8152600401602060405180830381865afa1580156124cd573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906124f19190614c9a565b90505b6001600160a01b038116158015906125205750670de0b6b3a764000061251e828460c00151612cc6565b105b1561259757604051632dc9c0eb60e21b81526001600160a01b0384169063b72703ac90612551908490600401614836565b602060405180830381865afa15801561256c573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906125909190614c9a565b90506124f4565b845f036125a357606494505b6001600160a01b038116158015906125bb5750815115155b80156125c657505f85115b156126c457846125d581614e35565b9550505f836001600160a01b031663b72703ac836040518263ffffffff1660e01b81526004016126059190614836565b602060405180830381865afa158015612620573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906126449190614c9a565b905061264f82612f83565b50505f6126688584865f01518760c001518e8e8e613b2e565b905080604001511561267b5750506126c4565b8051602085015161268c9190614d20565b60208086019190915281015160408501516126a79190614d20565b6040850152805184516126ba9190614d0d565b84525090506125a3565b5f8260400151116127175760405162461bcd60e51b815260206004820152601b60248201527f556e61626c6520746f2072656465656d20616e7920616d6f756e7400000000006044820152606401610c23565b600f5460ff1661273a5761273882604001518360c001518460e00151613e2f565b505b600f5460ff1661275e5761275961274f6111bf565b8360400151613ec0565b612760565b5f5b606083018190526040830151612777919086613f30565b6128047f000000000000000000000000f6ec524105548c37d3c2eb482ba197ae19740d576001600160a01b031663b3f006746040518163ffffffff1660e01b8152600401602060405180830381865afa1580156127d6573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906127fa9190614c9a565b836060015161343e565b816060015182604001516128189190614d0d565b826080018181525050336001600160a01b03167f08b6f1ce3f9ab2722e8ea40c31a3e3a806a41702c5994f29af43dc0c1f2837df8b846020015185604001518660600151604051612882949392919093845260208401929092526040830152606082015260800190565b60405180910390a26020820151604051632770a7eb60e21b81526001600160a01b037f0000000000000000000000000f26bbb8962d73bc891327f14db5162d5279899f1691639dc29fac916128db913391600401614d54565b5f604051808303815f87803b1580156128f2575f80fd5b505af1158015612904573d5f803e3d5ffd5b5050506020830151601a546129199250614d0d565b601a55608082015161292c90339061343e565b6129346134a6565b50505050505050505050565b5f6111cb61294c61363e565b6134fa565b601a545f908161295f6136f5565b915050801561298f575f61297f8383676765c793fa10079d601b1b61375f565b905061298b8184614d20565b9250505b50919050565b6001600160a01b0381165f9081526021602090815260408083208151808301909252805480835260019091015492820192909252601554839283916129da9190614d0d565b90505f82602001516016546129ef9190614d0d565b90506129fb8183614d20565b1580612a36575060016001600160a01b0387165f908152601f602052604090206003015460ff166004811115612a3357612a33614a39565b14155b15612a4857505f958695509350505050565b6001600160a01b0386165f908152601f6020526040902060020154670de0b6b3a7640000612a768483614be5565b612a809190614c10565b670de0b6b3a7640000612a938484614be5565b612a9d9190614c10565b9550955050505050915091565b5f805f612ab5612f1b565b8880612abe57508b5b15612b3e57600f54610100900460ff1615612aeb5760405162461bcd60e51b8152600401610c2390614d6d565b600f5460ff1615612b3e5760405162461bcd60e51b815260206004820181905260248201527f43616e6e6f7420696e637265617365207768696c652073756e73657474696e676044820152606401610c23565b6001600160a01b0385165f908152601f602052604090206001600382015460ff166004811115612b7057612b70614a39565b14612b8d5760405162461bcd60e51b8152600401610c2390614ccc565b80548c15612bd1578d15612bb757612ba58c82614d20565b9050612bb2868d8f613fad565b612bcd565b612bc18c82614d0d565b9050612bcd868e614073565b8082555b60018201548a15612c22578b15612c0457612bec8b82614d20565b90508a601954612bfc9190614d20565b601955612c1a565b612c0e8b82614d0d565b9050612c1a878c61343e565b600183018190555b5f612c2d82846139b7565b905060035f9054906101000a90046001600160a01b03166001600160a01b0316632be212608a838e8e6040518563ffffffff1660e01b8152600401612c759493929190614d98565b5f604051808303815f87803b158015612c8c575f80fd5b505af1158015612c9e573d5f803e3d5ffd5b505050508183612cad8661393a565b9650965096505050505099509950999650505050505050565b5f805f612cd285612ef7565b915091505f612ce2838387614103565b9695505050505050565b612cfc6301e13380612710614be5565b612d13676765c793fa10079d601b1b611388614be5565b612d1d9190614c10565b81565b5f611126612d2c612940565b83613ec0565b5f60016001600160a01b0383165f908152601f602052604090206003015460ff166004811115612d6457612d64614a39565b14612d7057505f919050565b506015546001600160a01b039091165f908152602160205260409020541090565b612d99613558565b612da38383614073565b6115e8838261343e565b612db5613558565b612dbf8585614131565b6019548315612dda57612dd28482614d0d565b601981905590505b601254601355601d548290612def9083614d20565b612df99190614d0d565b60148190556013546040517f51bf4c63ec3cba9d03d43238abbdd979dd91bd16d9895c74ceea9118c7baaf6092612e37928252602082015260400190565b60405180910390a1604051631062c15f60e11b81526001600160a01b037f000000000000000000000000130541a39cfaa89c9ed8f387d479b277321d1ad4811660048301528881166024830152604482018590527f0000000000000000000000000f26bbb8962d73bc891327f14db5162d5279899f16906320c582be906064015f604051808303815f87803b158015612ece575f80fd5b505af1158015612ee0573d5f803e3d5ffd5b50505050612eee878361343e565b50505050505050565b5f80612f0283612049565b5090959194509092505050565b5f6111cb60105461367a565b336001600160a01b037f00000000000000000000000049fd0c4fb5172b20b7636b13c49fb15da52d5bd416146116e55760405162461bcd60e51b815260206004820152600d60248201526c43616c6c6572206e6f7420424f60981b6044820152606401610c23565b6001600160a01b0381165f908152601f6020526040812081906001600382015460ff166004811115612fb757612fb7614a39565b036130ac5760048101545f612fca613104565b835460018501549650945090508381831015612fff5782612feb8387614be5565b612ff59190614c10565b6004850183905594505b6015546001600160a01b0388165f90815260216020526040902054101561309d575f8061302b89612995565b909250905061303a8289614d20565b60018701819055975061304d8188614d20565b9650613058896138c2565b6130628183613694565b886001600160a01b03165f80516020614f22833981519152888a89600201545f6040516130929493929190614e5e565b60405180910390a250505b8481146130a8578484555b5050505b50915091565b5f806130bc61363e565b60108190556040518181529091507fc454ee9b76c52f782a256af821b857ca6e125d1e3333bcede402fec2bed9600c9060200160405180910390a16130ff61429f565b919050565b5f805f61310f6136f5565b9092509050801561298f57601a545f6131348284676765c793fa10079d601b1b61375f565b90506131408183614d20565b601a55601b54613151908290614d20565b601b555050600c82905542600d5550919050565b6001600160a01b0381165f908152601f602052604090206002015460125461318e908290614d0d565b601255506001600160a01b03165f908152601f6020526040812060020155565b6022546001600160a01b0383165f908152601f6020526040902060038101805484919060ff191660018360048111156131e9576131e9614a39565b02179055505f6001808301829055818355600483018290556003546001600160a01b03878116845260216020526040842084815583019390935591909116908311801561329557506001816001600160a01b031663de8fa4316040518163ffffffff1660e01b8152600401602060405180830381865afa15801561326f573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906132939190614cb5565b115b1561339a57600382015461010090046001600160801b03165f60226132bb600187614d0d565b815481106132cb576132cb614dfa565b5f91825260209091200154602280546001600160a01b03909216925082916001600160801b03851690811061330257613302614dfa565b5f91825260208083209190910180546001600160a01b0319166001600160a01b03948516179055918316808252601f83526040918290206003018054610100600160881b0319166101006001600160801b038816908102919091179091558251918252928101929092527f2391d278b0562640dd6add67aa715b4dab2327f1ec896819ff2a809adea29a36910160405180910390a150505b60228054806133ab576133ab614e80565b5f8281526020902081015f1990810180546001600160a01b0319169055019055604051631484968760e11b81526001600160a01b038216906329092d0e906133f7908890600401614836565b5f604051808303815f87803b15801561340e575f80fd5b505af1158015613420573d5f803e3d5ffd5b50505060039092018054610100600160881b03191690555050505050565b801561129257806019546134529190614d0d565b6019556040517f342693d2465f6f44931e41128424a0227e0cbc69d1c3917a839e6de71696d44c906134879084908490614d54565b60405180910390a1600254611292906001600160a01b031683836135e8565b6022545f036116e557676765c793fa10079d601b1b600c5542600d555f60128190556013819055601481905560158190556016819055601781905560188190556019819055601a819055601d819055601e55565b5f6111268260065461350c9190614d20565b600754614311565b602380546001600160a01b0319166001600160a01b0392909216919091179055565b602480546001600160a01b0319166001600160a01b0392909216919091179055565b336001600160a01b037f000000000000000000000000fa2de0dcaa6dfdc0d01ad2677258a641bdae084016146116e55760405162461bcd60e51b81526020600482015260176024820152762737ba102634b8bab4b230ba34b7b71026b0b730b3b2b960491b6044820152606401610c23565b5f670de0b6b3a76400006135de8385614be5565b6120429190614c10565b6115e88363a9059cbb60e01b8484604051602401613607929190614d54565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152614326565b5f806136486143f7565b90505f61365760055483614408565b9050670de0b6b3a7640000816010546136709190614be5565b61186f9190614c10565b5f6111268260085461368c9190614d20565b600954614311565b81601e5f8282546136a59190614d0d565b9250508190555081601a5f8282546136bd9190614d20565b9250508190555080601d5f8282546136d59190614d0d565b925050819055508060195f82825461181b9190614d20565b6112b2613104565b600d545f90819042810361370e575050600c54915f9150565b600b54600c5493508015613759575f6137278342614d0d565b90506137338282614be5565b935061374b8585676765c793fa10079d601b1b61375f565b6137559086614d20565b9450505b50509091565b5f80805f19858709858702925082811083820303915050805f036137965783828161378c5761378c614bfc565b0492505050612042565b8084116137a1575f80fd5b5f84868809600260036001881981018916988990049182028318808302840302808302840302808302840302808302840302808302840302918202909203025f889003889004909101858311909403939093029303949094049190911702949350505050565b6023546001600160a01b038281169116148061383057506024546001600160a01b038281169116145b6112b25760405162461bcd60e51b815260206004820152605760248201527f5065726d697373696f6e6564506f736974696f6e4d616e616765723a204f6e6c60448201527f7920746865205065726d697373696f6e65642f50726f746f636f6c506f73697460648201527634b7b71031b0b71037b832b71030903837b9b4ba34b7b760491b608482015260a401610c23565b60155460165460408051808201825283815260208082018481526001600160a01b0387165f90815260218352849020925183555160019092019190915581518481529081018390527fc2910901d6342262f6857ac83c05564d215eef237fb5bcdf69013b47bbf4b8a8910160405180910390a1505050565b5f8061394983600101546144b0565b60028401805490829055601254919250905f908390613969908490614d0d565b6139739190614d20565b60128190556040518181529091507f6bac5e0eb3c44eb03a60ab11ec3a2c051771616aecadbcfff2630aabae5203829060200160405180910390a150909392505050565b5f81156139e357816139d268056bc75e2d6310000085614be5565b6139dc9190614c10565b9050611126565b505f19611126565b5f6001600160a01b0383161580613a6a5750604051630bb7c8fd60e31b81526001600160a01b03851690635dbe47e890613a29908690600401614836565b602060405180830381865afa158015613a44573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613a689190614e94565b155b80613a855750670de0b6b3a7640000613a838484612cc6565b105b15613a9157505f612042565b60405163765e015960e01b81525f906001600160a01b0386169063765e015990613abf908790600401614836565b602060405180830381865afa158015613ada573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613afe9190614c9a565b90506001600160a01b0381161580611fe55750670de0b6b3a7640000613b248285612cc6565b1095945050505050565b613b5160405180606001604052805f81526020015f81526020015f151581525090565b6001600160a01b0387165f908152601f602052604090208054613ba0908890613b9b907f0000000000000000000000000000000000000000000000000de0b6b3a764000090614d0d565b614311565b8083528690613bb890670de0b6b3a764000090614be5565b613bc29190614c10565b6020830152815181545f91613bd691614d0d565b90505f83602001518360010154613bed9190614d0d565b90507f0000000000000000000000000000000000000000000000000de0b6b3a76400008203613c8f57613c1f8a613165565b613c2a8a60046131ae565b613c558a7f0000000000000000000000000000000000000000000000000de0b6b3a7640000836144f6565b896001600160a01b03165f80516020614f228339815191525f805f6003604051613c829493929190614e5e565b60405180910390a2613e20565b5f613c9a82846139b7565b90505f818711613cb357613cae8783614d0d565b613cbd565b613cbd8288614d0d565b90506601c6bf52634000811180613d5a57507f00000000000000000000000049fd0c4fb5172b20b7636b13c49fb15da52d5bd46001600160a01b031663969c24526040518163ffffffff1660e01b8152600401602060405180830381865afa158015613d2b573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613d4f9190614cb5565b613d58856145ea565b105b15613d715750506001604085015250613e24915050565b5060405163015f109360e51b81526001600160a01b038d1690632be2126090613da4908e9085908d908d90600401614d98565b5f604051808303815f87803b158015613dbb575f80fd5b505af1158015613dcd573d5f803e3d5ffd5b5050508385555060018401829055613de48461393a565b508a6001600160a01b03165f80516020614f22833981519152848487600201546003604051613e169493929190614e5e565b60405180910390a2505b5050505b979650505050505050565b5f80613e3961363e565b90505f83613e478688614be5565b613e519190614c10565b90505f613e5f600283614c10565b613e699084614d20565b9050613e7d81670de0b6b3a7640000614311565b60108190556040518181529091507fc454ee9b76c52f782a256af821b857ca6e125d1e3333bcede402fec2bed9600c9060200160405180910390a1612ce261429f565b5f80670de0b6b3a7640000613ed58486614be5565b613edf9190614c10565b90508281106120425760405162461bcd60e51b815260206004820152601f60248201527f46656520657863656564732072657475726e656420636f6c6c61746572616c006044820152606401610c23565b5f825f03613f3e575f613f5b565b82613f51670de0b6b3a764000086614be5565b613f5b9190614c10565b9050818111156111b95760405162461bcd60e51b815260206004820152601d60248201527f4665652065786365656465642070726f7669646564206d6178696d756d0000006044820152606401610c23565b5f82601a54613fbc9190614d20565b9050600a54601e5482613fcf9190614d20565b1115613fed5760405162461bcd60e51b8152600401610c2390614dc3565b601a8190556040516340c10f1960e01b81526001600160a01b037f0000000000000000000000000f26bbb8962d73bc891327f14db5162d5279899f16906340c10f19906140409087908690600401614d54565b5f604051808303815f87803b158015614057575f80fd5b505af1158015614069573d5f803e3d5ffd5b5050505050505050565b604051632770a7eb60e21b81526001600160a01b037f0000000000000000000000000f26bbb8962d73bc891327f14db5162d5279899f1690639dc29fac906140c19085908590600401614d54565b5f604051808303815f87803b1580156140d8575f80fd5b505af11580156140ea573d5f803e3d5ffd5b5050505080601a546140fc9190614d0d565b601a555050565b5f8215614129575f836141168487614be5565b6141209190614c10565b91506120429050565b505f19612042565b815f0361413c575050565b6017545f90614153670de0b6b3a764000084614be5565b61415d9190614d20565b90505f601854670de0b6b3a7640000856141779190614be5565b6141819190614d20565b6012549091505f6141928285614c10565b90505f61419f8385614c10565b90506141ab8383614be5565b6141b59086614d0d565b6017556141c28382614be5565b6141cc9085614d0d565b6018556015545f906141df908490614d20565b90505f826016546141f09190614d20565b6015839055601681905560408051848152602081018390529192507f9f8bc8ab0daf5bceef75ecfd2085d1fcc6548c657ea970d9a23a60610d0737e3910160405180910390a188601a5f8282546142479190614d0d565b9250508190555088601e5f82825461425f9190614d20565b9250508190555087601d5f8282546142779190614d20565b925050819055508760195f82825461428f9190614d0d565b9091555050505050505050505050565b5f601154426142ae9190614d0d565b9050603c81106112b257603c6142c26143f7565b6142cc9190614be5565b60115f8282546142dc9190614d20565b90915550506040514281527f860f8d2f0c74dd487e89e2883e3b25b8159ce1e1b3433a291cba7b82c508f3bc906020016117e2565b5f81831061431f5781612042565b5090919050565b5f61437a826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166146159092919063ffffffff16565b8051909150156115e857808060200190518101906143989190614e94565b6115e85760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610c23565b5f603c60115442611bc79190614d0d565b5f631f54050082111561441d57631f54050091505b815f036144335750670de0b6b3a7640000611126565b670de0b6b3a764000083835b60018111156144a657614453600282614eaf565b5f0361447757614463828361462b565b9150614470600282614c10565b905061443f565b614481828461462b565b925061448d828361462b565b9150600261449c600183614d0d565b6144709190614c10565b612ce2828461462b565b6014545f9081908082036144c6578391506144ef565b601354806144d6576144d6614ec2565b816144e18287614be5565b6144eb9190614c10565b9250505b5092915050565b604051632770a7eb60e21b81526001600160a01b037f0000000000000000000000000f26bbb8962d73bc891327f14db5162d5279899f1690639dc29fac90614564907f000000000000000000000000130541a39cfaa89c9ed8f387d479b277321d1ad4908690600401614d54565b5f604051808303815f87803b15801561457b575f80fd5b505af115801561458d573d5f803e3d5ffd5b5050505081601a5461459f9190614d0d565b601a556001600160a01b0383165f908152602080526040812080548392906145c8908490614d20565b925050819055508060195f8282546145e09190614d0d565b9091555050505050565b5f6111267f0000000000000000000000000000000000000000000000000de0b6b3a764000083614d0d565b606061462384845f85614661565b949350505050565b5f806146378385614be5565b9050670de0b6b3a764000061464d600282614c10565b6146579083614d20565b6146239190614c10565b6060824710156146c25760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401610c23565b5f80866001600160a01b031685876040516146dd9190614ed6565b5f6040518083038185875af1925050503d805f8114614717576040519150601f19603f3d011682016040523d82523d5f602084013e61471c565b606091505b5091509150613e2487838387606083156147965782515f0361478f576001600160a01b0385163b61478f5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610c23565b5081614623565b61462383838151156147ab5781518083602001fd5b8060405162461bcd60e51b8152600401610c239190614eec565b6001600160a01b03811681146112b2575f80fd5b5f602082840312156147e9575f80fd5b8135612042816147c5565b5f610120828403128015614806575f80fd5b509092915050565b80151581146112b2575f80fd5b5f6020828403121561482b575f80fd5b81356120428161480e565b6001600160a01b0391909116815260200190565b5f805f806080858703121561485d575f80fd5b8435614868816147c5565b93506020850135614878816147c5565b93969395505050506040820135916060013590565b5f806040838503121561489e575f80fd5b82356148a9816147c5565b915060208301356148b9816147c5565b809150509250929050565b5f805f606084860312156148d6575f80fd5b83356148e1816147c5565b925060208401356148f1816147c5565b91506040840135614901816147c5565b809150509250925092565b5f6020828403121561491c575f80fd5b5035919050565b5f8060408385031215614934575f80fd5b50508035926020909101359150565b5f8060408385031215614954575f80fd5b823561495f816147c5565b946020939093013593505050565b5f805f805f8060c08789031215614982575f80fd5b863561498d816147c5565b955060208701359450604087013593506060870135925060808701356149b2816147c5565b915060a08701356149c2816147c5565b809150509295509295509295565b5f805f805f805f60e0888a0312156149e6575f80fd5b8735965060208801356149f8816147c5565b95506040880135614a08816147c5565b94506060880135614a18816147c5565b9699959850939660808101359560a0820135955060c0909101359350915050565b634e487b7160e01b5f52602160045260245ffd5b868152602081018690526040810185905260c0810160058510614a7257614a72614a39565b60608201949094526001600160801b0392909216608083015260a0909101529392505050565b5f805f805f805f805f6101208a8c031215614ab1575f80fd5b8935614abc8161480e565b985060208a0135975060408a0135965060608a0135614ada8161480e565b955060808a0135945060a08a0135614af1816147c5565b935060c08a0135614b01816147c5565b925060e08a0135614b11816147c5565b91506101008a0135614b22816147c5565b809150509295985092959850929598565b5f805f60608486031215614b45575f80fd5b8335614b50816147c5565b95602085013595506040909401359392505050565b5f805f805f8060c08789031215614b7a575f80fd5b8635614b85816147c5565b9860208801359850604088013597606081013597506080810135965060a00135945092505050565b6020808252600a908201526927b7363c9037bbb732b960b11b604082015260600190565b634e487b7160e01b5f52601160045260245ffd5b808202811582820484141761112657611126614bd1565b634e487b7160e01b5f52601260045260245ffd5b5f82614c1e57614c1e614bfc565b500490565b813581526020808301359082015260408083013590820152606080830135908201526080808301359082015260a0808301359082015260c0808301359082015260e080830135908201526101208101610100830135614c81816147c5565b6001600160a01b03166101009290920191909152919050565b5f60208284031215614caa575f80fd5b8151612042816147c5565b5f60208284031215614cc5575f80fd5b5051919050565b60208082526021908201527f506f736974696f6e20636c6f736564206f7220646f6573206e6f7420657869736040820152601d60fa1b606082015260800190565b8181038181111561112657611126614bd1565b8082018082111561112657611126614bd1565b5f60208284031215614d43575f80fd5b815161ffff81168114612042575f80fd5b6001600160a01b03929092168252602082015260400190565b60208082526011908201527010dbdb1b185d195c985b0814185d5cd959607a1b604082015260600190565b6001600160a01b03948516815260208101939093529083166040830152909116606082015260800190565b6020808252601d908201527f436f6c6c61746572616c2064656274206c696d69742072656163686564000000604082015260600190565b634e487b7160e01b5f52603260045260245ffd5b5f60208284031215614e1e575f80fd5b815167ffffffffffffffff81168114612042575f80fd5b5f81614e4357614e43614bd1565b505f190190565b60048110614e5a57614e5a614a39565b9052565b848152602081018490526040810183905260808101611fe56060830184614e4a565b634e487b7160e01b5f52603160045260245ffd5b5f60208284031215614ea4575f80fd5b81516120428161480e565b5f82614ebd57614ebd614bfc565b500690565b634e487b7160e01b5f52600160045260245ffd5b5f82518060208501845e5f920191825250919050565b602081525f82518060208401528060208501604085015e5f604082850101526040601f19601f8301168401019150509291505056fe4fe7fb62190647b8a7596709832f68a365082b18206e55ae330b95593c369affa2646970667358221220195e3f78c14044321bcd2e37d0d99b55a0b623110838e1bb64abb1b416068d4a64736f6c634300081a0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000f6ec524105548c37d3c2eb482ba197ae19740d57000000000000000000000000130541a39cfaa89c9ed8f387d479b277321d1ad40000000000000000000000000f26bbb8962d73bc891327f14db5162d5279899f00000000000000000000000049fd0c4fb5172b20b7636b13c49fb15da52d5bd4000000000000000000000000fa2de0dcaa6dfdc0d01ad2677258a641bdae08400000000000000000000000000000000000000000000000000de0b6b3a7640000
-----Decoded View---------------
Arg [0] : _core (address): 0xF6ec524105548C37D3C2eB482BA197AE19740d57
Arg [1] : _gasPoolAddress (address): 0x130541A39cfaA89c9eD8f387d479B277321D1ad4
Arg [2] : _debtTokenAddress (address): 0x0F26bBb8962d73bC891327F14dB5162D5279899F
Arg [3] : _borrowerOperations (address): 0x49FD0C4fb5172b20b7636b13c49fb15dA52D5bd4
Arg [4] : _liquidationManager (address): 0xfa2dE0DCAa6dfDc0D01aD2677258A641BdAe0840
Arg [5] : _gasCompensation (uint256): 1000000000000000000
-----Encoded View---------------
6 Constructor Arguments found :
Arg [0] : 000000000000000000000000f6ec524105548c37d3c2eb482ba197ae19740d57
Arg [1] : 000000000000000000000000130541a39cfaa89c9ed8f387d479b277321d1ad4
Arg [2] : 0000000000000000000000000f26bbb8962d73bc891327f14db5162d5279899f
Arg [3] : 00000000000000000000000049fd0c4fb5172b20b7636b13c49fb15da52d5bd4
Arg [4] : 000000000000000000000000fa2de0dcaa6dfdc0d01ad2677258a641bdae0840
Arg [5] : 0000000000000000000000000000000000000000000000000de0b6b3a7640000
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 34 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.