ETH Price: $4,351.28 (-1.79%)

Contract

0x9431A1CD7f53FDf299f89EAc7450682Ff3551313

Overview

ETH Balance

0 ETH

ETH Value

$0.00

More Info

Private Name Tags

Multichain Info

N/A
Transaction Hash
Method
Block
From
To
Redeem Collatera...22076802025-06-03 11:34:51128 days ago1748950491IN
0x9431A1CD...Ff3551313
0 ETH0.000000780.00100025
Redeem Collatera...21155982025-06-02 10:00:09129 days ago1748858409IN
0x9431A1CD...Ff3551313
0 ETH0.000000580.0012003

View more zero value Internal Transactions in Advanced View mode

Advanced mode:

Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
CollateralRegistry

Compiler Version
v0.8.24+commit.e11b9ed9

Optimization Enabled:
Yes with 1 runs

Other Settings:
cancun EvmVersion
// SPDX-License-Identifier: BUSL-1.1

pragma solidity 0.8.24;

import "openzeppelin-contracts/contracts/token/ERC20/extensions/IERC20Metadata.sol";

import "./Dependencies/Constants.sol";
import "./Dependencies/LiquityMath.sol";
import "./Dependencies/Owned.sol";

import "./Interfaces/ITroveManager.sol";
import "./Interfaces/IBoldToken.sol";
import "./Interfaces/ICollateralRegistry.sol";
import "./Interfaces/IWhitelist.sol";

contract CollateralRegistry is Owned, ICollateralRegistry {
    IBoldToken public immutable boldToken;

    uint256 public totalCollaterals;
    IERC20Metadata[10] internal collateralTokens;
    ITroveManager[10] internal troveManagers;

    uint256 public baseRate;

    // The timestamp of the latest fee operation (redemption or new Bold issuance)
    uint256 public lastFeeOperationTime = block.timestamp;

    event BaseRateUpdated(uint256 _baseRate);
    event LastFeeOpTimeUpdated(uint256 _lastFeeOpTime);
    event NewCollateralAdded(address collateral, address troveManager);
    event CollateralRemoved(address collateral, address troveManager);
    event WhitelistSet(address whitelist);

    error ZeroAddress();

    // --- Constructor ---

    constructor(
        IBoldToken _boldToken,
        IERC20Metadata[] memory _tokens,
        ITroveManager[] memory _troveManagers,
        address _owner
    ) Owned(_owner) {
        uint256 numTokens = _tokens.length;
        require(numTokens > 0 && numTokens <= 10, "Collateral list invalid");

        totalCollaterals = numTokens;
        boldToken = _boldToken;

        for (uint8 i; i < numTokens; i++) {
            requireNotZeroAddress(address(_tokens[i]));
            requireNotZeroAddress(address(_troveManagers[i]));

            collateralTokens[i] = _tokens[i];
            troveManagers[i] = _troveManagers[i];
        }

        // Initialize the baseRate state variable
        baseRate = INITIAL_BASE_RATE;

        emit BaseRateUpdated(INITIAL_BASE_RATE);
    }

    function addNewCollaterals(
        IERC20Metadata[] memory _tokens,
        ITroveManager[] memory _troveManagers
    ) external override onlyOwner {
        uint256 numTokens = _tokens.length;
        uint256 numCollaterals = totalCollaterals;
        require(
            numTokens > 0 && numTokens == _troveManagers.length,
            "Invalid input"
        );

        require(numCollaterals + numTokens <= 10, "Max collaterals");

        // add new collaterals and trove managers
        for (uint8 i; i < numTokens; i++) {
            requireNotZeroAddress(address(_tokens[i]));
            requireNotZeroAddress(address(_troveManagers[i]));

            collateralTokens[numCollaterals+i] = _tokens[i];
            troveManagers[numCollaterals+i] = _troveManagers[i];

            emit NewCollateralAdded(address(_tokens[i]), address(_troveManagers[i]));
        }

        // update total Collaterals
        totalCollaterals += numTokens;
    }

    // this function removes a branch from the collateralRegistry list
    // and swaps the elements in order to push zero values at the end of the array
    // it's meant to "clean up" space in the collaterals/troveManagers array
    // can be executed only if the branch is in shutdown state
    function removeCollateral(uint256 index) external override onlyOwner {
        // remove collaterals and trove managers
        require(index <= 9, "Invalid index");
        require(
            address(collateralTokens[index]) != address(0),
            "Branch not initialised"
        );

        ITroveManager troveManager = ITroveManager(troveManagers[index]);

        // revert if branch is not shutdown
        require(troveManager.shutdownTime() != 0, "Branch is not shutdown");

        emit CollateralRemoved(
            address(collateralTokens[index]),
            address(troveManagers[index])
        );

        // push the zero element at the end
        uint256 swapIndex = totalCollaterals - 1;
        if (swapIndex > index) {
            // swap
            collateralTokens[index] = collateralTokens[swapIndex];
            troveManagers[index] = ITroveManager(troveManagers[swapIndex]);

            collateralTokens[swapIndex] = IERC20Metadata(address(0));
            troveManagers[swapIndex] = ITroveManager(address(0));
        } else {
            // no swap. deleted index is the last in the array
            collateralTokens[index] = IERC20Metadata(address(0));
            troveManagers[index] = ITroveManager(address(0));
        }

        totalCollaterals--;
    }

    // --- Redemption functions ---

    function redeemCollateral(
        uint256 _boldAmount,
        uint256 _maxIterationsPerCollateral,
        uint256 _maxFeePercentage
    ) external {
        _requireValidMaxFeePercentage(_maxFeePercentage);
        _requireAmountGreaterThanZero(_boldAmount);

        RedemptionTotals memory totals;

        totals.numCollaterals = totalCollaterals;
        uint256[] memory unbackedPortions = new uint256[](
            totals.numCollaterals
        );
        uint256[] memory prices = new uint256[](totals.numCollaterals);

        totals.boldSupplyAtStart = boldToken.totalSupply();
        // Decay the baseRate due to time passed, and then increase it according to the size of this redemption.
        // Use the saved total Bold supply value, from before it was reduced by the redemption.
        // We only compute it here, and update it at the end,
        // because the final redeemed amount may be less than the requested amount
        // Redeemers should take this into account in order to request the optimal amount to not overpay
        uint256 redemptionRate = _calcRedemptionRate(
            _getUpdatedBaseRateFromRedemption(
                _boldAmount,
                totals.boldSupplyAtStart
            )
        );
        require(
            redemptionRate <= _maxFeePercentage,
            "CR: Fee exceeded provided maximum"
        );
        // Implicit by the above and the _requireValidMaxFeePercentage checks
        //require(newBaseRate < DECIMAL_PRECISION, "CR: Fee would eat up all collateral");

        // Gather and accumulate unbacked portions
        for (uint256 index = 0; index < totals.numCollaterals; index++) {
            ITroveManager troveManager = getTroveManager(index);
            (
                uint256 unbackedPortion,
                uint256 price,
                bool redeemable
            ) = troveManager.getUnbackedPortionPriceAndRedeemability();
            prices[index] = price;
            if (redeemable && troveManager.isWhitelisted(msg.sender)) {
                totals.unbacked += unbackedPortion;
                unbackedPortions[index] = unbackedPortion;
            }
        }

        // There’s an unlikely scenario where all the normally redeemable branches (i.e. having TCR > SCR) have 0 unbacked
        // In that case, we redeem proportinally to branch size
        if (totals.unbacked == 0) {
            unbackedPortions = new uint256[](totals.numCollaterals);
            for (uint256 index = 0; index < totals.numCollaterals; index++) {
                ITroveManager troveManager = getTroveManager(index);
                (, , bool redeemable) = troveManager
                    .getUnbackedPortionPriceAndRedeemability();
                if (redeemable && troveManager.isWhitelisted(msg.sender)) {
                    uint256 unbackedPortion = troveManager
                        .getEntireBranchDebt();
                    totals.unbacked += unbackedPortion;
                    unbackedPortions[index] = unbackedPortion;
                }
            }
        }

        // Compute redemption amount for each collateral and redeem against the corresponding TroveManager
        for (uint256 index = 0; index < totals.numCollaterals; index++) {
            //uint256 unbackedPortion = unbackedPortions[index];
            if (unbackedPortions[index] > 0) {
                uint256 redeemAmount = (_boldAmount * unbackedPortions[index]) /
                    totals.unbacked;
                if (redeemAmount > 0) {
                    ITroveManager troveManager = getTroveManager(index);
                    uint256 redeemedAmount = troveManager.redeemCollateral(
                        msg.sender,
                        redeemAmount,
                        prices[index],
                        redemptionRate,
                        _maxIterationsPerCollateral
                    );
                    totals.redeemedAmount += redeemedAmount;
                }
            }
        }

        _updateBaseRateAndGetRedemptionRate(
            totals.redeemedAmount,
            totals.boldSupplyAtStart
        );

        // Burn the total Bold that is cancelled with debt
        if (totals.redeemedAmount > 0) {
            boldToken.burn(msg.sender, totals.redeemedAmount);
        }
    }

    // --- Internal fee functions ---

    // Update the last fee operation time only if time passed >= decay interval. This prevents base rate griefing.
    function _updateLastFeeOpTime() internal {
        uint256 minutesPassed = _minutesPassedSinceLastFeeOp();

        if (minutesPassed > 0) {
            lastFeeOperationTime += ONE_MINUTE * minutesPassed;
            emit LastFeeOpTimeUpdated(lastFeeOperationTime);
        }
    }

    function _minutesPassedSinceLastFeeOp() internal view returns (uint256) {
        return (block.timestamp - lastFeeOperationTime) / ONE_MINUTE;
    }

    // Updates the `baseRate` state with math from `_getUpdatedBaseRateFromRedemption`
    function _updateBaseRateAndGetRedemptionRate(
        uint256 _boldAmount,
        uint256 _totalBoldSupplyAtStart
    ) internal {
        uint256 newBaseRate = _getUpdatedBaseRateFromRedemption(
            _boldAmount,
            _totalBoldSupplyAtStart
        );

        //assert(newBaseRate <= DECIMAL_PRECISION); // This is already enforced in `_getUpdatedBaseRateFromRedemption`

        // Update the baseRate state variable
        baseRate = newBaseRate;
        emit BaseRateUpdated(newBaseRate);

        _updateLastFeeOpTime();
    }

    /*
     * This function calculates the new baseRate in the following way:
     * 1) decays the baseRate based on time passed since last redemption or Bold borrowing operation.
     * then,
     * 2) increases the baseRate based on the amount redeemed, as a proportion of total supply
     */
    function _getUpdatedBaseRateFromRedemption(
        uint256 _redeemAmount,
        uint256 _totalBoldSupply
    ) internal view returns (uint256) {
        // decay the base rate
        uint256 decayedBaseRate = _calcDecayedBaseRate();

        // get the fraction of total supply that was redeemed
        uint256 redeemedBoldFraction = (_redeemAmount * DECIMAL_PRECISION) /
            _totalBoldSupply;

        uint256 newBaseRate = decayedBaseRate +
            redeemedBoldFraction /
            REDEMPTION_BETA;
        newBaseRate = LiquityMath._min(newBaseRate, DECIMAL_PRECISION); // cap baseRate at a maximum of 100%

        return newBaseRate;
    }

    function _calcDecayedBaseRate() internal view returns (uint256) {
        uint256 minutesPassed = _minutesPassedSinceLastFeeOp();
        uint256 decayFactor = LiquityMath._decPow(
            REDEMPTION_MINUTE_DECAY_FACTOR,
            minutesPassed
        );

        return (baseRate * decayFactor) / DECIMAL_PRECISION;
    }

    function _calcRedemptionRate(
        uint256 _baseRate
    ) internal pure returns (uint256) {
        return
            LiquityMath._min(
                REDEMPTION_FEE_FLOOR + _baseRate,
                DECIMAL_PRECISION // cap at a maximum of 100%
            );
    }

    function _calcRedemptionFee(
        uint256 _redemptionRate,
        uint256 _amount
    ) internal pure returns (uint256) {
        uint256 redemptionFee = (_redemptionRate * _amount) / DECIMAL_PRECISION;
        return redemptionFee;
    }

    // external redemption rate/fee getters

    function getRedemptionRate() external view override returns (uint256) {
        return _calcRedemptionRate(baseRate);
    }

    function getRedemptionRateWithDecay()
        public
        view
        override
        returns (uint256)
    {
        return _calcRedemptionRate(_calcDecayedBaseRate());
    }

    function getRedemptionRateForRedeemedAmount(
        uint256 _redeemAmount
    ) external view returns (uint256) {
        uint256 totalBoldSupply = boldToken.totalSupply();
        uint256 newBaseRate = _getUpdatedBaseRateFromRedemption(
            _redeemAmount,
            totalBoldSupply
        );
        return _calcRedemptionRate(newBaseRate);
    }

    function getRedemptionFeeWithDecay(
        uint256 _ETHDrawn
    ) external view override returns (uint256) {
        return _calcRedemptionFee(getRedemptionRateWithDecay(), _ETHDrawn);
    }

    function getEffectiveRedemptionFeeInBold(
        uint256 _redeemAmount
    ) external view override returns (uint256) {
        uint256 totalBoldSupply = boldToken.totalSupply();
        uint256 newBaseRate = _getUpdatedBaseRateFromRedemption(
            _redeemAmount,
            totalBoldSupply
        );
        return
            _calcRedemptionFee(_calcRedemptionRate(newBaseRate), _redeemAmount);
    }

    // getters

    function getToken(uint256 _index) external view returns (IERC20Metadata) {
        require(_index < 10, "Invalid index");

        return collateralTokens[_index];
    }

    function getTroveManager(
        uint256 _index
    ) public view returns (ITroveManager) {
        require(_index < 10, "Invalid index");

        return troveManagers[_index];
    }

    // require functions
    function _requireValidMaxFeePercentage(
        uint256 _maxFeePercentage
    ) internal pure {
        require(
            _maxFeePercentage >= REDEMPTION_FEE_FLOOR &&
                _maxFeePercentage <= DECIMAL_PRECISION,
            "Max fee percentage must be between 0.5% and 100%"
        );
    }

    function _requireAmountGreaterThanZero(uint256 _amount) internal pure {
        require(
            _amount > 0,
            "CollateralRegistry: Amount must be greater than zero"
        );
    }

    function requireNotZeroAddress(address _address) internal pure {
        if (_address == address(0)) revert ZeroAddress();
    }
}

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import "./IActivePool.sol";
import "./IDefaultPool.sol";
import "./IPriceFeed.sol";
import "./IWhitelist.sol";

