Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
Latest 5 from a total of 5 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Redeem Collatera... | 18329170 | 518 days ago | IN | 0 ETH | 0.0026197 | ||||
Redeem Collatera... | 18329036 | 518 days ago | IN | 0 ETH | 0.00370106 | ||||
Redeem Collatera... | 18328963 | 518 days ago | IN | 0 ETH | 0.00278844 | ||||
Liquidate | 18300929 | 522 days ago | IN | 0 ETH | 0.00013278 | ||||
Set Addresses | 18281872 | 524 days ago | IN | 0 ETH | 0.00174667 |
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Contract Name:
TroveManager
Compiler Version
v0.8.17+commit.8df45f5f
Optimization Enabled:
Yes with 100 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT pragma solidity ^0.8.17; import "./Interfaces/ITroveManager.sol"; import "./Interfaces/IStabilityPool.sol"; import "./Interfaces/ICollSurplusPool.sol"; import "./Interfaces/IGasPool.sol"; import "./Interfaces/ITHUSDToken.sol"; import "./Interfaces/ISortedTroves.sol"; import "./Interfaces/IPCV.sol"; import "./Dependencies/LiquityBase.sol"; import "./Dependencies/Ownable.sol"; import "./Dependencies/CheckContract.sol"; contract TroveManager is LiquityBase, Ownable, CheckContract, ITroveManager { string constant public NAME = "TroveManager"; // --- Connected contract declarations --- address public borrowerOperationsAddress; IStabilityPool public override stabilityPool; address gasPoolAddress; ICollSurplusPool collSurplusPool; ITHUSDToken public override thusdToken; IPCV public override pcv; // A doubly linked list of Troves, sorted by their sorted by their collateral ratios ISortedTroves public sortedTroves; // --- Data structures --- /* * Half-life of 12h. 12h = 720 min * (1/2) = d^720 => d = (1/2)^(1/720) */ uint256 constant public MINUTE_DECAY_FACTOR = 999037758833783000; uint256 constant public REDEMPTION_FEE_FLOOR = DECIMAL_PRECISION / 1000 * 5; // 0.5% uint256 constant public MAX_BORROWING_FEE = DECIMAL_PRECISION / 100 * 5; // 5% /* * 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 public BETA = 2; uint256 public baseRate; // The timestamp of the latest fee operation (redemption or new THUSD issuance) uint256 public lastFeeOperationTime; // Store the necessary data for a trove struct Trove { uint256 debt; uint256 coll; uint256 stake; Status status; uint128 arrayIndex; } mapping (address => Trove) public Troves; uint256 public totalStakes; // Snapshot of the value of totalStakes, taken immediately after the latest liquidation uint256 public totalStakesSnapshot; // Snapshot of the total collateral across the ActivePool and DefaultPool, immediately after the latest liquidation. uint256 public totalCollateralSnapshot; /* * L_Collateral and L_THUSDDebt 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 THUSDDebt increase of ( stake * [L_THUSDDebt - L_THUSDDebt(0)] ) * * Where L_Collateral(0) and L_THUSDDebt(0) are snapshots of L_Collateral and L_THUSDDebt for the active Trove taken at the instant the stake was made */ uint256 public L_Collateral; uint256 public L_THUSDDebt; // Map addresses with active troves to their RewardSnapshot mapping (address => RewardSnapshot) public rewardSnapshots; // Object containing the collateral and THUSD snapshots for a given active trove struct RewardSnapshot { uint256 collateral; uint256 THUSDDebt;} // Array of all active trove addresses - used to to compute an approximate hint off-chain, for the sorted list insertion address[] public TroveOwners; // Error trackers for the trove redistribution calculation uint256 public lastCollateralError_Redistribution; uint256 public lastTHUSDDebtError_Redistribution; /* * --- Variable container structs for liquidations --- * * These structs are used to hold, return and assign variables inside the liquidation functions, * in order to avoid the error: "CompilerError: Stack too deep". **/ struct LocalVariables_OuterLiquidationFunction { uint256 price; uint256 THUSDInStabPool; bool recoveryModeAtStart; uint256 liquidatedDebt; uint256 liquidatedColl; } struct LocalVariables_InnerSingleLiquidateFunction { uint256 collToLiquidate; uint256 pendingDebtReward; uint256 pendingCollReward; } struct LocalVariables_LiquidationSequence { uint256 remainingTHUSDInStabPool; uint256 i; uint256 ICR; address user; bool backToNormalMode; uint256 entireSystemDebt; uint256 entireSystemColl; } struct LiquidationValues { uint256 entireTroveDebt; uint256 entireTroveColl; uint256 collGasCompensation; uint256 THUSDGasCompensation; uint256 debtToOffset; uint256 collToSendToSP; uint256 debtToRedistribute; uint256 collToRedistribute; uint256 collSurplus; } struct LiquidationTotals { uint256 totalCollInSequence; uint256 totalDebtInSequence; uint256 totalCollGasCompensation; uint256 totalTHUSDGasCompensation; uint256 totalDebtToOffset; uint256 totalCollToSendToSP; uint256 totalDebtToRedistribute; uint256 totalCollToRedistribute; uint256 totalCollSurplus; } struct ContractsCache { IActivePool activePool; IDefaultPool defaultPool; ITHUSDToken thusdToken; IPCV pcv; ISortedTroves sortedTroves; ICollSurplusPool collSurplusPool; address gasPoolAddress; } // --- Variable container structs for redemptions --- struct RedemptionTotals { uint256 remainingTHUSD; uint256 totalTHUSDToRedeem; uint256 totalCollateralDrawn; uint256 collateralFee; uint256 collateralToSendToRedeemer; uint256 decayedBaseRate; uint256 price; uint256 totalTHUSDDebtAtStart; } struct SingleRedemptionValues { uint256 THUSDLot; uint256 collateralLot; bool cancelledPartial; } // --- Events --- event TroveUpdated(address indexed _borrower, uint256 _debt, uint256 _coll, uint256 _stake, TroveManagerOperation _operation); event TroveLiquidated(address indexed _borrower, uint256 _debt, uint256 _coll, TroveManagerOperation _operation); enum TroveManagerOperation { applyPendingRewards, liquidateInNormalMode, liquidateInRecoveryMode, redeemCollateral } // --- Dependency setter --- function setAddresses( address _borrowerOperationsAddress, address _activePoolAddress, address _defaultPoolAddress, address _stabilityPoolAddress, address _gasPoolAddress, address _collSurplusPoolAddress, address _priceFeedAddress, address _thusdTokenAddress, address _sortedTrovesAddress, address _pcvAddress ) external override onlyOwner { checkContract(_borrowerOperationsAddress); checkContract(_activePoolAddress); checkContract(_defaultPoolAddress); checkContract(_stabilityPoolAddress); checkContract(_gasPoolAddress); checkContract(_collSurplusPoolAddress); checkContract(_priceFeedAddress); checkContract(_thusdTokenAddress); checkContract(_sortedTrovesAddress); checkContract(_pcvAddress); borrowerOperationsAddress = _borrowerOperationsAddress; activePool = IActivePool(_activePoolAddress); defaultPool = IDefaultPool(_defaultPoolAddress); stabilityPool = IStabilityPool(_stabilityPoolAddress); gasPoolAddress = _gasPoolAddress; collSurplusPool = ICollSurplusPool(_collSurplusPoolAddress); priceFeed = IPriceFeed(_priceFeedAddress); thusdToken = ITHUSDToken(_thusdTokenAddress); sortedTroves = ISortedTroves(_sortedTrovesAddress); pcv = IPCV(_pcvAddress); emit BorrowerOperationsAddressChanged(_borrowerOperationsAddress); emit ActivePoolAddressChanged(_activePoolAddress); emit DefaultPoolAddressChanged(_defaultPoolAddress); emit StabilityPoolAddressChanged(_stabilityPoolAddress); emit GasPoolAddressChanged(_gasPoolAddress); emit CollSurplusPoolAddressChanged(_collSurplusPoolAddress); emit PriceFeedAddressChanged(_priceFeedAddress); emit THUSDTokenAddressChanged(_thusdTokenAddress); emit SortedTrovesAddressChanged(_sortedTrovesAddress); emit PCVAddressChanged(_pcvAddress); _renounceOwnership(); } // --- Getters --- function getTroveOwnersCount() external view override returns (uint) { return TroveOwners.length; } function getTroveFromTroveOwnersArray(uint256 _index) external view override returns (address) { return TroveOwners[_index]; } // --- Trove Liquidation functions --- // Single liquidation function. Closes the trove if its ICR is lower than the minimum collateral ratio. function liquidate(address _borrower) external override { _requireTroveIsActive(_borrower); address[] memory borrowers = new address[](1); borrowers[0] = _borrower; batchLiquidateTroves(borrowers); } // --- Inner single liquidation functions --- // Liquidate one trove, in Normal Mode. function _liquidateNormalMode( IActivePool _activePool, IDefaultPool _defaultPool, address _borrower, uint256 _THUSDInStabPool ) internal returns (LiquidationValues memory singleLiquidation) { LocalVariables_InnerSingleLiquidateFunction memory vars; (singleLiquidation.entireTroveDebt, singleLiquidation.entireTroveColl, vars.pendingDebtReward, vars.pendingCollReward) = getEntireDebtAndColl(_borrower); _movePendingTroveRewardsToActivePool(_activePool, _defaultPool, vars.pendingDebtReward, vars.pendingCollReward); _removeStake(_borrower); singleLiquidation.collGasCompensation = _getCollGasCompensation(singleLiquidation.entireTroveColl); singleLiquidation.THUSDGasCompensation = THUSD_GAS_COMPENSATION; uint256 collToLiquidate = singleLiquidation.entireTroveColl - singleLiquidation.collGasCompensation; (singleLiquidation.debtToOffset, singleLiquidation.collToSendToSP, singleLiquidation.debtToRedistribute, singleLiquidation.collToRedistribute) = _getOffsetAndRedistributionVals(singleLiquidation.entireTroveDebt, collToLiquidate, _THUSDInStabPool); _closeTrove(_borrower, Status.closedByLiquidation); emit TroveLiquidated(_borrower, singleLiquidation.entireTroveDebt, singleLiquidation.entireTroveColl, TroveManagerOperation.liquidateInNormalMode); emit TroveUpdated(_borrower, 0, 0, 0, TroveManagerOperation.liquidateInNormalMode); return singleLiquidation; } // Liquidate one trove, in Recovery Mode. function _liquidateRecoveryMode( IActivePool _activePool, IDefaultPool _defaultPool, address _borrower, uint256 _ICR, uint256 _THUSDInStabPool, uint256 _TCR, uint256 _price ) internal returns (LiquidationValues memory singleLiquidation) { LocalVariables_InnerSingleLiquidateFunction memory vars; if (TroveOwners.length <= 1) {return singleLiquidation;} // don't liquidate if last trove (singleLiquidation.entireTroveDebt, singleLiquidation.entireTroveColl, vars.pendingDebtReward, vars.pendingCollReward) = getEntireDebtAndColl(_borrower); singleLiquidation.collGasCompensation = _getCollGasCompensation(singleLiquidation.entireTroveColl); singleLiquidation.THUSDGasCompensation = THUSD_GAS_COMPENSATION; vars.collToLiquidate = singleLiquidation.entireTroveColl - singleLiquidation.collGasCompensation; // If ICR <= 100%, purely redistribute the Trove across all active Troves if (_ICR <= _100pct) { _movePendingTroveRewardsToActivePool(_activePool, _defaultPool, vars.pendingDebtReward, vars.pendingCollReward); _removeStake(_borrower); singleLiquidation.debtToOffset = 0; singleLiquidation.collToSendToSP = 0; singleLiquidation.debtToRedistribute = singleLiquidation.entireTroveDebt; singleLiquidation.collToRedistribute = vars.collToLiquidate; _closeTrove(_borrower, Status.closedByLiquidation); emit TroveLiquidated(_borrower, singleLiquidation.entireTroveDebt, singleLiquidation.entireTroveColl, TroveManagerOperation.liquidateInRecoveryMode); emit TroveUpdated(_borrower, 0, 0, 0, TroveManagerOperation.liquidateInRecoveryMode); // If 100% < ICR < MCR, offset as much as possible, and redistribute the remainder } else if ((_ICR > _100pct) && (_ICR < MCR)) { _movePendingTroveRewardsToActivePool(_activePool, _defaultPool, vars.pendingDebtReward, vars.pendingCollReward); _removeStake(_borrower); (singleLiquidation.debtToOffset, singleLiquidation.collToSendToSP, singleLiquidation.debtToRedistribute, singleLiquidation.collToRedistribute) = _getOffsetAndRedistributionVals(singleLiquidation.entireTroveDebt, vars.collToLiquidate, _THUSDInStabPool); _closeTrove(_borrower, Status.closedByLiquidation); emit TroveLiquidated(_borrower, singleLiquidation.entireTroveDebt, singleLiquidation.entireTroveColl, TroveManagerOperation.liquidateInRecoveryMode); emit TroveUpdated(_borrower, 0, 0, 0, TroveManagerOperation.liquidateInRecoveryMode); /* * If 110% <= ICR < current TCR (accounting for the preceding liquidations in the current sequence) * and there is THUSD in the Stability Pool, only offset, with no redistribution, * but at a capped rate of 1.1 and only if the whole debt can be liquidated. * The remainder due to the capped rate will be claimable as collateral surplus. */ } else if ((_ICR >= MCR) && (_ICR < _TCR) && (singleLiquidation.entireTroveDebt <= _THUSDInStabPool)) { _movePendingTroveRewardsToActivePool(_activePool, _defaultPool, vars.pendingDebtReward, vars.pendingCollReward); assert(_THUSDInStabPool != 0); _removeStake(_borrower); singleLiquidation = _getCappedOffsetVals(singleLiquidation.entireTroveDebt, singleLiquidation.entireTroveColl, _price); _closeTrove(_borrower, Status.closedByLiquidation); if (singleLiquidation.collSurplus > 0) { collSurplusPool.accountSurplus(_borrower, singleLiquidation.collSurplus); } emit TroveLiquidated(_borrower, singleLiquidation.entireTroveDebt, singleLiquidation.collToSendToSP, TroveManagerOperation.liquidateInRecoveryMode); emit TroveUpdated(_borrower, 0, 0, 0, TroveManagerOperation.liquidateInRecoveryMode); } else { // if (_ICR >= MCR && ( _ICR >= _TCR || singleLiquidation.entireTroveDebt > _THUSDInStabPool)) LiquidationValues memory zeroVals; return zeroVals; } return singleLiquidation; } /* In a full liquidation, returns the values for a trove's coll and debt to be offset, and coll and debt to be * redistributed to active troves. */ function _getOffsetAndRedistributionVals ( uint256 _debt, uint256 _coll, uint256 _THUSDInStabPool ) internal pure returns (uint256 debtToOffset, uint256 collToSendToSP, uint256 debtToRedistribute, uint256 collToRedistribute) { if (_THUSDInStabPool > 0) { /* * Offset as much debt & collateral as possible against the Stability Pool, and redistribute the remainder * between all active troves. * * If the trove's debt is larger than the deposited THUSD in the Stability Pool: * * - Offset an amount of the trove's debt equal to the THUSD in the Stability Pool * - Send a fraction of the trove's collateral to the Stability Pool, equal to the fraction of its offset debt * */ debtToOffset = LiquityMath._min(_debt, _THUSDInStabPool); collToSendToSP = _coll * debtToOffset / _debt; debtToRedistribute = _debt - debtToOffset; collToRedistribute = _coll - collToSendToSP; } else { debtToOffset = 0; collToSendToSP = 0; debtToRedistribute = _debt; collToRedistribute = _coll; } } /* * Get its offset coll/debt and collateral gas comp, and close the trove. */ function _getCappedOffsetVals ( uint256 _entireTroveDebt, uint256 _entireTroveColl, uint256 _price ) internal pure returns (LiquidationValues memory singleLiquidation) { singleLiquidation.entireTroveDebt = _entireTroveDebt; singleLiquidation.entireTroveColl = _entireTroveColl; uint256 cappedCollPortion = _entireTroveDebt * MCR / _price; singleLiquidation.collGasCompensation = _getCollGasCompensation(cappedCollPortion); singleLiquidation.THUSDGasCompensation = THUSD_GAS_COMPENSATION; singleLiquidation.debtToOffset = _entireTroveDebt; singleLiquidation.collToSendToSP = cappedCollPortion - singleLiquidation.collGasCompensation; singleLiquidation.collSurplus = _entireTroveColl - cappedCollPortion; singleLiquidation.debtToRedistribute = 0; singleLiquidation.collToRedistribute = 0; } /* * Liquidate a sequence of troves. Closes a maximum number of n under-collateralized Troves, * starting from the one with the lowest collateral ratio in the system, and moving upwards */ function liquidateTroves(uint256 _n) external override { ContractsCache memory contractsCache = ContractsCache( activePool, defaultPool, ITHUSDToken(address(0)), IPCV(address(0)), sortedTroves, ICollSurplusPool(address(0)), address(0) ); IStabilityPool stabilityPoolCached = stabilityPool; LocalVariables_OuterLiquidationFunction memory vars; LiquidationTotals memory totals; vars.price = priceFeed.fetchPrice(); vars.THUSDInStabPool = stabilityPoolCached.getTotalTHUSDDeposits(); vars.recoveryModeAtStart = _checkRecoveryMode(vars.price); // Perform the appropriate liquidation sequence - tally the values, and obtain their totals if (vars.recoveryModeAtStart) { totals = _getTotalsFromLiquidateTrovesSequence_RecoveryMode(contractsCache, vars.price, vars.THUSDInStabPool, _n); } else { // if !vars.recoveryModeAtStart totals = _getTotalsFromLiquidateTrovesSequence_NormalMode(contractsCache.activePool, contractsCache.defaultPool, vars.price, vars.THUSDInStabPool, _n); } require(totals.totalDebtInSequence > 0, "TroveManager: nothing to liquidate"); // Move liquidated collateral and THUSD to the appropriate pools stabilityPoolCached.offset(totals.totalDebtToOffset, totals.totalCollToSendToSP); _redistributeDebtAndColl(contractsCache.activePool, contractsCache.defaultPool, totals.totalDebtToRedistribute, totals.totalCollToRedistribute); if (totals.totalCollSurplus > 0) { contractsCache.activePool.sendCollateral(address(collSurplusPool), totals.totalCollSurplus); } // Update system snapshots _updateSystemSnapshots_excludeCollRemainder(contractsCache.activePool, totals.totalCollGasCompensation); vars.liquidatedDebt = totals.totalDebtInSequence; vars.liquidatedColl = totals.totalCollInSequence - totals.totalCollGasCompensation - totals.totalCollSurplus; emit Liquidation(vars.liquidatedDebt, vars.liquidatedColl, totals.totalCollGasCompensation, totals.totalTHUSDGasCompensation); // Send gas compensation to caller _sendGasCompensation(contractsCache.activePool, msg.sender, totals.totalTHUSDGasCompensation, totals.totalCollGasCompensation); } /* * This function is used when the liquidateTroves sequence starts during Recovery Mode. However, it * handle the case where the system *leaves* Recovery Mode, part way through the liquidation sequence */ function _getTotalsFromLiquidateTrovesSequence_RecoveryMode ( ContractsCache memory _contractsCache, uint256 _price, uint256 _THUSDInStabPool, uint256 _n ) internal returns(LiquidationTotals memory totals) { LocalVariables_LiquidationSequence memory vars; LiquidationValues memory singleLiquidation; vars.remainingTHUSDInStabPool = _THUSDInStabPool; vars.backToNormalMode = false; vars.entireSystemDebt = getEntireSystemDebt(); vars.entireSystemColl = getEntireSystemColl(); vars.user = _contractsCache.sortedTroves.getLast(); address firstUser = _contractsCache.sortedTroves.getFirst(); for (vars.i = 0; vars.i < _n && vars.user != firstUser; vars.i++) { // we need to cache it, because current user is likely going to be deleted address nextUser = _contractsCache.sortedTroves.getPrev(vars.user); vars.ICR = getCurrentICR(vars.user, _price); if (!vars.backToNormalMode) { // Break the loop if ICR is greater than MCR and Stability Pool is empty if (vars.ICR >= MCR && vars.remainingTHUSDInStabPool == 0) { break; } uint256 TCR = LiquityMath._computeCR(vars.entireSystemColl, vars.entireSystemDebt, _price); singleLiquidation = _liquidateRecoveryMode(_contractsCache.activePool, _contractsCache.defaultPool, vars.user, vars.ICR, vars.remainingTHUSDInStabPool, TCR, _price); // Update aggregate trackers vars.remainingTHUSDInStabPool -= singleLiquidation.debtToOffset; vars.entireSystemDebt -= singleLiquidation.debtToOffset; vars.entireSystemColl -= singleLiquidation.collToSendToSP + singleLiquidation.collGasCompensation + singleLiquidation.collSurplus; // Add liquidation values to their respective running totals totals = _addLiquidationValuesToTotals(totals, singleLiquidation); vars.backToNormalMode = !_checkPotentialRecoveryMode(vars.entireSystemColl, vars.entireSystemDebt, _price); } else if (vars.backToNormalMode && vars.ICR < MCR) { singleLiquidation = _liquidateNormalMode(_contractsCache.activePool, _contractsCache.defaultPool, vars.user, vars.remainingTHUSDInStabPool); vars.remainingTHUSDInStabPool -= singleLiquidation.debtToOffset; // Add liquidation values to their respective running totals totals = _addLiquidationValuesToTotals(totals, singleLiquidation); } else break; // break if the loop reaches a Trove with ICR >= MCR vars.user = nextUser; } } function _getTotalsFromLiquidateTrovesSequence_NormalMode ( IActivePool _activePool, IDefaultPool _defaultPool, uint256 _price, uint256 _THUSDInStabPool, uint256 _n ) internal returns(LiquidationTotals memory totals) { LocalVariables_LiquidationSequence memory vars; LiquidationValues memory singleLiquidation; ISortedTroves sortedTrovesCached = sortedTroves; vars.remainingTHUSDInStabPool = _THUSDInStabPool; for (vars.i = 0; vars.i < _n; vars.i++) { vars.user = sortedTrovesCached.getLast(); vars.ICR = getCurrentICR(vars.user, _price); if (vars.ICR < MCR) { singleLiquidation = _liquidateNormalMode(_activePool, _defaultPool, vars.user, vars.remainingTHUSDInStabPool); vars.remainingTHUSDInStabPool -= singleLiquidation.debtToOffset; // Add liquidation values to their respective running totals totals = _addLiquidationValuesToTotals(totals, singleLiquidation); } else break; // break if the loop reaches a Trove with ICR >= MCR } } /* * Attempt to liquidate a custom list of troves provided by the caller. */ function batchLiquidateTroves(address[] memory _troveArray) public override { require(_troveArray.length != 0, "TroveManager: Calldata address array must not be empty"); IActivePool activePoolCached = activePool; IDefaultPool defaultPoolCached = defaultPool; IStabilityPool stabilityPoolCached = stabilityPool; LocalVariables_OuterLiquidationFunction memory vars; LiquidationTotals memory totals; vars.price = priceFeed.fetchPrice(); vars.THUSDInStabPool = stabilityPoolCached.getTotalTHUSDDeposits(); vars.recoveryModeAtStart = _checkRecoveryMode(vars.price); // Perform the appropriate liquidation sequence - tally values and obtain their totals. if (vars.recoveryModeAtStart) { totals = _getTotalFromBatchLiquidate_RecoveryMode(activePoolCached, defaultPoolCached, vars.price, vars.THUSDInStabPool, _troveArray); } else { // if !vars.recoveryModeAtStart totals = _getTotalsFromBatchLiquidate_NormalMode(activePoolCached, defaultPoolCached, vars.price, vars.THUSDInStabPool, _troveArray); } require(totals.totalDebtInSequence > 0, "TroveManager: nothing to liquidate"); // Move liquidated collateral and THUSD to the appropriate pools stabilityPoolCached.offset(totals.totalDebtToOffset, totals.totalCollToSendToSP); _redistributeDebtAndColl(activePoolCached, defaultPoolCached, totals.totalDebtToRedistribute, totals.totalCollToRedistribute); if (totals.totalCollSurplus > 0) { activePoolCached.sendCollateral(address(collSurplusPool), totals.totalCollSurplus); } // Update system snapshots _updateSystemSnapshots_excludeCollRemainder(activePoolCached, totals.totalCollGasCompensation); vars.liquidatedDebt = totals.totalDebtInSequence; vars.liquidatedColl = totals.totalCollInSequence - totals.totalCollGasCompensation - totals.totalCollSurplus; emit Liquidation(vars.liquidatedDebt, vars.liquidatedColl, totals.totalCollGasCompensation, totals.totalTHUSDGasCompensation); // Send gas compensation to caller _sendGasCompensation(activePoolCached, msg.sender, totals.totalTHUSDGasCompensation, totals.totalCollGasCompensation); } /* * This function is used when the batch liquidation sequence starts during Recovery Mode. However, it * handle the case where the system *leaves* Recovery Mode, part way through the liquidation sequence */ function _getTotalFromBatchLiquidate_RecoveryMode ( IActivePool _activePool, IDefaultPool _defaultPool, uint256 _price, uint256 _THUSDInStabPool, address[] memory _troveArray ) internal returns(LiquidationTotals memory totals) { LocalVariables_LiquidationSequence memory vars; LiquidationValues memory singleLiquidation; vars.remainingTHUSDInStabPool = _THUSDInStabPool; vars.backToNormalMode = false; vars.entireSystemDebt = getEntireSystemDebt(); vars.entireSystemColl = getEntireSystemColl(); for (vars.i = 0; vars.i < _troveArray.length; vars.i++) { vars.user = _troveArray[vars.i]; // Skip non-active troves if (Troves[vars.user].status != Status.active) { continue; } vars.ICR = getCurrentICR(vars.user, _price); if (!vars.backToNormalMode) { // Skip this trove if ICR is greater than MCR and Stability Pool is empty if (vars.ICR >= MCR && vars.remainingTHUSDInStabPool == 0) { continue; } uint256 TCR = LiquityMath._computeCR(vars.entireSystemColl, vars.entireSystemDebt, _price); singleLiquidation = _liquidateRecoveryMode(_activePool, _defaultPool, vars.user, vars.ICR, vars.remainingTHUSDInStabPool, TCR, _price); // Update aggregate trackers vars.remainingTHUSDInStabPool -= singleLiquidation.debtToOffset; vars.entireSystemDebt -= singleLiquidation.debtToOffset; vars.entireSystemColl -= singleLiquidation.collToSendToSP + singleLiquidation.collGasCompensation + singleLiquidation.collSurplus; // Add liquidation values to their respective running totals totals = _addLiquidationValuesToTotals(totals, singleLiquidation); vars.backToNormalMode = !_checkPotentialRecoveryMode(vars.entireSystemColl, vars.entireSystemDebt, _price); } else if (vars.backToNormalMode && vars.ICR < MCR) { singleLiquidation = _liquidateNormalMode(_activePool, _defaultPool, vars.user, vars.remainingTHUSDInStabPool); vars.remainingTHUSDInStabPool -= singleLiquidation.debtToOffset; // Add liquidation values to their respective running totals totals = _addLiquidationValuesToTotals(totals, singleLiquidation); } else continue; // In Normal Mode skip troves with ICR >= MCR } } function _getTotalsFromBatchLiquidate_NormalMode ( IActivePool _activePool, IDefaultPool _defaultPool, uint256 _price, uint256 _THUSDInStabPool, address[] memory _troveArray ) internal returns(LiquidationTotals memory totals) { LocalVariables_LiquidationSequence memory vars; LiquidationValues memory singleLiquidation; vars.remainingTHUSDInStabPool = _THUSDInStabPool; for (vars.i = 0; vars.i < _troveArray.length; vars.i++) { vars.user = _troveArray[vars.i]; vars.ICR = getCurrentICR(vars.user, _price); if (vars.ICR < MCR) { singleLiquidation = _liquidateNormalMode(_activePool, _defaultPool, vars.user, vars.remainingTHUSDInStabPool); vars.remainingTHUSDInStabPool -= singleLiquidation.debtToOffset; // Add liquidation values to their respective running totals totals = _addLiquidationValuesToTotals(totals, singleLiquidation); } } } // --- Liquidation helper functions --- function _addLiquidationValuesToTotals(LiquidationTotals memory oldTotals, LiquidationValues memory singleLiquidation) internal pure returns(LiquidationTotals memory newTotals) { // Tally all the values with their respective running totals newTotals.totalCollGasCompensation = oldTotals.totalCollGasCompensation + singleLiquidation.collGasCompensation; newTotals.totalTHUSDGasCompensation = oldTotals.totalTHUSDGasCompensation + singleLiquidation.THUSDGasCompensation; newTotals.totalDebtInSequence = oldTotals.totalDebtInSequence + singleLiquidation.entireTroveDebt; newTotals.totalCollInSequence = oldTotals.totalCollInSequence + singleLiquidation.entireTroveColl; newTotals.totalDebtToOffset = oldTotals.totalDebtToOffset + singleLiquidation.debtToOffset; newTotals.totalCollToSendToSP = oldTotals.totalCollToSendToSP + singleLiquidation.collToSendToSP; newTotals.totalDebtToRedistribute = oldTotals.totalDebtToRedistribute + singleLiquidation.debtToRedistribute; newTotals.totalCollToRedistribute = oldTotals.totalCollToRedistribute + singleLiquidation.collToRedistribute; newTotals.totalCollSurplus = oldTotals.totalCollSurplus + singleLiquidation.collSurplus; return newTotals; } function _sendGasCompensation(IActivePool _activePool, address _liquidator, uint256 _THUSD, uint256 _collateral) internal { if (_THUSD > 0) { IGasPool(gasPoolAddress).sendTHUSD(_liquidator, _THUSD); } if (_collateral > 0) { _activePool.sendCollateral(_liquidator, _collateral); } } // Move a Trove's pending debt and collateral rewards from distributions, from the Default Pool to the Active Pool function _movePendingTroveRewardsToActivePool(IActivePool _activePool, IDefaultPool _defaultPool, uint256 _THUSD, uint256 _collateral) internal { _defaultPool.decreaseTHUSDDebt(_THUSD); _activePool.increaseTHUSDDebt(_THUSD); _defaultPool.sendCollateralToActivePool(_collateral); } // --- Redemption functions --- // Redeem as much collateral as possible from _borrower's Trove in exchange for THUSD up to _maxTHUSDamount function _redeemCollateralFromTrove( ContractsCache memory _contractsCache, address _borrower, uint256 _maxTHUSDamount, uint256 _price, address _upperPartialRedemptionHint, address _lowerPartialRedemptionHint, uint256 _partialRedemptionHintNICR ) internal returns (SingleRedemptionValues memory singleRedemption) { // Determine the remaining amount (lot) to be redeemed, capped by the entire debt of the Trove minus the liquidation reserve singleRedemption.THUSDLot = LiquityMath._min(_maxTHUSDamount, Troves[_borrower].debt - THUSD_GAS_COMPENSATION); // Get the collateralLot of equivalent value in USD singleRedemption.collateralLot = singleRedemption.THUSDLot * DECIMAL_PRECISION / _price; // Decrease the debt and collateral of the current Trove according to the THUSD lot and corresponding collateral to send uint256 newDebt = Troves[_borrower].debt - singleRedemption.THUSDLot; uint256 newColl = Troves[_borrower].coll - singleRedemption.collateralLot; if (newDebt == THUSD_GAS_COMPENSATION) { // No debt left in the Trove (except for the liquidation reserve), therefore the trove gets closed _removeStake(_borrower); _closeTrove(_borrower, Status.closedByRedemption); _redeemCloseTrove(_contractsCache, _borrower, THUSD_GAS_COMPENSATION, newColl); emit TroveUpdated(_borrower, 0, 0, 0, TroveManagerOperation.redeemCollateral); } else { uint256 newNICR = LiquityMath._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. */ if (newNICR != _partialRedemptionHintNICR || _getNetDebt(newDebt) < MIN_NET_DEBT) { singleRedemption.cancelledPartial = true; return singleRedemption; } _contractsCache.sortedTroves.reInsert(_borrower, newNICR, _upperPartialRedemptionHint, _lowerPartialRedemptionHint); Troves[_borrower].debt = newDebt; Troves[_borrower].coll = newColl; _updateStakeAndTotalStakes(_borrower); emit TroveUpdated( _borrower, newDebt, newColl, Troves[_borrower].stake, TroveManagerOperation.redeemCollateral ); } return singleRedemption; } /* * Called when a full redemption occurs, and closes the trove. * The redeemer swaps (debt - liquidation reserve) THUSD for (debt - liquidation reserve) worth of collateral, so the THUSD liquidation reserve left corresponds to the remaining debt. * In order to close the trove, the THUSD liquidation reserve is burned, and the corresponding debt is removed from the active pool. * The debt recorded on the trove's struct is zero'd elswhere, in _closeTrove. * Any surplus collateral left in the trove, is sent to the Coll surplus pool, and can be later claimed by the borrower. */ function _redeemCloseTrove(ContractsCache memory _contractsCache, address _borrower, uint256 _THUSD, uint256 _collateral) internal { _contractsCache.thusdToken.burn(gasPoolAddress, _THUSD); // Update Active Pool THUSD, and send collateral to account _contractsCache.activePool.decreaseTHUSDDebt(_THUSD); // send collateral from Active Pool to CollSurplus Pool _contractsCache.collSurplusPool.accountSurplus(_borrower, _collateral); _contractsCache.activePool.sendCollateral(address(_contractsCache.collSurplusPool), _collateral); } function _isValidFirstRedemptionHint(ISortedTroves _sortedTroves, address _firstRedemptionHint, uint256 _price) internal view returns (bool) { if (_firstRedemptionHint == address(0) || !_sortedTroves.contains(_firstRedemptionHint) || getCurrentICR(_firstRedemptionHint, _price) < MCR ) { return false; } address nextTrove = _sortedTroves.getNext(_firstRedemptionHint); return nextTrove == address(0) || getCurrentICR(nextTrove, _price) < MCR; } /* Send _THUSDamount THUSD to the system and redeem the corresponding amount of collateral from as many Troves as are needed to fill the redemption * request. Applies pending rewards to a Trove before reducing its debt and coll. * * Note that if _amount is very large, this function can run out of gas, specially if traversed troves 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 Troves 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 trove 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 Troves 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 Trove 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 Trove will be after redemption, and pass a hint for its position * in the sortedTroves 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 Trove 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 Trove and the sender will keep the remaining THUSD amount, which they can attempt * to redeem later. */ function redeemCollateral( uint256 _THUSDamount, address _firstRedemptionHint, address _upperPartialRedemptionHint, address _lowerPartialRedemptionHint, uint256 _partialRedemptionHintNICR, uint256 _maxIterations, uint256 _maxFeePercentage ) external override { ContractsCache memory contractsCache = ContractsCache( activePool, defaultPool, thusdToken, pcv, sortedTroves, collSurplusPool, gasPoolAddress ); RedemptionTotals memory totals; _requireValidMaxFeePercentage(_maxFeePercentage); totals.price = priceFeed.fetchPrice(); _requireTCRoverMCR(totals.price); _requireAmountGreaterThanZero(_THUSDamount); _requireTHUSDBalanceCoversRedemption(contractsCache.thusdToken, msg.sender, _THUSDamount); totals.totalTHUSDDebtAtStart = getEntireSystemDebt(); totals.remainingTHUSD = _THUSDamount; address currentBorrower; if (_isValidFirstRedemptionHint(contractsCache.sortedTroves, _firstRedemptionHint, totals.price)) { currentBorrower = _firstRedemptionHint; } else { currentBorrower = contractsCache.sortedTroves.getLast(); // Find the first trove with ICR >= MCR while (currentBorrower != address(0) && getCurrentICR(currentBorrower, totals.price) < MCR) { currentBorrower = contractsCache.sortedTroves.getPrev(currentBorrower); } } // Loop through the Troves starting from the one with lowest collateral ratio until _amount of THUSD is exchanged for collateral if (_maxIterations == 0) { _maxIterations = type(uint256).max; } while (currentBorrower != address(0) && totals.remainingTHUSD > 0 && _maxIterations > 0) { _maxIterations--; // Save the address of the Trove preceding the current one, before potentially modifying the list address nextUserToCheck = contractsCache.sortedTroves.getPrev(currentBorrower); _applyPendingRewards(contractsCache.activePool, contractsCache.defaultPool, currentBorrower); SingleRedemptionValues memory singleRedemption = _redeemCollateralFromTrove( contractsCache, currentBorrower, totals.remainingTHUSD, 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 Trove totals.totalTHUSDToRedeem += singleRedemption.THUSDLot; totals.totalCollateralDrawn += singleRedemption.collateralLot; totals.remainingTHUSD -= singleRedemption.THUSDLot; currentBorrower = nextUserToCheck; } require(totals.totalCollateralDrawn > 0, "TroveManager: 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 THUSD supply value, from before it was reduced by the redemption. _updateBaseRateFromRedemption(totals.totalCollateralDrawn, totals.price, totals.totalTHUSDDebtAtStart); // Calculate the collateral fee totals.collateralFee = _getRedemptionFee(totals.totalCollateralDrawn); _requireUserAcceptsFee(totals.collateralFee, totals.totalCollateralDrawn, _maxFeePercentage); // Send the collateral fee to the PCV contract contractsCache.activePool.sendCollateral(address(contractsCache.pcv), totals.collateralFee); totals.collateralToSendToRedeemer = totals.totalCollateralDrawn - totals.collateralFee; emit Redemption(_THUSDamount, totals.totalTHUSDToRedeem, totals.totalCollateralDrawn, totals.collateralFee); // Burn the total THUSD that is cancelled with debt, and send the redeemed collateral to msg.sender contractsCache.thusdToken.burn(msg.sender, totals.totalTHUSDToRedeem); // Update Active Pool THUSD, and send collateral to account contractsCache.activePool.decreaseTHUSDDebt(totals.totalTHUSDToRedeem); contractsCache.activePool.sendCollateral(msg.sender, totals.collateralToSendToRedeemer); } // --- Helper functions --- // Return the nominal collateral ratio (ICR) of a given Trove, without the price. Takes a trove's pending coll and debt rewards from redistributions into account. function getNominalICR(address _borrower) public view override returns (uint) { (uint256 currentCollateral, uint256 currentTHUSDDebt) = _getCurrentTroveAmounts(_borrower); uint256 NICR = LiquityMath._computeNominalCR(currentCollateral, currentTHUSDDebt); return NICR; } // Return the current collateral ratio (ICR) of a given Trove. Takes a trove's pending coll and debt rewards from redistributions into account. function getCurrentICR(address _borrower, uint256 _price) public view override returns (uint) { (uint256 currentCollateral, uint256 currentTHUSDDebt) = _getCurrentTroveAmounts(_borrower); uint256 ICR = LiquityMath._computeCR(currentCollateral, currentTHUSDDebt, _price); return ICR; } function _getCurrentTroveAmounts(address _borrower) internal view returns (uint, uint) { uint256 pendingCollateralReward = getPendingCollateralReward(_borrower); uint256 pendingTHUSDDebtReward = getPendingTHUSDDebtReward(_borrower); uint256 currentCollateral = Troves[_borrower].coll + pendingCollateralReward; uint256 currentTHUSDDebt = Troves[_borrower].debt + pendingTHUSDDebtReward; return (currentCollateral, currentTHUSDDebt); } function applyPendingRewards(address _borrower) external override { _requireCallerIsBorrowerOperations(); return _applyPendingRewards(activePool, defaultPool, _borrower); } // Add the borrowers's coll and debt rewards earned from redistributions, to their Trove function _applyPendingRewards(IActivePool _activePool, IDefaultPool _defaultPool, address _borrower) internal { if (hasPendingRewards(_borrower)) { _requireTroveIsActive(_borrower); // Compute pending rewards uint256 pendingCollateralReward = getPendingCollateralReward(_borrower); uint256 pendingTHUSDDebtReward = getPendingTHUSDDebtReward(_borrower); // Apply pending rewards to trove's state Troves[_borrower].coll += pendingCollateralReward; Troves[_borrower].debt += pendingTHUSDDebtReward; _updateTroveRewardSnapshots(_borrower); // Transfer from DefaultPool to ActivePool _movePendingTroveRewardsToActivePool(_activePool, _defaultPool, pendingTHUSDDebtReward, pendingCollateralReward); emit TroveUpdated( _borrower, Troves[_borrower].debt, Troves[_borrower].coll, Troves[_borrower].stake, TroveManagerOperation.applyPendingRewards ); } } // Update borrower's snapshots of L_Collateral and L_THUSDDebt to reflect the current values function updateTroveRewardSnapshots(address _borrower) external override { _requireCallerIsBorrowerOperations(); return _updateTroveRewardSnapshots(_borrower); } function _updateTroveRewardSnapshots(address _borrower) internal { rewardSnapshots[_borrower].collateral = L_Collateral; rewardSnapshots[_borrower].THUSDDebt = L_THUSDDebt; emit TroveSnapshotsUpdated(L_Collateral, L_THUSDDebt); } // Get the borrower's pending accumulated collateral reward, earned by their stake function getPendingCollateralReward(address _borrower) public view override returns (uint) { uint256 snapshotCollateral = rewardSnapshots[_borrower].collateral; uint256 rewardPerUnitStaked = L_Collateral - snapshotCollateral; if ( rewardPerUnitStaked == 0 || Troves[_borrower].status != Status.active) { return 0; } uint256 stake = Troves[_borrower].stake; uint256 pendingCollateralReward = stake * rewardPerUnitStaked / DECIMAL_PRECISION; return pendingCollateralReward; } // Get the borrower's pending accumulated THUSD reward, earned by their stake function getPendingTHUSDDebtReward(address _borrower) public view override returns (uint) { uint256 snapshotTHUSDDebt = rewardSnapshots[_borrower].THUSDDebt; uint256 rewardPerUnitStaked = L_THUSDDebt - snapshotTHUSDDebt; if ( rewardPerUnitStaked == 0 || Troves[_borrower].status != Status.active) { return 0; } uint256 stake = Troves[_borrower].stake; uint256 pendingTHUSDDebtReward = stake * rewardPerUnitStaked / DECIMAL_PRECISION; return pendingTHUSDDebtReward; } function hasPendingRewards(address _borrower) public view override returns (bool) { /* * A Trove 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 (Troves[_borrower].status != Status.active) {return false;} return (rewardSnapshots[_borrower].collateral < L_Collateral); } // Return the Troves entire debt and coll, including pending rewards from redistributions. function getEntireDebtAndColl( address _borrower ) public view override returns (uint256 debt, uint256 coll, uint256 pendingTHUSDDebtReward, uint256 pendingCollateralReward) { debt = Troves[_borrower].debt; coll = Troves[_borrower].coll; pendingTHUSDDebtReward = getPendingTHUSDDebtReward(_borrower); pendingCollateralReward = getPendingCollateralReward(_borrower); debt += pendingTHUSDDebtReward; coll += pendingCollateralReward; } function removeStake(address _borrower) external override { _requireCallerIsBorrowerOperations(); return _removeStake(_borrower); } // Remove borrower's stake from the totalStakes sum, and set their stake to 0 function _removeStake(address _borrower) internal { uint256 stake = Troves[_borrower].stake; totalStakes -= stake; Troves[_borrower].stake = 0; } function updateStakeAndTotalStakes(address _borrower) external override returns (uint) { _requireCallerIsBorrowerOperations(); return _updateStakeAndTotalStakes(_borrower); } // Update borrower's stake based on their latest collateral value function _updateStakeAndTotalStakes(address _borrower) internal returns (uint) { uint256 newStake = _computeNewStake(Troves[_borrower].coll); uint256 oldStake = Troves[_borrower].stake; Troves[_borrower].stake = newStake; totalStakes = totalStakes - oldStake + newStake; emit TotalStakesUpdated(totalStakes); 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 (uint) { uint256 stake; if (totalCollateralSnapshot == 0) { stake = _coll; } else { /* * The following assert() holds true because: * - The system always contains >= 1 trove * - When we close or liquidate a trove, we redistribute the pending rewards, so if all troves were closed/liquidated, * rewards would’ve been emptied and totalCollateralSnapshot would be zero too. */ assert(totalStakesSnapshot > 0); stake = _coll * totalStakesSnapshot / totalCollateralSnapshot; } return stake; } function _redistributeDebtAndColl(IActivePool _activePool, IDefaultPool _defaultPool, 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_THUSDDebt: * * 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 denominator, 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 THUSDDebtNumerator = _debt * DECIMAL_PRECISION + lastTHUSDDebtError_Redistribution; // Get the per-unit-staked terms uint256 collateralRewardPerUnitStaked = collateralNumerator / totalStakes; uint256 THUSDDebtRewardPerUnitStaked = THUSDDebtNumerator / totalStakes; lastCollateralError_Redistribution = collateralNumerator - (collateralRewardPerUnitStaked * totalStakes); lastTHUSDDebtError_Redistribution = THUSDDebtNumerator - (THUSDDebtRewardPerUnitStaked * totalStakes); // Add per-unit-staked terms to the running totals L_Collateral += collateralRewardPerUnitStaked; L_THUSDDebt += THUSDDebtRewardPerUnitStaked; emit LTermsUpdated(L_Collateral, L_THUSDDebt); // Transfer coll and debt from ActivePool to DefaultPool _activePool.decreaseTHUSDDebt(_debt); _defaultPool.increaseTHUSDDebt(_debt); _activePool.sendCollateral(address(_defaultPool), _coll); } function closeTrove(address _borrower) external override { _requireCallerIsBorrowerOperations(); return _closeTrove(_borrower, Status.closedByOwner); } function _closeTrove(address _borrower, Status closedStatus) internal { assert(closedStatus != Status.nonExistent && closedStatus != Status.active); uint256 TroveOwnersArrayLength = TroveOwners.length; if (thusdToken.mintList(borrowerOperationsAddress)) { _requireMoreThanOneTroveInSystem(TroveOwnersArrayLength); } Troves[_borrower].status = closedStatus; Troves[_borrower].coll = 0; Troves[_borrower].debt = 0; rewardSnapshots[_borrower].collateral = 0; rewardSnapshots[_borrower].THUSDDebt = 0; _removeTroveOwner(_borrower, TroveOwnersArrayLength); sortedTroves.remove(_borrower); } /* * Updates snapshots of system total stakes and total collateral, excluding a given collateral remainder from the calculation. * Used in a liquidation sequence. * * The calculation excludes a portion of collateral that is in the ActivePool: * * the total collateral gas compensation from the liquidation sequence * * The collateral as compensation must be excluded as it is always sent out at the very end of the liquidation sequence. */ function _updateSystemSnapshots_excludeCollRemainder(IActivePool _activePool, uint256 _collRemainder) internal { totalStakesSnapshot = totalStakes; uint256 activeColl = _activePool.getCollateralBalance(); uint256 liquidatedColl = defaultPool.getCollateralBalance(); totalCollateralSnapshot = activeColl - _collRemainder + liquidatedColl; emit SystemSnapshotsUpdated(totalStakesSnapshot, totalCollateralSnapshot); } // Push the owner's address to the Trove owners list, and record the corresponding array index on the Trove struct function addTroveOwnerToArray(address _borrower) external override returns (uint256 index) { _requireCallerIsBorrowerOperations(); return _addTroveOwnerToArray(_borrower); } function _addTroveOwnerToArray(address _borrower) internal returns (uint128 index) { /* Max array size is 2**128 - 1, i.e. ~3e30 troves. No risk of overflow, since troves have minimum THUSD debt of liquidation reserve plus MIN_NET_DEBT. 3e30 THUSD dwarfs the value of all wealth in the world ( which is < 1e15 USD). */ // Push the Troveowner to the array TroveOwners.push(_borrower); // Record the index of the new Troveowner on their Trove struct index = uint128(TroveOwners.length - 1); Troves[_borrower].arrayIndex = index; return index; } /* * Remove a Trove owner from the TroveOwners array, not preserving array order. Removing owner 'B' does the following: * [A B C D E] => [A E C D], and updates E's Trove struct to point to its new array index. */ function _removeTroveOwner(address _borrower, uint256 TroveOwnersArrayLength) internal { Status troveStatus = Troves[_borrower].status; // It’s set in caller function `_closeTrove` assert(troveStatus != Status.nonExistent && troveStatus != Status.active); uint128 index = Troves[_borrower].arrayIndex; uint256 length = TroveOwnersArrayLength; uint256 idxLast = length - 1; assert(index <= idxLast); address addressToMove = TroveOwners[idxLast]; TroveOwners[index] = addressToMove; Troves[addressToMove].arrayIndex = index; emit TroveIndexUpdated(addressToMove, index); TroveOwners.pop(); } // --- Recovery Mode and TCR functions --- function getTCR(uint256 _price) external view override returns (uint) { return _getTCR(_price); } function checkRecoveryMode(uint256 _price) external view override returns (bool) { return _checkRecoveryMode(_price); } // Check whether or not the system *would be* in Recovery Mode, given an collateral:USD price, and the entire system coll and debt. function _checkPotentialRecoveryMode( uint256 _entireSystemColl, uint256 _entireSystemDebt, uint256 _price ) internal pure returns (bool) { uint256 TCR = LiquityMath._computeCR(_entireSystemColl, _entireSystemDebt, _price); return TCR < CCR; } // --- 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 THUSD borrowing operation. * then, * 2) increases the baseRate based on the amount redeemed, as a proportion of total debt */ function _updateBaseRateFromRedemption(uint256 _collateralDrawn, uint256 _price, uint256 _totalTHUSDDebt) internal returns (uint) { uint256 decayedBaseRate = _calcDecayedBaseRate(); /* Convert the drawn collateral back to THUSD at face value rate (1 THUSD:1 USD), in order to get * the fraction of total supply that was redeemed at face value. */ uint256 redeemedTHUSDFraction = _collateralDrawn * _price / _totalTHUSDDebt; uint256 newBaseRate = decayedBaseRate + (redeemedTHUSDFraction / BETA); newBaseRate = LiquityMath._min(newBaseRate, DECIMAL_PRECISION); // cap baseRate at a maximum of 100% //assert(newBaseRate <= DECIMAL_PRECISION); // This is already enforced in the line above assert(newBaseRate > 0); // Base rate is always non-zero after redemption // Update the baseRate state variable baseRate = newBaseRate; emit BaseRateUpdated(newBaseRate); _updateLastFeeOpTime(); return newBaseRate; } function getRedemptionRate() public view override returns (uint) { return _calcRedemptionRate(baseRate); } function getRedemptionRateWithDecay() public view override returns (uint) { return _calcRedemptionRate(_calcDecayedBaseRate()); } function _calcRedemptionRate(uint256 _baseRate) internal pure returns (uint) { return LiquityMath._min( REDEMPTION_FEE_FLOOR + _baseRate, DECIMAL_PRECISION // cap at a maximum of 100% ); } function _getRedemptionFee(uint256 _collateralDrawn) internal view returns (uint) { return _calcRedemptionFee(getRedemptionRate(), _collateralDrawn); } function getRedemptionFeeWithDecay(uint256 _collateralDrawn) external view override returns (uint) { return _calcRedemptionFee(getRedemptionRateWithDecay(), _collateralDrawn); } function _calcRedemptionFee(uint256 _redemptionRate, uint256 _collateralDrawn) internal pure returns (uint) { uint256 redemptionFee = _redemptionRate * _collateralDrawn / DECIMAL_PRECISION; require(redemptionFee < _collateralDrawn, "TroveManager: Fee would eat up all returned collateral"); return redemptionFee; } // --- Borrowing fee functions --- function getBorrowingRate() public view override returns (uint) { return _calcBorrowingRate(baseRate); } function getBorrowingRateWithDecay() public view override returns (uint) { return _calcBorrowingRate(_calcDecayedBaseRate()); } function _calcBorrowingRate(uint256 _baseRate) internal pure returns (uint) { return LiquityMath._min( BORROWING_FEE_FLOOR + _baseRate, MAX_BORROWING_FEE ); } function getBorrowingFee(uint256 _THUSDDebt) external view override returns (uint) { return _calcBorrowingFee(getBorrowingRate(), _THUSDDebt); } function getBorrowingFeeWithDecay(uint256 _THUSDDebt) external view override returns (uint) { return _calcBorrowingFee(getBorrowingRateWithDecay(), _THUSDDebt); } function _calcBorrowingFee(uint256 _borrowingRate, uint256 _THUSDDebt) internal pure returns (uint) { return _borrowingRate * _THUSDDebt / DECIMAL_PRECISION; } // Updates the baseRate state variable based on time elapsed since the last redemption or THUSD borrowing operation. function decayBaseRateFromBorrowing() external override { _requireCallerIsBorrowerOperations(); uint256 decayedBaseRate = _calcDecayedBaseRate(); assert(decayedBaseRate <= DECIMAL_PRECISION); // The baseRate can decay to 0 baseRate = decayedBaseRate; emit BaseRateUpdated(decayedBaseRate); _updateLastFeeOpTime(); } // --- 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 >= 1 minutes) { lastFeeOperationTime = block.timestamp; emit LastFeeOpTimeUpdated(block.timestamp); } } function _calcDecayedBaseRate() internal view returns (uint) { uint256 minutesPassed = _minutesPassedSinceLastFeeOp(); uint256 decayFactor = LiquityMath._decPow(MINUTE_DECAY_FACTOR, minutesPassed); return baseRate * decayFactor / DECIMAL_PRECISION; } function _minutesPassedSinceLastFeeOp() internal view returns (uint) { return (block.timestamp - lastFeeOperationTime) / 1 minutes; } // --- 'require' wrapper functions --- function _requireCallerIsBorrowerOperations() internal view { require(msg.sender == borrowerOperationsAddress, "TroveManager: Caller is not the BorrowerOperations contract"); } function _requireTroveIsActive(address _borrower) internal view { require(Troves[_borrower].status == Status.active, "TroveManager: Trove does not exist or is closed"); } function _requireTHUSDBalanceCoversRedemption(ITHUSDToken _thusdToken, address _redeemer, uint256 _amount) internal view { require(_thusdToken.balanceOf(_redeemer) >= _amount, "TroveManager: Requested redemption amount must be <= user's THUSD token balance"); } function _requireMoreThanOneTroveInSystem(uint256 TroveOwnersArrayLength) internal view { require (TroveOwnersArrayLength > 1 && sortedTroves.getSize() > 1, "TroveManager: Only one trove in the system"); } function _requireAmountGreaterThanZero(uint256 _amount) internal pure { require(_amount > 0, "TroveManager: Amount must be greater than zero"); } function _requireTCRoverMCR(uint256 _price) internal view { require(_getTCR(_price) >= MCR, "TroveManager: Cannot redeem when TCR < MCR"); } function _requireValidMaxFeePercentage(uint256 _maxFeePercentage) internal pure { require(_maxFeePercentage >= REDEMPTION_FEE_FLOOR && _maxFeePercentage <= DECIMAL_PRECISION, "Max fee percentage must be between 0.5% and 100%"); } // --- Trove property getters --- function getTroveStatus(address _borrower) external view override returns (Status) { return Troves[_borrower].status; } function getTroveStake(address _borrower) external view override returns (uint) { return Troves[_borrower].stake; } function getTroveDebt(address _borrower) external view override returns (uint) { return Troves[_borrower].debt; } function getTroveColl(address _borrower) external view override returns (uint) { return Troves[_borrower].coll; } // --- Trove property setters, called by BorrowerOperations --- function setTroveStatus(address _borrower, Status _status) external override { _requireCallerIsBorrowerOperations(); Troves[_borrower].status = _status; } function increaseTroveColl(address _borrower, uint256 _collIncrease) external override returns (uint) { _requireCallerIsBorrowerOperations(); uint256 newColl = Troves[_borrower].coll + _collIncrease; Troves[_borrower].coll = newColl; return newColl; } function decreaseTroveColl(address _borrower, uint256 _collDecrease) external override returns (uint) { _requireCallerIsBorrowerOperations(); uint256 newColl = Troves[_borrower].coll - _collDecrease; Troves[_borrower].coll = newColl; return newColl; } function increaseTroveDebt(address _borrower, uint256 _debtIncrease) external override returns (uint) { _requireCallerIsBorrowerOperations(); uint256 newDebt = Troves[_borrower].debt + _debtIncrease; Troves[_borrower].debt = newDebt; return newDebt; } function decreaseTroveDebt(address _borrower, uint256 _debtDecrease) external override returns (uint) { _requireCallerIsBorrowerOperations(); uint256 newDebt = Troves[_borrower].debt - _debtDecrease; Troves[_borrower].debt = newDebt; return newDebt; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol) pragma solidity ^0.8.0; import "../IERC20.sol"; /** * @dev Interface for the optional metadata functions from the ERC20 standard. * * _Available since v4.1._ */ interface IERC20Metadata is IERC20 { /** * @dev Returns the name of the token. */ function name() external view returns (string memory); /** * @dev Returns the symbol of the token. */ function symbol() external view returns (string memory); /** * @dev Returns the decimals places of the token. */ function decimals() external view returns (uint8); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.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 pragma solidity ^0.8.17; contract BaseMath { uint256 constant public DECIMAL_PRECISION = 1e18; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.17; contract CheckContract { /** * Check that the account is an already deployed non-destroyed contract. * See: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/Address.sol#L12 */ function checkContract(address _account) internal view { require(_account != address(0), "Account cannot be zero address"); uint256 size; // solhint-disable-next-line no-inline-assembly assembly { size := extcodesize(_account) } require(size > 0, "Account code size cannot be zero"); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.17; /** * @dev Interface of the ERC2612 standard as defined in the EIP. * * Adds the {permit} method, which can be used to change one's * {IERC20-allowance} without having to send a transaction, by signing a * message. This allows users to spend tokens without having to hold Ether. * * See https://eips.ethereum.org/EIPS/eip-2612. * * Code adapted from https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2237/ */ interface IERC2612 { /** * @dev Sets `amount` as the allowance of `spender` over `owner`'s tokens, * given `owner`'s signed approval. * * IMPORTANT: The same issues {IERC20-approve} has related to transaction * ordering also apply here. * * Emits an {Approval} event. * * Requirements: * * - `owner` cannot be the zero address. * - `spender` cannot be the zero address. * - `deadline` must be a timestamp in the future. * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner` * over the EIP712-formatted function arguments. * - the signature must use ``owner``'s current nonce (see {nonces}). * * For more information on the signature format, see the * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP * section]. */ function permit(address owner, address spender, uint256 amount, uint256 deadline, uint8 v, bytes32 r, bytes32 s) external; /** * @dev Returns the current ERC2612 nonce for `owner`. This value must be * included whenever a signature is generated for {permit}. * * Every successful call to {permit} increases `owner`'s nonce by one. This * prevents a signature from being used multiple times. * * `owner` can limit the time a Permit is valid for by setting `deadline` to * a value in the near future. The deadline argument can be set to uint(-1) to * create Permits that effectively never expire. */ function nonces(address owner) external view returns (uint256); function version() external view returns (string memory); function permitTypeHash() external view returns (bytes32); function domainSeparator() external view returns (bytes32); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.17; import "./BaseMath.sol"; import "./LiquityMath.sol"; import "../Interfaces/IActivePool.sol"; import "../Interfaces/IDefaultPool.sol"; import "../Interfaces/IPriceFeed.sol"; import "../Interfaces/ILiquityBase.sol"; /* * Base contract for TroveManager, BorrowerOperations and StabilityPool. Contains global system constants and * common functions. */ contract LiquityBase is BaseMath, ILiquityBase { uint256 constant public _100pct = 1e18; // 1e18 == 100% // Minimum collateral ratio for individual troves uint256 constant public MCR = 1.1e18; // 110% // Critical system collateral ratio. If the system's total collateral ratio (TCR) falls below the CCR, Recovery Mode is triggered. uint256 constant public CCR = 1.5e18; // 150% // Amount of THUSD to be locked in gas pool on opening troves uint256 constant public THUSD_GAS_COMPENSATION = 200e18; // Minimum amount of net THUSD debt a trove must have uint256 constant public MIN_NET_DEBT = 1800e18; // uint256 constant public MIN_NET_DEBT = 0; uint256 constant public PERCENT_DIVISOR = 200; // dividing by 200 yields 0.5% uint256 constant public BORROWING_FEE_FLOOR = DECIMAL_PRECISION / 1000 * 5; // 0.5% IActivePool public activePool; IDefaultPool public defaultPool; IPriceFeed public override priceFeed; // --- Gas compensation functions --- // Returns the composite debt (drawn debt + gas compensation) of a trove, for the purpose of ICR calculation function _getCompositeDebt(uint256 _debt) internal pure returns (uint) { return _debt + THUSD_GAS_COMPENSATION; } function _getNetDebt(uint256 _debt) internal pure returns (uint) { return _debt - THUSD_GAS_COMPENSATION; } // Return the amount of collateral to be drawn from a trove's collateral and sent as gas compensation. function _getCollGasCompensation(uint256 _entireColl) internal pure returns (uint) { return _entireColl / PERCENT_DIVISOR; } function getEntireSystemColl() public view returns (uint256 entireSystemColl) { uint256 activeColl = activePool.getCollateralBalance(); uint256 liquidatedColl = defaultPool.getCollateralBalance(); return activeColl + liquidatedColl; } function getEntireSystemDebt() public view returns (uint256 entireSystemDebt) { uint256 activeDebt = activePool.getTHUSDDebt(); uint256 closedDebt = defaultPool.getTHUSDDebt(); return activeDebt + closedDebt; } function _getTCR(uint256 _price) internal view returns (uint256 TCR) { uint256 entireSystemColl = getEntireSystemColl(); uint256 entireSystemDebt = getEntireSystemDebt(); TCR = LiquityMath._computeCR(entireSystemColl, entireSystemDebt, _price); return TCR; } function _checkRecoveryMode(uint256 _price) internal view returns (bool) { uint256 TCR = _getTCR(_price); return TCR < CCR; } function _requireUserAcceptsFee(uint256 _fee, uint256 _amount, uint256 _maxFeePercentage) internal pure { uint256 feePercentage = _fee * DECIMAL_PRECISION / _amount; require(feePercentage <= _maxFeePercentage, "Fee exceeded provided maximum"); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.17; library LiquityMath { 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 ETH, * and will only truncate to 0 if the denominator is at least 1e20 times greater than the numerator. * */ uint256 internal constant NICR_PRECISION = 1e20; function _min(uint256 _a, uint256 _b) internal pure returns (uint) { return (_a < _b) ? _a : _b; } function _max(uint256 _a, uint256 _b) internal pure returns (uint) { 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 one function that represent time in units of minutes: * 1) TroveManager._calcDecayedBaseRate * * 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 (uint) { 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 (uint) { return (_a >= _b) ? _a - _b : _b - _a; } function _computeNominalCR(uint256 _coll, uint256 _debt) internal pure returns (uint) { if (_debt > 0) { return _coll * NICR_PRECISION / _debt; } // Return the maximal value for uint256 if the Trove has a debt of 0. Represents "infinite" CR. else { // if (_debt == 0) return type(uint256).max; } } function _computeCR(uint256 _coll, uint256 _debt, uint256 _price) internal pure returns (uint) { if (_debt > 0) { uint256 newCollRatio = _coll * _price / _debt; return newCollRatio; } // Return the maximal value for uint256 if the Trove has a debt of 0. Represents "infinite" CR. else { // if (_debt == 0) return type(uint256).max; } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.17; /** * Based on OpenZeppelin's Ownable contract: * https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/access/Ownable.sol * * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be applied to your functions to restrict their use to * the owner. */ contract Ownable { address private _owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the deployer as the initial owner. */ constructor () { _owner = msg.sender; emit OwnershipTransferred(address(0), msg.sender); } /** * @dev Returns the address of the current owner. */ function owner() public view returns (address) { return _owner; } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { require(isOwner(), "Ownable: caller is not the owner"); _; } /** * @dev Returns true if the caller is the current owner. */ function isOwner() public view returns (bool) { return msg.sender == _owner; } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions anymore. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby removing any functionality that is only available to the owner. * * NOTE: This function is not safe, as it doesn’t check owner is calling it. * Make sure you check it before calling it. */ function _renounceOwnership() internal { emit OwnershipTransferred(_owner, address(0)); _owner = address(0); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual onlyOwner { require(newOwner != address(0), "Ownable: new owner is the zero address"); _transferOwnership(newOwner); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Internal function without access restriction. */ function _transferOwnership(address newOwner) internal virtual { address oldOwner = _owner; _owner = newOwner; emit OwnershipTransferred(oldOwner, newOwner); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.17; import "./IPool.sol"; interface IActivePool is IPool { // --- Events --- event BorrowerOperationsAddressChanged(address _newBorrowerOperationsAddress); event TroveManagerAddressChanged(address _newTroveManagerAddress); event ActivePoolTHUSDDebtUpdated(uint256 _THUSDDebt); event ActivePoolCollateralBalanceUpdated(uint256 _collateral); event CollateralAddressChanged(address _newCollateralAddress); event CollSurplusPoolAddressChanged(address _newCollSurplusPoolAddress); // --- Functions --- function sendCollateral(address _account, uint256 _amount) external; function updateCollateralBalance(uint256 _amount) external; function collateralAddress() external view returns(address); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.17; interface ICollSurplusPool { // --- Events --- event BorrowerOperationsAddressChanged(address _newBorrowerOperationsAddress); event TroveManagerAddressChanged(address _newTroveManagerAddress); event ActivePoolAddressChanged(address _newActivePoolAddress); event CollateralAddressChanged(address _newCollateralAddress); event CollBalanceUpdated(address indexed _account, uint256 _newBalance); event CollateralSent(address _to, uint256 _amount); // --- Contract setters --- function setAddresses( address _borrowerOperationsAddress, address _troveManagerAddress, address _activePoolAddress, address _collateralAddress ) external; function getCollateralBalance() external view returns (uint); function getCollateral(address _account) external view returns (uint); function accountSurplus(address _account, uint256 _amount) external; function claimColl(address _account) external; function updateCollateralBalance(uint256 _amount) external; function collateralAddress() external view returns(address); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.17; import "./IPool.sol"; interface IDefaultPool is IPool { // --- Events --- event TroveManagerAddressChanged(address _newTroveManagerAddress); event DefaultPoolTHUSDDebtUpdated(uint256 _THUSDDebt); event DefaultPoolCollateralBalanceUpdated(uint256 _collateral); event CollateralAddressChanged(address _newCollateralAddress); // --- Functions --- function sendCollateralToActivePool(uint256 _amount) external; function updateCollateralBalance(uint256 _amount) external; function collateralAddress() external view returns(address); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.17; interface IGasPool { // --- Events --- event TroveManagerAddressChanged(address _newTroveManagerAddress); event THUSDTokenAddressChanged(address _thusdTokenAddress); // --- Functions --- function sendTHUSD(address _account, uint256 _amount) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.17; import "./IPriceFeed.sol"; interface ILiquityBase { function priceFeed() external view returns (IPriceFeed); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.17; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "./ITHUSDToken.sol"; interface IPCV { // --- Events -- event THUSDTokenAddressSet(address _thusdTokenAddress); event BorrowerOperationsAddressSet(address _borrowerOperationsAddress); event CollateralAddressSet(address _collateralAddress); event BAMMAddressSet(address _bammAddress); event RolesSet(address _council, address _treasury); event BAMMDeposit(uint256 _thusdAmount); event BAMMWithdraw(uint256 _numShares); event THUSDWithdraw(address _recipient, uint256 _thusdAmount); event CollateralWithdraw(address _recipient, uint256 _collateralAmount); event PCVDebtPaid(uint256 _paidDebt); event RecipientAdded(address _recipient); event RecipientRemoved(address _recipient); // --- Functions --- function debtToPay() external returns(uint256); function payDebt(uint256 _thusdToBurn) external; function setAddresses( address _thusdTokenAddress, address _borrowerOperations, address payable _bammAddress, address _collateralERC20 ) external; function initialize() external; function depositToBAMM(uint256 _thusdAmount) external; function withdrawFromBAMM(uint256 _numShares) external; function withdrawTHUSD(address _recipient, uint256 _thusdAmount) external; function withdrawCollateral(address _recipient, uint256 _collateralAmount) external; function addRecipientToWhitelist(address _recipient) external; function addRecipientsToWhitelist(address[] calldata _recipients) external; function removeRecipientFromWhitelist(address _recipient) external; function removeRecipientsFromWhitelist(address[] calldata _recipients) external; function startChangingRoles(address _council, address _treasury) external; function cancelChangingRoles() external; function finalizeChangingRoles() external; function collateralERC20() external view returns(IERC20); function thusdToken() external view returns(ITHUSDToken); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.17; // Common interface for the Pools. interface IPool { // --- Events --- event CollateralBalanceUpdated(uint256 _newBalance); event THUSDBalanceUpdated(uint256 _newBalance); event ActivePoolAddressChanged(address _newActivePoolAddress); event DefaultPoolAddressChanged(address _newDefaultPoolAddress); event StabilityPoolAddressChanged(address _newStabilityPoolAddress); event CollateralSent(address _to, uint256 _amount); // --- Functions --- function getCollateralBalance() external view returns (uint); function getTHUSDDebt() external view returns (uint); function increaseTHUSDDebt(uint256 _amount) external; function decreaseTHUSDDebt(uint256 _amount) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.17; interface IPriceFeed { // --- Events --- event LastGoodPriceUpdated(uint256 _lastGoodPrice); // --- Function --- function fetchPrice() external returns (uint); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.17; // Common interface for the SortedTroves Doubly Linked List. interface ISortedTroves { // --- Events --- event SortedTrovesAddressChanged(address _sortedDoublyLLAddress); event BorrowerOperationsAddressChanged(address _borrowerOperationsAddress); event NodeAdded(address _id, uint256 _NICR); event NodeRemoved(address _id); // --- Functions --- function setParams(uint256 _size, address _TroveManagerAddress, address _borrowerOperationsAddress) external; function insert(address _id, uint256 _ICR, address _prevId, address _nextId) external; function remove(address _id) external; function reInsert(address _id, uint256 _newICR, address _prevId, address _nextId) external; function contains(address _id) external view returns (bool); function isFull() external view returns (bool); function isEmpty() external view returns (bool); function getSize() external view returns (uint256); function getMaxSize() external view returns (uint256); function getFirst() external view returns (address); function getLast() external view returns (address); function getNext(address _id) external view returns (address); function getPrev(address _id) external view returns (address); function validInsertPosition(uint256 _ICR, address _prevId, address _nextId) external view returns (bool); function findInsertPosition(uint256 _ICR, address _prevId, address _nextId) external view returns (address, address); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.17; /* * The Stability Pool holds THUSD tokens deposited by Stability Pool depositors. * * When a trove is liquidated, then depending on system conditions, some of its THUSD debt gets offset with * THUSD in the Stability Pool: that is, the offset debt evaporates, and an equal amount of THUSD tokens in the Stability Pool is burned. * * Thus, a liquidation causes each depositor to receive a THUSD loss, in proportion to their deposit as a share of total deposits. * They also receive an collateral gain, as the collateral of the liquidated trove is distributed among Stability depositors, * in the same proportion. * * When a liquidation occurs, it depletes every deposit by the same fraction: for example, a liquidation that depletes 40% * of the total THUSD in the Stability Pool, depletes 40% of each deposit. * * A deposit that has experienced a series of liquidations is termed a "compounded deposit": each liquidation depletes the deposit, * multiplying it by some factor in range ]0,1[ * * Please see the implementation spec in the proof document, which closely follows on from the compounded deposit / collateral gain derivations: * https://github.com/liquity/liquity/blob/master/papers/Scalable_Reward_Distribution_with_Compounding_Stakes.pdf * */ interface IStabilityPool { // --- Events --- event StabilityPoolCollateralBalanceUpdated(uint256 _newBalance); event StabilityPoolTHUSDBalanceUpdated(uint256 _newBalance); event BorrowerOperationsAddressChanged(address _newBorrowerOperationsAddress); event TroveManagerAddressChanged(address _newTroveManagerAddress); event ActivePoolAddressChanged(address _newActivePoolAddress); event DefaultPoolAddressChanged(address _newDefaultPoolAddress); event THUSDTokenAddressChanged(address _newTHUSDTokenAddress); event SortedTrovesAddressChanged(address _newSortedTrovesAddress); event PriceFeedAddressChanged(address _newPriceFeedAddress); event CollateralAddressChanged(address _newCollateralAddress); event P_Updated(uint256 _P); event S_Updated(uint256 _S, uint128 _epoch, uint128 _scale); event EpochUpdated(uint128 _currentEpoch); event ScaleUpdated(uint128 _currentScale); event DepositSnapshotUpdated(address indexed _depositor, uint256 _P, uint256 _S); event UserDepositChanged(address indexed _depositor, uint256 _newDeposit); event CollateralGainWithdrawn(address indexed _depositor, uint256 _collateral, uint256 _THUSDLoss); event CollateralSent(address _to, uint256 _amount); // --- Functions --- /* * Called only once on init, to set addresses of other Liquity contracts * Callable only by owner, renounces ownership at the end */ function setAddresses( address _borrowerOperationsAddress, address _troveManagerAddress, address _activePoolAddress, address _thusdTokenAddress, address _sortedTrovesAddress, address _priceFeedAddress, address _collateralAddress ) external; /* * Initial checks: * - _amount is not zero * --- * - Sends depositor's accumulated gains (collateral) to depositor */ function provideToSP(uint256 _amount) external; /* * Initial checks: * - _amount is zero or there are no under collateralized troves left in the system * - User has a non zero deposit * --- * - Sends all depositor's accumulated gains (collateral) to depositor * - Decreases deposit stake, and takes new snapshot. * * If _amount > userDeposit, the user withdraws all of their compounded deposit. */ function withdrawFromSP(uint256 _amount) external; /* * Initial checks: * - User has a non zero deposit * - User has an open trove * - User has some collateral gain * --- * - Transfers the depositor's entire collateral gain from the Stability Pool to the caller's trove * - Leaves their compounded deposit in the Stability Pool * - Updates snapshots for deposit */ function withdrawCollateralGainToTrove(address _upperHint, address _lowerHint) external; /* * Initial checks: * - Caller is TroveManager * --- * Cancels out the specified debt against the THUSD contained in the Stability Pool (as far as possible) * and transfers the Trove's collateral from ActivePool to StabilityPool. * Only called by liquidation functions in the TroveManager. */ function offset(uint256 _debt, uint256 _coll) external; /* * Returns the total amount of collateral held by the pool, accounted in an internal variable instead of `balance`, * to exclude edge cases like collateral received from a self-destruct. */ function getCollateralBalance() external view returns (uint); /* * Returns THUSD held in the pool. Changes when users deposit/withdraw, and when Trove debt is offset. */ function getTotalTHUSDDeposits() external view returns (uint); /* * Calculates the collateral gain earned by the deposit since its last snapshots were taken. */ function getDepositorCollateralGain(address _depositor) external view returns (uint); /* * Return the user's compounded deposit. */ function getCompoundedTHUSDDeposit(address _depositor) external view returns (uint); /* * Only callable by Active Pool, updates ERC20 tokens recieved */ function updateCollateralBalance(uint256 _amount) external; /* * Fallback function * Only callable by Active Pool, it just accounts for ETH received * receive() external payable; */ function collateralAddress() external view returns(address); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.17; import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol"; import "../Dependencies/IERC2612.sol"; interface ITHUSDToken is IERC20Metadata, IERC2612 { // --- Events --- event TroveManagerAddressAdded(address _troveManagerAddress); event StabilityPoolAddressAdded(address _newStabilityPoolAddress); event BorrowerOperationsAddressAdded(address _newBorrowerOperationsAddress); event THUSDTokenBalanceUpdated(address _user, uint256 _amount); // --- Functions --- function mintList(address contractAddress) external view returns (bool); function burnList(address contractAddress) external view returns (bool); function mint(address _account, uint256 _amount) external; function burn(address _account, uint256 _amount) external; function increaseAllowance(address spender, uint256 addedValue) external returns (bool); function decreaseAllowance(address spender, uint256 subtractedValue) external returns (bool); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.17; import "./ILiquityBase.sol"; import "./IStabilityPool.sol"; import "./ITHUSDToken.sol"; import "./IPCV.sol"; // Common interface for the Trove Manager. interface ITroveManager is ILiquityBase { enum Status { nonExistent, active, closedByOwner, closedByLiquidation, closedByRedemption } // --- Events --- event BorrowerOperationsAddressChanged(address _newBorrowerOperationsAddress); event PriceFeedAddressChanged(address _newPriceFeedAddress); event THUSDTokenAddressChanged(address _newTHUSDTokenAddress); event ActivePoolAddressChanged(address _activePoolAddress); event DefaultPoolAddressChanged(address _defaultPoolAddress); event StabilityPoolAddressChanged(address _stabilityPoolAddress); event GasPoolAddressChanged(address _gasPoolAddress); event CollSurplusPoolAddressChanged(address _collSurplusPoolAddress); event SortedTrovesAddressChanged(address _sortedTrovesAddress); event PCVAddressChanged(address _pcvAddress); event Liquidation(uint256 _liquidatedDebt, uint256 _liquidatedColl, uint256 _collGasCompensation, uint256 _THUSDGasCompensation); event Redemption(uint256 _attemptedTHUSDAmount, uint256 _actualTHUSDAmount, uint256 _collateralSent, uint256 _collateralFee); event TroveUpdated(address indexed _borrower, uint256 _debt, uint256 _coll, uint256 stake, uint8 operation); event TroveLiquidated(address indexed _borrower, uint256 _debt, uint256 _coll, uint8 operation); 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_THUSDDebt); event TroveSnapshotsUpdated(uint256 _L_Collateral, uint256 _L_THUSDDebt); event TroveIndexUpdated(address _borrower, uint256 _newIndex); // --- Functions --- function setAddresses( address _borrowerOperationsAddress, address _activePoolAddress, address _defaultPoolAddress, address _stabilityPoolAddress, address _gasPoolAddress, address _collSurplusPoolAddress, address _priceFeedAddress, address _thusdTokenAddress, address _sortedTrovesAddress, address _pcvAddress ) external; function stabilityPool() external view returns (IStabilityPool); function thusdToken() external view returns (ITHUSDToken); function pcv() external view returns (IPCV); function getTroveOwnersCount() external view returns (uint); function getTroveFromTroveOwnersArray(uint256 _index) external view returns (address); function getNominalICR(address _borrower) external view returns (uint); function getCurrentICR(address _borrower, uint256 _price) external view returns (uint); function liquidate(address _borrower) external; function liquidateTroves(uint256 _n) external; function batchLiquidateTroves(address[] calldata _troveArray) external; function redeemCollateral( uint256 _THUSDAmount, address _firstRedemptionHint, address _upperPartialRedemptionHint, address _lowerPartialRedemptionHint, uint256 _partialRedemptionHintNICR, uint256 _maxIterations, uint256 _maxFee ) external; function updateStakeAndTotalStakes(address _borrower) external returns (uint); function updateTroveRewardSnapshots(address _borrower) external; function addTroveOwnerToArray(address _borrower) external returns (uint256 index); function applyPendingRewards(address _borrower) external; function getPendingCollateralReward(address _borrower) external view returns (uint); function getPendingTHUSDDebtReward(address _borrower) external view returns (uint); function hasPendingRewards(address _borrower) external view returns (bool); function getEntireDebtAndColl(address _borrower) external view returns ( uint256 debt, uint256 coll, uint256 pendingTHUSDDebtReward, uint256 pendingCollateralReward ); function closeTrove(address _borrower) external; function removeStake(address _borrower) external; function getRedemptionRate() external view returns (uint); function getRedemptionRateWithDecay() external view returns (uint); function getRedemptionFeeWithDecay(uint256 _collateralDrawn) external view returns (uint); function getBorrowingRate() external view returns (uint); function getBorrowingRateWithDecay() external view returns (uint); function getBorrowingFee(uint256 THUSDDebt) external view returns (uint); function getBorrowingFeeWithDecay(uint256 _THUSDDebt) external view returns (uint); function decayBaseRateFromBorrowing() external; function getTroveStatus(address _borrower) external view returns (Status); function getTroveStake(address _borrower) external view returns (uint); function getTroveDebt(address _borrower) external view returns (uint); function getTroveColl(address _borrower) external view returns (uint); function setTroveStatus(address _borrower, Status _status) external; function increaseTroveColl(address _borrower, uint256 _collIncrease) external returns (uint); function decreaseTroveColl(address _borrower, uint256 _collDecrease) external returns (uint); function increaseTroveDebt(address _borrower, uint256 _debtIncrease) external returns (uint); function decreaseTroveDebt(address _borrower, uint256 _collDecrease) external returns (uint); function getTCR(uint256 _price) external view returns (uint); function checkRecoveryMode(uint256 _price) external view returns (bool); }
{ "optimizer": { "enabled": true, "runs": 100 }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_activePoolAddress","type":"address"}],"name":"ActivePoolAddressChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_baseRate","type":"uint256"}],"name":"BaseRateUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_newBorrowerOperationsAddress","type":"address"}],"name":"BorrowerOperationsAddressChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_collSurplusPoolAddress","type":"address"}],"name":"CollSurplusPoolAddressChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_defaultPoolAddress","type":"address"}],"name":"DefaultPoolAddressChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_gasPoolAddress","type":"address"}],"name":"GasPoolAddressChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_L_Collateral","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_L_THUSDDebt","type":"uint256"}],"name":"LTermsUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_lastFeeOpTime","type":"uint256"}],"name":"LastFeeOpTimeUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_liquidatedDebt","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_liquidatedColl","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_collGasCompensation","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_THUSDGasCompensation","type":"uint256"}],"name":"Liquidation","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_pcvAddress","type":"address"}],"name":"PCVAddressChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_newPriceFeedAddress","type":"address"}],"name":"PriceFeedAddressChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_attemptedTHUSDAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_actualTHUSDAmount","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":"address","name":"_sortedTrovesAddress","type":"address"}],"name":"SortedTrovesAddressChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_stabilityPoolAddress","type":"address"}],"name":"StabilityPoolAddressChanged","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":"address","name":"_newTHUSDTokenAddress","type":"address"}],"name":"THUSDTokenAddressChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_newTotalStakes","type":"uint256"}],"name":"TotalStakesUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_borrower","type":"address"},{"indexed":false,"internalType":"uint256","name":"_newIndex","type":"uint256"}],"name":"TroveIndexUpdated","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":"enum TroveManager.TroveManagerOperation","name":"_operation","type":"uint8"}],"name":"TroveLiquidated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_L_Collateral","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_L_THUSDDebt","type":"uint256"}],"name":"TroveSnapshotsUpdated","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 TroveManager.TroveManagerOperation","name":"_operation","type":"uint8"}],"name":"TroveUpdated","type":"event"},{"inputs":[],"name":"BETA","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"BORROWING_FEE_FLOOR","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"CCR","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DECIMAL_PRECISION","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"L_Collateral","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"L_THUSDDebt","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_BORROWING_FEE","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":"MINUTE_DECAY_FACTOR","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_NET_DEBT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"NAME","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PERCENT_DIVISOR","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"REDEMPTION_FEE_FLOOR","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"THUSD_GAS_COMPENSATION","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"TroveOwners","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"Troves","outputs":[{"internalType":"uint256","name":"debt","type":"uint256"},{"internalType":"uint256","name":"coll","type":"uint256"},{"internalType":"uint256","name":"stake","type":"uint256"},{"internalType":"enum ITroveManager.Status","name":"status","type":"uint8"},{"internalType":"uint128","name":"arrayIndex","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"_100pct","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"activePool","outputs":[{"internalType":"contract IActivePool","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_borrower","type":"address"}],"name":"addTroveOwnerToArray","outputs":[{"internalType":"uint256","name":"index","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_borrower","type":"address"}],"name":"applyPendingRewards","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"baseRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"_troveArray","type":"address[]"}],"name":"batchLiquidateTroves","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"borrowerOperationsAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_price","type":"uint256"}],"name":"checkRecoveryMode","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_borrower","type":"address"}],"name":"closeTrove","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"decayBaseRateFromBorrowing","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_borrower","type":"address"},{"internalType":"uint256","name":"_collDecrease","type":"uint256"}],"name":"decreaseTroveColl","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_borrower","type":"address"},{"internalType":"uint256","name":"_debtDecrease","type":"uint256"}],"name":"decreaseTroveDebt","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"defaultPool","outputs":[{"internalType":"contract IDefaultPool","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_THUSDDebt","type":"uint256"}],"name":"getBorrowingFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_THUSDDebt","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":"pendingTHUSDDebtReward","type":"uint256"},{"internalType":"uint256","name":"pendingCollateralReward","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getEntireSystemColl","outputs":[{"internalType":"uint256","name":"entireSystemColl","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getEntireSystemDebt","outputs":[{"internalType":"uint256","name":"entireSystemDebt","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":"getPendingCollateralReward","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_borrower","type":"address"}],"name":"getPendingTHUSDDebtReward","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":[{"internalType":"uint256","name":"_price","type":"uint256"}],"name":"getTCR","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_borrower","type":"address"}],"name":"getTroveColl","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_borrower","type":"address"}],"name":"getTroveDebt","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_index","type":"uint256"}],"name":"getTroveFromTroveOwnersArray","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTroveOwnersCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_borrower","type":"address"}],"name":"getTroveStake","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_borrower","type":"address"}],"name":"getTroveStatus","outputs":[{"internalType":"enum ITroveManager.Status","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_borrower","type":"address"}],"name":"hasPendingRewards","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_borrower","type":"address"},{"internalType":"uint256","name":"_collIncrease","type":"uint256"}],"name":"increaseTroveColl","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_borrower","type":"address"},{"internalType":"uint256","name":"_debtIncrease","type":"uint256"}],"name":"increaseTroveDebt","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"isOwner","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastCollateralError_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":"lastTHUSDDebtError_Redistribution","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_borrower","type":"address"}],"name":"liquidate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_n","type":"uint256"}],"name":"liquidateTroves","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pcv","outputs":[{"internalType":"contract IPCV","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"priceFeed","outputs":[{"internalType":"contract IPriceFeed","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_THUSDamount","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":[{"internalType":"address","name":"_borrower","type":"address"}],"name":"removeStake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"rewardSnapshots","outputs":[{"internalType":"uint256","name":"collateral","type":"uint256"},{"internalType":"uint256","name":"THUSDDebt","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_borrowerOperationsAddress","type":"address"},{"internalType":"address","name":"_activePoolAddress","type":"address"},{"internalType":"address","name":"_defaultPoolAddress","type":"address"},{"internalType":"address","name":"_stabilityPoolAddress","type":"address"},{"internalType":"address","name":"_gasPoolAddress","type":"address"},{"internalType":"address","name":"_collSurplusPoolAddress","type":"address"},{"internalType":"address","name":"_priceFeedAddress","type":"address"},{"internalType":"address","name":"_thusdTokenAddress","type":"address"},{"internalType":"address","name":"_sortedTrovesAddress","type":"address"},{"internalType":"address","name":"_pcvAddress","type":"address"}],"name":"setAddresses","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_borrower","type":"address"},{"internalType":"enum ITroveManager.Status","name":"_status","type":"uint8"}],"name":"setTroveStatus","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"sortedTroves","outputs":[{"internalType":"contract ISortedTroves","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"stabilityPool","outputs":[{"internalType":"contract IStabilityPool","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"thusdToken","outputs":[{"internalType":"contract ITHUSDToken","name":"","type":"address"}],"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":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_borrower","type":"address"}],"name":"updateStakeAndTotalStakes","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_borrower","type":"address"}],"name":"updateTroveRewardSnapshots","outputs":[],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
608060405234801561001057600080fd5b50600380546001600160a01b031916339081179091556040516000907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908290a3615461806100606000396000f3fe608060405234801561001057600080fd5b50600436106104145760003560e01c8063795d26c311610221578063bcd375261161012b578063d5b35635116100c3578063ee266b8711610087578063ee266b87146109c5578063f2fde38b146109ce578063f36b2425146109e1578063f92d343314610562578063fe2ba848146109e957600080fd5b8063d5b356351461095a578063d66a25531461096d578063d9a7244414610996578063e2ac77b0146109a9578063e6a91f16146109bc57600080fd5b8063bcd37526146108dc578063bf9befb1146108ef578063c52861f2146108f8578063c7b5548114610900578063cbd138ae1461090f578063d293c71014610922578063d380a37c14610935578063d38b05581461093e578063d3d6f8431461094757600080fd5b80639976cf45116101b9578063ae9187541161017d578063ae9187541461085d578063b0d8e18114610870578063b7f8cf9b14610883578063b82f263d14610896578063b91af97c146108a957600080fd5b80639976cf45146107f65780639ba7a40814610809578063a20baee614610720578063a3f4df7e1461081c578063a68b663e1461085457600080fd5b8063795d26c3146107775780637f7dde4a1461077f578063807d138d1461079257806382fe3eb91461079b578063887105d3146107ae5780638da5cb5b146107b65780638f32d59b146107c7578063953f0bb1146107da57806396d711ff146107ed57600080fd5b8063480cd57811610322578063653d46e7116102ba57806372fe25aa1161027e57806372fe25aa14610720578063741bef1a1461072f578063756b253e1461074257806377e16f1e14610755578063794e57241461076857600080fd5b8063653d46e71461068657806366ca4a21146106995780636c37a4af146106a15780636ef64338146106b457806372423c171461070d57600080fd5b8063480cd578146105be5780634870dd9a146105ea57806349eefeee146105f25780634a3c95c4146105fa5780634e443d9e1461060d5780635733d58f146106305780635dba4c4a1461063f578063631203b01461064757806364cee2601461065a57600080fd5b80631f68f20a116103b05780632b11551a116103745780632b11551a1461056a5780632f865568146105725780633cc74225146105855780634597f6ed14610598578063477d66cf146105ab57600080fd5b80631f68f20a146105055780631fd6a4341461050e57806321e378011461051e578063240926691461055a57806328d28b5b1461056257600080fd5b8063048c661d14610419578063071a7541146104425780630b0765571461045857806312610e921461046d57806315d549f1146104805780631673c79a1461049357806318f2817a146104cf5780631bf43555146104e25780631e8b1c2b146104f2575b600080fd5b60055461042c906001600160a01b031681565b6040516104399190614e03565b60405180910390f35b61044a600281565b604051908152602001610439565b61046b610466366004614e3c565b6109fc565b005b61044a61047b366004614e59565b610a24565b61044a61048e366004614e3c565b610a77565b6104ba6104a1366004614e3c565b6013602052600090815260409020805460019091015482565b60408051928352602083019190915201610439565b61044a6104dd366004614e3c565b610a99565b61044a686194049f30f720000081565b61046b610500366004614e9b565b610aac565b61044a600b5481565b61044a680ad78ebc5ac620000081565b61054d61052c366004614e3c565b6001600160a01b03166000908152600d602052604090206003015460ff1690565b6040516104399190614f8a565b61044a610e4d565b61044a610e6e565b61044a610e82565b61046b610580366004614e3c565b610e94565b60015461042c906001600160a01b031681565b60095461042c906001600160a01b031681565b61044a6105b9366004614f98565b610f00565b61044a6105cc366004614e3c565b6001600160a01b03166000908152600d602052604090206001015490565b61044a60c881565b60145461044a565b61044a610608366004614e3c565b610f13565b61062061061b366004614f98565b610fce565b6040519015158152602001610439565b61044a6714d1120d7b16000081565b61046b610fd9565b61044a610655366004614f98565b611045565b61044a610668366004614e3c565b6001600160a01b03166000908152600d602052604090206002015490565b61046b610694366004614f98565b611052565b61044a6113c8565b61046b6106af366004614fb1565b6113da565b6106fc6106c2366004614e3c565b600d6020526000908152604090208054600182015460028301546003909301549192909160ff81169061010090046001600160801b031685565b60405161043995949392919061507d565b61044a61071b366004614e59565b61172b565b61044a670de0b6b3a764000081565b60025461042c906001600160a01b031681565b61042c610750366004614f98565b611783565b60085461042c906001600160a01b031681565b61044a670f43fc2c04ee000081565b61044a6117ad565b60005461042c906001600160a01b031681565b61044a600f5481565b61046b6107a9366004614e3c565b6118a9565b61044a6118ba565b6003546001600160a01b031661042c565b6003546001600160a01b03163314610620565b61046b6107e83660046150ba565b61197f565b61044a60105481565b61044a610804366004614e59565b6119c8565b61044a610817366004614e3c565b6119f6565b6108476040518060400160405280600c81526020016b2a3937bb32a6b0b730b3b2b960a11b81525081565b60405161043991906150f7565b61044a60125481565b600a5461042c906001600160a01b031681565b61044a61087e366004614e3c565b611a22565b60045461042c906001600160a01b031681565b61044a6108a4366004614f98565b611a49565b6108bc6108b7366004614e3c565b611a54565b604080519485526020850193909352918301526060820152608001610439565b61046b6108ea366004615145565b611aac565b61044a600e5481565b61044a612148565b61044a670ddd4b8c6c7d70d881565b61046b61091d366004614e3c565b61215a565b61044a610930366004614e59565b61216d565b61044a600c5481565b61044a60155481565b61044a610955366004614e59565b61218c565b61044a610968366004614f98565b6121bd565b61044a61097b366004614e3c565b6001600160a01b03166000908152600d602052604090205490565b61042c6109a4366004614f98565b6121d0565b6106206109b7366004614e3c565b612200565b61044a60165481565b61044a60115481565b61046b6109dc366004614e3c565b612263565b61044a6122fb565b61046b6109f7366004614e3c565b612308565b610a04612319565b600054600154610a21916001600160a01b0390811691168361239b565b50565b6000610a2e612319565b6001600160a01b0383166000908152600d6020526040812054610a529084906151c9565b6001600160a01b0385166000908152600d602052604090208190559150505b92915050565b6000610a81612319565b610a8a82612497565b6001600160801b031692915050565b6000610aa3612319565b610a7182612530565b8051600003610b215760405162461bcd60e51b815260206004820152603660248201527f54726f76654d616e616765723a2043616c6c646174612061646472657373206160448201527572726179206d757374206e6f7420626520656d70747960501b60648201526084015b60405180910390fd5b6000546001546005546001600160a01b03928316929182169116610b43614d3e565b610b4b614d6f565b600260009054906101000a90046001600160a01b03166001600160a01b0316630fdb11cf6040518163ffffffff1660e01b81526004016020604051808303816000875af1158015610ba0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bc491906151dc565b826000018181525050826001600160a01b03166301081fda6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610c0b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c2f91906151dc565b60208301528151610c3f906125d5565b1580156040840152610c6757610c608585846000015185602001518a6125f2565b9050610c7f565b610c7c8585846000015185602001518a612827565b90505b6000816020015111610ca35760405162461bcd60e51b8152600401610b18906151f5565b608081015160a082015160405163335525ad60e01b81526001600160a01b0386169263335525ad92610ce092600401918252602082015260400190565b600060405180830381600087803b158015610cfa57600080fd5b505af1158015610d0e573d6000803e3d6000fd5b50505050610d2685858360c001518460e001516128fc565b61010081015115610d9d57600754610100820151604051636250216960e01b81526001600160a01b0388811693636250216993610d6a939290911691600401615237565b600060405180830381600087803b158015610d8457600080fd5b505af1158015610d98573d6000803e3d6000fd5b505050505b610dab858260400151612b3b565b6020810151606083015261010081015160408201518251610dcc91906151c9565b610dd691906151c9565b6080838101829052606080850151604085810151868401518251938452602084019690965290820152908101929092527f4152c73dd2614c4f9fc35e8c9cf16013cd588c75b49a4c1673ecffdcbcda9403910160405180910390a1610e45853383606001518460400151612c86565b505050505050565b610e606064670de0b6b3a7640000615266565b610e6b90600561527a565b81565b610e606103e8670de0b6b3a7640000615266565b6000610e8f600b54612d5d565b905090565b610e9d81612d9a565b604080516001808252818301909252600091602080830190803683370190505090508181600081518110610ed357610ed3615291565b60200260200101906001600160a01b031690816001600160a01b031681525050610efc81610aac565b5050565b6000610a71610f0d6113c8565b83612e31565b6001600160a01b0381166000908152601360205260408120546011548290610f3c9083906151c9565b9050801580610f7b575060016001600160a01b0385166000908152600d602052604090206003015460ff166004811115610f7857610f78614f60565b14155b15610f8a575060009392505050565b6001600160a01b0384166000908152600d602052604081206002015490670de0b6b3a7640000610fba848461527a565b610fc49190615266565b9695505050505050565b6000610a71826125d5565b610fe1612319565b6000610feb612e57565b9050670de0b6b3a7640000811115611005576110056152a7565b600b8190556040518181527fc454ee9b76c52f782a256af821b857ca6e125d1e3333bcede402fec2bed9600c9060200160405180910390a1610a21612e9b565b6000610a71610f0d6122fb565b6040805160e081018252600080546001600160a01b0390811683526001548116602084015292820181905260608201819052600a548316608083015260a0820181905260c08201526005549091166110a8614d3e565b6110b0614d6f565b600260009054906101000a90046001600160a01b03166001600160a01b0316630fdb11cf6040518163ffffffff1660e01b81526004016020604051808303816000875af1158015611105573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061112991906151dc565b826000018181525050826001600160a01b03166301081fda6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611170573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061119491906151dc565b602083015281516111a4906125d5565b15801560408401526111cb576111c4848360000151846020015188612ef2565b90506111eb565b6111e884600001518560200151846000015185602001518961327e565b90505b600081602001511161120f5760405162461bcd60e51b8152600401610b18906151f5565b608081015160a082015160405163335525ad60e01b81526001600160a01b0386169263335525ad9261124c92600401918252602082015260400190565b600060405180830381600087803b15801561126657600080fd5b505af115801561127a573d6000803e3d6000fd5b5050505061129a846000015185602001518360c001518460e001516128fc565b61010081015115611311578351600754610100830151604051636250216960e01b81526001600160a01b03938416936362502169936112de93911691600401615237565b600060405180830381600087803b1580156112f857600080fd5b505af115801561130c573d6000803e3d6000fd5b505050505b61132384600001518260400151612b3b565b602081015160608301526101008101516040820151825161134491906151c9565b61134e91906151c9565b6080838101829052606080850151604085810151868401518251938452602084019690965290820152908101929092527f4152c73dd2614c4f9fc35e8c9cf16013cd588c75b49a4c1673ecffdcbcda9403910160405180910390a16113c184600001513383606001518460400151612c86565b5050505050565b6000610e8f6113d5612e57565b6133b4565b6003546001600160a01b031633146114045760405162461bcd60e51b8152600401610b18906152bd565b61140d8a613406565b61141689613406565b61141f88613406565b61142887613406565b61143186613406565b61143a85613406565b61144384613406565b61144c83613406565b61145582613406565b61145e81613406565b600480546001600160a01b03199081166001600160a01b038d8116919091179092556000805482168c84161790556001805482168b84161790556005805482168a8416179055600680548216898416179055600780548216888416179055600280548216878416179055600880548216868416179055600a80548216858416179055600980549091169183169190911790556040517f3ca631ffcd2a9b5d9ae18543fc82f58eb4ca33af9e6ab01b7a8e95331e6ed98590611520908c90614e03565b60405180910390a17f78f058b189175430c48dc02699e3a0031ea4ff781536dc2fab847de4babdd882896040516115579190614e03565b60405180910390a17f5ee0cae2f063ed938bb55046f6a932fb6ae792bf43624806bb90abe68a50be9b8860405161158e9190614e03565b60405180910390a17f82966d27eea39b038ee0fa30cd16532bb24f6e65d31cb58fb227aa5766cdcc7f876040516115c59190614e03565b60405180910390a17fcfb07d791fcafc032b35837b50eb84b74df518cf4cc287e8084f47630fa70fa0866040516115fc9190614e03565b60405180910390a17fe67f36a6e961157d6eff83b91f3af5a62131ceb6f04954ef74f51c1c05e7f88d856040516116339190614e03565b60405180910390a17f8c537274438aa850a330284665d81a85dd38267d09e4050d416bfc94142db2648460405161166a9190614e03565b60405180910390a17fe1e858a66c0bbbcdfa22d58dde1e5d42370be20cdb176e560287f85412e546e0836040516116a19190614e03565b60405180910390a17f65f4cf077bc01e4742eb5ad98326f6e95b63548ea24b17f8d5e823111fe78800826040516116d89190614e03565b60405180910390a17f38335c64466e2376ab931166337e19127650d842036ebe01da1ba3e5c1255ebb8160405161170f9190614e03565b60405180910390a161171f6134ab565b50505050505050505050565b6000611735612319565b6001600160a01b0383166000908152600d602052604081206001015461175c9084906152f2565b6001600160a01b0385166000908152600d6020526040902060010181905591505092915050565b6014818154811061179357600080fd5b6000918252602090912001546001600160a01b0316905081565b600080546040805163f07424e960e01b8152905183926001600160a01b03169163f07424e99160048083019260209291908290030181865afa1580156117f7573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061181b91906151dc565b90506000600160009054906101000a90046001600160a01b03166001600160a01b031663f07424e96040518163ffffffff1660e01b8152600401602060405180830381865afa158015611872573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061189691906151dc565b90506118a281836152f2565b9250505090565b6118b1612319565b610a21816134f5565b6000805460408051631529a63960e01b8152905183926001600160a01b031691631529a6399160048083019260209291908290030181865afa158015611904573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061192891906151dc565b90506000600160009054906101000a90046001600160a01b03166001600160a01b0316631529a6396040518163ffffffff1660e01b8152600401602060405180830381865afa158015611872573d6000803e3d6000fd5b611987612319565b6001600160a01b0382166000908152600d60205260409020600301805482919060ff191660018360048111156119bf576119bf614f60565b02179055505050565b60006119d2612319565b6001600160a01b0383166000908152600d6020526040812054610a529084906152f2565b6001600160a01b0381166000908152601360205260408120600101546012548290610f3c9083906151c9565b6000806000611a3084613559565b915091506000611a4083836135d5565b95945050505050565b6000610a718261360b565b6001600160a01b0381166000908152600d602052604081208054600190910154909180611a80856119f6565b9150611a8b85610f13565b9050611a9782856152f2565b9350611aa381846152f2565b92509193509193565b6040805160e08082018352600080546001600160a01b03908116845260015481166020808601919091526008548216858701526009548216606080870191909152600a548316608080880191909152600754841660a08089019190915260065490941660c080890191909152885161010081018a5286815293840186905297830185905290820184905281018390529081018290529384018190529083015290611b5583613637565b600260009054906101000a90046001600160a01b03166001600160a01b0316630fdb11cf6040518163ffffffff1660e01b81526004016020604051808303816000875af1158015611baa573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611bce91906151dc565b60c08201819052611bde906136d2565b611be789613745565b611bf68260400151338b6137ac565b611bfe6117ad565b60e0820152888152608082015160c0820151600091611c1e918b906138a7565b15611c2a575087611d3c565b82608001516001600160a01b0316634d6228316040518163ffffffff1660e01b8152600401602060405180830381865afa158015611c6c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c909190615305565b90505b6001600160a01b03811615801590611cbf5750670f43fc2c04ee0000611cbd828460c0015161216d565b105b15611d3c5782608001516001600160a01b031663b72703ac826040518263ffffffff1660e01b8152600401611cf49190614e03565b602060405180830381865afa158015611d11573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d359190615305565b9050611c93565b84600003611d4a5760001994505b6001600160a01b03811615801590611d625750815115155b8015611d6e5750600085115b15611e815784611d7d81615322565b955050600083608001516001600160a01b031663b72703ac836040518263ffffffff1660e01b8152600401611db29190614e03565b602060405180830381865afa158015611dcf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611df39190615305565b9050611e08846000015185602001518461239b565b6000611e21858486600001518760c001518e8e8e6139f1565b9050806040015115611e34575050611e81565b8051602085018051611e479083906152f2565b9052506020810151604085018051611e609083906152f2565b905250805184518590611e749083906151c9565b905250909150611d4a9050565b6000826040015111611ee75760405162461bcd60e51b815260206004820152602960248201527f54726f76654d616e616765723a20556e61626c6520746f2072656465656d20616044820152681b9e48185b5bdd5b9d60ba1b6064820152608401610b18565b611efe82604001518360c001518460e00151613c7f565b50611f0c8260400151613d22565b606083018190526040830151611f23919086613d2f565b825160608085015190840151604051636250216960e01b81526001600160a01b0390931692636250216992611f5c929091600401615237565b600060405180830381600087803b158015611f7657600080fd5b505af1158015611f8a573d6000803e3d6000fd5b50505060608301516040840151611fa192506151c9565b60808301526020820151604080840151606085015191517f43a3f4082a4dbc33d78e317d2497d3a730bc7fc3574159dcea1056e62e5d9ad893611ffd938f93919293845260208401929092526040830152606082015260800190565b60405180910390a182604001516001600160a01b0316639dc29fac3384602001516040518363ffffffff1660e01b815260040161203b929190615237565b600060405180830381600087803b15801561205557600080fd5b505af1158015612069573d6000803e3d6000fd5b505084516020850151604051637b7fc9eb60e11b81526001600160a01b03909216935063f6ff93d692506120a39160040190815260200190565b600060405180830381600087803b1580156120bd57600080fd5b505af11580156120d1573d6000803e3d6000fd5b505084516080850151604051636250216960e01b81526001600160a01b0390921693506362502169925061210a91339190600401615237565b600060405180830381600087803b15801561212457600080fd5b505af1158015612138573d6000803e3d6000fd5b5050505050505050505050505050565b6000610e8f612155612e57565b612d5d565b612162612319565b610a21816002613da0565b600080600061217b85613559565b915091506000610fc4838387613f47565b6000612196612319565b6001600160a01b0383166000908152600d602052604081206001015461175c9084906151c9565b6000610a716121ca612148565b83613f78565b6000601482815481106121e5576121e5615291565b6000918252602090912001546001600160a01b031692915050565b600060016001600160a01b0383166000908152600d602052604090206003015460ff16600481111561223457612234614f60565b1461224157506000919050565b506011546001600160a01b039091166000908152601360205260409020541090565b6003546001600160a01b0316331461228d5760405162461bcd60e51b8152600401610b18906152bd565b6001600160a01b0381166122f25760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610b18565b610a2181614008565b6000610e8f600b546133b4565b612310612319565b610a218161405a565b6004546001600160a01b031633146123995760405162461bcd60e51b815260206004820152603b60248201527f54726f76654d616e616765723a2043616c6c6572206973206e6f74207468652060448201527f426f72726f7765724f7065726174696f6e7320636f6e747261637400000000006064820152608401610b18565b565b6123a481612200565b15612492576123b281612d9a565b60006123bd82610f13565b905060006123ca836119f6565b6001600160a01b0384166000908152600d60205260408120600101805492935084929091906123fa9084906152f2565b90915550506001600160a01b0383166000908152600d6020526040812080548392906124279084906152f2565b909155506124369050836134f5565b612442858583856140ac565b6001600160a01b0383166000818152600d602052604080822080546001820154600290920154925160008051602061540c833981519152946124879492939291615349565b60405180910390a250505b505050565b601480546001808201835560008381527fce6d7b5282bd9a3661ae061feed1dbda4e52ab073b1f9285be6e155d9c38d4ec90920180546001600160a01b0319166001600160a01b038616179055915490916124f1916151c9565b6001600160a01b03929092166000908152600d602052604090206003018054610100600160881b0319166101006001600160801b038516021790555090565b6001600160a01b0381166000908152600d602052604081206001015481906125579061418d565b6001600160a01b0384166000908152600d60205260409020600201805490829055600e5491925090829061258c9083906151c9565b61259691906152f2565b600e8190556040519081527f6bac5e0eb3c44eb03a60ab11ec3a2c051771616aecadbcfff2630aabae5203829060200160405180910390a15092915050565b6000806125e18361360b565b6714d1120d7b160000119392505050565b6125fa614d6f565b612602614dbb565b61260a614d6f565b8482526000608083015261261c6117ad565b60a08301526126296118ba565b60c0830152600060208301525b83518260200151101561281c578382602001518151811061265957612659615291565b6020908102919091018101516001600160a01b0316606084018190526000908152600d909152604090206003015460019060ff16600481111561269e5761269e614f60565b03612804576126b182606001518761216d565b604083015260808201516127a757670f43fc2c04ee00008260400151101580156126da57508151155b6128045760006126f38360c001518460a0015189613f47565b90506127108989856060015186604001518760000151868d6141c3565b915081608001518360000181815161272891906151c9565b905250608082015160a0840180516127419083906151c9565b905250610100820151604083015160a084015161275e91906152f2565b61276891906152f2565b8360c00181815161277991906151c9565b90525061278684836144be565b935061279b8360c001518460a00151896145a8565b15608084015250612804565b816080015180156127c35750670f43fc2c04ee00008260400151105b15612804576127dc8888846060015185600001516145c9565b90508060800151826000018181516127f491906151c9565b90525061280183826144be565b92505b602082018051906128148261536b565b905250612636565b505095945050505050565b61282f614d6f565b612837614dbb565b61283f614d6f565b848252600060208301525b83518260200151101561281c578382602001518151811061286d5761286d615291565b60209081029190910101516001600160a01b031660608301819052612892908761216d565b60408301819052670f43fc2c04ee000011156128e4576128bc8888846060015185600001516145c9565b90508060800151826000018181516128d491906151c9565b9052506128e183826144be565b92505b602082018051906128f48261536b565b90525061284a565b8115612b355760155460009061291a670de0b6b3a76400008461527a565b61292491906152f2565b90506000601654670de0b6b3a76400008561293f919061527a565b61294991906152f2565b90506000600e548361295b9190615266565b90506000600e548361296d9190615266565b9050600e548261297d919061527a565b61298790856151c9565b601555600e54612997908261527a565b6129a190846151c9565b60168190555081601160008282546129b991906152f2565b9250508190555080601260008282546129d291906152f2565b90915550506011546012546040517f9f8bc8ab0daf5bceef75ecfd2085d1fcc6548c657ea970d9a23a60610d0737e392612a1492908252602082015260400190565b60405180910390a1604051637b7fc9eb60e11b8152600481018790526001600160a01b0389169063f6ff93d690602401600060405180830381600087803b158015612a5e57600080fd5b505af1158015612a72573d6000803e3d6000fd5b50506040516342c31a2360e01b8152600481018990526001600160a01b038a1692506342c31a239150602401600060405180830381600087803b158015612ab857600080fd5b505af1158015612acc573d6000803e3d6000fd5b5050604051636250216960e01b81526001600160a01b038b16925063625021699150612afe908a908990600401615237565b600060405180830381600087803b158015612b1857600080fd5b505af1158015612b2c573d6000803e3d6000fd5b50505050505050505b50505050565b600e54600f819055506000826001600160a01b0316631529a6396040518163ffffffff1660e01b8152600401602060405180830381865afa158015612b84573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ba891906151dc565b90506000600160009054906101000a90046001600160a01b03166001600160a01b0316631529a6396040518163ffffffff1660e01b8152600401602060405180830381865afa158015612bff573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c2391906151dc565b905080612c3084846151c9565b612c3a91906152f2565b6010819055600f546040517f51bf4c63ec3cba9d03d43238abbdd979dd91bd16d9895c74ceea9118c7baaf6092612c78928252602082015260400190565b60405180910390a150505050565b8115612cf1576006546040516316268b0d60e21b81526001600160a01b039091169063589a2c3490612cbe9086908690600401615237565b600060405180830381600087803b158015612cd857600080fd5b505af1158015612cec573d6000803e3d6000fd5b505050505b8015612b3557604051636250216960e01b81526001600160a01b03851690636250216990612d259086908590600401615237565b600060405180830381600087803b158015612d3f57600080fd5b505af1158015612d53573d6000803e3d6000fd5b5050505050505050565b6000610a7182612d776103e8670de0b6b3a7640000615266565b612d8290600561527a565b612d8c91906152f2565b670de0b6b3a7640000614710565b60016001600160a01b0382166000908152600d602052604090206003015460ff166004811115612dcc57612dcc614f60565b14610a215760405162461bcd60e51b815260206004820152602f60248201527f54726f76654d616e616765723a2054726f766520646f6573206e6f742065786960448201526e1cdd081bdc881a5cc818db1bdcd959608a1b6064820152608401610b18565b6000670de0b6b3a7640000612e46838561527a565b612e509190615266565b9392505050565b600080612e62614726565b90506000612e78670ddd4b8c6c7d70d883614742565b9050670de0b6b3a764000081600b54612e91919061527a565b6118a29190615266565b6000600c5442612eab91906151c9565b9050603c8110610a215742600c8190556040519081527f860f8d2f0c74dd487e89e2883e3b25b8159ce1e1b3433a291cba7b82c508f3bc906020015b60405180910390a150565b612efa614d6f565b612f02614dbb565b612f0a614d6f565b84825260006080830152612f1c6117ad565b60a0830152612f296118ba565b8260c001818152505086608001516001600160a01b0316634d6228316040518163ffffffff1660e01b8152600401602060405180830381865afa158015612f74573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f989190615305565b82606001906001600160a01b031690816001600160a01b031681525050600087608001516001600160a01b0316631e2231436040518163ffffffff1660e01b8152600401602060405180830381865afa158015612ff9573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061301d9190615305565b6000602085015290505b8483602001511080156130505750806001600160a01b031683606001516001600160a01b031614155b156132735760808801516060840151604051632dc9c0eb60e21b81526000926001600160a01b03169163b72703ac9161308c9190600401614e03565b602060405180830381865afa1580156130a9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130cd9190615305565b90506130dd84606001518961216d565b604085015260808401516131de57670f43fc2c04ee000084604001511015801561310657508351155b156131115750613273565b60006131268560c001518660a001518b613f47565b8a5160208c015160608801516040890151895194955061314794868f6141c3565b935083608001518560000181815161315f91906151c9565b905250608084015160a0860180516131789083906151c9565b905250610100840151604085015160a086015161319591906152f2565b61319f91906152f2565b8560c0018181516131b091906151c9565b9052506131bd86856144be565b95506131d28560c001518660a001518b6145a8565b1560808601525061324d565b836080015180156131fa5750670f43fc2c04ee00008460400151105b156132475761321b89600001518a60200151866060015187600001516145c9565b925082608001518460000181815161323391906151c9565b90525061324085846144be565b945061324d565b50613273565b6001600160a01b031660608401526020830180519061326b8261536b565b905250613027565b505050949350505050565b613286614d6f565b61328e614dbb565b613296614d6f565b600a54858352600060208401526001600160a01b03165b84836020015110156133a857806001600160a01b0316634d6228316040518163ffffffff1660e01b8152600401602060405180830381865afa1580156132f7573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061331b9190615305565b6001600160a01b031660608401819052613335908861216d565b60408401819052670f43fc2c04ee0000111561338b5761335f8989856060015186600001516145c9565b915081608001518360000181815161337791906151c9565b90525061338484836144be565b9350613390565b6133a8565b602083018051906133a08261536b565b9052506132ad565b50505095945050505050565b6000610a71826133ce6103e8670de0b6b3a7640000615266565b6133d990600561527a565b6133e391906152f2565b6133f66064670de0b6b3a7640000615266565b61340190600561527a565b614710565b6001600160a01b03811661345c5760405162461bcd60e51b815260206004820152601e60248201527f4163636f756e742063616e6e6f74206265207a65726f206164647265737300006044820152606401610b18565b803b80610efc5760405162461bcd60e51b815260206004820181905260248201527f4163636f756e7420636f64652073697a652063616e6e6f74206265207a65726f6044820152606401610b18565b6003546040516000916001600160a01b0316907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908390a3600380546001600160a01b0319169055565b601180546001600160a01b038316600090815260136020526040908190209182556012546001909201829055915491517fc437f324d85e369394148dd9d62f98f534b382e01ed3dd2eb98138fb6d3ab49a92612ee792908252602082015260400190565b600080600061356784610f13565b90506000613574856119f6565b6001600160a01b0386166000908152600d60205260408120600101549192509061359f9084906152f2565b6001600160a01b0387166000908152600d6020526040812054919250906135c79084906152f2565b919791965090945050505050565b6000811561360257816135f168056bc75e2d631000008561527a565b6135fb9190615266565b9050610a71565b50600019610a71565b6000806136166118ba565b905060006136226117ad565b905061362f828286613f47565b949350505050565b61364b6103e8670de0b6b3a7640000615266565b61365690600561527a565b811015801561366d5750670de0b6b3a76400008111155b610a215760405162461bcd60e51b815260206004820152603060248201527f4d6178206665652070657263656e74616765206d75737420626520626574776560448201526f656e20302e352520616e64203130302560801b6064820152608401610b18565b670f43fc2c04ee00006136e48261360b565b1015610a215760405162461bcd60e51b815260206004820152602a60248201527f54726f76654d616e616765723a2043616e6e6f742072656465656d207768656e604482015269102a21a9101e1026a1a960b11b6064820152608401610b18565b60008111610a215760405162461bcd60e51b815260206004820152602e60248201527f54726f76654d616e616765723a20416d6f756e74206d7573742062652067726560448201526d61746572207468616e207a65726f60901b6064820152608401610b18565b6040516370a0823160e01b815281906001600160a01b038516906370a08231906137da908690600401614e03565b602060405180830381865afa1580156137f7573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061381b91906151dc565b10156124925760405162461bcd60e51b815260206004820152604f60248201527f54726f76654d616e616765723a2052657175657374656420726564656d70746960448201527f6f6e20616d6f756e74206d757374206265203c3d20757365722773205448555360648201526e4420746f6b656e2062616c616e636560881b608482015260a401610b18565b60006001600160a01b03831615806139295750604051630bb7c8fd60e31b81526001600160a01b03851690635dbe47e8906138e6908690600401614e03565b602060405180830381865afa158015613903573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906139279190615384565b155b806139445750670f43fc2c04ee0000613942848461216d565b105b1561395157506000612e50565b60405163765e015960e01b81526000906001600160a01b0386169063765e015990613980908790600401614e03565b602060405180830381865afa15801561399d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906139c19190615305565b90506001600160a01b0381161580611a405750670f43fc2c04ee00006139e7828561216d565b1095945050505050565b613a17604051806060016040528060008152602001600081526020016000151581525090565b6001600160a01b0387166000908152600d6020526040902054613a4a90879061340190680ad78ebc5ac6200000906151c9565b8082528590613a6290670de0b6b3a76400009061527a565b613a6c9190615266565b60208083019190915281516001600160a01b0389166000908152600d9092526040822054613a9a91906151c9565b6020808401516001600160a01b038b166000908152600d90925260408220600101549293509091613acb91906151c9565b9050680ad78ebc5ac62000008203613b4357613ae68961405a565b613af1896004613da0565b613b068a8a680ad78ebc5ac6200000846147ed565b886001600160a01b031660008051602061540c83398151915260008060006003604051613b369493929190615349565b60405180910390a2613c71565b6000613b4f82846135d5565b90508481141580613b705750686194049f30f7200000613b6e8461494c565b105b15613b845750506001604083015250613c74565b60808b015160405163015f109360e51b81526001600160a01b038c81166004830152602482018490528981166044830152888116606483015290911690632be2126090608401600060405180830381600087803b158015613be457600080fd5b505af1158015613bf8573d6000803e3d6000fd5b5050506001600160a01b038b166000908152600d6020526040902084815560010183905550613c268a612530565b506001600160a01b038a166000818152600d60205260409081902060020154905160008051602061540c83398151915291613c679187918791600390615349565b60405180910390a2505b50505b979650505050505050565b600080613c8a612e57565b9050600083613c99868861527a565b613ca39190615266565b90506000613cb2600283615266565b613cbc90846152f2565b9050613cd081670de0b6b3a7640000614710565b905060008111613ce257613ce26152a7565b600b8190556040518181527fc454ee9b76c52f782a256af821b857ca6e125d1e3333bcede402fec2bed9600c9060200160405180910390a1610fc4612e9b565b6000610a716121ca610e82565b600082613d44670de0b6b3a76400008661527a565b613d4e9190615266565b905081811115612b355760405162461bcd60e51b815260206004820152601d60248201527f4665652065786365656465642070726f7669646564206d6178696d756d0000006044820152606401610b18565b6000816004811115613db457613db4614f60565b14158015613dd457506001816004811115613dd157613dd1614f60565b14155b613de057613de06152a7565b60145460085460048054604051635f7a196360e11b81526001600160a01b039384169363bef432c693613e17939091169101614e03565b602060405180830381865afa158015613e34573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613e589190615384565b15613e6657613e6681614961565b6001600160a01b0383166000908152600d60205260409020600301805483919060ff19166001836004811115613e9e57613e9e614f60565b02179055506001600160a01b0383166000908152600d60209081526040808320600180820185905590849055601390925282208281550155613ee08382614a3b565b600a54604051631484968760e11b81526001600160a01b03909116906329092d0e90613f10908690600401614e03565b600060405180830381600087803b158015613f2a57600080fd5b505af1158015613f3e573d6000803e3d6000fd5b50505050505050565b60008215613f6f57600083613f5c848761527a565b613f669190615266565b9150612e509050565b50600019612e50565b600080670de0b6b3a7640000613f8e848661527a565b613f989190615266565b9050828110612e505760405162461bcd60e51b815260206004820152603660248201527f54726f76654d616e616765723a2046656520776f756c642065617420757020616044820152751b1b081c995d1d5c9b99590818dbdb1b185d195c985b60521b6064820152608401610b18565b600380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6001600160a01b0381166000908152600d6020526040812060020154600e8054919283926140899084906151c9565b9091555050506001600160a01b03166000908152600d6020526040812060020155565b604051637b7fc9eb60e11b8152600481018390526001600160a01b0384169063f6ff93d690602401600060405180830381600087803b1580156140ee57600080fd5b505af1158015614102573d6000803e3d6000fd5b50506040516342c31a2360e01b8152600481018590526001600160a01b03871692506342c31a239150602401600060405180830381600087803b15801561414857600080fd5b505af115801561415c573d6000803e3d6000fd5b5050604051633ef8ba8160e11b8152600481018490526001600160a01b0386169250637df175029150602401612d25565b6000806010546000036141a1575081610a71565b6000600f54116141b3576141b36152a7565b601054600f54612e46908561527a565b6141cb614d6f565b6141ef60405180606001604052806000815260200160008152602001600081525090565b6014546001106141ff5750613c74565b61420887611a54565b6040850152602084810191909152840181905290835261422790614c0b565b60408301819052680ad78ebc5ac62000006060840152602083015161424c91906151c9565b8152670de0b6b3a76400008611614317576142718989836020015184604001516140ac565b61427a8761405a565b60006080830181905260a0830152815160c0830152805160e08301526142a1876003613da0565b815160208301516040516001600160a01b038a16926000805160206153ec833981519152926142d2926002906153a6565b60405180910390a2866001600160a01b031660008051602061540c8339815191526000806000600260405161430a9493929190615349565b60405180910390a26144b2565b670de0b6b3a7640000861180156143355750670f43fc2c04ee000086105b156143855761434e8989836020015184604001516140ac565b6143578761405a565b81518151614366919087614c18565b60e086015260c085015260a084015260808301526142a1876003613da0565b670f43fc2c04ee0000861015801561439c57508386105b80156143a9575081518510155b156144a1576143c28989836020015184604001516140ac565b846000036143d2576143d26152a7565b6143db8761405a565b6143ee8260000151836020015185614c79565b91506143fb876003613da0565b6101008201511561447057600754610100830151604051633f10abab60e01b81526001600160a01b0390921691633f10abab9161443d918b9190600401615237565b600060405180830381600087803b15801561445757600080fd5b505af115801561446b573d6000803e3d6000fd5b505050505b815160a08301516040516001600160a01b038a16926000805160206153ec833981519152926142d2926002906153a6565b6144a9614d6f565b9150613c749050565b50979650505050505050565b6144c6614d6f565b816040015183604001516144da91906152f2565b6040820152606080830151908401516144f391906152f2565b60608201528151602084015161450991906152f2565b602080830191909152820151835161452191906152f2565b81526080808301519084015161453791906152f2565b608082015260a0808301519084015161455091906152f2565b60a082015260c0808301519084015161456991906152f2565b60c082015260e0808301519084015161458291906152f2565b60e0820152610100808301519084015161459c91906152f2565b61010082015292915050565b6000806145b6858585613f47565b6714d1120d7b1600001195945050505050565b6145d1614d6f565b6145f560405180606001604052806000815260200160008152602001600081525090565b6145fe84611a54565b604085019081526020858101928352860192909252918452905190516146289188918891906140ac565b6146318461405a565b61463e8260200151614c0b565b60408301819052680ad78ebc5ac620000060608401526020830151600091614665916151c9565b905061467683600001518286614c18565b60e087015260c086015260a08501526080840152614695856003613da0565b825160208401516040516001600160a01b038816926000805160206153ec833981519152926146c6926001906153a6565b60405180910390a2846001600160a01b031660008051602061540c833981519152600080600060016040516146fe9493929190615349565b60405180910390a25050949350505050565b600081831061471f5781612e50565b5090919050565b6000603c600c544261473891906151c9565b610e8f9190615266565b6000631f54050082111561475857631f54050091505b8160000361476f5750670de0b6b3a7640000610a71565b670de0b6b3a764000083835b60018111156147e35761478f6002826153c1565b6000036147b4576147a08283614d07565b91506147ad600282615266565b905061477b565b6147be8284614d07565b92506147ca8283614d07565b915060026147d96001836151c9565b6147ad9190615266565b610fc48284614d07565b6040808501516006549151632770a7eb60e21b81526001600160a01b0391821692639dc29fac92614825929116908690600401615237565b600060405180830381600087803b15801561483f57600080fd5b505af1158015614853573d6000803e3d6000fd5b50508551604051637b7fc9eb60e11b8152600481018690526001600160a01b03909116925063f6ff93d69150602401600060405180830381600087803b15801561489c57600080fd5b505af11580156148b0573d6000803e3d6000fd5b505050508360a001516001600160a01b0316633f10abab84836040518363ffffffff1660e01b81526004016148e6929190615237565b600060405180830381600087803b15801561490057600080fd5b505af1158015614914573d6000803e3d6000fd5b5050855160a0870151604051636250216960e01b81526001600160a01b03909216935063625021699250612d25918590600401615237565b6000610a71680ad78ebc5ac6200000836151c9565b6001811180156149dc5750600a546040805163de8fa43160e01b815290516001926001600160a01b03169163de8fa4319160048083019260209291908290030181865afa1580156149b6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906149da91906151dc565b115b610a215760405162461bcd60e51b815260206004820152602a60248201527f54726f76654d616e616765723a204f6e6c79206f6e652074726f766520696e206044820152697468652073797374656d60b01b6064820152608401610b18565b6001600160a01b0382166000908152600d602052604081206003015460ff1690816004811115614a6d57614a6d614f60565b14158015614a8d57506001816004811115614a8a57614a8a614f60565b14155b614a9957614a996152a7565b6001600160a01b0383166000908152600d602052604081206003015461010090046001600160801b0316908390614ad16001836151c9565b905080836001600160801b03161115614aec57614aec6152a7565b600060148281548110614b0157614b01615291565b600091825260209091200154601480546001600160a01b03909216925082916001600160801b038716908110614b3957614b39615291565b600091825260208083209190910180546001600160a01b0319166001600160a01b03948516179055918316808252600d83526040918290206003018054610100600160881b0319166101006001600160801b038a16908102919091179091558251918252928101929092527f02b04ae5f7be9ca7c103293a2aa15f3c339d15d6eda53b721fef7b0e609c831a910160405180910390a16014805480614be057614be06153d5565b600082815260209020810160001990810180546001600160a01b031916905501905550505050505050565b6000610a7160c883615266565b60008080808415614c6357614c2d8786614710565b935086614c3a858861527a565b614c449190615266565b9250614c5084886151c9565b9150614c5c83876151c9565b9050614c70565b5060009250829150859050845b93509350935093565b614c81614d6f565b83815260208101839052600082614ca0670f43fc2c04ee00008761527a565b614caa9190615266565b9050614cb581614c0b565b60408301819052680ad78ebc5ac6200000606084015260808301869052614cdc90826151c9565b60a0830152614ceb81856151c9565b61010083015250600060c0820181905260e08201529392505050565b600080614d14838561527a565b9050670de0b6b3a7640000614d2a600282615266565b614d3490836152f2565b61362f9190615266565b6040518060a00160405280600081526020016000815260200160001515815260200160008152602001600081525090565b6040518061012001604052806000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b6040518060e0016040528060008152602001600081526020016000815260200160006001600160a01b0316815260200160001515815260200160008152602001600081525090565b6001600160a01b0391909116815260200190565b6001600160a01b0381168114610a2157600080fd5b8035614e3781614e17565b919050565b600060208284031215614e4e57600080fd5b8135612e5081614e17565b60008060408385031215614e6c57600080fd5b8235614e7781614e17565b946020939093013593505050565b634e487b7160e01b600052604160045260246000fd5b60006020808385031215614eae57600080fd5b823567ffffffffffffffff80821115614ec657600080fd5b818501915085601f830112614eda57600080fd5b813581811115614eec57614eec614e85565b8060051b604051601f19603f83011681018181108582111715614f1157614f11614e85565b604052918252848201925083810185019188831115614f2f57600080fd5b938501935b82851015614f5457614f4585614e2c565b84529385019392850192614f34565b98975050505050505050565b634e487b7160e01b600052602160045260246000fd5b60058110614f8657614f86614f60565b9052565b60208101610a718284614f76565b600060208284031215614faa57600080fd5b5035919050565b6000806000806000806000806000806101408b8d031215614fd157600080fd5b8a35614fdc81614e17565b995060208b0135614fec81614e17565b985060408b0135614ffc81614e17565b975060608b013561500c81614e17565b965060808b013561501c81614e17565b955060a08b013561502c81614e17565b945060c08b013561503c81614e17565b935060e08b013561504c81614e17565b92506101008b013561505d81614e17565b915061506c6101208c01614e2c565b90509295989b9194979a5092959850565b858152602081018590526040810184905260a0810161509f6060830185614f76565b6001600160801b039290921660809190910152949350505050565b600080604083850312156150cd57600080fd5b82356150d881614e17565b91506020830135600581106150ec57600080fd5b809150509250929050565b600060208083528351808285015260005b8181101561512457858101830151858201604001528201615108565b506000604082860101526040601f19601f8301168501019250505092915050565b600080600080600080600060e0888a03121561516057600080fd5b87359650602088013561517281614e17565b9550604088013561518281614e17565b9450606088013561519281614e17565b9699959850939660808101359560a0820135955060c0909101359350915050565b634e487b7160e01b600052601160045260246000fd5b81810381811115610a7157610a716151b3565b6000602082840312156151ee57600080fd5b5051919050565b60208082526022908201527f54726f76654d616e616765723a206e6f7468696e6720746f206c697175696461604082015261746560f01b606082015260800190565b6001600160a01b03929092168252602082015260400190565b634e487b7160e01b600052601260045260246000fd5b60008261527557615275615250565b500490565b8082028115828204841417610a7157610a716151b3565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052600160045260246000fd5b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b80820180821115610a7157610a716151b3565b60006020828403121561531757600080fd5b8151612e5081614e17565b600081615331576153316151b3565b506000190190565b60048110614f8657614f86614f60565b848152602081018490526040810183905260808101611a406060830184615339565b60006001820161537d5761537d6151b3565b5060010190565b60006020828403121561539657600080fd5b81518015158114612e5057600080fd5b838152602081018390526060810161362f6040830184615339565b6000826153d0576153d0615250565b500690565b634e487b7160e01b600052603160045260246000fdfeea67486ed7ebe3eea8ab3390efd4a3c8aae48be5bea27df104a8af786c408434c3770d654ed33aeea6bf11ac8ef05d02a6a04ed4686dd2f624d853bbec43cc8ba26469706673582212202d04ada939169bc7aa7216586e65c2ce4e3fc480b31b737556f319a5eca7f7f364736f6c63430008110033
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106104145760003560e01c8063795d26c311610221578063bcd375261161012b578063d5b35635116100c3578063ee266b8711610087578063ee266b87146109c5578063f2fde38b146109ce578063f36b2425146109e1578063f92d343314610562578063fe2ba848146109e957600080fd5b8063d5b356351461095a578063d66a25531461096d578063d9a7244414610996578063e2ac77b0146109a9578063e6a91f16146109bc57600080fd5b8063bcd37526146108dc578063bf9befb1146108ef578063c52861f2146108f8578063c7b5548114610900578063cbd138ae1461090f578063d293c71014610922578063d380a37c14610935578063d38b05581461093e578063d3d6f8431461094757600080fd5b80639976cf45116101b9578063ae9187541161017d578063ae9187541461085d578063b0d8e18114610870578063b7f8cf9b14610883578063b82f263d14610896578063b91af97c146108a957600080fd5b80639976cf45146107f65780639ba7a40814610809578063a20baee614610720578063a3f4df7e1461081c578063a68b663e1461085457600080fd5b8063795d26c3146107775780637f7dde4a1461077f578063807d138d1461079257806382fe3eb91461079b578063887105d3146107ae5780638da5cb5b146107b65780638f32d59b146107c7578063953f0bb1146107da57806396d711ff146107ed57600080fd5b8063480cd57811610322578063653d46e7116102ba57806372fe25aa1161027e57806372fe25aa14610720578063741bef1a1461072f578063756b253e1461074257806377e16f1e14610755578063794e57241461076857600080fd5b8063653d46e71461068657806366ca4a21146106995780636c37a4af146106a15780636ef64338146106b457806372423c171461070d57600080fd5b8063480cd578146105be5780634870dd9a146105ea57806349eefeee146105f25780634a3c95c4146105fa5780634e443d9e1461060d5780635733d58f146106305780635dba4c4a1461063f578063631203b01461064757806364cee2601461065a57600080fd5b80631f68f20a116103b05780632b11551a116103745780632b11551a1461056a5780632f865568146105725780633cc74225146105855780634597f6ed14610598578063477d66cf146105ab57600080fd5b80631f68f20a146105055780631fd6a4341461050e57806321e378011461051e578063240926691461055a57806328d28b5b1461056257600080fd5b8063048c661d14610419578063071a7541146104425780630b0765571461045857806312610e921461046d57806315d549f1146104805780631673c79a1461049357806318f2817a146104cf5780631bf43555146104e25780631e8b1c2b146104f2575b600080fd5b60055461042c906001600160a01b031681565b6040516104399190614e03565b60405180910390f35b61044a600281565b604051908152602001610439565b61046b610466366004614e3c565b6109fc565b005b61044a61047b366004614e59565b610a24565b61044a61048e366004614e3c565b610a77565b6104ba6104a1366004614e3c565b6013602052600090815260409020805460019091015482565b60408051928352602083019190915201610439565b61044a6104dd366004614e3c565b610a99565b61044a686194049f30f720000081565b61046b610500366004614e9b565b610aac565b61044a600b5481565b61044a680ad78ebc5ac620000081565b61054d61052c366004614e3c565b6001600160a01b03166000908152600d602052604090206003015460ff1690565b6040516104399190614f8a565b61044a610e4d565b61044a610e6e565b61044a610e82565b61046b610580366004614e3c565b610e94565b60015461042c906001600160a01b031681565b60095461042c906001600160a01b031681565b61044a6105b9366004614f98565b610f00565b61044a6105cc366004614e3c565b6001600160a01b03166000908152600d602052604090206001015490565b61044a60c881565b60145461044a565b61044a610608366004614e3c565b610f13565b61062061061b366004614f98565b610fce565b6040519015158152602001610439565b61044a6714d1120d7b16000081565b61046b610fd9565b61044a610655366004614f98565b611045565b61044a610668366004614e3c565b6001600160a01b03166000908152600d602052604090206002015490565b61046b610694366004614f98565b611052565b61044a6113c8565b61046b6106af366004614fb1565b6113da565b6106fc6106c2366004614e3c565b600d6020526000908152604090208054600182015460028301546003909301549192909160ff81169061010090046001600160801b031685565b60405161043995949392919061507d565b61044a61071b366004614e59565b61172b565b61044a670de0b6b3a764000081565b60025461042c906001600160a01b031681565b61042c610750366004614f98565b611783565b60085461042c906001600160a01b031681565b61044a670f43fc2c04ee000081565b61044a6117ad565b60005461042c906001600160a01b031681565b61044a600f5481565b61046b6107a9366004614e3c565b6118a9565b61044a6118ba565b6003546001600160a01b031661042c565b6003546001600160a01b03163314610620565b61046b6107e83660046150ba565b61197f565b61044a60105481565b61044a610804366004614e59565b6119c8565b61044a610817366004614e3c565b6119f6565b6108476040518060400160405280600c81526020016b2a3937bb32a6b0b730b3b2b960a11b81525081565b60405161043991906150f7565b61044a60125481565b600a5461042c906001600160a01b031681565b61044a61087e366004614e3c565b611a22565b60045461042c906001600160a01b031681565b61044a6108a4366004614f98565b611a49565b6108bc6108b7366004614e3c565b611a54565b604080519485526020850193909352918301526060820152608001610439565b61046b6108ea366004615145565b611aac565b61044a600e5481565b61044a612148565b61044a670ddd4b8c6c7d70d881565b61046b61091d366004614e3c565b61215a565b61044a610930366004614e59565b61216d565b61044a600c5481565b61044a60155481565b61044a610955366004614e59565b61218c565b61044a610968366004614f98565b6121bd565b61044a61097b366004614e3c565b6001600160a01b03166000908152600d602052604090205490565b61042c6109a4366004614f98565b6121d0565b6106206109b7366004614e3c565b612200565b61044a60165481565b61044a60115481565b61046b6109dc366004614e3c565b612263565b61044a6122fb565b61046b6109f7366004614e3c565b612308565b610a04612319565b600054600154610a21916001600160a01b0390811691168361239b565b50565b6000610a2e612319565b6001600160a01b0383166000908152600d6020526040812054610a529084906151c9565b6001600160a01b0385166000908152600d602052604090208190559150505b92915050565b6000610a81612319565b610a8a82612497565b6001600160801b031692915050565b6000610aa3612319565b610a7182612530565b8051600003610b215760405162461bcd60e51b815260206004820152603660248201527f54726f76654d616e616765723a2043616c6c646174612061646472657373206160448201527572726179206d757374206e6f7420626520656d70747960501b60648201526084015b60405180910390fd5b6000546001546005546001600160a01b03928316929182169116610b43614d3e565b610b4b614d6f565b600260009054906101000a90046001600160a01b03166001600160a01b0316630fdb11cf6040518163ffffffff1660e01b81526004016020604051808303816000875af1158015610ba0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bc491906151dc565b826000018181525050826001600160a01b03166301081fda6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610c0b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c2f91906151dc565b60208301528151610c3f906125d5565b1580156040840152610c6757610c608585846000015185602001518a6125f2565b9050610c7f565b610c7c8585846000015185602001518a612827565b90505b6000816020015111610ca35760405162461bcd60e51b8152600401610b18906151f5565b608081015160a082015160405163335525ad60e01b81526001600160a01b0386169263335525ad92610ce092600401918252602082015260400190565b600060405180830381600087803b158015610cfa57600080fd5b505af1158015610d0e573d6000803e3d6000fd5b50505050610d2685858360c001518460e001516128fc565b61010081015115610d9d57600754610100820151604051636250216960e01b81526001600160a01b0388811693636250216993610d6a939290911691600401615237565b600060405180830381600087803b158015610d8457600080fd5b505af1158015610d98573d6000803e3d6000fd5b505050505b610dab858260400151612b3b565b6020810151606083015261010081015160408201518251610dcc91906151c9565b610dd691906151c9565b6080838101829052606080850151604085810151868401518251938452602084019690965290820152908101929092527f4152c73dd2614c4f9fc35e8c9cf16013cd588c75b49a4c1673ecffdcbcda9403910160405180910390a1610e45853383606001518460400151612c86565b505050505050565b610e606064670de0b6b3a7640000615266565b610e6b90600561527a565b81565b610e606103e8670de0b6b3a7640000615266565b6000610e8f600b54612d5d565b905090565b610e9d81612d9a565b604080516001808252818301909252600091602080830190803683370190505090508181600081518110610ed357610ed3615291565b60200260200101906001600160a01b031690816001600160a01b031681525050610efc81610aac565b5050565b6000610a71610f0d6113c8565b83612e31565b6001600160a01b0381166000908152601360205260408120546011548290610f3c9083906151c9565b9050801580610f7b575060016001600160a01b0385166000908152600d602052604090206003015460ff166004811115610f7857610f78614f60565b14155b15610f8a575060009392505050565b6001600160a01b0384166000908152600d602052604081206002015490670de0b6b3a7640000610fba848461527a565b610fc49190615266565b9695505050505050565b6000610a71826125d5565b610fe1612319565b6000610feb612e57565b9050670de0b6b3a7640000811115611005576110056152a7565b600b8190556040518181527fc454ee9b76c52f782a256af821b857ca6e125d1e3333bcede402fec2bed9600c9060200160405180910390a1610a21612e9b565b6000610a71610f0d6122fb565b6040805160e081018252600080546001600160a01b0390811683526001548116602084015292820181905260608201819052600a548316608083015260a0820181905260c08201526005549091166110a8614d3e565b6110b0614d6f565b600260009054906101000a90046001600160a01b03166001600160a01b0316630fdb11cf6040518163ffffffff1660e01b81526004016020604051808303816000875af1158015611105573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061112991906151dc565b826000018181525050826001600160a01b03166301081fda6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611170573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061119491906151dc565b602083015281516111a4906125d5565b15801560408401526111cb576111c4848360000151846020015188612ef2565b90506111eb565b6111e884600001518560200151846000015185602001518961327e565b90505b600081602001511161120f5760405162461bcd60e51b8152600401610b18906151f5565b608081015160a082015160405163335525ad60e01b81526001600160a01b0386169263335525ad9261124c92600401918252602082015260400190565b600060405180830381600087803b15801561126657600080fd5b505af115801561127a573d6000803e3d6000fd5b5050505061129a846000015185602001518360c001518460e001516128fc565b61010081015115611311578351600754610100830151604051636250216960e01b81526001600160a01b03938416936362502169936112de93911691600401615237565b600060405180830381600087803b1580156112f857600080fd5b505af115801561130c573d6000803e3d6000fd5b505050505b61132384600001518260400151612b3b565b602081015160608301526101008101516040820151825161134491906151c9565b61134e91906151c9565b6080838101829052606080850151604085810151868401518251938452602084019690965290820152908101929092527f4152c73dd2614c4f9fc35e8c9cf16013cd588c75b49a4c1673ecffdcbcda9403910160405180910390a16113c184600001513383606001518460400151612c86565b5050505050565b6000610e8f6113d5612e57565b6133b4565b6003546001600160a01b031633146114045760405162461bcd60e51b8152600401610b18906152bd565b61140d8a613406565b61141689613406565b61141f88613406565b61142887613406565b61143186613406565b61143a85613406565b61144384613406565b61144c83613406565b61145582613406565b61145e81613406565b600480546001600160a01b03199081166001600160a01b038d8116919091179092556000805482168c84161790556001805482168b84161790556005805482168a8416179055600680548216898416179055600780548216888416179055600280548216878416179055600880548216868416179055600a80548216858416179055600980549091169183169190911790556040517f3ca631ffcd2a9b5d9ae18543fc82f58eb4ca33af9e6ab01b7a8e95331e6ed98590611520908c90614e03565b60405180910390a17f78f058b189175430c48dc02699e3a0031ea4ff781536dc2fab847de4babdd882896040516115579190614e03565b60405180910390a17f5ee0cae2f063ed938bb55046f6a932fb6ae792bf43624806bb90abe68a50be9b8860405161158e9190614e03565b60405180910390a17f82966d27eea39b038ee0fa30cd16532bb24f6e65d31cb58fb227aa5766cdcc7f876040516115c59190614e03565b60405180910390a17fcfb07d791fcafc032b35837b50eb84b74df518cf4cc287e8084f47630fa70fa0866040516115fc9190614e03565b60405180910390a17fe67f36a6e961157d6eff83b91f3af5a62131ceb6f04954ef74f51c1c05e7f88d856040516116339190614e03565b60405180910390a17f8c537274438aa850a330284665d81a85dd38267d09e4050d416bfc94142db2648460405161166a9190614e03565b60405180910390a17fe1e858a66c0bbbcdfa22d58dde1e5d42370be20cdb176e560287f85412e546e0836040516116a19190614e03565b60405180910390a17f65f4cf077bc01e4742eb5ad98326f6e95b63548ea24b17f8d5e823111fe78800826040516116d89190614e03565b60405180910390a17f38335c64466e2376ab931166337e19127650d842036ebe01da1ba3e5c1255ebb8160405161170f9190614e03565b60405180910390a161171f6134ab565b50505050505050505050565b6000611735612319565b6001600160a01b0383166000908152600d602052604081206001015461175c9084906152f2565b6001600160a01b0385166000908152600d6020526040902060010181905591505092915050565b6014818154811061179357600080fd5b6000918252602090912001546001600160a01b0316905081565b600080546040805163f07424e960e01b8152905183926001600160a01b03169163f07424e99160048083019260209291908290030181865afa1580156117f7573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061181b91906151dc565b90506000600160009054906101000a90046001600160a01b03166001600160a01b031663f07424e96040518163ffffffff1660e01b8152600401602060405180830381865afa158015611872573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061189691906151dc565b90506118a281836152f2565b9250505090565b6118b1612319565b610a21816134f5565b6000805460408051631529a63960e01b8152905183926001600160a01b031691631529a6399160048083019260209291908290030181865afa158015611904573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061192891906151dc565b90506000600160009054906101000a90046001600160a01b03166001600160a01b0316631529a6396040518163ffffffff1660e01b8152600401602060405180830381865afa158015611872573d6000803e3d6000fd5b611987612319565b6001600160a01b0382166000908152600d60205260409020600301805482919060ff191660018360048111156119bf576119bf614f60565b02179055505050565b60006119d2612319565b6001600160a01b0383166000908152600d6020526040812054610a529084906152f2565b6001600160a01b0381166000908152601360205260408120600101546012548290610f3c9083906151c9565b6000806000611a3084613559565b915091506000611a4083836135d5565b95945050505050565b6000610a718261360b565b6001600160a01b0381166000908152600d602052604081208054600190910154909180611a80856119f6565b9150611a8b85610f13565b9050611a9782856152f2565b9350611aa381846152f2565b92509193509193565b6040805160e08082018352600080546001600160a01b03908116845260015481166020808601919091526008548216858701526009548216606080870191909152600a548316608080880191909152600754841660a08089019190915260065490941660c080890191909152885161010081018a5286815293840186905297830185905290820184905281018390529081018290529384018190529083015290611b5583613637565b600260009054906101000a90046001600160a01b03166001600160a01b0316630fdb11cf6040518163ffffffff1660e01b81526004016020604051808303816000875af1158015611baa573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611bce91906151dc565b60c08201819052611bde906136d2565b611be789613745565b611bf68260400151338b6137ac565b611bfe6117ad565b60e0820152888152608082015160c0820151600091611c1e918b906138a7565b15611c2a575087611d3c565b82608001516001600160a01b0316634d6228316040518163ffffffff1660e01b8152600401602060405180830381865afa158015611c6c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c909190615305565b90505b6001600160a01b03811615801590611cbf5750670f43fc2c04ee0000611cbd828460c0015161216d565b105b15611d3c5782608001516001600160a01b031663b72703ac826040518263ffffffff1660e01b8152600401611cf49190614e03565b602060405180830381865afa158015611d11573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d359190615305565b9050611c93565b84600003611d4a5760001994505b6001600160a01b03811615801590611d625750815115155b8015611d6e5750600085115b15611e815784611d7d81615322565b955050600083608001516001600160a01b031663b72703ac836040518263ffffffff1660e01b8152600401611db29190614e03565b602060405180830381865afa158015611dcf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611df39190615305565b9050611e08846000015185602001518461239b565b6000611e21858486600001518760c001518e8e8e6139f1565b9050806040015115611e34575050611e81565b8051602085018051611e479083906152f2565b9052506020810151604085018051611e609083906152f2565b905250805184518590611e749083906151c9565b905250909150611d4a9050565b6000826040015111611ee75760405162461bcd60e51b815260206004820152602960248201527f54726f76654d616e616765723a20556e61626c6520746f2072656465656d20616044820152681b9e48185b5bdd5b9d60ba1b6064820152608401610b18565b611efe82604001518360c001518460e00151613c7f565b50611f0c8260400151613d22565b606083018190526040830151611f23919086613d2f565b825160608085015190840151604051636250216960e01b81526001600160a01b0390931692636250216992611f5c929091600401615237565b600060405180830381600087803b158015611f7657600080fd5b505af1158015611f8a573d6000803e3d6000fd5b50505060608301516040840151611fa192506151c9565b60808301526020820151604080840151606085015191517f43a3f4082a4dbc33d78e317d2497d3a730bc7fc3574159dcea1056e62e5d9ad893611ffd938f93919293845260208401929092526040830152606082015260800190565b60405180910390a182604001516001600160a01b0316639dc29fac3384602001516040518363ffffffff1660e01b815260040161203b929190615237565b600060405180830381600087803b15801561205557600080fd5b505af1158015612069573d6000803e3d6000fd5b505084516020850151604051637b7fc9eb60e11b81526001600160a01b03909216935063f6ff93d692506120a39160040190815260200190565b600060405180830381600087803b1580156120bd57600080fd5b505af11580156120d1573d6000803e3d6000fd5b505084516080850151604051636250216960e01b81526001600160a01b0390921693506362502169925061210a91339190600401615237565b600060405180830381600087803b15801561212457600080fd5b505af1158015612138573d6000803e3d6000fd5b5050505050505050505050505050565b6000610e8f612155612e57565b612d5d565b612162612319565b610a21816002613da0565b600080600061217b85613559565b915091506000610fc4838387613f47565b6000612196612319565b6001600160a01b0383166000908152600d602052604081206001015461175c9084906151c9565b6000610a716121ca612148565b83613f78565b6000601482815481106121e5576121e5615291565b6000918252602090912001546001600160a01b031692915050565b600060016001600160a01b0383166000908152600d602052604090206003015460ff16600481111561223457612234614f60565b1461224157506000919050565b506011546001600160a01b039091166000908152601360205260409020541090565b6003546001600160a01b0316331461228d5760405162461bcd60e51b8152600401610b18906152bd565b6001600160a01b0381166122f25760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610b18565b610a2181614008565b6000610e8f600b546133b4565b612310612319565b610a218161405a565b6004546001600160a01b031633146123995760405162461bcd60e51b815260206004820152603b60248201527f54726f76654d616e616765723a2043616c6c6572206973206e6f74207468652060448201527f426f72726f7765724f7065726174696f6e7320636f6e747261637400000000006064820152608401610b18565b565b6123a481612200565b15612492576123b281612d9a565b60006123bd82610f13565b905060006123ca836119f6565b6001600160a01b0384166000908152600d60205260408120600101805492935084929091906123fa9084906152f2565b90915550506001600160a01b0383166000908152600d6020526040812080548392906124279084906152f2565b909155506124369050836134f5565b612442858583856140ac565b6001600160a01b0383166000818152600d602052604080822080546001820154600290920154925160008051602061540c833981519152946124879492939291615349565b60405180910390a250505b505050565b601480546001808201835560008381527fce6d7b5282bd9a3661ae061feed1dbda4e52ab073b1f9285be6e155d9c38d4ec90920180546001600160a01b0319166001600160a01b038616179055915490916124f1916151c9565b6001600160a01b03929092166000908152600d602052604090206003018054610100600160881b0319166101006001600160801b038516021790555090565b6001600160a01b0381166000908152600d602052604081206001015481906125579061418d565b6001600160a01b0384166000908152600d60205260409020600201805490829055600e5491925090829061258c9083906151c9565b61259691906152f2565b600e8190556040519081527f6bac5e0eb3c44eb03a60ab11ec3a2c051771616aecadbcfff2630aabae5203829060200160405180910390a15092915050565b6000806125e18361360b565b6714d1120d7b160000119392505050565b6125fa614d6f565b612602614dbb565b61260a614d6f565b8482526000608083015261261c6117ad565b60a08301526126296118ba565b60c0830152600060208301525b83518260200151101561281c578382602001518151811061265957612659615291565b6020908102919091018101516001600160a01b0316606084018190526000908152600d909152604090206003015460019060ff16600481111561269e5761269e614f60565b03612804576126b182606001518761216d565b604083015260808201516127a757670f43fc2c04ee00008260400151101580156126da57508151155b6128045760006126f38360c001518460a0015189613f47565b90506127108989856060015186604001518760000151868d6141c3565b915081608001518360000181815161272891906151c9565b905250608082015160a0840180516127419083906151c9565b905250610100820151604083015160a084015161275e91906152f2565b61276891906152f2565b8360c00181815161277991906151c9565b90525061278684836144be565b935061279b8360c001518460a00151896145a8565b15608084015250612804565b816080015180156127c35750670f43fc2c04ee00008260400151105b15612804576127dc8888846060015185600001516145c9565b90508060800151826000018181516127f491906151c9565b90525061280183826144be565b92505b602082018051906128148261536b565b905250612636565b505095945050505050565b61282f614d6f565b612837614dbb565b61283f614d6f565b848252600060208301525b83518260200151101561281c578382602001518151811061286d5761286d615291565b60209081029190910101516001600160a01b031660608301819052612892908761216d565b60408301819052670f43fc2c04ee000011156128e4576128bc8888846060015185600001516145c9565b90508060800151826000018181516128d491906151c9565b9052506128e183826144be565b92505b602082018051906128f48261536b565b90525061284a565b8115612b355760155460009061291a670de0b6b3a76400008461527a565b61292491906152f2565b90506000601654670de0b6b3a76400008561293f919061527a565b61294991906152f2565b90506000600e548361295b9190615266565b90506000600e548361296d9190615266565b9050600e548261297d919061527a565b61298790856151c9565b601555600e54612997908261527a565b6129a190846151c9565b60168190555081601160008282546129b991906152f2565b9250508190555080601260008282546129d291906152f2565b90915550506011546012546040517f9f8bc8ab0daf5bceef75ecfd2085d1fcc6548c657ea970d9a23a60610d0737e392612a1492908252602082015260400190565b60405180910390a1604051637b7fc9eb60e11b8152600481018790526001600160a01b0389169063f6ff93d690602401600060405180830381600087803b158015612a5e57600080fd5b505af1158015612a72573d6000803e3d6000fd5b50506040516342c31a2360e01b8152600481018990526001600160a01b038a1692506342c31a239150602401600060405180830381600087803b158015612ab857600080fd5b505af1158015612acc573d6000803e3d6000fd5b5050604051636250216960e01b81526001600160a01b038b16925063625021699150612afe908a908990600401615237565b600060405180830381600087803b158015612b1857600080fd5b505af1158015612b2c573d6000803e3d6000fd5b50505050505050505b50505050565b600e54600f819055506000826001600160a01b0316631529a6396040518163ffffffff1660e01b8152600401602060405180830381865afa158015612b84573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ba891906151dc565b90506000600160009054906101000a90046001600160a01b03166001600160a01b0316631529a6396040518163ffffffff1660e01b8152600401602060405180830381865afa158015612bff573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c2391906151dc565b905080612c3084846151c9565b612c3a91906152f2565b6010819055600f546040517f51bf4c63ec3cba9d03d43238abbdd979dd91bd16d9895c74ceea9118c7baaf6092612c78928252602082015260400190565b60405180910390a150505050565b8115612cf1576006546040516316268b0d60e21b81526001600160a01b039091169063589a2c3490612cbe9086908690600401615237565b600060405180830381600087803b158015612cd857600080fd5b505af1158015612cec573d6000803e3d6000fd5b505050505b8015612b3557604051636250216960e01b81526001600160a01b03851690636250216990612d259086908590600401615237565b600060405180830381600087803b158015612d3f57600080fd5b505af1158015612d53573d6000803e3d6000fd5b5050505050505050565b6000610a7182612d776103e8670de0b6b3a7640000615266565b612d8290600561527a565b612d8c91906152f2565b670de0b6b3a7640000614710565b60016001600160a01b0382166000908152600d602052604090206003015460ff166004811115612dcc57612dcc614f60565b14610a215760405162461bcd60e51b815260206004820152602f60248201527f54726f76654d616e616765723a2054726f766520646f6573206e6f742065786960448201526e1cdd081bdc881a5cc818db1bdcd959608a1b6064820152608401610b18565b6000670de0b6b3a7640000612e46838561527a565b612e509190615266565b9392505050565b600080612e62614726565b90506000612e78670ddd4b8c6c7d70d883614742565b9050670de0b6b3a764000081600b54612e91919061527a565b6118a29190615266565b6000600c5442612eab91906151c9565b9050603c8110610a215742600c8190556040519081527f860f8d2f0c74dd487e89e2883e3b25b8159ce1e1b3433a291cba7b82c508f3bc906020015b60405180910390a150565b612efa614d6f565b612f02614dbb565b612f0a614d6f565b84825260006080830152612f1c6117ad565b60a0830152612f296118ba565b8260c001818152505086608001516001600160a01b0316634d6228316040518163ffffffff1660e01b8152600401602060405180830381865afa158015612f74573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f989190615305565b82606001906001600160a01b031690816001600160a01b031681525050600087608001516001600160a01b0316631e2231436040518163ffffffff1660e01b8152600401602060405180830381865afa158015612ff9573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061301d9190615305565b6000602085015290505b8483602001511080156130505750806001600160a01b031683606001516001600160a01b031614155b156132735760808801516060840151604051632dc9c0eb60e21b81526000926001600160a01b03169163b72703ac9161308c9190600401614e03565b602060405180830381865afa1580156130a9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130cd9190615305565b90506130dd84606001518961216d565b604085015260808401516131de57670f43fc2c04ee000084604001511015801561310657508351155b156131115750613273565b60006131268560c001518660a001518b613f47565b8a5160208c015160608801516040890151895194955061314794868f6141c3565b935083608001518560000181815161315f91906151c9565b905250608084015160a0860180516131789083906151c9565b905250610100840151604085015160a086015161319591906152f2565b61319f91906152f2565b8560c0018181516131b091906151c9565b9052506131bd86856144be565b95506131d28560c001518660a001518b6145a8565b1560808601525061324d565b836080015180156131fa5750670f43fc2c04ee00008460400151105b156132475761321b89600001518a60200151866060015187600001516145c9565b925082608001518460000181815161323391906151c9565b90525061324085846144be565b945061324d565b50613273565b6001600160a01b031660608401526020830180519061326b8261536b565b905250613027565b505050949350505050565b613286614d6f565b61328e614dbb565b613296614d6f565b600a54858352600060208401526001600160a01b03165b84836020015110156133a857806001600160a01b0316634d6228316040518163ffffffff1660e01b8152600401602060405180830381865afa1580156132f7573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061331b9190615305565b6001600160a01b031660608401819052613335908861216d565b60408401819052670f43fc2c04ee0000111561338b5761335f8989856060015186600001516145c9565b915081608001518360000181815161337791906151c9565b90525061338484836144be565b9350613390565b6133a8565b602083018051906133a08261536b565b9052506132ad565b50505095945050505050565b6000610a71826133ce6103e8670de0b6b3a7640000615266565b6133d990600561527a565b6133e391906152f2565b6133f66064670de0b6b3a7640000615266565b61340190600561527a565b614710565b6001600160a01b03811661345c5760405162461bcd60e51b815260206004820152601e60248201527f4163636f756e742063616e6e6f74206265207a65726f206164647265737300006044820152606401610b18565b803b80610efc5760405162461bcd60e51b815260206004820181905260248201527f4163636f756e7420636f64652073697a652063616e6e6f74206265207a65726f6044820152606401610b18565b6003546040516000916001600160a01b0316907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908390a3600380546001600160a01b0319169055565b601180546001600160a01b038316600090815260136020526040908190209182556012546001909201829055915491517fc437f324d85e369394148dd9d62f98f534b382e01ed3dd2eb98138fb6d3ab49a92612ee792908252602082015260400190565b600080600061356784610f13565b90506000613574856119f6565b6001600160a01b0386166000908152600d60205260408120600101549192509061359f9084906152f2565b6001600160a01b0387166000908152600d6020526040812054919250906135c79084906152f2565b919791965090945050505050565b6000811561360257816135f168056bc75e2d631000008561527a565b6135fb9190615266565b9050610a71565b50600019610a71565b6000806136166118ba565b905060006136226117ad565b905061362f828286613f47565b949350505050565b61364b6103e8670de0b6b3a7640000615266565b61365690600561527a565b811015801561366d5750670de0b6b3a76400008111155b610a215760405162461bcd60e51b815260206004820152603060248201527f4d6178206665652070657263656e74616765206d75737420626520626574776560448201526f656e20302e352520616e64203130302560801b6064820152608401610b18565b670f43fc2c04ee00006136e48261360b565b1015610a215760405162461bcd60e51b815260206004820152602a60248201527f54726f76654d616e616765723a2043616e6e6f742072656465656d207768656e604482015269102a21a9101e1026a1a960b11b6064820152608401610b18565b60008111610a215760405162461bcd60e51b815260206004820152602e60248201527f54726f76654d616e616765723a20416d6f756e74206d7573742062652067726560448201526d61746572207468616e207a65726f60901b6064820152608401610b18565b6040516370a0823160e01b815281906001600160a01b038516906370a08231906137da908690600401614e03565b602060405180830381865afa1580156137f7573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061381b91906151dc565b10156124925760405162461bcd60e51b815260206004820152604f60248201527f54726f76654d616e616765723a2052657175657374656420726564656d70746960448201527f6f6e20616d6f756e74206d757374206265203c3d20757365722773205448555360648201526e4420746f6b656e2062616c616e636560881b608482015260a401610b18565b60006001600160a01b03831615806139295750604051630bb7c8fd60e31b81526001600160a01b03851690635dbe47e8906138e6908690600401614e03565b602060405180830381865afa158015613903573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906139279190615384565b155b806139445750670f43fc2c04ee0000613942848461216d565b105b1561395157506000612e50565b60405163765e015960e01b81526000906001600160a01b0386169063765e015990613980908790600401614e03565b602060405180830381865afa15801561399d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906139c19190615305565b90506001600160a01b0381161580611a405750670f43fc2c04ee00006139e7828561216d565b1095945050505050565b613a17604051806060016040528060008152602001600081526020016000151581525090565b6001600160a01b0387166000908152600d6020526040902054613a4a90879061340190680ad78ebc5ac6200000906151c9565b8082528590613a6290670de0b6b3a76400009061527a565b613a6c9190615266565b60208083019190915281516001600160a01b0389166000908152600d9092526040822054613a9a91906151c9565b6020808401516001600160a01b038b166000908152600d90925260408220600101549293509091613acb91906151c9565b9050680ad78ebc5ac62000008203613b4357613ae68961405a565b613af1896004613da0565b613b068a8a680ad78ebc5ac6200000846147ed565b886001600160a01b031660008051602061540c83398151915260008060006003604051613b369493929190615349565b60405180910390a2613c71565b6000613b4f82846135d5565b90508481141580613b705750686194049f30f7200000613b6e8461494c565b105b15613b845750506001604083015250613c74565b60808b015160405163015f109360e51b81526001600160a01b038c81166004830152602482018490528981166044830152888116606483015290911690632be2126090608401600060405180830381600087803b158015613be457600080fd5b505af1158015613bf8573d6000803e3d6000fd5b5050506001600160a01b038b166000908152600d6020526040902084815560010183905550613c268a612530565b506001600160a01b038a166000818152600d60205260409081902060020154905160008051602061540c83398151915291613c679187918791600390615349565b60405180910390a2505b50505b979650505050505050565b600080613c8a612e57565b9050600083613c99868861527a565b613ca39190615266565b90506000613cb2600283615266565b613cbc90846152f2565b9050613cd081670de0b6b3a7640000614710565b905060008111613ce257613ce26152a7565b600b8190556040518181527fc454ee9b76c52f782a256af821b857ca6e125d1e3333bcede402fec2bed9600c9060200160405180910390a1610fc4612e9b565b6000610a716121ca610e82565b600082613d44670de0b6b3a76400008661527a565b613d4e9190615266565b905081811115612b355760405162461bcd60e51b815260206004820152601d60248201527f4665652065786365656465642070726f7669646564206d6178696d756d0000006044820152606401610b18565b6000816004811115613db457613db4614f60565b14158015613dd457506001816004811115613dd157613dd1614f60565b14155b613de057613de06152a7565b60145460085460048054604051635f7a196360e11b81526001600160a01b039384169363bef432c693613e17939091169101614e03565b602060405180830381865afa158015613e34573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613e589190615384565b15613e6657613e6681614961565b6001600160a01b0383166000908152600d60205260409020600301805483919060ff19166001836004811115613e9e57613e9e614f60565b02179055506001600160a01b0383166000908152600d60209081526040808320600180820185905590849055601390925282208281550155613ee08382614a3b565b600a54604051631484968760e11b81526001600160a01b03909116906329092d0e90613f10908690600401614e03565b600060405180830381600087803b158015613f2a57600080fd5b505af1158015613f3e573d6000803e3d6000fd5b50505050505050565b60008215613f6f57600083613f5c848761527a565b613f669190615266565b9150612e509050565b50600019612e50565b600080670de0b6b3a7640000613f8e848661527a565b613f989190615266565b9050828110612e505760405162461bcd60e51b815260206004820152603660248201527f54726f76654d616e616765723a2046656520776f756c642065617420757020616044820152751b1b081c995d1d5c9b99590818dbdb1b185d195c985b60521b6064820152608401610b18565b600380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6001600160a01b0381166000908152600d6020526040812060020154600e8054919283926140899084906151c9565b9091555050506001600160a01b03166000908152600d6020526040812060020155565b604051637b7fc9eb60e11b8152600481018390526001600160a01b0384169063f6ff93d690602401600060405180830381600087803b1580156140ee57600080fd5b505af1158015614102573d6000803e3d6000fd5b50506040516342c31a2360e01b8152600481018590526001600160a01b03871692506342c31a239150602401600060405180830381600087803b15801561414857600080fd5b505af115801561415c573d6000803e3d6000fd5b5050604051633ef8ba8160e11b8152600481018490526001600160a01b0386169250637df175029150602401612d25565b6000806010546000036141a1575081610a71565b6000600f54116141b3576141b36152a7565b601054600f54612e46908561527a565b6141cb614d6f565b6141ef60405180606001604052806000815260200160008152602001600081525090565b6014546001106141ff5750613c74565b61420887611a54565b6040850152602084810191909152840181905290835261422790614c0b565b60408301819052680ad78ebc5ac62000006060840152602083015161424c91906151c9565b8152670de0b6b3a76400008611614317576142718989836020015184604001516140ac565b61427a8761405a565b60006080830181905260a0830152815160c0830152805160e08301526142a1876003613da0565b815160208301516040516001600160a01b038a16926000805160206153ec833981519152926142d2926002906153a6565b60405180910390a2866001600160a01b031660008051602061540c8339815191526000806000600260405161430a9493929190615349565b60405180910390a26144b2565b670de0b6b3a7640000861180156143355750670f43fc2c04ee000086105b156143855761434e8989836020015184604001516140ac565b6143578761405a565b81518151614366919087614c18565b60e086015260c085015260a084015260808301526142a1876003613da0565b670f43fc2c04ee0000861015801561439c57508386105b80156143a9575081518510155b156144a1576143c28989836020015184604001516140ac565b846000036143d2576143d26152a7565b6143db8761405a565b6143ee8260000151836020015185614c79565b91506143fb876003613da0565b6101008201511561447057600754610100830151604051633f10abab60e01b81526001600160a01b0390921691633f10abab9161443d918b9190600401615237565b600060405180830381600087803b15801561445757600080fd5b505af115801561446b573d6000803e3d6000fd5b505050505b815160a08301516040516001600160a01b038a16926000805160206153ec833981519152926142d2926002906153a6565b6144a9614d6f565b9150613c749050565b50979650505050505050565b6144c6614d6f565b816040015183604001516144da91906152f2565b6040820152606080830151908401516144f391906152f2565b60608201528151602084015161450991906152f2565b602080830191909152820151835161452191906152f2565b81526080808301519084015161453791906152f2565b608082015260a0808301519084015161455091906152f2565b60a082015260c0808301519084015161456991906152f2565b60c082015260e0808301519084015161458291906152f2565b60e0820152610100808301519084015161459c91906152f2565b61010082015292915050565b6000806145b6858585613f47565b6714d1120d7b1600001195945050505050565b6145d1614d6f565b6145f560405180606001604052806000815260200160008152602001600081525090565b6145fe84611a54565b604085019081526020858101928352860192909252918452905190516146289188918891906140ac565b6146318461405a565b61463e8260200151614c0b565b60408301819052680ad78ebc5ac620000060608401526020830151600091614665916151c9565b905061467683600001518286614c18565b60e087015260c086015260a08501526080840152614695856003613da0565b825160208401516040516001600160a01b038816926000805160206153ec833981519152926146c6926001906153a6565b60405180910390a2846001600160a01b031660008051602061540c833981519152600080600060016040516146fe9493929190615349565b60405180910390a25050949350505050565b600081831061471f5781612e50565b5090919050565b6000603c600c544261473891906151c9565b610e8f9190615266565b6000631f54050082111561475857631f54050091505b8160000361476f5750670de0b6b3a7640000610a71565b670de0b6b3a764000083835b60018111156147e35761478f6002826153c1565b6000036147b4576147a08283614d07565b91506147ad600282615266565b905061477b565b6147be8284614d07565b92506147ca8283614d07565b915060026147d96001836151c9565b6147ad9190615266565b610fc48284614d07565b6040808501516006549151632770a7eb60e21b81526001600160a01b0391821692639dc29fac92614825929116908690600401615237565b600060405180830381600087803b15801561483f57600080fd5b505af1158015614853573d6000803e3d6000fd5b50508551604051637b7fc9eb60e11b8152600481018690526001600160a01b03909116925063f6ff93d69150602401600060405180830381600087803b15801561489c57600080fd5b505af11580156148b0573d6000803e3d6000fd5b505050508360a001516001600160a01b0316633f10abab84836040518363ffffffff1660e01b81526004016148e6929190615237565b600060405180830381600087803b15801561490057600080fd5b505af1158015614914573d6000803e3d6000fd5b5050855160a0870151604051636250216960e01b81526001600160a01b03909216935063625021699250612d25918590600401615237565b6000610a71680ad78ebc5ac6200000836151c9565b6001811180156149dc5750600a546040805163de8fa43160e01b815290516001926001600160a01b03169163de8fa4319160048083019260209291908290030181865afa1580156149b6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906149da91906151dc565b115b610a215760405162461bcd60e51b815260206004820152602a60248201527f54726f76654d616e616765723a204f6e6c79206f6e652074726f766520696e206044820152697468652073797374656d60b01b6064820152608401610b18565b6001600160a01b0382166000908152600d602052604081206003015460ff1690816004811115614a6d57614a6d614f60565b14158015614a8d57506001816004811115614a8a57614a8a614f60565b14155b614a9957614a996152a7565b6001600160a01b0383166000908152600d602052604081206003015461010090046001600160801b0316908390614ad16001836151c9565b905080836001600160801b03161115614aec57614aec6152a7565b600060148281548110614b0157614b01615291565b600091825260209091200154601480546001600160a01b03909216925082916001600160801b038716908110614b3957614b39615291565b600091825260208083209190910180546001600160a01b0319166001600160a01b03948516179055918316808252600d83526040918290206003018054610100600160881b0319166101006001600160801b038a16908102919091179091558251918252928101929092527f02b04ae5f7be9ca7c103293a2aa15f3c339d15d6eda53b721fef7b0e609c831a910160405180910390a16014805480614be057614be06153d5565b600082815260209020810160001990810180546001600160a01b031916905501905550505050505050565b6000610a7160c883615266565b60008080808415614c6357614c2d8786614710565b935086614c3a858861527a565b614c449190615266565b9250614c5084886151c9565b9150614c5c83876151c9565b9050614c70565b5060009250829150859050845b93509350935093565b614c81614d6f565b83815260208101839052600082614ca0670f43fc2c04ee00008761527a565b614caa9190615266565b9050614cb581614c0b565b60408301819052680ad78ebc5ac6200000606084015260808301869052614cdc90826151c9565b60a0830152614ceb81856151c9565b61010083015250600060c0820181905260e08201529392505050565b600080614d14838561527a565b9050670de0b6b3a7640000614d2a600282615266565b614d3490836152f2565b61362f9190615266565b6040518060a00160405280600081526020016000815260200160001515815260200160008152602001600081525090565b6040518061012001604052806000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b6040518060e0016040528060008152602001600081526020016000815260200160006001600160a01b0316815260200160001515815260200160008152602001600081525090565b6001600160a01b0391909116815260200190565b6001600160a01b0381168114610a2157600080fd5b8035614e3781614e17565b919050565b600060208284031215614e4e57600080fd5b8135612e5081614e17565b60008060408385031215614e6c57600080fd5b8235614e7781614e17565b946020939093013593505050565b634e487b7160e01b600052604160045260246000fd5b60006020808385031215614eae57600080fd5b823567ffffffffffffffff80821115614ec657600080fd5b818501915085601f830112614eda57600080fd5b813581811115614eec57614eec614e85565b8060051b604051601f19603f83011681018181108582111715614f1157614f11614e85565b604052918252848201925083810185019188831115614f2f57600080fd5b938501935b82851015614f5457614f4585614e2c565b84529385019392850192614f34565b98975050505050505050565b634e487b7160e01b600052602160045260246000fd5b60058110614f8657614f86614f60565b9052565b60208101610a718284614f76565b600060208284031215614faa57600080fd5b5035919050565b6000806000806000806000806000806101408b8d031215614fd157600080fd5b8a35614fdc81614e17565b995060208b0135614fec81614e17565b985060408b0135614ffc81614e17565b975060608b013561500c81614e17565b965060808b013561501c81614e17565b955060a08b013561502c81614e17565b945060c08b013561503c81614e17565b935060e08b013561504c81614e17565b92506101008b013561505d81614e17565b915061506c6101208c01614e2c565b90509295989b9194979a5092959850565b858152602081018590526040810184905260a0810161509f6060830185614f76565b6001600160801b039290921660809190910152949350505050565b600080604083850312156150cd57600080fd5b82356150d881614e17565b91506020830135600581106150ec57600080fd5b809150509250929050565b600060208083528351808285015260005b8181101561512457858101830151858201604001528201615108565b506000604082860101526040601f19601f8301168501019250505092915050565b600080600080600080600060e0888a03121561516057600080fd5b87359650602088013561517281614e17565b9550604088013561518281614e17565b9450606088013561519281614e17565b9699959850939660808101359560a0820135955060c0909101359350915050565b634e487b7160e01b600052601160045260246000fd5b81810381811115610a7157610a716151b3565b6000602082840312156151ee57600080fd5b5051919050565b60208082526022908201527f54726f76654d616e616765723a206e6f7468696e6720746f206c697175696461604082015261746560f01b606082015260800190565b6001600160a01b03929092168252602082015260400190565b634e487b7160e01b600052601260045260246000fd5b60008261527557615275615250565b500490565b8082028115828204841417610a7157610a716151b3565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052600160045260246000fd5b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b80820180821115610a7157610a716151b3565b60006020828403121561531757600080fd5b8151612e5081614e17565b600081615331576153316151b3565b506000190190565b60048110614f8657614f86614f60565b848152602081018490526040810183905260808101611a406060830184615339565b60006001820161537d5761537d6151b3565b5060010190565b60006020828403121561539657600080fd5b81518015158114612e5057600080fd5b838152602081018390526060810161362f6040830184615339565b6000826153d0576153d0615250565b500690565b634e487b7160e01b600052603160045260246000fdfeea67486ed7ebe3eea8ab3390efd4a3c8aae48be5bea27df104a8af786c408434c3770d654ed33aeea6bf11ac8ef05d02a6a04ed4686dd2f624d853bbec43cc8ba26469706673582212202d04ada939169bc7aa7216586e65c2ce4e3fc480b31b737556f319a5eca7f7f364736f6c63430008110033
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 35 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.