interface ILiquityBase {
    function activePool() external view returns (IActivePool);
    function getEntireBranchDebt() external view returns (uint256);
    function getEntireBranchColl() external view returns (uint256);

    function setWhitelist(IWhitelist _whitelist) external;
}

File 3 of 33 : ITroveManager.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import "./ILiquityBase.sol";
import "./ITroveNFT.sol";
import "./IBorrowerOperations.sol";
import "./IStabilityPool.sol";
import "./IBoldToken.sol";
import "./ISortedTroves.sol";
import "../Types/LatestTroveData.sol";
import "../Types/LatestBatchData.sol";
import "./IAddressesRegistryWhitelist.sol";

// Common interface for the Trove Manager.
interface ITroveManager is ILiquityBase {
    enum Status {
        nonExistent,
        active,
        closedByOwner,
        closedByLiquidation,
        zombie
    }

    function shutdownTime() external view returns (uint256);

    function troveNFT() external view returns (ITroveNFT);
    function stabilityPool() external view returns (IStabilityPool);

    //function boldToken() external view returns (IBoldToken);
    function sortedTroves() external view returns (ISortedTroves);
    function borrowerOperations() external view returns (IBorrowerOperations);
    function updateCRs(uint256 newCCR, uint256 newSCR, uint256 newMCR) external;
    function updateLiquidationValues(uint256 newLiquidationPenaltySP, uint256 newliquidationPenaltyRedistribution)
        external;
    function isWhitelisted(address user) external view returns (bool);

    function Troves(uint256 _id)
        external
        view
        returns (
            uint256 debt,
            uint256 coll,
            uint256 stake,
            Status status,
            uint64 arrayIndex,
            uint64 lastDebtUpdateTime,
            uint64 lastInterestRateAdjTime,
            uint256 annualInterestRate,
            address interestBatchManager,
            uint256 batchDebtShares
        );

    function rewardSnapshots(uint256 _id) external view returns (uint256 coll, uint256 boldDebt);

    function getTroveIdsCount() external view returns (uint256);

    function getTroveFromTroveIdsArray(uint256 _index) external view returns (uint256);

    function getCurrentICR(uint256 _troveId, uint256 _price) external view returns (uint256);

    function lastZombieTroveId() external view returns (uint256);

    function batchLiquidateTroves(uint256[] calldata _troveArray) external;

    function redeemCollateral(
        address _sender,
        uint256 _boldAmount,
        uint256 _price,
        uint256 _redemptionRate,
        uint256 _maxIterations
    ) external returns (uint256 _redemeedAmount);

    function shutdown() external;
    function urgentRedemption(uint256 _boldAmount, uint256[] calldata _troveIds, uint256 _minCollateral) external;

    function getUnbackedPortionPriceAndRedeemability() external returns (uint256, uint256, bool);

    function getLatestTroveData(uint256 _troveId) external view returns (LatestTroveData memory);
    function getTroveAnnualInterestRate(uint256 _troveId) external view returns (uint256);

    function getTroveStatus(uint256 _troveId) external view returns (Status);

    function getLatestBatchData(address _batchAddress) external view returns (LatestBatchData memory);

    // -- permissioned functions called by BorrowerOperations

    function onOpenTrove(address _owner, uint256 _troveId, TroveChange memory _troveChange, uint256 _annualInterestRate)
        external;
    function onOpenTroveAndJoinBatch(
        address _owner,
        uint256 _troveId,
        TroveChange memory _troveChange,
        address _batchAddress,
        uint256 _batchColl,
        uint256 _batchDebt
    ) external;

    // Called from `adjustZombieTrove()`
    function setTroveStatusToActive(uint256 _troveId) external;

    function onAdjustTroveInterestRate(
        uint256 _troveId,
        uint256 _newColl,
        uint256 _newDebt,
        uint256 _newAnnualInterestRate,
        TroveChange calldata _troveChange
    ) external;

    function onAdjustTrove(uint256 _troveId, uint256 _newColl, uint256 _newDebt, TroveChange calldata _troveChange)
        external;

    function onAdjustTroveInsideBatch(
        uint256 _troveId,
        uint256 _newTroveColl,
        uint256 _newTroveDebt,
        TroveChange memory _troveChange,
        address _batchAddress,
        uint256 _newBatchColl,
        uint256 _newBatchDebt
    ) external;

    function onApplyTroveInterest(
        uint256 _troveId,
        uint256 _newTroveColl,
        uint256 _newTroveDebt,
        address _batchAddress,
        uint256 _newBatchColl,
        uint256 _newBatchDebt,
        TroveChange calldata _troveChange
    ) external;

    function onCloseTrove(
        uint256 _troveId,
        TroveChange memory _troveChange, // decrease vars: entire, with interest, batch fee and redistribution
        address _batchAddress,
        uint256 _newBatchColl,
        uint256 _newBatchDebt // entire, with interest and batch fee
    ) external;

    // -- batches --
    function onRegisterBatchManager(address _batchAddress, uint256 _annualInterestRate, uint256 _annualFee) external;
    function onLowerBatchManagerAnnualFee(
        address _batchAddress,
        uint256 _newColl,
        uint256 _newDebt,
        uint256 _newAnnualManagementFee
    ) external;
    function onSetBatchManagerAnnualInterestRate(
        address _batchAddress,
        uint256 _newColl,
        uint256 _newDebt,
        uint256 _newAnnualInterestRate,
        uint256 _upfrontFee // needed by BatchUpdated event
    ) external;

    struct OnSetInterestBatchManagerParams {
        uint256 troveId;
        uint256 troveColl; // entire, with redistribution
        uint256 troveDebt; // entire, with interest, batch fee and redistribution
        TroveChange troveChange;
        address newBatchAddress;
        uint256 newBatchColl; // updated collateral for new batch manager
        uint256 newBatchDebt; // updated debt for new batch manager
    }

    function onSetInterestBatchManager(OnSetInterestBatchManagerParams calldata _params) external;
    function onRemoveFromBatch(
        uint256 _troveId,
        uint256 _newTroveColl, // entire, with redistribution
        uint256 _newTroveDebt, // entire, with interest, batch fee and redistribution
        TroveChange memory _troveChange,
        address _batchAddress,
        uint256 _newBatchColl,
        uint256 _newBatchDebt, // entire, with interest and batch fee
        uint256 _newAnnualInterestRate
    ) external;

    // -- end of permissioned functions --
}

File 4 of 33 : Constants.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.24;

address constant ZERO_ADDRESS = address(0);

uint256 constant MAX_UINT256 = type(uint256).max;

uint256 constant DECIMAL_PRECISION = 1e18;
uint256 constant _100pct = DECIMAL_PRECISION;
uint256 constant _1pct = DECIMAL_PRECISION / 100;

// Amount of ETH to be locked in gas pool on opening troves
uint256 constant ETH_GAS_COMPENSATION = 0.0375 ether;

// Liquidation
uint256 constant MIN_LIQUIDATION_PENALTY_SP = 5e16; // 5%
uint256 constant MAX_LIQUIDATION_PENALTY_REDISTRIBUTION = 20e16; // 20%

// Batch CR buffer (same for all branches for now)
// On top of MCR to join a batch, or adjust inside a batch
uint256 constant BCR_ALL = 10 * _1pct;

// Fraction of collateral awarded to liquidator
uint256 constant COLL_GAS_COMPENSATION_DIVISOR = 200; // dividing by 200 yields 0.5%
uint256 constant COLL_GAS_COMPENSATION_CAP = 2 ether; // Max coll gas compensation capped at 2 ETH

// Minimum amount of net Bold debt a trove must have
uint256 constant MIN_DEBT = 2e18;

uint256 constant MIN_ANNUAL_INTEREST_RATE = _1pct / 2; // 0.5%
uint256 constant MAX_ANNUAL_INTEREST_RATE = 250 * _1pct;

// Batch management params
uint128 constant MAX_ANNUAL_BATCH_MANAGEMENT_FEE = uint128(_100pct / 10); // 10%
uint128 constant MIN_INTEREST_RATE_CHANGE_PERIOD = 1 hours; // only applies to batch managers / batched Troves

uint256 constant REDEMPTION_FEE_FLOOR = _1pct / 2; // 0.5%

// For the debt / shares ratio to increase by a factor 1e9
// at a average annual debt increase (compounded interest + fees) of 10%, it would take more than 217 years (log(1e9)/log(1.1))
// at a average annual debt increase (compounded interest + fees) of 50%, it would take more than 51 years (log(1e9)/log(1.5))
// The increase pace could be forced to be higher through an inflation attack,
// but precisely the fact that we have this max value now prevents the attack
uint256 constant MAX_BATCH_SHARES_RATIO = 1e9;

// Half-life of 6h. 6h = 360 min
// (1/2) = d^360 => d = (1/2)^(1/360)
uint256 constant REDEMPTION_MINUTE_DECAY_FACTOR = 998076443575628800;

// 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 REDEMPTION_BETA = 1;

// To prevent redemptions unless Bold depegs below 0.95 and allow the system to take off
uint256 constant INITIAL_BASE_RATE = _100pct; // 100% initial redemption rate

// Discount to be used once the shutdown thas been triggered
uint256 constant URGENT_REDEMPTION_BONUS = 2e16; // 2%

uint256 constant ONE_MINUTE = 1 minutes;
uint256 constant ONE_YEAR = 365 days;
uint256 constant UPFRONT_INTEREST_PERIOD = 7 days;
uint256 constant INTEREST_RATE_ADJ_COOLDOWN = 7 days;

uint256 constant MIN_BOLD_IN_SP = 1e18;

// Dummy contract that lets legacy Hardhat tests query some of the constants
contract Constants {
    uint256 public constant _ETH_GAS_COMPENSATION = ETH_GAS_COMPENSATION;
    uint256 public constant _MIN_DEBT = MIN_DEBT;
}

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import "./IActivePool.sol";
import "./ILiquityBase.sol";
import "./IBoldToken.sol";
import "./ITroveManager.sol";
import "./IBoldRewardsReceiver.sol";

/*
 * The Stability Pool holds Bold tokens deposited by Stability Pool depositors.
 *
 * When a trove is liquidated, then depending on system conditions, some of its Bold debt gets offset with
 * Bold in the Stability Pool:  that is, the offset debt evaporates, and an equal amount of Bold tokens in the Stability Pool is burned.
 *
 * Thus, a liquidation causes each depositor to receive a Bold loss, in proportion to their deposit as a share of total deposits.
 * They also receive an Coll 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 Bold 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 / Coll gain derivations:
 * https://github.com/liquity/liquity/blob/master/papers/Scalable_Reward_Distribution_with_Compounding_Stakes.pdf
 *
*/
interface IStabilityPool is ILiquityBase, IBoldRewardsReceiver {
    function boldToken() external view returns (IBoldToken);
    function troveManager() external view returns (ITroveManager);

    /*  provideToSP():
    * - Calculates depositor's Coll gain
    * - Calculates the compounded deposit
    * - Increases deposit, and takes new snapshots of accumulators P and S
    * - Sends depositor's accumulated Coll gains to depositor
    */
    function provideToSP(uint256 _amount, bool _doClaim) external;

    /*  withdrawFromSP():
    * - Calculates depositor's Coll gain
    * - Calculates the compounded deposit
    * - Sends the requested BOLD withdrawal to depositor
    * - (If _amount > userDeposit, the user withdraws all of their compounded deposit)
    * - Decreases deposit by withdrawn amount and takes new snapshots of accumulators P and S
    */
    function withdrawFromSP(uint256 _amount, bool doClaim) external;

    function claimAllCollGains() external;

    /*
     * Initial checks:
     * - Caller is TroveManager
     * ---
     * Cancels out the specified debt against the Bold 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;

    function deposits(address _depositor) external view returns (uint256 initialValue);
    function stashedColl(address _depositor) external view returns (uint256);

    /*
     * Returns the total amount of Coll held by the pool, accounted in an internal variable instead of `balance`,
     * to exclude edge cases like Coll received from a self-destruct.
     */
    function getCollBalance() external view returns (uint256);

    /*
     * Returns Bold held in the pool. Changes when users deposit/withdraw, and when Trove debt is offset.
     */
    function getTotalBoldDeposits() external view returns (uint256);

    function getYieldGainsOwed() external view returns (uint256);
    function getYieldGainsPending() external view returns (uint256);

    /*
     * Calculates the Coll gain earned by the deposit since its last snapshots were taken.
     */
    function getDepositorCollGain(address _depositor) external view returns (uint256);

    /*
     * Calculates the BOLD yield gain earned by the deposit since its last snapshots were taken.
     */
    function getDepositorYieldGain(address _depositor) external view returns (uint256);

    /*
     * Calculates what `getDepositorYieldGain` will be if interest is minted now.
     */
    function getDepositorYieldGainWithPending(address _depositor) external view returns (uint256);

    /*
     * Return the user's compounded deposit.
     */
    function getCompoundedBoldDeposit(address _depositor) external view returns (uint256);

    function scaleToS(uint256 _scale) external view returns (uint256);

    function scaleToB(uint256 _scale) external view returns (uint256);

    function P() external view returns (uint256);
    function currentScale() external view returns (uint256);

    function P_PRECISION() external view returns (uint256);
}

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

interface IDefaultPool {
    function troveManagerAddress() external view returns (address);
    function activePoolAddress() external view returns (address);
    // --- Functions ---
    function getCollBalance() external view returns (uint256);
    function getBoldDebt() external view returns (uint256);
    function sendCollToActivePool(uint256 _amount) external;
    function receiveColl(uint256 _amount) external;

    function increaseBoldDebt(uint256 _amount) external;
    function decreaseBoldDebt(uint256 _amount) external;
}

// SPDX-License-Identifier: MIT

pragma solidity 0.8.24;

import {DECIMAL_PRECISION} from "./Constants.sol";

library LiquityMath {
    function _min(uint256 _a, uint256 _b) internal pure returns (uint256) {
        return (_a < _b) ? _a : _b;
    }

    function _max(uint256 _a, uint256 _b) internal pure returns (uint256) {
        return (_a >= _b) ? _a : _b;
    }

    function _sub_min_0(uint256 _a, uint256 _b) internal pure returns (uint256) {
        return (_a > _b) ? _a - _b : 0;
    }

    /* 
    * 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 function CollateralRegistry._calcDecayedBaseRate, that represent time in units of minutes
    *
    * The exponent is capped to avoid reverting due to overflow. The cap 525600000 equals
    * "minutes in 1000 years": 60 * 24 * 365 * 1000
    * 
    * If a period of > 1000 years is ever used as an exponent in either of the above functions, the result will be
    * negligibly different from just passing the cap, since: 
    *
    * In function 1), the decayed base rate will be 0 for 1000 years or > 1000 years
    * In function 2), the difference in tokens issued at 1000 years and any time > 1000 years, will be negligible
    */
    function _decPow(uint256 _base, uint256 _minutes) internal pure returns (uint256) {
        if (_minutes > 525600000) _minutes = 525600000; // cap to avoid overflow

        if (_minutes == 0) return DECIMAL_PRECISION;

        uint256 y = DECIMAL_PRECISION;
        uint256 x = _base;
        uint256 n = _minutes;

        // Exponentiation-by-squaring
        while (n > 1) {
            if (n % 2 == 0) {
                x = decMul(x, x);
                n = n / 2;
            } else {
                // if (n % 2 != 0)
                y = decMul(x, y);
                x = decMul(x, x);
                n = (n - 1) / 2;
            }
        }

        return decMul(x, y);
    }

    function _getAbsoluteDifference(uint256 _a, uint256 _b) internal pure returns (uint256) {
        return (_a >= _b) ? _a - _b : _b - _a;
    }

    function _computeCR(uint256 _coll, uint256 _debt, uint256 _price) internal pure returns (uint256) {
        if (_debt > 0) {
            uint256 newCollRatio = _coll * _price / _debt;

            return newCollRatio;
        }
        // Return the maximal value for uint256 if the debt is 0. Represents "infinite" CR.
        else {
            // if (_debt == 0)
            return 2 ** 256 - 1;
        }
    }
}

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import "./ILiquityBase.sol";
import "./IAddRemoveManagers.sol";
import "./IBoldToken.sol";
import "./IPriceFeed.sol";
import "./ISortedTroves.sol";
import "./ITroveManager.sol";
import "./IWETH.sol";

// Common interface for the Borrower Operations.
interface IBorrowerOperations is ILiquityBase, IAddRemoveManagers {
    function CCR() external view returns (uint256);
    function MCR() external view returns (uint256);
    function SCR() external view returns (uint256);
    function BCR() external view returns (uint256);

    function updateCRs(uint256 newCCR, uint256 newSCR, uint256 newMCR, uint256 newBCR) external;

    function openTrove(
        address _owner,
        uint256 _ownerIndex,
        uint256 _ETHAmount,
        uint256 _boldAmount,
        uint256 _upperHint,
        uint256 _lowerHint,
        uint256 _annualInterestRate,
        uint256 _maxUpfrontFee,
        address _addManager,
        address _removeManager,
        address _receiver
    ) external returns (uint256);

    struct OpenTroveAndJoinInterestBatchManagerParams {
        address owner;
        uint256 ownerIndex;
        uint256 collAmount;
        uint256 boldAmount;
        uint256 upperHint;
        uint256 lowerHint;
        address interestBatchManager;
        uint256 maxUpfrontFee;
        address addManager;
        address removeManager;
        address receiver;
    }

    function openTroveAndJoinInterestBatchManager(OpenTroveAndJoinInterestBatchManagerParams calldata _params)
        external
        returns (uint256);

    function addColl(uint256 _troveId, uint256 _ETHAmount) external;

    function withdrawColl(uint256 _troveId, uint256 _amount) external;

    function withdrawBold(uint256 _troveId, uint256 _amount, uint256 _maxUpfrontFee) external;

    function repayBold(uint256 _troveId, uint256 _amount) external;

    function closeTrove(uint256 _troveId) external;

    function adjustTrove(
        uint256 _troveId,
        uint256 _collChange,
        bool _isCollIncrease,
        uint256 _debtChange,
        bool isDebtIncrease,
        uint256 _maxUpfrontFee
    ) external;

    function adjustZombieTrove(
        uint256 _troveId,
        uint256 _collChange,
        bool _isCollIncrease,
        uint256 _boldChange,
        bool _isDebtIncrease,
        uint256 _upperHint,
        uint256 _lowerHint,
        uint256 _maxUpfrontFee
    ) external;

    function adjustTroveInterestRate(
        uint256 _troveId,
        uint256 _newAnnualInterestRate,
        uint256 _upperHint,
        uint256 _lowerHint,
        uint256 _maxUpfrontFee
    ) external;

    function applyPendingDebt(uint256 _troveId, uint256 _lowerHint, uint256 _upperHint) external;

    function onLiquidateTrove(uint256 _troveId) external;

    function claimCollateral() external;

    function hasBeenShutDown() external view returns (bool);
    function shutdown() external;
    function shutdownFromOracleFailure() external;

    function checkBatchManagerExists(address _batchMananger) external view returns (bool);

    // -- individual delegation --
    struct InterestIndividualDelegate {
        address account;
        uint128 minInterestRate;
        uint128 maxInterestRate;
        uint256 minInterestRateChangePeriod;
    }

    function getInterestIndividualDelegateOf(uint256 _troveId)
        external
        view
        returns (InterestIndividualDelegate memory);
    function setInterestIndividualDelegate(
        uint256 _troveId,
        address _delegate,
        uint128 _minInterestRate,
        uint128 _maxInterestRate,
        // only needed if trove was previously in a batch:
        uint256 _newAnnualInterestRate,
        uint256 _upperHint,
        uint256 _lowerHint,
        uint256 _maxUpfrontFee,
        uint256 _minInterestRateChangePeriod
    ) external;
    function removeInterestIndividualDelegate(uint256 _troveId) external;

    // -- batches --
    struct InterestBatchManager {
        uint128 minInterestRate;
        uint128 maxInterestRate;
        uint256 minInterestRateChangePeriod;
    }

    function registerBatchManager(
        uint128 minInterestRate,
        uint128 maxInterestRate,
        uint128 currentInterestRate,
        uint128 fee,
        uint128 minInterestRateChangePeriod
    ) external;
    function lowerBatchManagementFee(uint256 _newAnnualFee) external;
    function setBatchManagerAnnualInterestRate(
        uint128 _newAnnualInterestRate,
        uint256 _upperHint,
        uint256 _lowerHint,
        uint256 _maxUpfrontFee
    ) external;
    function interestBatchManagerOf(uint256 _troveId) external view returns (address);
    function getInterestBatchManager(address _account) external view returns (InterestBatchManager memory);
    function setInterestBatchManager(
        uint256 _troveId,
        address _newBatchManager,
        uint256 _upperHint,
        uint256 _lowerHint,
        uint256 _maxUpfrontFee
    ) external;
    function removeFromBatch(
        uint256 _troveId,
        uint256 _newAnnualInterestRate,
        uint256 _upperHint,
        uint256 _lowerHint,
        uint256 _maxUpfrontFee
    ) external;
    function switchBatchManager(
        uint256 _troveId,
        uint256 _removeUpperHint,
        uint256 _removeLowerHint,
        address _newBatchManager,
        uint256 _addUpperHint,
        uint256 _addLowerHint,
        uint256 _maxUpfrontFee
    ) external;
}

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

interface IWhitelist {
    function addToWhitelist(address callingContract, address user) external;
    function removeFromWhitelist(address callingContract, address user) external;
    function isWhitelisted(address callingContract, address user) external view returns (bool);
}

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

interface IAddRemoveManagers {
    function setAddManager(uint256 _troveId, address _manager) external;
    function setRemoveManagerWithReceiver(uint256 _troveId, address _manager, address _receiver) external;
    function addManagerOf(uint256 _troveId) external view returns (address);
    function removeManagerReceiverOf(uint256 _troveId) external view returns (address, address);
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC165 standard, as defined in the
 * https://eips.ethereum.org/EIPS/eip-165[EIP].
 *
 * Implementers can declare support of contract interfaces, which can then be
 * queried by others ({ERC165Checker}).
 *
 * For an implementation, see {ERC165}.
 */
interface IERC165 {
    /**
     * @dev Returns true if this contract implements the interface defined by
     * `interfaceId`. See the corresponding
     * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
     * to learn more about how these ids are created.
     *
     * This function call must use less than 30 000 gas.
     */
    function supportsInterface(bytes4 interfaceId) external view returns (bool);
}

File 12 of 33 : LatestTroveData.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.24;

struct LatestTroveData {
    uint256 entireDebt;
    uint256 entireColl;
    uint256 redistBoldDebtGain;
    uint256 redistCollGain;
    uint256 accruedInterest;
    uint256 recordedDebt;
    uint256 annualInterestRate;
    uint256 weightedRecordedDebt;
    uint256 accruedBatchManagementFee;
    uint256 lastInterestRateAdjTime;
}

// 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.0;

interface IBoldRewardsReceiver {
    function triggerBoldRewards(uint256 _boldYield) external;
}

File 15 of 33 : LatestBatchData.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.24;

struct LatestBatchData {
    uint256 entireDebtWithoutRedistribution;
    uint256 entireCollWithoutRedistribution;
    uint256 accruedInterest;
    uint256 recordedDebt;
    uint256 annualInterestRate;
    uint256 weightedRecordedDebt;
    uint256 annualManagementFee;
    uint256 accruedManagementFee;
    uint256 weightedRecordedBatchManagementFee;
    uint256 lastDebtUpdateTime;
    uint256 lastInterestRateAdjTime;
}

// 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

pragma solidity ^0.8.0;

interface IPriceFeed {
    function fetchPrice() external returns (uint256, bool);
    function fetchRedemptionPrice() external returns (uint256, bool);
    function lastGoodPrice() external view returns (uint256);
    function setAddresses(address _borrowerOperationsAddress) external;
}

// SPDX-License-Identifier: GPL-3.0
// Docgen-SOLC: 0.8.25

pragma solidity 0.8.24;

import "../Interfaces/IOwned.sol";

// https://docs.synthetix.io/contracts/source/contracts/owned
contract Owned is IOwned {
    address public override owner;
    address public override nominatedOwner;

    event OwnerNominated(address newOwner);
    event OwnerChanged(address oldOwner, address newOwner);

    constructor(address _owner) {
        require(_owner != address(0), "Owned/owner-zero");
        owner = _owner;

        emit OwnerChanged(address(0), _owner);
    }

    function nominateNewOwner(address _owner) external virtual override onlyOwner {
        nominatedOwner = _owner;

        emit OwnerNominated(_owner);
    }

    function acceptOwnership() external virtual override {
        require(msg.sender == nominatedOwner, "Owned/not-nominated");

        emit OwnerChanged(owner, nominatedOwner);

        owner = nominatedOwner;
        nominatedOwner = address(0);
    }

    modifier onlyOwner() {
        _onlyOwner();
        _;
    }

    function _onlyOwner() private view {
        require(msg.sender == owner, "Owned/not-owner");
    }
}

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import "./ITroveManager.sol";
import {BatchId, BATCH_ID_ZERO} from "../Types/BatchId.sol";

interface ISortedTroves {
    // -- Mutating functions (permissioned) --
    function insert(uint256 _id, uint256 _annualInterestRate, uint256 _prevId, uint256 _nextId) external;
    function insertIntoBatch(
        uint256 _troveId,
        BatchId _batchId,
        uint256 _annualInterestRate,
        uint256 _prevId,
        uint256 _nextId
    ) external;

    function remove(uint256 _id) external;
    function removeFromBatch(uint256 _id) external;

    function reInsert(uint256 _id, uint256 _newAnnualInterestRate, uint256 _prevId, uint256 _nextId) external;
    function reInsertBatch(BatchId _id, uint256 _newAnnualInterestRate, uint256 _prevId, uint256 _nextId) external;

    // -- View functions --

    function contains(uint256 _id) external view returns (bool);
    function isBatchedNode(uint256 _id) external view returns (bool);
    function isEmptyBatch(BatchId _id) external view returns (bool);

    function isEmpty() external view returns (bool);
    function getSize() external view returns (uint256);

    function getFirst() external view returns (uint256);
    function getLast() external view returns (uint256);
    function getNext(uint256 _id) external view returns (uint256);
    function getPrev(uint256 _id) external view returns (uint256);

    function validInsertPosition(uint256 _annualInterestRate, uint256 _prevId, uint256 _nextId)
        external
        view
        returns (bool);
    function findInsertPosition(uint256 _annualInterestRate, uint256 _prevId, uint256 _nextId)
        external
        view
        returns (uint256, uint256);

    // Public state variable getters
    function borrowerOperationsAddress() external view returns (address);
    function troveManager() external view returns (ITroveManager);
    function size() external view returns (uint256);
    function nodes(uint256 _id) external view returns (uint256 nextId, uint256 prevId, BatchId batchId, bool exists);
    function batches(BatchId _id) external view returns (uint256 head, uint256 tail);
}

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import "openzeppelin-contracts/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import "./IBoldToken.sol";
import "./ITroveManager.sol";

interface ICollateralRegistry {
    struct RedemptionTotals {
        uint256 numCollaterals;
        uint256 boldSupplyAtStart;
        uint256 unbacked;
        uint256 redeemedAmount;
    }

    function addNewCollaterals(
        IERC20Metadata[] memory _tokens,
        ITroveManager[] memory _troveManagers
    ) external;
    function removeCollateral(uint256 index) external;

    function baseRate() external view returns (uint256);
    function lastFeeOperationTime() external view returns (uint256);

    function redeemCollateral(uint256 _boldamount, uint256 _maxIterations, uint256 _maxFeePercentage) external;
    // getters
    function totalCollaterals() external view returns (uint256);
    function getToken(uint256 _index) external view returns (IERC20Metadata);
    function getTroveManager(uint256 _index) external view returns (ITroveManager);
    function boldToken() external view returns (IBoldToken);

    function getRedemptionRate() external view returns (uint256);
    function getRedemptionRateWithDecay() external view returns (uint256);
    function getRedemptionRateForRedeemedAmount(uint256 _redeemAmount) external view returns (uint256);

    function getRedemptionFeeWithDecay(uint256 _ETHDrawn) external view returns (uint256);
    function getEffectiveRedemptionFeeInBold(uint256 _redeemAmount) external view returns (uint256);
}

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

interface IOwned {
    function owner() external view returns (address);

    function nominatedOwner() external view returns (address);

    function nominateNewOwner(address owner) external;

    function acceptOwnership() external;
}

File 22 of 33 : IERC5267.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (interfaces/IERC5267.sol)

pragma solidity ^0.8.0;

interface IERC5267 {
    /**
     * @dev MAY be emitted to signal that the domain could have changed.
     */
    event EIP712DomainChanged();

    /**
     * @dev returns the fields and values that describe the domain separator used by this contract for EIP-712
     * signature.
     */
    function eip712Domain()
        external
        view
        returns (
            bytes1 fields,
            string memory name,
            string memory version,
            uint256 chainId,
            address verifyingContract,
            bytes32 salt,
            uint256[] memory extensions
        );
}

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import "openzeppelin-contracts/contracts/token/ERC721/extensions/IERC721Metadata.sol";

import "./ITroveManager.sol";
import "../Interfaces/IWhitelist.sol";

interface ITroveNFT is IERC721Metadata {
    function mint(address _owner, uint256 _troveId) external;
    function burn(uint256 _troveId) external;
    function setWhitelist(IWhitelist _whitelist) external;
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC721/extensions/IERC721Metadata.sol)

pragma solidity ^0.8.0;

import "../IERC721.sol";

/**
 * @title ERC-721 Non-Fungible Token Standard, optional metadata extension
 * @dev See https://eips.ethereum.org/EIPS/eip-721
 */
interface IERC721Metadata is IERC721 {
    /**
     * @dev Returns the token collection name.
     */
    function name() external view returns (string memory);

    /**
     * @dev Returns the token collection symbol.
     */
    function symbol() external view returns (string memory);

    /**
     * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token.
     */
    function tokenURI(uint256 tokenId) external view returns (string memory);
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.4) (token/ERC20/extensions/IERC20Permit.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
 * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
 *
 * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
 * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
 * need to send a transaction, and thus is not required to hold Ether at all.
 *
 * ==== Security Considerations
 *
 * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature
 * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be
 * considered as an intention to spend the allowance in any specific way. The second is that because permits have
 * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should
 * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be
 * generally recommended is:
 *
 * ```solidity
 * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {
 *     try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}
 *     doThing(..., value);
 * }
 *
 * function doThing(..., uint256 value) public {
 *     token.safeTransferFrom(msg.sender, address(this), value);
 *     ...
 * }
 * ```
 *
 * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of
 * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also
 * {SafeERC20-safeTransferFrom}).
 *
 * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so
 * contracts should have entry points that don't rely on permit.
 */
interface IERC20Permit {
    /**
     * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
     * given ``owner``'s signed approval.
     *
     * IMPORTANT: The same issues {IERC20-approve} has related to transaction
     * ordering also apply here.
     *
     * Emits an {Approval} event.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     * - `deadline` must be a timestamp in the future.
     * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
     * over the EIP712-formatted function arguments.
     * - the signature must use ``owner``'s current nonce (see {nonces}).
     *
     * For more information on the signature format, see the
     * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
     * section].
     *
     * CAUTION: See Security Considerations above.
     */
    function permit(
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external;

    /**
     * @dev Returns the current nonce for `owner`. This value must be
     * included whenever a signature is generated for {permit}.
     *
     * Every successful call to {permit} increases ``owner``'s nonce by one. This
     * prevents a signature from being used multiple times.
     */
    function nonces(address owner) external view returns (uint256);

    /**
     * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
     */
    // solhint-disable-next-line func-name-mixedcase
    function DOMAIN_SEPARATOR() external view returns (bytes32);
}

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import "openzeppelin-contracts/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import "openzeppelin-contracts/contracts/token/ERC20/extensions/IERC20Permit.sol";
import "openzeppelin-contracts/contracts/interfaces/IERC5267.sol";

import "./IOwned.sol";

interface IBoldToken is IERC20Metadata, IERC20Permit, IOwned, IERC5267 {
    function mint(address _account, uint256 _amount) external;

    function burn(address _account, uint256 _amount) external;

    function sendToPool(address _sender, address poolAddress, uint256 _amount) external;

    function returnFromPool(address poolAddress, address user, uint256 _amount) external;

    function setCollateralRegistry(address _collateralRegistryAddress) external;

    function setMinter(address minter, bool isMinter) external;

    function setBurner(address burner, bool isBurner) external;

    function setStabilityPool(address stabilityPool, bool isStabilityPool) external;

    function isMinter(address minter) external view returns (bool);

    function isBurner(address burner) external view returns (bool);

    function isStabilityPool(address stabilityPool) external view returns (bool);
}

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import "./IInterestRouter.sol";
import "./IBoldRewardsReceiver.sol";
import "../Types/TroveChange.sol";

interface IActivePool {
    function SP_YIELD_SPLIT() external view returns (uint256);
    function defaultPoolAddress() external view returns (address);
    function borrowerOperationsAddress() external view returns (address);
    function troveManagerAddress() external view returns (address);
    function interestRouter() external view returns (IInterestRouter);
    // We avoid IStabilityPool here in order to prevent creating a dependency cycle that would break flattening
    function stabilityPool() external view returns (IBoldRewardsReceiver);

    function getCollBalance() external view returns (uint256);
    function getBoldDebt() external view returns (uint256);
    function lastAggUpdateTime() external view returns (uint256);
    function aggRecordedDebt() external view returns (uint256);
    function aggWeightedDebtSum() external view returns (uint256);
    function aggBatchManagementFees() external view returns (uint256);
    function aggWeightedBatchManagementFeeSum() external view returns (uint256);
    function calcPendingAggInterest() external view returns (uint256);
    function calcPendingSPYield() external view returns (uint256);
    function calcPendingAggBatchManagementFee() external view returns (uint256);
    function getNewApproxAvgInterestRateFromTroveChange(TroveChange calldata _troveChange)
        external
        view
        returns (uint256);

    function mintAggInterest() external;
    function mintAggInterestAndAccountForTroveChange(TroveChange calldata _troveChange, address _batchManager)
        external;
    function mintBatchManagementFeeAndAccountForChange(TroveChange calldata _troveChange, address _batchAddress)
        external;

    function setShutdownFlag() external;
    function hasBeenShutDown() external view returns (bool);
    function shutdownTime() external view returns (uint256);

    function sendColl(address _account, uint256 _amount) external;
    function sendCollToDefaultPool(uint256 _amount) external;
    function receiveColl(uint256 _amount) external;
    function accountForReceivedColl(uint256 _amount) external;
}

File 28 of 33 : IInterestRouter.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

interface IInterestRouter {
// Currently the Interest Router doesn’t need any specific function
}

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import "openzeppelin-contracts/contracts/token/ERC20/extensions/IERC20Metadata.sol";

interface IWETH is IERC20Metadata {
    function deposit() external payable;
    function withdraw(uint256 wad) external;
}

// SPDX-License-Identifier: MIT

pragma solidity 0.8.24;

type BatchId is address;

using {equals as ==, notEquals as !=, isZero, isNotZero} for BatchId global;

function equals(BatchId a, BatchId b) pure returns (bool) {
    return BatchId.unwrap(a) == BatchId.unwrap(b);
}

function notEquals(BatchId a, BatchId b) pure returns (bool) {
    return !(a == b);
}

function isZero(BatchId x) pure returns (bool) {
    return x == BATCH_ID_ZERO;
}

function isNotZero(BatchId x) pure returns (bool) {
    return !x.isZero();
}

BatchId constant BATCH_ID_ZERO = BatchId.wrap(address(0));

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC721/IERC721.sol)

pragma solidity ^0.8.0;

import "../../utils/introspection/IERC165.sol";

/**
 * @dev Required interface of an ERC721 compliant contract.
 */
interface IERC721 is IERC165 {
    /**
     * @dev Emitted when `tokenId` token is transferred from `from` to `to`.
     */
    event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);

    /**
     * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.
     */
    event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);

    /**
     * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.
     */
    event ApprovalForAll(address indexed owner, address indexed operator, bool approved);

    /**
     * @dev Returns the number of tokens in ``owner``'s account.
     */
    function balanceOf(address owner) external view returns (uint256 balance);

    /**
     * @dev Returns the owner of the `tokenId` token.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     */
    function ownerOf(uint256 tokenId) external view returns (address owner);

    /**
     * @dev Safely transfers `tokenId` token from `from` to `to`.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must exist and be owned by `from`.
     * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
     *
     * Emits a {Transfer} event.
     */
    function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external;

    /**
     * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
     * are aware of the ERC721 protocol to prevent tokens from being forever locked.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must exist and be owned by `from`.
     * - If the caller is not `from`, it must have been allowed to move this token by either {approve} or {setApprovalForAll}.
     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
     *
     * Emits a {Transfer} event.
     */
    function safeTransferFrom(address from, address to, uint256 tokenId) external;

    /**
     * @dev Transfers `tokenId` token from `from` to `to`.
     *
     * WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC721
     * or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must
     * understand this adds an external call which potentially creates a reentrancy vulnerability.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must be owned by `from`.
     * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(address from, address to, uint256 tokenId) external;

    /**
     * @dev Gives permission to `to` to transfer `tokenId` token to another account.
     * The approval is cleared when the token is transferred.
     *
     * Only a single account can be approved at a time, so approving the zero address clears previous approvals.
     *
     * Requirements:
     *
     * - The caller must own the token or be an approved operator.
     * - `tokenId` must exist.
     *
     * Emits an {Approval} event.
     */
    function approve(address to, uint256 tokenId) external;

    /**
     * @dev Approve or remove `operator` as an operator for the caller.
     * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.
     *
     * Requirements:
     *
     * - The `operator` cannot be the caller.
     *
     * Emits an {ApprovalForAll} event.
     */
    function setApprovalForAll(address operator, bool approved) external;

    /**
     * @dev Returns the account approved for `tokenId` token.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     */
    function getApproved(uint256 tokenId) external view returns (address operator);

    /**
     * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
     *
     * See {setApprovalForAll}
     */
    function isApprovedForAll(address owner, address operator) external view returns (bool);
}

File 32 of 33 : TroveChange.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.24;

struct TroveChange {
    uint256 appliedRedistBoldDebtGain;
    uint256 appliedRedistCollGain;
    uint256 collIncrease;
    uint256 collDecrease;
    uint256 debtIncrease;
    uint256 debtDecrease;
    uint256 newWeightedRecordedDebt;
    uint256 oldWeightedRecordedDebt;
    uint256 upfrontFee;
    uint256 batchAccruedManagementFee;
    uint256 newWeightedRecordedBatchManagementFee;
    uint256 oldWeightedRecordedBatchManagementFee;
}

File 33 of 33 : IAddressesRegistryWhitelist.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import "./IWhitelist.sol";

interface IAddressesRegistryWhitelist {
    function whitelist() external view returns (IWhitelist);
}

Settings
{
  "evmVersion": "cancun",
  "libraries": {},
  "metadata": {
    "appendCBOR": true,
    "bytecodeHash": "ipfs",
    "useLiteralContent": false
  },
  "optimizer": {
    "enabled": true,
    "runs": 1
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "remappings": [
    "openzeppelin/=lib/V2-gov/lib/openzeppelin-contracts/",
    "@chimera/=lib/V2-gov/lib/chimera/src/",
    "@openzeppelin/contracts/=lib/V2-gov/lib/openzeppelin-contracts/contracts/",
    "Solady/=lib/Solady/src/",
    "V2-gov/=lib/V2-gov/",
    "chimera/=lib/V2-gov/lib/chimera/src/",
    "ds-test/=lib/openzeppelin-contracts/lib/forge-std/lib/ds-test/src/",
    "erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/",
    "forge-std/=lib/forge-std/src/",
    "openzeppelin-contracts/=lib/openzeppelin-contracts/",
    "v4-core/=lib/V2-gov/lib/v4-core/"
  ],
  "viaIR": false
}

Contract Security Audit

Contract ABI

API
[{"inputs":[{"internalType":"contract IBoldToken","name":"_boldToken","type":"address"},{"internalType":"contract IERC20Metadata[]","name":"_tokens","type":"address[]"},{"internalType":"contract ITroveManager[]","name":"_troveManagers","type":"address[]"},{"internalType":"address","name":"_owner","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"ZeroAddress","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_baseRate","type":"uint256"}],"name":"BaseRateUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"collateral","type":"address"},{"indexed":false,"internalType":"address","name":"troveManager","type":"address"}],"name":"CollateralRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_lastFeeOpTime","type":"uint256"}],"name":"LastFeeOpTimeUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"collateral","type":"address"},{"indexed":false,"internalType":"address","name":"troveManager","type":"address"}],"name":"NewCollateralAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldOwner","type":"address"},{"indexed":false,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnerChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnerNominated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"whitelist","type":"address"}],"name":"WhitelistSet","type":"event"},{"inputs":[],"name":"acceptOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IERC20Metadata[]","name":"_tokens","type":"address[]"},{"internalType":"contract ITroveManager[]","name":"_troveManagers","type":"address[]"}],"name":"addNewCollaterals","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"baseRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"boldToken","outputs":[{"internalType":"contract IBoldToken","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_redeemAmount","type":"uint256"}],"name":"getEffectiveRedemptionFeeInBold","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_ETHDrawn","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":[{"internalType":"uint256","name":"_redeemAmount","type":"uint256"}],"name":"getRedemptionRateForRedeemedAmount","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":"_index","type":"uint256"}],"name":"getToken","outputs":[{"internalType":"contract IERC20Metadata","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_index","type":"uint256"}],"name":"getTroveManager","outputs":[{"internalType":"contract ITroveManager","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastFeeOperationTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"nominateNewOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"nominatedOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_boldAmount","type":"uint256"},{"internalType":"uint256","name":"_maxIterationsPerCollateral","type":"uint256"},{"internalType":"uint256","name":"_maxFeePercentage","type":"uint256"}],"name":"redeemCollateral","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"}],"name":"removeCollateral","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"totalCollaterals","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}]

60a06040524260185534801562000014575f80fd5b5060405162001f9a38038062001f9a8339810160408190526200003791620003ff565b806001600160a01b038116620000875760405162461bcd60e51b815260206004820152601060248201526f4f776e65642f6f776e65722d7a65726f60801b60448201526064015b60405180910390fd5b5f80546001600160a01b0319166001600160a01b03831690811782556040805192835260208301919091527fb532073b38c83145e3e5135377a08bf9aab55bc0fd7c1179cd4fb995d2a5159c910160405180910390a15082518015801590620000f15750600a8111155b6200013f5760405162461bcd60e51b815260206004820152601760248201527f436f6c6c61746572616c206c69737420696e76616c696400000000000000000060448201526064016200007e565b60028190556001600160a01b0385166080525f5b818160ff16101562000275576200018f858260ff16815181106200017b576200017b620004f3565b6020026020010151620002c260201b60201c565b620001ab848260ff16815181106200017b576200017b620004f3565b848160ff1681518110620001c357620001c3620004f3565b602002602001015160038260ff16600a8110620001e457620001e4620004f3565b015f6101000a8154816001600160a01b0302191690836001600160a01b03160217905550838160ff1681518110620002205762000220620004f3565b6020026020010151600d8260ff16600a8110620002415762000241620004f3565b0180546001600160a01b0319166001600160a01b0392909216919091179055806200026c8162000507565b91505062000153565b50670de0b6b3a764000060178190556040519081527fc454ee9b76c52f782a256af821b857ca6e125d1e3333bcede402fec2bed9600c9060200160405180910390a1505050505062000532565b6001600160a01b038116620002ea5760405163d92e233d60e01b815260040160405180910390fd5b50565b6001600160a01b0381168114620002ea575f80fd5b634e487b7160e01b5f52604160045260245ffd5b604051601f8201601f191681016001600160401b038111828210171562000341576200034162000302565b604052919050565b5f6001600160401b0382111562000364576200036462000302565b5060051b60200190565b5f82601f8301126200037e575f80fd5b8151602062000397620003918362000349565b62000316565b8083825260208201915060208460051b870101935086841115620003b9575f80fd5b602086015b84811015620003e2578051620003d481620002ed565b8352918301918301620003be565b509695505050505050565b8051620003fa81620002ed565b919050565b5f805f806080858703121562000413575f80fd5b84516200042081620002ed565b602086810151919550906001600160401b03808211156200043f575f80fd5b818801915088601f83011262000453575f80fd5b815162000464620003918262000349565b81815260059190911b8301840190848101908b83111562000483575f80fd5b938501935b82851015620004ae5784516200049e81620002ed565b8252938501939085019062000488565b60408b01519098509450505080831115620004c7575f80fd5b5050620004d7878288016200036e565b925050620004e860608601620003ed565b905092959194509250565b634e487b7160e01b5f52603260045260245ffd5b5f60ff821660ff81036200052957634e487b7160e01b5f52601160045260245ffd5b60010192915050565b608051611a33620005675f395f8181610179015281816106700152818161089c01528181610e6a0152610ed70152611a335ff3fe608060405234801561000f575f80fd5b50600436106100e4575f3560e01c80630bc17feb146100e85780631627540c146101115780631f68f20a146101265780632b11551a1461013d57806330504b6f146101455780633237c1581461014e57806353a47bb714610161578063630afce51461017457806363f1134e1461019b57806379ba5097146101ae5780638da5cb5b146101b6578063ab6d53bd146101c8578063c3bfd842146101db578063c52861f2146101ee578063d380a37c146101f6578063d5b35635146101ff578063e4b50cb814610212578063e6845f7314610225575b5f80fd5b6100fb6100f636600461165b565b610238565b6040516101089190611672565b60405180910390f35b61012461011f36600461169a565b610286565b005b61012f60175481565b604051908152602001610108565b61012f6102e4565b61012f60025481565b61012461015c36600461165b565b6102f5565b6001546100fb906001600160a01b031681565b6100fb7f000000000000000000000000000000000000000000000000000000000000000081565b61012f6101a936600461165b565b61066c565b61012461070e565b5f546100fb906001600160a01b031681565b6101246101d63660046116b5565b6107ce565b61012f6101e936600461165b565b610ed3565b61012f610f76565b61012f60185481565b61012f61020d36600461165b565b610f82565b6100fb61022036600461165b565b610f9a565b6101246102333660046117b9565b610fce565b5f600a82106102625760405162461bcd60e51b815260040161025990611874565b60405180910390fd5b600d82600a81106102755761027561189b565b01546001600160a01b031692915050565b61028e611220565b600180546001600160a01b0319166001600160a01b0383161790556040517f906a1c6bd7e3091ea86693dd029a831c19049ce77f1dce2ce0bab1cacbabce22906102d9908390611672565b60405180910390a150565b5f6102f060175461126d565b905090565b6102fd611220565b600981111561031e5760405162461bcd60e51b815260040161025990611874565b5f600382600a81106103325761033261189b565b01546001600160a01b0316036103835760405162461bcd60e51b8152602060048201526016602482015275109c985b98da081b9bdd081a5b9a5d1a585b1a5cd95960521b6044820152606401610259565b5f600d82600a81106103975761039761189b565b015f9054906101000a90046001600160a01b03169050806001600160a01b031663585690816040518163ffffffff1660e01b8152600401602060405180830381865afa1580156103e9573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061040d91906118af565b5f036104545760405162461bcd60e51b8152602060048201526016602482015275213930b731b41034b9903737ba1039b43aba3237bbb760511b6044820152606401610259565b7ff30858681fdd836ac4f2fe8faf8ebad8a26300210abba0a1998218472772b523600383600a81106104885761048861189b565b01546001600160a01b0316600d84600a81106104a6576104a661189b565b01546040516104bf92916001600160a01b0316906118c6565b60405180910390a15f60016002546104d791906118f4565b9050828111156105ec57600381600a81106104f4576104f461189b565b01546001600160a01b0316600384600a81106105125761051261189b565b0180546001600160a01b0319166001600160a01b0392909216919091179055600d81600a81106105445761054461189b565b01546001600160a01b0316600d84600a81106105625761056261189b565b0180546001600160a01b0319166001600160a01b03929092169190911790555f600382600a81106105955761059561189b565b0180546001600160a01b0319166001600160a01b03929092169190911790555f600d82600a81106105c8576105c861189b565b0180546001600160a01b0319166001600160a01b0392909216919091179055610653565b5f600384600a81106106005761060061189b565b0180546001600160a01b0319166001600160a01b03929092169190911790555f600d84600a81106106335761063361189b565b0180546001600160a01b0319166001600160a01b03929092169190911790555b60028054905f61066283611907565b9190505550505050565b5f807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156106ca573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906106ee91906118af565b90505f6106fb84836112a9565b90506107068161126d565b949350505050565b6001546001600160a01b0316331461075e5760405162461bcd60e51b815260206004820152601360248201527213dddb99590bdb9bdd0b5b9bdb5a5b985d1959606a1b6044820152606401610259565b5f546001546040517fb532073b38c83145e3e5135377a08bf9aab55bc0fd7c1179cd4fb995d2a5159c926107a0926001600160a01b03918216929116906118c6565b60405180910390a1600180545f80546001600160a01b03199081166001600160a01b03841617909155169055565b6107d781611309565b6107e0836113a7565b61080760405180608001604052805f81526020015f81526020015f81526020015f81525090565b6002548082525f906001600160401b03811115610826576108266116de565b60405190808252806020026020018201604052801561084f578160200160208202803683370190505b5090505f825f01516001600160401b0381111561086e5761086e6116de565b604051908082528060200260200182016040528015610897578160200160208202803683370190505b5090507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156108f6573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061091a91906118af565b602084018190525f90610937906109329089906112a9565b61126d565b9050848111156109935760405162461bcd60e51b815260206004820152602160248201527f43523a204665652065786365656465642070726f7669646564206d6178696d756044820152606d60f81b6064820152608401610259565b5f5b8451811015610af3575f6109a882610238565b90505f805f836001600160a01b0316634ea15f376040518163ffffffff1660e01b81526004016060604051808303815f875af11580156109ea573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610a0e9190611930565b92509250925081878681518110610a2757610a2761189b565b602002602001018181525050808015610aa65750604051633af32abf60e01b81526001600160a01b03851690633af32abf90610a67903390600401611672565b602060405180830381865afa158015610a82573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610aa69190611962565b15610ae3578289604001818151610abd919061197b565b90525087518390899087908110610ad657610ad661189b565b6020026020010181815250505b5050600190920191506109959050565b5083604001515f03610ce15783516001600160401b03811115610b1857610b186116de565b604051908082528060200260200182016040528015610b41578160200160208202803683370190505b5092505f5b8451811015610cdf575f610b5982610238565b90505f816001600160a01b0316634ea15f376040518163ffffffff1660e01b81526004016060604051808303815f875af1158015610b99573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610bbd9190611930565b92505050808015610c345750604051633af32abf60e01b81526001600160a01b03831690633af32abf90610bf5903390600401611672565b602060405180830381865afa158015610c10573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610c349190611962565b15610cd5575f826001600160a01b031663105b403b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610c76573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610c9a91906118af565b90508088604001818151610cae919061197b565b90525086518190889086908110610cc757610cc761189b565b602002602001018181525050505b5050600101610b46565b505b5f5b8451811015610e2b575f848281518110610cff57610cff61189b565b60200260200101511115610e23575f8560400151858381518110610d2557610d2561189b565b60200260200101518a610d38919061198e565b610d4291906119b9565b90508015610e21575f610d5483610238565b90505f816001600160a01b031663f8a239e83385898881518110610d7a57610d7a61189b565b60209081029190910101516040516001600160e01b031960e086901b1681526001600160a01b0390931660048401526024830191909152604482015260648101889052608481018d905260a4016020604051808303815f875af1158015610de3573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610e0791906118af565b90508088606001818151610e1b919061197b565b90525050505b505b600101610ce3565b50610e3e84606001518560200151611413565b606084015115610eca576060840151604051632770a7eb60e21b815233600482015260248101919091527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690639dc29fac906044015f604051808303815f87803b158015610eb3575f80fd5b505af1158015610ec5573d5f803e3d5ffd5b505050505b50505050505050565b5f807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610f31573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610f5591906118af565b90505f610f6284836112a9565b9050610706610f708261126d565b85611466565b5f6102f0610932611485565b5f610f94610f8e610f76565b83611466565b92915050565b5f600a8210610fbb5760405162461bcd60e51b815260040161025990611874565b600382600a81106102755761027561189b565b610fd6611220565b81516002548115801590610fea5750825182145b6110265760405162461bcd60e51b815260206004820152600d60248201526c125b9d985b1a59081a5b9c1d5d609a1b6044820152606401610259565b600a611032838361197b565b11156110725760405162461bcd60e51b815260206004820152600f60248201526e4d617820636f6c6c61746572616c7360881b6044820152606401610259565b5f5b828160ff161015611203576110a4858260ff16815181106110975761109761189b565b60200260200101516114ce565b6110bc848260ff16815181106110975761109761189b565b848160ff16815181106110d1576110d161189b565b602002602001015160038260ff16846110ea919061197b565b600a81106110fa576110fa61189b565b015f6101000a8154816001600160a01b0302191690836001600160a01b03160217905550838160ff16815181106111335761113361189b565b6020026020010151600d8260ff168461114c919061197b565b600a811061115c5761115c61189b565b015f6101000a8154816001600160a01b0302191690836001600160a01b031602179055507fe3ff17581c53bf246f14c95373f2d316943397252dfe0c882513e68375b6e021858260ff16815181106111b6576111b661189b565b6020026020010151858360ff16815181106111d3576111d361189b565b60200260200101516040516111e99291906118c6565b60405180910390a1806111fb816119cc565b915050611074565b508160025f828254611215919061197b565b909155505050505050565b5f546001600160a01b0316331461126b5760405162461bcd60e51b815260206004820152600f60248201526e27bbb732b217b737ba16b7bbb732b960891b6044820152606401610259565b565b5f610f948260026112876064670de0b6b3a76400006119b9565b61129191906119b9565b61129b919061197b565b670de0b6b3a76400006114f5565b5f806112b3611485565b90505f836112c9670de0b6b3a76400008761198e565b6112d391906119b9565b90505f6112e16001836119b9565b6112eb908461197b565b90506112ff81670de0b6b3a76400006114f5565b9695505050505050565b600261131e6064670de0b6b3a76400006119b9565b61132891906119b9565b811015801561133f5750670de0b6b3a76400008111155b6113a45760405162461bcd60e51b815260206004820152603060248201527f4d6178206665652070657263656e74616765206d75737420626520626574776560448201526f656e20302e352520616e64203130302560801b6064820152608401610259565b50565b5f81116113a45760405162461bcd60e51b815260206004820152603460248201527f436f6c6c61746572616c52656769737472793a20416d6f756e74206d7573742060448201527362652067726561746572207468616e207a65726f60601b6064820152608401610259565b5f61141e83836112a9565b60178190556040518181529091507fc454ee9b76c52f782a256af821b857ca6e125d1e3333bcede402fec2bed9600c9060200160405180910390a161146161150c565b505050565b5f80670de0b6b3a764000061147b848661198e565b61070691906119b9565b5f8061148f611570565b90505f6114a4670dd9e13cc602b4008361158b565b9050670de0b6b3a7640000816017546114bd919061198e565b6114c791906119b9565b9250505090565b6001600160a01b0381166113a45760405163d92e233d60e01b815260040160405180910390fd5b5f8183106115035781611505565b825b9392505050565b5f611515611570565b905080156113a45761152881603c61198e565b60185f828254611538919061197b565b90915550506018546040519081527f860f8d2f0c74dd487e89e2883e3b25b8159ce1e1b3433a291cba7b82c508f3bc906020016102d9565b5f603c6018544261158191906118f4565b6102f091906119b9565b5f631f5405008211156115a057631f54050091505b815f036115b65750670de0b6b3a7640000610f94565b670de0b6b3a764000083835b6001811115611629576115d66002826119ea565b5f036115fa576115e6828361162f565b91506115f36002826119b9565b90506115c2565b611604828461162f565b9250611610828361162f565b9150600261161f6001836118f4565b6115f391906119b9565b6112ff82845b5f8061163b838561198e565b9050670de0b6b3a76400006116516002826119b9565b61147b908361197b565b5f6020828403121561166b575f80fd5b5035919050565b6001600160a01b0391909116815260200190565b6001600160a01b03811681146113a4575f80fd5b5f602082840312156116aa575f80fd5b813561150581611686565b5f805f606084860312156116c7575f80fd5b505081359360208301359350604090920135919050565b634e487b7160e01b5f52604160045260245ffd5b604051601f8201601f191681016001600160401b038111828210171561171a5761171a6116de565b604052919050565b5f6001600160401b0382111561173a5761173a6116de565b5060051b60200190565b5f82601f830112611753575f80fd5b8135602061176861176383611722565b6116f2565b8083825260208201915060208460051b870101935086841115611789575f80fd5b602086015b848110156117ae5780356117a181611686565b835291830191830161178e565b509695505050505050565b5f80604083850312156117ca575f80fd5b82356001600160401b03808211156117e0575f80fd5b818501915085601f8301126117f3575f80fd5b8135602061180361176383611722565b82815260059290921b84018101918181019089841115611821575f80fd5b948201945b8386101561184857853561183981611686565b82529482019490820190611826565b9650508601359250508082111561185d575f80fd5b5061186a85828601611744565b9150509250929050565b6020808252600d908201526c092dcecc2d8d2c840d2dcc8caf609b1b604082015260600190565b634e487b7160e01b5f52603260045260245ffd5b5f602082840312156118bf575f80fd5b5051919050565b6001600160a01b0392831681529116602082015260400190565b634e487b7160e01b5f52601160045260245ffd5b81810381811115610f9457610f946118e0565b5f81611915576119156118e0565b505f190190565b8051801515811461192b575f80fd5b919050565b5f805f60608486031215611942575f80fd5b83519250602084015191506119596040850161191c565b90509250925092565b5f60208284031215611972575f80fd5b6115058261191c565b80820180821115610f9457610f946118e0565b8082028115828204841417610f9457610f946118e0565b634e487b7160e01b5f52601260045260245ffd5b5f826119c7576119c76119a5565b500490565b5f60ff821660ff81036119e1576119e16118e0565b60010192915050565b5f826119f8576119f86119a5565b50069056fea26469706673582212200cd7b45cf0cb23066fae2defb8c031191ca1333838a97fbf637e9b82dac3967d64736f6c6343000818003300000000000000000000000096c6995a7737959708c2ed9129d07c94f012d2ce00000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000100000000000000000000000000919d5a6f2cbc0731380c26b4ac4f6183dd3a40c800000000000000000000000000000000000000000000000000000000000000030000000000000000000000007b42e0d1b7f2111b04c6547fca8ca2b0f271498c0000000000000000000000001f45f163c6fea687c66365f3d75f18c71706c069000000000000000000000000985a39b8dfaa7689b05e6e7bd1b2a66b8b5b1e4e0000000000000000000000000000000000000000000000000000000000000003000000000000000000000000a4867b8f66e724072802a7c8cfd59a26e40ac7210000000000000000000000003fa5b92c2b53348d383fd265e6ec13473537fb210000000000000000000000000079eb9ebd9820c5961b406c1400e1e5dd177592

Deployed Bytecode

0x608060405234801561000f575f80fd5b50600436106100e4575f3560e01c80630bc17feb146100e85780631627540c146101115780631f68f20a146101265780632b11551a1461013d57806330504b6f146101455780633237c1581461014e57806353a47bb714610161578063630afce51461017457806363f1134e1461019b57806379ba5097146101ae5780638da5cb5b146101b6578063ab6d53bd146101c8578063c3bfd842146101db578063c52861f2146101ee578063d380a37c146101f6578063d5b35635146101ff578063e4b50cb814610212578063e6845f7314610225575b5f80fd5b6100fb6100f636600461165b565b610238565b6040516101089190611672565b60405180910390f35b61012461011f36600461169a565b610286565b005b61012f60175481565b604051908152602001610108565b61012f6102e4565b61012f60025481565b61012461015c36600461165b565b6102f5565b6001546100fb906001600160a01b031681565b6100fb7f00000000000000000000000096c6995a7737959708c2ed9129d07c94f012d2ce81565b61012f6101a936600461165b565b61066c565b61012461070e565b5f546100fb906001600160a01b031681565b6101246101d63660046116b5565b6107ce565b61012f6101e936600461165b565b610ed3565b61012f610f76565b61012f60185481565b61012f61020d36600461165b565b610f82565b6100fb61022036600461165b565b610f9a565b6101246102333660046117b9565b610fce565b5f600a82106102625760405162461bcd60e51b815260040161025990611874565b60405180910390fd5b600d82600a81106102755761027561189b565b01546001600160a01b031692915050565b61028e611220565b600180546001600160a01b0319166001600160a01b0383161790556040517f906a1c6bd7e3091ea86693dd029a831c19049ce77f1dce2ce0bab1cacbabce22906102d9908390611672565b60405180910390a150565b5f6102f060175461126d565b905090565b6102fd611220565b600981111561031e5760405162461bcd60e51b815260040161025990611874565b5f600382600a81106103325761033261189b565b01546001600160a01b0316036103835760405162461bcd60e51b8152602060048201526016602482015275109c985b98da081b9bdd081a5b9a5d1a585b1a5cd95960521b6044820152606401610259565b5f600d82600a81106103975761039761189b565b015f9054906101000a90046001600160a01b03169050806001600160a01b031663585690816040518163ffffffff1660e01b8152600401602060405180830381865afa1580156103e9573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061040d91906118af565b5f036104545760405162461bcd60e51b8152602060048201526016602482015275213930b731b41034b9903737ba1039b43aba3237bbb760511b6044820152606401610259565b7ff30858681fdd836ac4f2fe8faf8ebad8a26300210abba0a1998218472772b523600383600a81106104885761048861189b565b01546001600160a01b0316600d84600a81106104a6576104a661189b565b01546040516104bf92916001600160a01b0316906118c6565b60405180910390a15f60016002546104d791906118f4565b9050828111156105ec57600381600a81106104f4576104f461189b565b01546001600160a01b0316600384600a81106105125761051261189b565b0180546001600160a01b0319166001600160a01b0392909216919091179055600d81600a81106105445761054461189b565b01546001600160a01b0316600d84600a81106105625761056261189b565b0180546001600160a01b0319166001600160a01b03929092169190911790555f600382600a81106105955761059561189b565b0180546001600160a01b0319166001600160a01b03929092169190911790555f600d82600a81106105c8576105c861189b565b0180546001600160a01b0319166001600160a01b0392909216919091179055610653565b5f600384600a81106106005761060061189b565b0180546001600160a01b0319166001600160a01b03929092169190911790555f600d84600a81106106335761063361189b565b0180546001600160a01b0319166001600160a01b03929092169190911790555b60028054905f61066283611907565b9190505550505050565b5f807f00000000000000000000000096c6995a7737959708c2ed9129d07c94f012d2ce6001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156106ca573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906106ee91906118af565b90505f6106fb84836112a9565b90506107068161126d565b949350505050565b6001546001600160a01b0316331461075e5760405162461bcd60e51b815260206004820152601360248201527213dddb99590bdb9bdd0b5b9bdb5a5b985d1959606a1b6044820152606401610259565b5f546001546040517fb532073b38c83145e3e5135377a08bf9aab55bc0fd7c1179cd4fb995d2a5159c926107a0926001600160a01b03918216929116906118c6565b60405180910390a1600180545f80546001600160a01b03199081166001600160a01b03841617909155169055565b6107d781611309565b6107e0836113a7565b61080760405180608001604052805f81526020015f81526020015f81526020015f81525090565b6002548082525f906001600160401b03811115610826576108266116de565b60405190808252806020026020018201604052801561084f578160200160208202803683370190505b5090505f825f01516001600160401b0381111561086e5761086e6116de565b604051908082528060200260200182016040528015610897578160200160208202803683370190505b5090507f00000000000000000000000096c6995a7737959708c2ed9129d07c94f012d2ce6001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156108f6573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061091a91906118af565b602084018190525f90610937906109329089906112a9565b61126d565b9050848111156109935760405162461bcd60e51b815260206004820152602160248201527f43523a204665652065786365656465642070726f7669646564206d6178696d756044820152606d60f81b6064820152608401610259565b5f5b8451811015610af3575f6109a882610238565b90505f805f836001600160a01b0316634ea15f376040518163ffffffff1660e01b81526004016060604051808303815f875af11580156109ea573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610a0e9190611930565b92509250925081878681518110610a2757610a2761189b565b602002602001018181525050808015610aa65750604051633af32abf60e01b81526001600160a01b03851690633af32abf90610a67903390600401611672565b602060405180830381865afa158015610a82573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610aa69190611962565b15610ae3578289604001818151610abd919061197b565b90525087518390899087908110610ad657610ad661189b565b6020026020010181815250505b5050600190920191506109959050565b5083604001515f03610ce15783516001600160401b03811115610b1857610b186116de565b604051908082528060200260200182016040528015610b41578160200160208202803683370190505b5092505f5b8451811015610cdf575f610b5982610238565b90505f816001600160a01b0316634ea15f376040518163ffffffff1660e01b81526004016060604051808303815f875af1158015610b99573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610bbd9190611930565b92505050808015610c345750604051633af32abf60e01b81526001600160a01b03831690633af32abf90610bf5903390600401611672565b602060405180830381865afa158015610c10573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610c349190611962565b15610cd5575f826001600160a01b031663105b403b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610c76573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610c9a91906118af565b90508088604001818151610cae919061197b565b90525086518190889086908110610cc757610cc761189b565b602002602001018181525050505b5050600101610b46565b505b5f5b8451811015610e2b575f848281518110610cff57610cff61189b565b60200260200101511115610e23575f8560400151858381518110610d2557610d2561189b565b60200260200101518a610d38919061198e565b610d4291906119b9565b90508015610e21575f610d5483610238565b90505f816001600160a01b031663f8a239e83385898881518110610d7a57610d7a61189b565b60209081029190910101516040516001600160e01b031960e086901b1681526001600160a01b0390931660048401526024830191909152604482015260648101889052608481018d905260a4016020604051808303815f875af1158015610de3573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610e0791906118af565b90508088606001818151610e1b919061197b565b90525050505b505b600101610ce3565b50610e3e84606001518560200151611413565b606084015115610eca576060840151604051632770a7eb60e21b815233600482015260248101919091527f00000000000000000000000096c6995a7737959708c2ed9129d07c94f012d2ce6001600160a01b031690639dc29fac906044015f604051808303815f87803b158015610eb3575f80fd5b505af1158015610ec5573d5f803e3d5ffd5b505050505b50505050505050565b5f807f00000000000000000000000096c6995a7737959708c2ed9129d07c94f012d2ce6001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610f31573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610f5591906118af565b90505f610f6284836112a9565b9050610706610f708261126d565b85611466565b5f6102f0610932611485565b5f610f94610f8e610f76565b83611466565b92915050565b5f600a8210610fbb5760405162461bcd60e51b815260040161025990611874565b600382600a81106102755761027561189b565b610fd6611220565b81516002548115801590610fea5750825182145b6110265760405162461bcd60e51b815260206004820152600d60248201526c125b9d985b1a59081a5b9c1d5d609a1b6044820152606401610259565b600a611032838361197b565b11156110725760405162461bcd60e51b815260206004820152600f60248201526e4d617820636f6c6c61746572616c7360881b6044820152606401610259565b5f5b828160ff161015611203576110a4858260ff16815181106110975761109761189b565b60200260200101516114ce565b6110bc848260ff16815181106110975761109761189b565b848160ff16815181106110d1576110d161189b565b602002602001015160038260ff16846110ea919061197b565b600a81106110fa576110fa61189b565b015f6101000a8154816001600160a01b0302191690836001600160a01b03160217905550838160ff16815181106111335761113361189b565b6020026020010151600d8260ff168461114c919061197b565b600a811061115c5761115c61189b565b015f6101000a8154816001600160a01b0302191690836001600160a01b031602179055507fe3ff17581c53bf246f14c95373f2d316943397252dfe0c882513e68375b6e021858260ff16815181106111b6576111b661189b565b6020026020010151858360ff16815181106111d3576111d361189b565b60200260200101516040516111e99291906118c6565b60405180910390a1806111fb816119cc565b915050611074565b508160025f828254611215919061197b565b909155505050505050565b5f546001600160a01b0316331461126b5760405162461bcd60e51b815260206004820152600f60248201526e27bbb732b217b737ba16b7bbb732b960891b6044820152606401610259565b565b5f610f948260026112876064670de0b6b3a76400006119b9565b61129191906119b9565b61129b919061197b565b670de0b6b3a76400006114f5565b5f806112b3611485565b90505f836112c9670de0b6b3a76400008761198e565b6112d391906119b9565b90505f6112e16001836119b9565b6112eb908461197b565b90506112ff81670de0b6b3a76400006114f5565b9695505050505050565b600261131e6064670de0b6b3a76400006119b9565b61132891906119b9565b811015801561133f5750670de0b6b3a76400008111155b6113a45760405162461bcd60e51b815260206004820152603060248201527f4d6178206665652070657263656e74616765206d75737420626520626574776560448201526f656e20302e352520616e64203130302560801b6064820152608401610259565b50565b5f81116113a45760405162461bcd60e51b815260206004820152603460248201527f436f6c6c61746572616c52656769737472793a20416d6f756e74206d7573742060448201527362652067726561746572207468616e207a65726f60601b6064820152608401610259565b5f61141e83836112a9565b60178190556040518181529091507fc454ee9b76c52f782a256af821b857ca6e125d1e3333bcede402fec2bed9600c9060200160405180910390a161146161150c565b505050565b5f80670de0b6b3a764000061147b848661198e565b61070691906119b9565b5f8061148f611570565b90505f6114a4670dd9e13cc602b4008361158b565b9050670de0b6b3a7640000816017546114bd919061198e565b6114c791906119b9565b9250505090565b6001600160a01b0381166113a45760405163d92e233d60e01b815260040160405180910390fd5b5f8183106115035781611505565b825b9392505050565b5f611515611570565b905080156113a45761152881603c61198e565b60185f828254611538919061197b565b90915550506018546040519081527f860f8d2f0c74dd487e89e2883e3b25b8159ce1e1b3433a291cba7b82c508f3bc906020016102d9565b5f603c6018544261158191906118f4565b6102f091906119b9565b5f631f5405008211156115a057631f54050091505b815f036115b65750670de0b6b3a7640000610f94565b670de0b6b3a764000083835b6001811115611629576115d66002826119ea565b5f036115fa576115e6828361162f565b91506115f36002826119b9565b90506115c2565b611604828461162f565b9250611610828361162f565b9150600261161f6001836118f4565b6115f391906119b9565b6112ff82845b5f8061163b838561198e565b9050670de0b6b3a76400006116516002826119b9565b61147b908361197b565b5f6020828403121561166b575f80fd5b5035919050565b6001600160a01b0391909116815260200190565b6001600160a01b03811681146113a4575f80fd5b5f602082840312156116aa575f80fd5b813561150581611686565b5f805f606084860312156116c7575f80fd5b505081359360208301359350604090920135919050565b634e487b7160e01b5f52604160045260245ffd5b604051601f8201601f191681016001600160401b038111828210171561171a5761171a6116de565b604052919050565b5f6001600160401b0382111561173a5761173a6116de565b5060051b60200190565b5f82601f830112611753575f80fd5b8135602061176861176383611722565b6116f2565b8083825260208201915060208460051b870101935086841115611789575f80fd5b602086015b848110156117ae5780356117a181611686565b835291830191830161178e565b509695505050505050565b5f80604083850312156117ca575f80fd5b82356001600160401b03808211156117e0575f80fd5b818501915085601f8301126117f3575f80fd5b8135602061180361176383611722565b82815260059290921b84018101918181019089841115611821575f80fd5b948201945b8386101561184857853561183981611686565b82529482019490820190611826565b9650508601359250508082111561185d575f80fd5b5061186a85828601611744565b9150509250929050565b6020808252600d908201526c092dcecc2d8d2c840d2dcc8caf609b1b604082015260600190565b634e487b7160e01b5f52603260045260245ffd5b5f602082840312156118bf575f80fd5b5051919050565b6001600160a01b0392831681529116602082015260400190565b634e487b7160e01b5f52601160045260245ffd5b81810381811115610f9457610f946118e0565b5f81611915576119156118e0565b505f190190565b8051801515811461192b575f80fd5b919050565b5f805f60608486031215611942575f80fd5b83519250602084015191506119596040850161191c565b90509250925092565b5f60208284031215611972575f80fd5b6115058261191c565b80820180821115610f9457610f946118e0565b8082028115828204841417610f9457610f946118e0565b634e487b7160e01b5f52601260045260245ffd5b5f826119c7576119c76119a5565b500490565b5f60ff821660ff81036119e1576119e16118e0565b60010192915050565b5f826119f8576119f86119a5565b50069056fea26469706673582212200cd7b45cf0cb23066fae2defb8c031191ca1333838a97fbf637e9b82dac3967d64736f6c63430008180033

Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)

00000000000000000000000096c6995a7737959708c2ed9129d07c94f012d2ce00000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000100000000000000000000000000919d5a6f2cbc0731380c26b4ac4f6183dd3a40c800000000000000000000000000000000000000000000000000000000000000030000000000000000000000007b42e0d1b7f2111b04c6547fca8ca2b0f271498c0000000000000000000000001f45f163c6fea687c66365f3d75f18c71706c069000000000000000000000000985a39b8dfaa7689b05e6e7bd1b2a66b8b5b1e4e0000000000000000000000000000000000000000000000000000000000000003000000000000000000000000a4867b8f66e724072802a7c8cfd59a26e40ac7210000000000000000000000003fa5b92c2b53348d383fd265e6ec13473537fb210000000000000000000000000079eb9ebd9820c5961b406c1400e1e5dd177592

-----Decoded View---------------
Arg [0] : _boldToken (address): 0x96C6995A7737959708C2eD9129d07c94F012D2Ce
Arg [1] : _tokens (address[]): 0x7B42e0d1B7f2111B04C6547FcA8Ca2b0f271498c,0x1F45f163C6feA687C66365F3D75f18c71706c069,0x985A39B8DfAA7689b05E6e7Bd1B2a66B8B5B1e4E
Arg [2] : _troveManagers (address[]): 0xA4867B8f66E724072802A7C8CFD59A26E40aC721,0x3Fa5b92c2b53348d383Fd265e6EC13473537Fb21,0x0079Eb9EbD9820C5961b406C1400e1E5dD177592
Arg [3] : _owner (address): 0x919D5a6F2CBc0731380C26B4AC4f6183dD3A40C8

-----Encoded View---------------
12 Constructor Arguments found :
Arg [0] : 00000000000000000000000096c6995a7737959708c2ed9129d07c94f012d2ce
Arg [1] : 0000000000000000000000000000000000000000000000000000000000000080
Arg [2] : 0000000000000000000000000000000000000000000000000000000000000100
Arg [3] : 000000000000000000000000919d5a6f2cbc0731380c26b4ac4f6183dd3a40c8
Arg [4] : 0000000000000000000000000000000000000000000000000000000000000003
Arg [5] : 0000000000000000000000007b42e0d1b7f2111b04c6547fca8ca2b0f271498c
Arg [6] : 0000000000000000000000001f45f163c6fea687c66365f3d75f18c71706c069
Arg [7] : 000000000000000000000000985a39b8dfaa7689b05e6e7bd1b2a66b8b5b1e4e
Arg [8] : 0000000000000000000000000000000000000000000000000000000000000003
Arg [9] : 000000000000000000000000a4867b8f66e724072802a7c8cfd59a26e40ac721
Arg [10] : 0000000000000000000000003fa5b92c2b53348d383fd265e6ec13473537fb21
Arg [11] : 0000000000000000000000000079eb9ebd9820c5961b406c1400e1e5dd177592


Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
0x9431A1CD7f53FDf299f89EAc7450682Ff3551313
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.