Contract 0x6387C0E385196FEcb43D5fe37EBe9777B790a882

Contract Overview

Balance:
0 AVAX
Txn Hash Method
Block
From
To
Value [Txn Fee]
0x3c4624cb91fc6f8bae4030590fba93fbe2f5e5b80ad725acb28b79187e03f615Adjust Trove96634452022-05-14 7:02:46145 days 22 hrs ago0xb56137b30bc37c3513420927586f87a80c6ae629 IN 0x6387c0e385196fecb43d5fe37ebe9777b790a8820 AVAX0.010558625 25
0xccd13f15844fd0091db949f11344d83aa664a273a042d7ccec8f2319c3db4e02Adjust Trove96634452022-05-14 7:02:46145 days 22 hrs ago0xb56137b30bc37c3513420927586f87a80c6ae629 IN 0x6387c0e385196fecb43d5fe37ebe9777b790a8820 AVAX0.0194479 25
0x979cbb37f982c099c873212b8e5bafac2b8afb00626bfa4f7ed5bdfe3b7a50f2Adjust Trove96634452022-05-14 7:02:46145 days 22 hrs ago0xb56137b30bc37c3513420927586f87a80c6ae629 IN 0x6387c0e385196fecb43d5fe37ebe9777b790a8820 AVAX0.0194479 25
0xc3438baa64c13ebca481b2121dcf1ef1a9c6c32813f136997be611d51da25cd1Adjust Trove96634452022-05-14 7:02:46145 days 22 hrs ago0xb56137b30bc37c3513420927586f87a80c6ae629 IN 0x6387c0e385196fecb43d5fe37ebe9777b790a8820 AVAX0.0194479 25
0x236c2394818a20f30c1ceabbb09e9ed711999d98665a31b98315827d3ac51508Adjust Trove96634452022-05-14 7:02:46145 days 22 hrs ago0xb56137b30bc37c3513420927586f87a80c6ae629 IN 0x6387c0e385196fecb43d5fe37ebe9777b790a8820 AVAX0.0194479 25
0x642d68c2524b2fe47c503e9fdd8e413edd26de1363d40ed37ae320c5dd877eacAdjust Trove96634452022-05-14 7:02:46145 days 22 hrs ago0xb56137b30bc37c3513420927586f87a80c6ae629 IN 0x6387c0e385196fecb43d5fe37ebe9777b790a8820 AVAX0.0173472 25
0xe4bf68e461dca241838b863f65484634d69230123387f36cf50f9b83de4b5938Open Trove92534272022-05-03 16:18:36156 days 13 hrs ago0x652750ab00be707e48e694eaeed04f6a846d0ace IN 0x6387c0e385196fecb43d5fe37ebe9777b790a8820 AVAX0.26834576749 268.802462875
0x77c896ea57f6e3875f7be5d3e546942bff55d1a62dd159f2b39feb3207612661Open Trove92534212022-05-03 16:18:18156 days 13 hrs ago0x652750ab00be707e48e694eaeed04f6a846d0ace IN 0x6387c0e385196fecb43d5fe37ebe9777b790a8820 AVAX0.25332463843 253.983471556
0xfc1a5c1deaf9d849cc563c38e0ef47b13df53f3d59e17ca0a51ba2e02c2cc08bOpen Trove92534212022-05-03 16:18:18156 days 13 hrs ago0x652750ab00be707e48e694eaeed04f6a846d0ace IN 0x6387c0e385196fecb43d5fe37ebe9777b790a8820 AVAX0.234174884895 236.936618116
0xe0fd92e04cbb02889059b755565ecb3a09e571badb8c4c57bbd2ef550d7ba30fOpen Trove92534202022-05-03 16:18:17156 days 13 hrs ago0x652750ab00be707e48e694eaeed04f6a846d0ace IN 0x6387c0e385196fecb43d5fe37ebe9777b790a8820 AVAX0.243997559153 247.062868159
0x114dd4a9e8d457457d9f51af3a03162fc9ada54527f7c281755aa76f1fb22c72Open Trove92534202022-05-03 16:18:17156 days 13 hrs ago0x652750ab00be707e48e694eaeed04f6a846d0ace IN 0x6387c0e385196fecb43d5fe37ebe9777b790a8820 AVAX0.187716070002 189.929892833
0xa05b0d14aed40bf263df31e2d249a66e49bbd5457d216e016401c5dded578ad6Open Trove89263122022-04-24 19:32:22165 days 9 hrs ago0x0cbc5763fae67985872f763cd080aeec39457344 IN 0x6387c0e385196fecb43d5fe37ebe9777b790a8820 AVAX0.02533415 25
0x3e366665429f41a79e482b074201a0557212bcce719470e4a070a0216a6e3ed4Open Trove88449722022-04-22 19:56:10167 days 9 hrs ago0xb84cf479b93eb5d864cb6408a4bb663970d72e78 IN 0x6387c0e385196fecb43d5fe37ebe9777b790a8820 AVAX0.02458105 25
0x46867b804ebfe11c3bcd96b7c024da79ad3e5e2c6f4dab78636453fa31f5331fOpen Trove88449722022-04-22 19:56:10167 days 9 hrs ago0xb84cf479b93eb5d864cb6408a4bb663970d72e78 IN 0x6387c0e385196fecb43d5fe37ebe9777b790a8820 AVAX0.0873086003 87.780067041
0x74268a5d28f9a781b616a030ae9c4763f0a36977ac7f2d5df0157fe65fb91b34Open Trove88449712022-04-22 19:56:09167 days 9 hrs ago0xb84cf479b93eb5d864cb6408a4bb663970d72e78 IN 0x6387c0e385196fecb43d5fe37ebe9777b790a8820 AVAX0.121013889838 123.07640422
0x1982b7ba8f60f51b701aa75733ab19b0c8ad1b14c8d7189602d3ff1ec1721b1aOpen Trove88449712022-04-22 19:56:09167 days 9 hrs ago0xb84cf479b93eb5d864cb6408a4bb663970d72e78 IN 0x6387c0e385196fecb43d5fe37ebe9777b790a8820 AVAX0.132583151658 134.842848107
0x0f2173c91a3c393aaf285c1142d6c9446cbd5490efa5d79e2b8b5e3e8dbd6700Open Trove88449702022-04-22 19:56:08167 days 9 hrs ago0xb84cf479b93eb5d864cb6408a4bb663970d72e78 IN 0x6387c0e385196fecb43d5fe37ebe9777b790a8820 AVAX0.3050632599 310.262641242
0x6b636d59413a326e83145359ccd46fd49656934d690c6a9d8c53ab2bdb4effcbOpen Trove88449692022-04-22 19:56:07167 days 9 hrs ago0xb84cf479b93eb5d864cb6408a4bb663970d72e78 IN 0x6387c0e385196fecb43d5fe37ebe9777b790a8820 AVAX0.306318716511 311.539495375
0x953bc8eaf2cc43888d1a40c06535d2166ba8936489d3b87e1a7eeb806cb22ca5Open Trove88449642022-04-22 19:56:02167 days 9 hrs ago0xb84cf479b93eb5d864cb6408a4bb663970d72e78 IN 0x6387c0e385196fecb43d5fe37ebe9777b790a8820 AVAX0.305033332788 308.855731319
0x37c06d3bd7243e956d66ba4718d4ba160787d8d3e435b3aef86d87a029b40248Open Trove80776162022-04-02 6:39:52187 days 22 hrs ago0x241392f26e4ed1ca51ca7ab7b352df625bcb08dc IN 0x6387c0e385196fecb43d5fe37ebe9777b790a8820 AVAX0.322727526136 308.648523727
0x8130aeded444c1c5ccca19d0cc226f59e9b09faec3fed902b89124110bd94aafOpen Trove78911172022-03-28 17:57:12192 days 11 hrs ago0x728d15179f6e24bc602bccd8157db750509a1055 IN 0x6387c0e385196fecb43d5fe37ebe9777b790a8820 AVAX0.0816233275 27.5
0xdc6fb43b1085c2f35c19f1b68fc16ec753fff1e466dc2cbd7130362404dad40eOpen Trove78910972022-03-28 17:56:32192 days 11 hrs ago0x47f786398beb431ccf941ade104f1c132d56fc51 IN 0x6387c0e385196fecb43d5fe37ebe9777b790a8820 AVAX0.0816231075 27.5
0xd2d7fb13a39482b099b1760c4895c7b5cb46848620d66282cf290f4b6f3b26c0Open Trove78910912022-03-28 17:56:20192 days 11 hrs ago0x47f786398beb431ccf941ade104f1c132d56fc51 IN 0x6387c0e385196fecb43d5fe37ebe9777b790a8820 AVAX0.0816228325 27.5
0x68648b8a0b2c0de0d6a2f299c0941192ed54b3931e4d2568afc2be083605c114Open Trove78910852022-03-28 17:56:08192 days 11 hrs ago0x47f786398beb431ccf941ade104f1c132d56fc51 IN 0x6387c0e385196fecb43d5fe37ebe9777b790a8820 AVAX0.0816228325 27.5
0xa2ec85b464f77d5e3e1d88d52ce08acd5c3341e29226b527faaedef48fc6e42cOpen Trove78909192022-03-28 17:50:36192 days 11 hrs ago0x99d3289d90e54f556059d284ac5e743c9f45d670 IN 0x6387c0e385196fecb43d5fe37ebe9777b790a8820 AVAX0.07420252525
[ Download CSV Export 
Latest 25 internal transaction
Parent Txn Hash Block From To Value
0x3c4624cb91fc6f8bae4030590fba93fbe2f5e5b80ad725acb28b79187e03f61596634452022-05-14 7:02:46145 days 22 hrs ago 0x6387c0e385196fecb43d5fe37ebe9777b790a8820x1aa108e2392cd316be9255f78a3673e9f6f654470 AVAX
0x3c4624cb91fc6f8bae4030590fba93fbe2f5e5b80ad725acb28b79187e03f61596634452022-05-14 7:02:46145 days 22 hrs ago 0x6387c0e385196fecb43d5fe37ebe9777b790a8820x1aa108e2392cd316be9255f78a3673e9f6f654470 AVAX
0x3c4624cb91fc6f8bae4030590fba93fbe2f5e5b80ad725acb28b79187e03f61596634452022-05-14 7:02:46145 days 22 hrs ago 0x6387c0e385196fecb43d5fe37ebe9777b790a8820x1aa108e2392cd316be9255f78a3673e9f6f654470 AVAX
0x3c4624cb91fc6f8bae4030590fba93fbe2f5e5b80ad725acb28b79187e03f61596634452022-05-14 7:02:46145 days 22 hrs ago 0x6387c0e385196fecb43d5fe37ebe9777b790a8820x1aa108e2392cd316be9255f78a3673e9f6f654470 AVAX
0x3c4624cb91fc6f8bae4030590fba93fbe2f5e5b80ad725acb28b79187e03f61596634452022-05-14 7:02:46145 days 22 hrs ago 0x6387c0e385196fecb43d5fe37ebe9777b790a8820x1aa108e2392cd316be9255f78a3673e9f6f654470 AVAX
0x3c4624cb91fc6f8bae4030590fba93fbe2f5e5b80ad725acb28b79187e03f61596634452022-05-14 7:02:46145 days 22 hrs ago 0x6387c0e385196fecb43d5fe37ebe9777b790a8820x1aa108e2392cd316be9255f78a3673e9f6f654470 AVAX
0x3c4624cb91fc6f8bae4030590fba93fbe2f5e5b80ad725acb28b79187e03f61596634452022-05-14 7:02:46145 days 22 hrs ago 0x6387c0e385196fecb43d5fe37ebe9777b790a8820x1aa108e2392cd316be9255f78a3673e9f6f654470 AVAX
0x3c4624cb91fc6f8bae4030590fba93fbe2f5e5b80ad725acb28b79187e03f61596634452022-05-14 7:02:46145 days 22 hrs ago 0x6387c0e385196fecb43d5fe37ebe9777b790a8820xcb74a8f05537e346ac54c173652e57c96b4339d20 AVAX
0x3c4624cb91fc6f8bae4030590fba93fbe2f5e5b80ad725acb28b79187e03f61596634452022-05-14 7:02:46145 days 22 hrs ago 0x6387c0e385196fecb43d5fe37ebe9777b790a8820x1aa108e2392cd316be9255f78a3673e9f6f654470 AVAX
0x3c4624cb91fc6f8bae4030590fba93fbe2f5e5b80ad725acb28b79187e03f61596634452022-05-14 7:02:46145 days 22 hrs ago 0x6387c0e385196fecb43d5fe37ebe9777b790a8820xcb74a8f05537e346ac54c173652e57c96b4339d20 AVAX
0x3c4624cb91fc6f8bae4030590fba93fbe2f5e5b80ad725acb28b79187e03f61596634452022-05-14 7:02:46145 days 22 hrs ago 0x6387c0e385196fecb43d5fe37ebe9777b790a8820xcb74a8f05537e346ac54c173652e57c96b4339d20 AVAX
0x3c4624cb91fc6f8bae4030590fba93fbe2f5e5b80ad725acb28b79187e03f61596634452022-05-14 7:02:46145 days 22 hrs ago 0x6387c0e385196fecb43d5fe37ebe9777b790a8820xf7d924a8f414a16a54f2cf9a98ac266281239ffb0 AVAX
0x3c4624cb91fc6f8bae4030590fba93fbe2f5e5b80ad725acb28b79187e03f61596634452022-05-14 7:02:46145 days 22 hrs ago 0x6387c0e385196fecb43d5fe37ebe9777b790a8820x0db336c1ab0cc14972b53caa4f100068731c54aa0 AVAX
0x3c4624cb91fc6f8bae4030590fba93fbe2f5e5b80ad725acb28b79187e03f61596634452022-05-14 7:02:46145 days 22 hrs ago 0x6387c0e385196fecb43d5fe37ebe9777b790a8820xf7d924a8f414a16a54f2cf9a98ac266281239ffb0 AVAX
0x3c4624cb91fc6f8bae4030590fba93fbe2f5e5b80ad725acb28b79187e03f61596634452022-05-14 7:02:46145 days 22 hrs ago 0x6387c0e385196fecb43d5fe37ebe9777b790a8820x0db336c1ab0cc14972b53caa4f100068731c54aa0 AVAX
0x3c4624cb91fc6f8bae4030590fba93fbe2f5e5b80ad725acb28b79187e03f61596634452022-05-14 7:02:46145 days 22 hrs ago 0x6387c0e385196fecb43d5fe37ebe9777b790a8820x1aa108e2392cd316be9255f78a3673e9f6f654470 AVAX
0xccd13f15844fd0091db949f11344d83aa664a273a042d7ccec8f2319c3db4e0296634452022-05-14 7:02:46145 days 22 hrs ago 0x6387c0e385196fecb43d5fe37ebe9777b790a8820x05671a0c758aaed71d759b41091c67457dc8882e0 AVAX
0xccd13f15844fd0091db949f11344d83aa664a273a042d7ccec8f2319c3db4e0296634452022-05-14 7:02:46145 days 22 hrs ago 0x6387c0e385196fecb43d5fe37ebe9777b790a8820xcb74a8f05537e346ac54c173652e57c96b4339d20 AVAX
0xccd13f15844fd0091db949f11344d83aa664a273a042d7ccec8f2319c3db4e0296634452022-05-14 7:02:46145 days 22 hrs ago 0x6387c0e385196fecb43d5fe37ebe9777b790a8820xcb74a8f05537e346ac54c173652e57c96b4339d20 AVAX
0xccd13f15844fd0091db949f11344d83aa664a273a042d7ccec8f2319c3db4e0296634452022-05-14 7:02:46145 days 22 hrs ago 0x6387c0e385196fecb43d5fe37ebe9777b790a8820xcb74a8f05537e346ac54c173652e57c96b4339d20 AVAX
0xccd13f15844fd0091db949f11344d83aa664a273a042d7ccec8f2319c3db4e0296634452022-05-14 7:02:46145 days 22 hrs ago 0x6387c0e385196fecb43d5fe37ebe9777b790a8820xf7d924a8f414a16a54f2cf9a98ac266281239ffb0 AVAX
0xccd13f15844fd0091db949f11344d83aa664a273a042d7ccec8f2319c3db4e0296634452022-05-14 7:02:46145 days 22 hrs ago 0x6387c0e385196fecb43d5fe37ebe9777b790a8820x0db336c1ab0cc14972b53caa4f100068731c54aa0 AVAX
0xccd13f15844fd0091db949f11344d83aa664a273a042d7ccec8f2319c3db4e0296634452022-05-14 7:02:46145 days 22 hrs ago 0x6387c0e385196fecb43d5fe37ebe9777b790a8820xf7d924a8f414a16a54f2cf9a98ac266281239ffb0 AVAX
0xccd13f15844fd0091db949f11344d83aa664a273a042d7ccec8f2319c3db4e0296634452022-05-14 7:02:46145 days 22 hrs ago 0x6387c0e385196fecb43d5fe37ebe9777b790a8820x0db336c1ab0cc14972b53caa4f100068731c54aa0 AVAX
0xccd13f15844fd0091db949f11344d83aa664a273a042d7ccec8f2319c3db4e0296634452022-05-14 7:02:46145 days 22 hrs ago 0x6387c0e385196fecb43d5fe37ebe9777b790a8820xcb74a8f05537e346ac54c173652e57c96b4339d20 AVAX
[ Download CSV Export 
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
BorrowerOperations

Compiler Version
v0.6.11+commit.5ef660b1

Optimization Enabled:
Yes with 100 runs

Other Settings:
default evmVersion

Contract Source Code (Solidity Standard Json-Input format)

File 1 of 26 : BorrowerOperations.sol
// SPDX-License-Identifier: UNLICENSED

pragma solidity 0.6.11;

import "./Interfaces/IBorrowerOperations.sol";
import "./Interfaces/ITroveManager.sol";
import "./Interfaces/IYUSDToken.sol";
import "./Interfaces/ICollSurplusPool.sol";
import "./Interfaces/ISortedTroves.sol";
import "./Interfaces/ISYETI.sol";
import "./Interfaces/IWhitelist.sol";
import "./Interfaces/IYetiRouter.sol";
import "./Dependencies/LiquityBase.sol";
import "./Dependencies/Ownable.sol";
import "./Dependencies/CheckContract.sol";
import "./Interfaces/IERC20.sol";

/** 
 * BorrowerOperations is the contract that handles most of external facing trove activities that 
 * a user would make with their own trove, like opening, closing, adjusting, increasing leverage, etc.
 */

 /**
   A summary of Lever Up:
   Takes in a collateral token A, and simulates borrowing of YUSD at a certain collateral ratio and
   buying more token A, putting back into protocol, buying more A, etc. at a certain leverage amount.
   So if at 3x leverage and 1000$ token A, it will mint 1000 * 3x * 2/3 = $2000 YUSD, then swap for
   token A by using some router strategy, returning a little under $2000 token A to put back in the
   trove. The number here is 2/3 because the math works out to be that collateral ratio is 150% if
   we have a 3x leverage. They now have a trove with $3000 of token A and a collateral ratio of 150%.
  */

contract BorrowerOperations is LiquityBase, Ownable, CheckContract, IBorrowerOperations {
    string public constant NAME = "BorrowerOperations";

    // --- Connected contract declarations ---

    ITroveManager public troveManager;

    address stabilityPoolAddress;

    address gasPoolAddress;

    ICollSurplusPool collSurplusPool;

    ISYETI public sYETI;
    address public sYETIAddress;

    IYUSDToken public yusdToken;

    uint public constant BOOTSTRAP_PERIOD = 14 days;
    uint deploymentTime;

    // A doubly linked list of Troves, sorted by their collateral ratios
    ISortedTroves public sortedTroves;

    struct CollateralData {
        address collateral;
        uint256 amount;
    }

    struct DepositFeeCalc {
        uint256 collateralYUSDFee;
        uint256 systemCollateralVC;
        uint256 collateralInputVC;
        uint256 systemTotalVC;
        address token;
    }

    /* --- Variable container structs  ---

    Used to hold, return and assign variables inside a function, in order to avoid the error:
    "CompilerError: Stack too deep". */
    struct AdjustTrove_Params {
        address[] _collsIn;
        uint256[] _amountsIn;
        address[] _collsOut;
        uint256[] _amountsOut;
        uint256[] _maxSlippages;
        uint256 _YUSDChange;
        uint256 _totalYUSDDebtFromLever;
        bool _isDebtIncrease;
        bool _isUnlever;
        address _upperHint;
        address _lowerHint;
        uint256 _maxFeePercentage;
    }

    struct LocalVariables_adjustTrove {
        uint256 netDebtChange;
        bool isCollIncrease;
        uint256 collChange;
        uint256 currVC;
        uint256 newVC;
        uint256 debt;
        address[] currAssets;
        uint256[] currAmounts;
        address[] newAssets;
        uint256[] newAmounts;
        uint256 oldICR;
        uint256 newICR;
        uint256 newTCR;
        uint256 YUSDFee;
        uint256 variableYUSDFee;
        uint256 newDebt;
        uint256 VCin;
        uint256 VCout;
        uint256 maxFeePercentageFactor;
    }

    struct LocalVariables_openTrove {
        address[] collaterals;
        uint256[] prices;
        uint256 YUSDFee;
        uint256 netDebt;
        uint256 compositeDebt;
        uint256 ICR;
        uint256 arrayIndex;
        address collAddress;
        uint256 VC;
        uint256 newTCR;
        bool isRecoveryMode;
    }

    struct CloseTrove_Params {
        address[] _collsOut;
        uint256[] _amountsOut;
        uint256[] _maxSlippages;
        bool _isUnlever;
    }

    struct ContractsCache {
        ITroveManager troveManager;
        IActivePool activePool;
        IYUSDToken yusdToken;
    }

    enum BorrowerOperation {
        openTrove,
        closeTrove,
        adjustTrove
    }

    event TroveManagerAddressChanged(address _newTroveManagerAddress);
    event ActivePoolAddressChanged(address _activePoolAddress);
    event DefaultPoolAddressChanged(address _defaultPoolAddress);
    event StabilityPoolAddressChanged(address _stabilityPoolAddress);
    event GasPoolAddressChanged(address _gasPoolAddress);
    event CollSurplusPoolAddressChanged(address _collSurplusPoolAddress);
    event PriceFeedAddressChanged(address _newPriceFeedAddress);
    event SortedTrovesAddressChanged(address _sortedTrovesAddress);
    event YUSDTokenAddressChanged(address _yusdTokenAddress);
    event SYETIAddressChanged(address _sYETIAddress);

    event TroveCreated(address indexed _borrower, uint256 arrayIndex);
    event TroveUpdated(
        address indexed _borrower,
        uint256 _debt,
        address[] _tokens,
        uint256[] _amounts,
        BorrowerOperation operation
    );
    event YUSDBorrowingFeePaid(address indexed _borrower, uint256 _YUSDFee);

    // --- Dependency setters ---

    function setAddresses(
        address _troveManagerAddress,
        address _activePoolAddress,
        address _defaultPoolAddress,
        address _stabilityPoolAddress,
        address _gasPoolAddress,
        address _collSurplusPoolAddress,
        address _sortedTrovesAddress,
        address _yusdTokenAddress,
        address _sYETIAddress,
        address _whitelistAddress
    ) external override onlyOwner {
        // This makes impossible to open a trove with zero withdrawn YUSD
        assert(MIN_NET_DEBT > 0);

        deploymentTime = block.timestamp;

        checkContract(_troveManagerAddress);
        checkContract(_activePoolAddress);
        checkContract(_defaultPoolAddress);
        checkContract(_stabilityPoolAddress);
        checkContract(_gasPoolAddress);
        checkContract(_collSurplusPoolAddress);
        checkContract(_sortedTrovesAddress);
        checkContract(_yusdTokenAddress);
        checkContract(_sYETIAddress);
        checkContract(_whitelistAddress);

        troveManager = ITroveManager(_troveManagerAddress);
        activePool = IActivePool(_activePoolAddress);
        defaultPool = IDefaultPool(_defaultPoolAddress);
        whitelist = IWhitelist(_whitelistAddress);
        stabilityPoolAddress = _stabilityPoolAddress;
        gasPoolAddress = _gasPoolAddress;
        collSurplusPool = ICollSurplusPool(_collSurplusPoolAddress);
        sortedTroves = ISortedTroves(_sortedTrovesAddress);
        yusdToken = IYUSDToken(_yusdTokenAddress);
        sYETIAddress = _sYETIAddress;

        emit TroveManagerAddressChanged(_troveManagerAddress);
        emit ActivePoolAddressChanged(_activePoolAddress);
        emit DefaultPoolAddressChanged(_defaultPoolAddress);
        emit StabilityPoolAddressChanged(_stabilityPoolAddress);
        emit GasPoolAddressChanged(_gasPoolAddress);
        emit CollSurplusPoolAddressChanged(_collSurplusPoolAddress);
        emit SortedTrovesAddressChanged(_sortedTrovesAddress);
        emit YUSDTokenAddressChanged(_yusdTokenAddress);
        emit SYETIAddressChanged(_sYETIAddress);

        _renounceOwnership();
    }

    // --- Borrower Trove Operations ---

    function openTrove(
        uint256 _maxFeePercentage,
        uint256 _YUSDAmount,
        address _upperHint,
        address _lowerHint,
        address[] memory _colls,
        uint256[] memory _amounts
    ) external override {
        require(_amounts.length != 0, "Amounts == 0");
        _requireValidDepositCollateral(_colls, _amounts);
        _requireNoDuplicateColls(_colls); // Check that there is no overlap in _colls

        // transfer collateral into ActivePool
        require(
            _transferCollateralsIntoActivePool(msg.sender, _colls, _amounts),
            "BOps: Transfer collateral into ActivePool failed"
        );

        _openTroveInternal(
            msg.sender,
            _maxFeePercentage,
            _YUSDAmount,
            0,
            _upperHint,
            _lowerHint,
            _colls,
            _amounts
        );
    }

    // amounts should be a uint array giving the amount of each collateral
    // to be transferred in in order of the current whitelist
    // Should be called *after* collateral has been already sent to the active pool
    // Should confirm _colls, is valid collateral prior to calling this
    function _openTroveInternal(
        address _troveOwner,
        uint256 _maxFeePercentage,
        uint256 _YUSDAmount,
        uint256 _totalYUSDDebtFromLever,
        address _upperHint,
        address _lowerHint,
        address[] memory _colls,
        uint256[] memory _amounts
    ) internal {
        LocalVariables_openTrove memory vars;

        vars.isRecoveryMode = _checkRecoveryMode();

        ContractsCache memory contractsCache = ContractsCache(troveManager, activePool, yusdToken);

        _requireValidMaxFeePercentage(_maxFeePercentage, vars.isRecoveryMode);
        _requireTroveisNotActive(contractsCache.troveManager, _troveOwner);

        vars.netDebt = _YUSDAmount;

        // For every collateral type in, calculate the VC and get the variable fee
        vars.VC = _getVC(_colls, _amounts);

        if (!vars.isRecoveryMode) {
            // when not in recovery mode, add in the 0.5% fee
            vars.YUSDFee = _triggerBorrowingFee(
                contractsCache.troveManager,
                contractsCache.yusdToken,
                _YUSDAmount,
                vars.VC, // here it is just VC in, which is always larger than YUSD amount
                _maxFeePercentage
            );
            _maxFeePercentage = _maxFeePercentage.sub(vars.YUSDFee.mul(DECIMAL_PRECISION).div(vars.VC));
        }

        // Add in variable fee. Always present, even in recovery mode.
        vars.YUSDFee = vars.YUSDFee.add(
            _getTotalVariableDepositFee(_colls, _amounts, vars.VC, 0, vars.VC, _maxFeePercentage, contractsCache)
        );

        // Adds total fees to netDebt
        vars.netDebt = vars.netDebt.add(vars.YUSDFee); // The raw debt change includes the fee

        _requireAtLeastMinNetDebt(vars.netDebt);
        // ICR is based on the composite debt, i.e. the requested YUSD amount + YUSD borrowing fee + YUSD gas comp.
        // _getCompositeDebt returns  vars.netDebt + YUSD gas comp.
        vars.compositeDebt = _getCompositeDebt(vars.netDebt);
        assert(vars.compositeDebt > 0);

        vars.ICR = LiquityMath._computeCR(vars.VC, vars.compositeDebt);
        if (vars.isRecoveryMode) {
            _requireICRisAboveCCR(vars.ICR);
        } else {
            _requireICRisAboveMCR(vars.ICR);
            vars.newTCR = _getNewTCRFromTroveChange(vars.VC, true, vars.compositeDebt, true); // bools: coll increase, debt increase
            _requireNewTCRisAboveCCR(vars.newTCR);
        }

        // Set the trove struct's properties
        contractsCache.troveManager.setTroveStatus(_troveOwner, 1);

        contractsCache.troveManager.updateTroveColl(_troveOwner, _colls, _amounts);
        contractsCache.troveManager.increaseTroveDebt(_troveOwner, vars.compositeDebt);

        contractsCache.troveManager.updateTroveRewardSnapshots(_troveOwner);

        contractsCache.troveManager.updateStakeAndTotalStakes(_troveOwner);

        sortedTroves.insert(_troveOwner, vars.ICR, _upperHint, _lowerHint);
        vars.arrayIndex = contractsCache.troveManager.addTroveOwnerToArray(_troveOwner);
        emit TroveCreated(_troveOwner, vars.arrayIndex);

        contractsCache.activePool.receiveCollateral(_colls, _amounts);

        _withdrawYUSD(
            contractsCache.activePool,
            contractsCache.yusdToken,
            _troveOwner,
            _YUSDAmount.sub(_totalYUSDDebtFromLever),
            vars.netDebt
        );

        // Move the YUSD gas compensation to the Gas Pool
        _withdrawYUSD(
            contractsCache.activePool,
            contractsCache.yusdToken,
            gasPoolAddress,
            YUSD_GAS_COMPENSATION,
            YUSD_GAS_COMPENSATION
        );

        emit TroveUpdated(
            _troveOwner,
            vars.compositeDebt,
            _colls,
            _amounts,
            BorrowerOperation.openTrove
        );
        emit YUSDBorrowingFeePaid(_troveOwner, vars.YUSDFee);
    }


    // add collateral to trove. Calls _adjustTrove with correct params. 
    function addColl(
        address[] memory _collsIn,
        uint256[] memory _amountsIn,
        address _upperHint,
        address _lowerHint, 
        uint256 _maxFeePercentage
    ) external override {
        AdjustTrove_Params memory params;
        params._collsIn = _collsIn;
        params._amountsIn = _amountsIn;
        params._upperHint = _upperHint;
        params._lowerHint = _lowerHint;
        params._maxFeePercentage = _maxFeePercentage;

        // check that all _collsIn collateral types are in the whitelist
        _requireValidDepositCollateral(params._collsIn, params._amountsIn);
        _requireNoDuplicateColls(params._collsIn); // Check that there is no overlap with in or out in itself

        // pull in deposit collateral
        require(
            _transferCollateralsIntoActivePool(msg.sender, params._collsIn, params._amountsIn),
            "BOps: Failed to transfer collateral into active pool"
        );
        _adjustTrove(params);
    }

    // Withdraw collateral from a trove. Calls _adjustTrove with correct params. 

    function withdrawColl(
        address[] memory _collsOut,
        uint256[] memory _amountsOut,
        address _upperHint,
        address _lowerHint
    ) external override {
        AdjustTrove_Params memory params;
        params._collsOut = _collsOut;
        params._amountsOut = _amountsOut;
        params._upperHint = _upperHint;
        params._lowerHint = _lowerHint;
        _adjustTrove(params);
    }

    // Withdraw YUSD tokens from a trove: mint new YUSD tokens to the owner, and increase the trove's debt accordingly. 
    // Calls _adjustTrove with correct params. 
    function withdrawYUSD(
        uint256 _maxFeePercentage,
        uint256 _YUSDAmount,
        address _upperHint,
        address _lowerHint
    ) external override {
        AdjustTrove_Params memory params;
        params._YUSDChange = _YUSDAmount;
        params._maxFeePercentage = _maxFeePercentage;
        params._upperHint = _upperHint;
        params._lowerHint = _lowerHint;
        params._isDebtIncrease = true;
        _adjustTrove(params);
    }

    // Repay YUSD tokens to a Trove: Burn the repaid YUSD tokens, and reduce the trove's debt accordingly. 
    // Calls _adjustTrove with correct params. 
    function repayYUSD(
        uint256 _YUSDAmount,
        address _upperHint,
        address _lowerHint
    ) external override {
        AdjustTrove_Params memory params;
        params._YUSDChange = _YUSDAmount;
        params._upperHint = _upperHint;
        params._lowerHint = _lowerHint;
        params._isDebtIncrease = false;
        _adjustTrove(params);
    }

    // Adjusts trove with multiple colls in / out. Calls _adjustTrove with correct params.
    function adjustTrove(
        address[] memory _collsIn,
        uint256[] memory _amountsIn,
        address[] memory _collsOut,
        uint256[] memory _amountsOut,
        uint256 _YUSDChange,
        bool _isDebtIncrease,
        address _upperHint,
        address _lowerHint,
        uint256 _maxFeePercentage
    ) external override {
        // check that all _collsIn collateral types are in the whitelist
        _requireValidDepositCollateral(_collsIn, _amountsIn);
        _requireValidDepositCollateral(_collsOut, _amountsOut);
        _requireNoOverlapColls(_collsIn, _collsOut); // check that there are no overlap between _collsIn and _collsOut
        _requireNoDuplicateColls(_collsOut);

        // pull in deposit collateral
        require(
            _transferCollateralsIntoActivePool(msg.sender, _collsIn, _amountsIn),
            "BOps: Failed to transfer collateral into active pool"
        );
        uint256[] memory maxSlippages = new uint256[](0);

        AdjustTrove_Params memory params = AdjustTrove_Params(
            _collsIn,
            _amountsIn,
            _collsOut,
            _amountsOut,
            maxSlippages,
            _YUSDChange,
            0,
            _isDebtIncrease,
            false,
            _upperHint,
            _lowerHint,
            _maxFeePercentage
        );

        _adjustTrove(params);
    }

    /*
     * _adjustTrove(): Alongside a debt change, this function can perform either a collateral top-up or a collateral withdrawal.
     * the ith element of _amountsIn and _amountsOut corresponds to the ith element of the addresses _collsIn and _collsOut passed in
     *
     * Should be called after the collsIn has been sent to ActivePool
     */
    function _adjustTrove(AdjustTrove_Params memory params) internal {
        ContractsCache memory contractsCache = ContractsCache(troveManager, activePool, yusdToken);
        LocalVariables_adjustTrove memory vars;

        bool isRecoveryMode = _checkRecoveryMode();

        if (params._isDebtIncrease) {
            _requireValidMaxFeePercentage(params._maxFeePercentage, isRecoveryMode);
            _requireNonZeroDebtChange(params._YUSDChange);
        }

        _requireNonZeroAdjustment(params._amountsIn, params._amountsOut, params._YUSDChange);
        _requireTroveisActive(contractsCache.troveManager, msg.sender);

        contractsCache.troveManager.applyPendingRewards(msg.sender);
        vars.netDebtChange = params._YUSDChange;

        vars.VCin = _getVC(params._collsIn, params._amountsIn);
        vars.VCout = _getVC(params._collsOut, params._amountsOut);

        if (params._isDebtIncrease) {
            vars.maxFeePercentageFactor = _max(vars.VCin, params._YUSDChange);
        } else {
            vars.maxFeePercentageFactor = vars.VCin;
        }
        
        // If the adjustment incorporates a debt increase and system is in Normal Mode, then trigger a borrowing fee
        if (params._isDebtIncrease && !isRecoveryMode) {
            vars.YUSDFee = _triggerBorrowingFee(
                contractsCache.troveManager,
                contractsCache.yusdToken,
                params._YUSDChange,
                vars.maxFeePercentageFactor, // max of VC in and YUSD change here to see what the max borrowing fee is triggered on.
                params._maxFeePercentage
            );
            // passed in max fee minus actual fee percent applied so far
            params._maxFeePercentage = params._maxFeePercentage.sub(vars.YUSDFee.mul(DECIMAL_PRECISION).div(vars.maxFeePercentageFactor)); 
            vars.netDebtChange = vars.netDebtChange.add(vars.YUSDFee); // The raw debt change includes the fee
        }

        // get current portfolio in trove
        (vars.currAssets, vars.currAmounts) = contractsCache.troveManager.getTroveColls(msg.sender);
        // current VC based on current portfolio and latest prices
        vars.currVC = _getVC(vars.currAssets, vars.currAmounts);

        // get new portfolio in trove after changes. Will error if invalid changes:
        (vars.newAssets, vars.newAmounts) = _getNewPortfolio(
            vars.currAssets,
            vars.currAmounts,
            params._collsIn,
            params._amountsIn,
            params._collsOut,
            params._amountsOut
        );
        // new VC based on new portfolio and latest prices
        vars.newVC = _getVC(vars.newAssets, vars.newAmounts);

        vars.isCollIncrease = vars.newVC > vars.currVC;
        vars.collChange = 0;
        if (vars.isCollIncrease) {
            vars.collChange = (vars.newVC).sub(vars.currVC);
        } else {
            vars.collChange = (vars.currVC).sub(vars.newVC);
        }

        vars.debt = contractsCache.troveManager.getTroveDebt(msg.sender);

        if (params._collsIn.length > 0) {
            vars.variableYUSDFee = _getTotalVariableDepositFee(
                    params._collsIn,
                    params._amountsIn,
                    vars.VCin,
                    vars.VCout,
                    vars.maxFeePercentageFactor,
                    params._maxFeePercentage,
                    contractsCache
            );
        }

        // Get the trove's old ICR before the adjustment, and what its new ICR will be after the adjustment
        vars.oldICR = LiquityMath._computeCR(vars.currVC, vars.debt);

        vars.debt = vars.debt.add(vars.variableYUSDFee); 

        vars.newICR = _getNewICRFromTroveChange(vars.newVC,
            vars.debt, // with variableYUSDFee already added. 
            vars.netDebtChange,
            params._isDebtIncrease 
        );

        // Check the adjustment satisfies all conditions for the current system mode
        _requireValidAdjustmentInCurrentMode(
            isRecoveryMode,
            params._amountsOut,
            params._isDebtIncrease,
            vars
        );

        // When the adjustment is a debt repayment, check it's a valid amount and that the caller has enough YUSD
        if (!params._isUnlever && !params._isDebtIncrease && params._YUSDChange > 0) {
            _requireAtLeastMinNetDebt(_getNetDebt(vars.debt).sub(vars.netDebtChange));
            _requireValidYUSDRepayment(vars.debt, vars.netDebtChange);
            _requireSufficientYUSDBalance(contractsCache.yusdToken, msg.sender, vars.netDebtChange);
        }

        if (params._collsIn.length > 0) {
            contractsCache.activePool.receiveCollateral(params._collsIn, params._amountsIn);
        }

        (vars.newVC, vars.newDebt) = _updateTroveFromAdjustment(
            contractsCache.troveManager,
            msg.sender,
            vars.newAssets,
            vars.newAmounts,
            vars.newVC,
            vars.netDebtChange,
            params._isDebtIncrease, 
            vars.variableYUSDFee
        );

        contractsCache.troveManager.updateStakeAndTotalStakes(msg.sender);

        // Re-insert trove in to the sorted list
        sortedTroves.reInsert(msg.sender, vars.newICR, params._upperHint, params._lowerHint);

        emit TroveUpdated(
            msg.sender,
            vars.newDebt,
            vars.newAssets,
            vars.newAmounts,
            BorrowerOperation.adjustTrove
        );
        emit YUSDBorrowingFeePaid(msg.sender, vars.YUSDFee);

        // in case of unlever up
        if (params._isUnlever) {
            // 1. withdraw the collateral from the active pool and perform the swap using single unlever up and corresponding router
            contractsCache.activePool.sendCollateralsUnwrap(msg.sender, params._collsOut, params._amountsOut, true);

            // 2. requires that the user has approved the contract to send its collateral if it is unlevering that amount. 
            for (uint i = 0; i < params._collsOut.length; i++) {
                if (params._maxSlippages[i] != 0) {
                    // add YUSD Amount from swap to total YUSD amount to repay debt
                    // _singleUnleverUp(params._collsOut[i], params._amountsOut[i], params._maxSlippages[i]); TODO UNCOMMENT
                    // TODO confirm amount transfered. Should we be transfering directly to active pool?
                } 
            }
            // 3. update the trove with the new collateral and debt, repaying the total amount of YUSD specified. 
            // require(finalYUSDAmount >= _YUSDAmount, "Unlever: Must have sold enough coll for YUSD");
            // if not enough coll sold for YUSD, must cover from user balance
            _requireAtLeastMinNetDebt(_getNetDebt(vars.debt).sub(params._YUSDChange));
            _requireValidYUSDRepayment(vars.debt, params._YUSDChange);
            _requireSufficientYUSDBalance(contractsCache.yusdToken, msg.sender, params._YUSDChange);
            _repayYUSD(contractsCache.activePool, contractsCache.yusdToken, msg.sender, params._YUSDChange);
        } else {
            // Use the unmodified _YUSDChange here, as we don't send the fee to the user
            _moveYUSD(
                contractsCache.activePool,
                contractsCache.yusdToken,
                msg.sender,
                params._YUSDChange.sub(params._totalYUSDDebtFromLever), // 0 in non lever case
                params._isDebtIncrease,
                vars.netDebtChange
            );

            // Additionally move the variable deposit fee to the active pool manually, as it is always an increase in debt
            _withdrawYUSD(
                contractsCache.activePool,
                contractsCache.yusdToken,
                msg.sender,
                0,
                vars.variableYUSDFee
            );

            // transfer withdrawn collateral to msg.sender from ActivePool
            activePool.sendCollateralsUnwrap(msg.sender, params._collsOut, params._amountsOut, true);
        }
    }

    function closeTrove() external override {
        CloseTrove_Params memory params; // default false
        _closeTrove(params);
    }

    /** 
     * Closes trove by applying pending rewards, making sure that the YUSD Balance is sufficient, and transferring the 
     * collateral to the owner, and repaying the debt.
     * if it is a unlever, then it will transfer the collaterals / sell before. Otherwise it will just do it last. 
     */
    function _closeTrove(
        CloseTrove_Params memory params
        ) internal {
        ContractsCache memory contractsCache = ContractsCache(troveManager, activePool, yusdToken);

        _requireTroveisActive(contractsCache.troveManager, msg.sender);
        _requireNotInRecoveryMode();

        contractsCache.troveManager.applyPendingRewards(msg.sender);

        uint256 troveVC = contractsCache.troveManager.getTroveVC(msg.sender); // should get the latest VC
        (address[] memory colls, uint256[] memory amounts) = contractsCache.troveManager.getTroveColls(
            msg.sender
        );
        uint256 debt = contractsCache.troveManager.getTroveDebt(msg.sender);

        // if unlever, will do extra.
        uint finalYUSDAmount;
        uint YUSDAmount;
        if (params._isUnlever) {
            contractsCache.activePool.sendCollateralsUnwrap(msg.sender, colls, amounts, true);
            // tracks the amount of YUSD that is received from swaps. Will send the _YUSDAmount back to repay debt while keeping remainder.
            
            // requires that the user has approved the contract to send its collateral if it is unlevering that amount. 
            for (uint i = 0; i < params._collsOut.length; i++) {
                if (params._maxSlippages[i] != 0) {
                    // add YUSD Amount from swap to total YUSD amount to repay debt
                    // _singleUnleverUp(params._collsOut[i], params._amountsOut[i], params._maxSlippages[i]); TODO uncomment
                    // TODO confirm amount transfered. Should we transfer directly to user?
                } 
            }   
        }

        // do check after unlever (if applies)
        _requireSufficientYUSDBalance(contractsCache.yusdToken, msg.sender, debt.sub(YUSD_GAS_COMPENSATION));
        uint256 newTCR = _getNewTCRFromTroveChange(troveVC, false, debt, false);
        _requireNewTCRisAboveCCR(newTCR);

        contractsCache.troveManager.removeStake(msg.sender);
        contractsCache.troveManager.closeTrove(msg.sender);

        address[] memory finalColls;
        uint256[] memory finalAmounts;

        emit TroveUpdated(msg.sender, 0, finalColls, finalAmounts, BorrowerOperation.closeTrove);

        // Burn the repaid YUSD from the user's balance and the gas compensation from the Gas Pool
        _repayYUSD(contractsCache.activePool, contractsCache.yusdToken, msg.sender, debt.sub(YUSD_GAS_COMPENSATION));
        _repayYUSD(contractsCache.activePool, contractsCache.yusdToken, gasPoolAddress, YUSD_GAS_COMPENSATION);

        // Send the collateral back to the user
        // Also sends the rewards
        if (!params._isUnlever) {
            contractsCache.activePool.sendCollateralsUnwrap(msg.sender, colls, amounts, true);
        }
    }

    /**
     * Claim remaining collateral from a redemption or from a liquidation with ICR > MCR in Recovery Mode
     */
    function claimCollateral() external override {
        // send collateral from CollSurplus Pool to owner
        collSurplusPool.claimColl(msg.sender);
    }

    // --- Helper functions ---

    /** 
     * Gets the variable deposit fee from the whitelist calculation. Multiplies the 
     * fee by the vc of the collateral.
     */
    function _getTotalVariableDepositFee(
        address[] memory _tokensIn,
        uint256[] memory _amountsIn,
        uint256 _VCin,
        uint256 _VCout,
        uint256 _maxFeePercentageFactor, 
        uint256 _maxFeePercentage,
        ContractsCache memory _contractsCache
    ) internal returns (uint256 YUSDFee) {
        if (_VCin == 0) {
            return 0;
        }
        DepositFeeCalc memory vars;
        // active pool total VC at current state.
        vars.systemTotalVC = _contractsCache.activePool.getVC().add(
            defaultPool.getVC()
        );
        // active pool total VC post adding and removing all collaterals
        uint256 activePoolVCPost = vars.systemTotalVC.add(_VCin).sub(_VCout);
        uint256 whitelistFee;

        for (uint256 i = 0; i < _tokensIn.length; i++) {
            vars.token = _tokensIn[i];
            // VC value of collateral of this type inputted
            vars.collateralInputVC = whitelist.getValueVC(vars.token, _amountsIn[i]);

            // total value in VC of this collateral in active pool (post adding input)
            vars.systemCollateralVC = _contractsCache.activePool.getCollateralVC(vars.token).add(
                defaultPool.getCollateralVC(vars.token)
            );

            // (collateral VC In) * (Collateral's Fee Given Yeti Protocol Backed by Given Collateral)
            whitelistFee = 
                    whitelist.getFeeAndUpdate(
                        vars.token,
                        vars.collateralInputVC,
                        vars.systemCollateralVC,
                        vars.systemTotalVC,
                        activePoolVCPost
                    );
            if (_isBeforeFeeBootstrapPeriod()) {
                whitelistFee = _min(whitelistFee, 1e16); // cap at 1%
            } 
            vars.collateralYUSDFee = vars.collateralInputVC
                .mul(whitelistFee).div(1e18);

            YUSDFee = YUSDFee.add(vars.collateralYUSDFee);
        }
        _requireUserAcceptsFee(YUSDFee, _maxFeePercentageFactor, _maxFeePercentage);
        _triggerDepositFee(_contractsCache.yusdToken, YUSDFee);
        return YUSDFee;
    }

    // Transfer in collateral and send to ActivePool
    // (where collateral is held)
    function _transferCollateralsIntoActivePool(
        address _from,
        address[] memory _colls,
        uint256[] memory _amounts
    ) internal returns (bool) {
        uint256 len = _amounts.length;
        for (uint256 i = 0; i < len; i++) {
            address collAddress = _colls[i];
            uint256 amount = _amounts[i];
            bool transferredToActivePool = _singleTransferCollateralIntoActivePool(
                _from,
                collAddress,
                amount
            );
            if (!transferredToActivePool) {
                return false;
            }
        }
        return true;
    }

    function _singleTransferCollateralIntoActivePool(
        address _from,
        address _coll,
        uint256 _amount
    ) internal returns (bool) {
        IERC20 coll = IERC20(_coll);
        bool transferredToActivePool = coll.transferFrom(_from, address(activePool), _amount);
        return transferredToActivePool;
    }

    /**
     * Triggers normal borrowing fee, calculated from base rate and on YUSD amount.
     */
    function _triggerBorrowingFee(
        ITroveManager _troveManager,
        IYUSDToken _yusdToken,
        uint256 _YUSDAmount,
        uint256 _maxFeePercentageFactor,
        uint256 _maxFeePercentage
    ) internal returns (uint256) {
        _troveManager.decayBaseRateFromBorrowing(); // decay the baseRate state variable
        uint256 YUSDFee = _troveManager.getBorrowingFee(_YUSDAmount);

        _requireUserAcceptsFee(YUSDFee, _maxFeePercentageFactor, _maxFeePercentage);

        // Send fee to sYETI contract
        _yusdToken.mint(sYETIAddress, YUSDFee);
        return YUSDFee;
    }

    function _triggerDepositFee(IYUSDToken _yusdToken, uint256 _YUSDFee) internal {
        // Send fee to sYETI contract
        _yusdToken.mint(sYETIAddress, _YUSDFee);
    }

    // Update trove's coll and debt based on whether they increase or decrease
    function _updateTroveFromAdjustment(
        ITroveManager _troveManager,
        address _borrower,
        address[] memory _finalColls,
        uint256[] memory _finalAmounts,
        uint256 _newVC,
        uint256 _debtChange,
        bool _isDebtIncrease, 
        uint256 _variableYUSDFee
    ) internal returns (uint256, uint256) {
        uint256 newDebt;
        _troveManager.updateTroveColl(_borrower, _finalColls, _finalAmounts);
        if (_isDebtIncrease) { // if debt increase, increase by both amounts
           newDebt = _troveManager.increaseTroveDebt(_borrower, _debtChange.add(_variableYUSDFee));
        } else {
            if (_debtChange > _variableYUSDFee) { // if debt decrease, and greater than variable fee, decrease 
                newDebt = _troveManager.decreaseTroveDebt(_borrower, _debtChange.sub(_variableYUSDFee));
            } else { // otherwise increase by opposite subtraction
                newDebt = _troveManager.increaseTroveDebt(_borrower, _variableYUSDFee.sub(_debtChange));
            }
        }

        return (_newVC, newDebt);
    }

    // gets the finalColls and finalAmounts after all deposits and withdrawals have been made
    // this function will error if trying to deposit a collateral that is not in the whitelist
    // or trying to withdraw more collateral of any type that is not in the trove
    function _getNewPortfolio(
        address[] memory _initialTokens,
        uint256[] memory _initialAmounts,
        address[] memory _tokensIn,
        uint256[] memory _amountsIn,
        address[] memory _tokensOut,
        uint256[] memory _amountsOut
    ) internal view returns (address[] memory finalColls, uint256[] memory finalAmounts) {
        _requireValidDepositCollateral(_tokensIn, _amountsIn);
        _requireValidDepositCollateral(_tokensOut, _amountsOut);

        // Initial Colls + Input Colls
        newColls memory cumulativeIn = _sumColls(
            _initialTokens,
            _initialAmounts,
            _tokensIn,
            _amountsIn
        );

        newColls memory newPortfolio = _subColls(cumulativeIn, _tokensOut, _amountsOut);
        return (newPortfolio.tokens, newPortfolio.amounts);
    }

    // Moves the YUSD around based on whether it is an increase or decrease in debt.
    function _moveYUSD(
        IActivePool _activePool,
        IYUSDToken _yusdToken,
        address _borrower,
        uint256 _YUSDChange,
        bool _isDebtIncrease,
        uint256 _netDebtChange
    ) internal {
        if (_isDebtIncrease) {
            _withdrawYUSD(_activePool, _yusdToken, _borrower, _YUSDChange, _netDebtChange);
        } else {
            _repayYUSD(_activePool, _yusdToken, _borrower, _YUSDChange);
        }
    }

    // Issue the specified amount of YUSD to _account and increases the total active debt (_netDebtIncrease potentially includes a YUSDFee)
    function _withdrawYUSD(
        IActivePool _activePool,
        IYUSDToken _yusdToken,
        address _account,
        uint256 _YUSDAmount,
        uint256 _netDebtIncrease
    ) internal {
        _activePool.increaseYUSDDebt(_netDebtIncrease);
        _yusdToken.mint(_account, _YUSDAmount);
    }

    // Burn the specified amount of YUSD from _account and decreases the total active debt
    function _repayYUSD(
        IActivePool _activePool,
        IYUSDToken _yusdToken,
        address _account,
        uint256 _YUSD
    ) internal {
        _activePool.decreaseYUSDDebt(_YUSD);
        _yusdToken.burn(_account, _YUSD);
    }

    // --- 'Require' wrapper functions ---

    function _requireValidDepositCollateral(address[] memory _colls, uint256[] memory _amounts) internal view {
        require(
            _colls.length == _amounts.length,
            "Length of collateral arrays must be equal"
        );
        for (uint256 i = 0; i < _colls.length; i++) {
            require(whitelist.getIsActive(_colls[i]), "BOps: Collateral not in whitelist");
            require(_amounts[i] > 0, "BOps: Collateral amount must be greater than 0");
        }
    }

    function _requireNonZeroAdjustment(
        uint256[] memory _amountsIn,
        uint256[] memory _amountsOut,
        uint256 _YUSDChange
    ) internal pure {
        require(
            _arrayIsNonzero(_amountsIn) || _arrayIsNonzero(_amountsOut) || _YUSDChange != 0,
            "BorrowerOps: There must be either a collateral change or a debt change"
        );
    }

    function _arrayIsNonzero(uint256[] memory arr) internal pure returns (bool) {
        for (uint256 i = 0; i < arr.length; i++) {
            if (arr[i] != 0) {
                return true;
            }
        }
        return false;
    }

    function _isBeforeFeeBootstrapPeriod() internal view returns (bool) {
        return block.timestamp < deploymentTime.add(BOOTSTRAP_PERIOD);
    }

    function _requireTroveisActive(ITroveManager _troveManager, address _borrower) internal view {
        require(_troveManager.isTroveActive(_borrower), "BorrowerOps: Trove does not exist or is closed");
    }

    function _requireTroveisNotActive(ITroveManager _troveManager, address _borrower) internal view {
        require(!_troveManager.isTroveActive(_borrower), "BorrowerOps: Trove is active");
    }

    function _requireNonZeroDebtChange(uint256 _YUSDChange) internal pure {
        require(_YUSDChange > 0, "BorrowerOps: Debt increase requires non-zero debtChange");
    }

    function _requireNoOverlapColls(address[] memory _colls1, address[] memory _colls2)
        internal
        pure
    {
        for (uint256 i = 0; i < _colls1.length; i++) {
            for (uint256 j = 0; j < _colls2.length; j++) {
                require(_colls1[i] != _colls2[j], "BorrowerOps: Collateral passed in overlaps");
            }
        }
    }


    function _requireNoDuplicateColls(address[] memory _colls) internal pure {
        for (uint256 i = 0; i < _colls.length; i++) {
            for (uint256 j = i + 1; j < _colls.length; j++) {
                require(_colls[i] != _colls[j], "BorrowerOps: Collateral passed in overlaps");
            }
        }
    }

    function _requireNotInRecoveryMode() internal view {
        require(!_checkRecoveryMode(), "BorrowerOps: Operation not permitted during Recovery Mode");
    }

    function _requireNoCollWithdrawal(uint256[] memory _amountOut) internal pure {
        require(
            !_arrayIsNonzero(_amountOut),
            "BorrowerOps: Collateral withdrawal not permitted Recovery Mode"
        );
    }

    function _requireValidAdjustmentInCurrentMode(
        bool _isRecoveryMode,
        uint256[] memory _collWithdrawal,
        bool _isDebtIncrease,
        LocalVariables_adjustTrove memory _vars
    ) internal view {
        /*
         *In Recovery Mode, only allow:
         *
         * - Pure collateral top-up
         * - Pure debt repayment
         * - Collateral top-up with debt repayment
         * - A debt increase combined with a collateral top-up which makes the ICR >= 150% and improves the ICR (and by extension improves the TCR).
         *
         * In Normal Mode, ensure:
         *
         * - The new ICR is above MCR
         * - The adjustment won't pull the TCR below CCR
         */
        if (_isRecoveryMode) {
            _requireNoCollWithdrawal(_collWithdrawal);
            if (_isDebtIncrease) {
                _requireICRisAboveCCR(_vars.newICR);
                _requireNewICRisAboveOldICR(_vars.newICR, _vars.oldICR);
            }
        } else {
            // if Normal Mode
            _requireICRisAboveMCR(_vars.newICR);
            _vars.newTCR = _getNewTCRFromTroveChange(
                _vars.collChange,
                _vars.isCollIncrease,
                _vars.netDebtChange,
                _isDebtIncrease
            );
            _requireNewTCRisAboveCCR(_vars.newTCR);
        }
    }

    function _requireICRisAboveMCR(uint256 _newICR) internal pure {
        require(
            _newICR >= MCR,
            "BorrowerOps: An operation that would result in ICR < MCR is not permitted"
        );
    }

    function _requireICRisAboveCCR(uint256 _newICR) internal pure {
        require(_newICR >= CCR, "BorrowerOps: Operation must leave trove with ICR >= CCR");
    }

    function _requireNewICRisAboveOldICR(uint256 _newICR, uint256 _oldICR) internal pure {
        require(
            _newICR >= _oldICR,
            "BorrowerOps: Cannot decrease your Trove's ICR in Recovery Mode"
        );
    }

    function _requireNewTCRisAboveCCR(uint256 _newTCR) internal pure {
        require(
            _newTCR >= CCR,
            "BorrowerOps: An operation that would result in TCR < CCR is not permitted"
        );
    }

    function _requireAtLeastMinNetDebt(uint256 _netDebt) internal pure {
        require(
            _netDebt >= MIN_NET_DEBT,
            "BorrowerOps: Trove's net debt must be greater than minimum"
        );
    }

    function _requireValidYUSDRepayment(uint256 _currentDebt, uint256 _debtRepayment) internal pure {
        require(
            _debtRepayment <= _currentDebt.sub(YUSD_GAS_COMPENSATION),
            "BorrowerOps: Amount repaid must not be larger than the Trove's debt"
        );
    }

    function _requireSufficientYUSDBalance(
        IYUSDToken _yusdToken,
        address _borrower,
        uint256 _debtRepayment
    ) internal view {
        require(
            _yusdToken.balanceOf(_borrower) >= _debtRepayment,
            "BorrowerOps: Caller doesnt have enough YUSD to make repayment"
        );
    }

    function _requireValidMaxFeePercentage(uint256 _maxFeePercentage, bool _isRecoveryMode)
        internal
        pure
    {
        if (_isRecoveryMode) {
            require(
                _maxFeePercentage <= DECIMAL_PRECISION,
                "Max fee percentage must less than or equal to 100%"
            );
        } else {
            require(
                _maxFeePercentage >= BORROWING_FEE_FLOOR && _maxFeePercentage <= DECIMAL_PRECISION,
                "Max fee percentage must be between 0.5% and 100%"
            );
        }
    }

    // checks lengths are all good and that all passed in routers are valid routers
    function _requireValidRouterParams(
        address[] memory _finalRoutedColls,
        uint[] memory _amounts,
        uint[] memory _minSwapAmounts,
        IYetiRouter[] memory _routers) internal view {
        require(_finalRoutedColls.length == _amounts.length);
        require(_amounts.length == _routers.length);
        require(_amounts.length == _minSwapAmounts.length);
        for (uint i = 0; i < _routers.length; i++) {
            require(whitelist.isValidRouter(address(_routers[i])));
        }
    }

    // requires that avax indices are in order
    function _requireRouterAVAXIndicesInOrder(uint[] memory _indices) internal pure {
        for (uint i = 0; i < _indices.length - 1; i++) {
            require(_indices[i] < _indices[i + 1]);
        }
    }


    // --- ICR and TCR getters ---

    // Compute the new collateral ratio, considering the change in coll and debt. Assumes 0 pending rewards.
    function _getNewICRFromTroveChange(
        uint256 _newVC,
        uint256 _debt,
        uint256 _debtChange,
        bool _isDebtIncrease
    ) internal pure returns (uint256) {
        uint256 newDebt = _isDebtIncrease ? _debt.add(_debtChange) : _debt.sub(_debtChange);

        uint256 newICR = LiquityMath._computeCR(_newVC, newDebt);
        return newICR;
    }

    function _getNewTCRFromTroveChange(
        uint256 _collChange,
        bool _isCollIncrease,
        uint256 _debtChange,
        bool _isDebtIncrease
    ) internal view returns (uint256) {
        uint256 totalColl = getEntireSystemColl();
        uint256 totalDebt = getEntireSystemDebt();

        totalColl = _isCollIncrease ? totalColl.add(_collChange) : totalColl.sub(_collChange);
        totalDebt = _isDebtIncrease ? totalDebt.add(_debtChange) : totalDebt.sub(_debtChange);

        uint256 newTCR = LiquityMath._computeCR(totalColl, totalDebt);
        return newTCR;
    }

    function getCompositeDebt(uint256 _debt) external pure override returns (uint256) {
        return _getCompositeDebt(_debt);
    }

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

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

File 2 of 26 : IBorrowerOperations.sol
// SPDX-License-Identifier: UNLICENSED

pragma solidity 0.6.11;

// Common interface for the Trove Manager.
interface IBorrowerOperations {

    // --- Events ---

    event TroveManagerAddressChanged(address _newTroveManagerAddress);
    event ActivePoolAddressChanged(address _activePoolAddress);
    event DefaultPoolAddressChanged(address _defaultPoolAddress);
    event StabilityPoolAddressChanged(address _stabilityPoolAddress);
    event GasPoolAddressChanged(address _gasPoolAddress);
    event CollSurplusPoolAddressChanged(address _collSurplusPoolAddress);
    event PriceFeedAddressChanged(address  _newPriceFeedAddress);
    event SortedTrovesAddressChanged(address _sortedTrovesAddress);
    event YUSDTokenAddressChanged(address _yusdTokenAddress);
    event SYETIAddressChanged(address _sYETIAddress);

    event TroveCreated(address indexed _borrower, uint arrayIndex);
    event TroveUpdated(address indexed _borrower, uint _debt, uint _coll, uint8 operation);
    event YUSDBorrowingFeePaid(address indexed _borrower, uint _YUSDFee);

    // --- Functions ---

    function setAddresses(
        address _troveManagerAddress,
        address _activePoolAddress,
        address _defaultPoolAddress,
        address _stabilityPoolAddress,
        address _gasPoolAddress,
        address _collSurplusPoolAddress,
        address _sortedTrovesAddress,
        address _yusdTokenAddress,
        address _sYETIAddress,
        address _whiteListAddress
    ) external;

    function openTrove(uint _maxFeePercentage, uint _YUSDAmount, address _upperHint,
        address _lowerHint,
        address[] calldata _colls,
        uint[] calldata _amounts) external;

    //     function openTroveLeverUp(
    //     uint256 _maxFeePercentage,
    //     uint256 _YUSDAmount,
    //     address _upperHint,
    //     address _lowerHint,
    //     address[] memory _colls,
    //     uint256[] memory _amounts, 
    //     uint256[] memory _leverages,
    //     uint256[] memory _maxSlippages
    // ) external;

    // function closeTroveUnlever(
    //     address[] memory _collsOut,
    //     uint256[] memory _amountsOut,
    //     uint256[] memory _maxSlippages
    // ) external;

    function closeTrove() external;

    function adjustTrove(
        address[] calldata _collsIn,
        uint[] calldata _amountsIn,
        address[] calldata _collsOut,
        uint[] calldata _amountsOut,
        uint _YUSDChange,
        bool _isDebtIncrease,
        address _upperHint,
        address _lowerHint,
        uint _maxFeePercentage) external;

    function addColl(address[] memory _collsIn, uint[] memory _amountsIn, address _upperHint, address _lowerHint, uint _maxFeePercentage) external;

    // function addCollLeverUp(
    //     address[] memory _collsIn,
    //     uint256[] memory _amountsIn,
    //     uint256[] memory _leverages,
    //     uint256[] memory _maxSlippages,
    //     uint256 _YUSDAmount,
    //     address _upperHint,
    //     address _lowerHint, 
    //     uint256 _maxFeePercentage
    // ) external;

    function withdrawColl(address[] memory _collsOut, uint[] memory _amountsOut, address _upperHint, address _lowerHint) external;

    // function withdrawCollUnleverUp(
    //     address[] memory _collsOut,
    //     uint256[] memory _amountsOut,
    //     uint256[] memory _maxSlippages,
    //     uint256 _YUSDAmount,
    //     address _upperHint,
    //     address _lowerHint
    // ) external;

    function withdrawYUSD(uint _maxFeePercentage, uint _YUSDAmount, address _upperHint, address _lowerHint) external;

    function repayYUSD(uint _YUSDAmount, address _upperHint, address _lowerHint) external;

    function claimCollateral() external;

    function getCompositeDebt(uint _debt) external pure returns (uint);
}

File 3 of 26 : ITroveManager.sol
// SPDX-License-Identifier: UNLICENSED

pragma solidity 0.6.11;

import "./ILiquityBase.sol";
import "./IStabilityPool.sol";
import "./IYUSDToken.sol";
import "./IYETIToken.sol";
import "./ISYETI.sol";
import "./IActivePool.sol";
import "./IDefaultPool.sol";


// Common interface for the Trove Manager.
interface ITroveManager is ILiquityBase {

    // --- Events ---

    event BorrowerOperationsAddressChanged(address _newBorrowerOperationsAddress);
    event PriceFeedAddressChanged(address _newPriceFeedAddress);
    event YUSDTokenAddressChanged(address _newYUSDTokenAddress);
    event ActivePoolAddressChanged(address _activePoolAddress);
    event DefaultPoolAddressChanged(address _defaultPoolAddress);
    event StabilityPoolAddressChanged(address _stabilityPoolAddress);
    event GasPoolAddressChanged(address _gasPoolAddress);
    event CollSurplusPoolAddressChanged(address _collSurplusPoolAddress);
    event SortedTrovesAddressChanged(address _sortedTrovesAddress);
    event YETITokenAddressChanged(address _yetiTokenAddress);
    event SYETIAddressChanged(address _sYETIAddress);

    event Liquidation(uint liquidatedAmount, uint totalYUSDGasCompensation, 
        address[] totalCollTokens, uint[] totalCollAmounts,
        address[] totalCollGasCompTokens, uint[] totalCollGasCompAmounts);
    event Redemption(uint _attemptedYUSDAmount, uint _actualYUSDAmount, uint YUSDfee, address[] tokens, uint[] amounts);
    event TroveLiquidated(address indexed _borrower, uint _debt, uint _coll, uint8 operation);
    event BaseRateUpdated(uint _baseRate);
    event LastFeeOpTimeUpdated(uint _lastFeeOpTime);
    event TotalStakesUpdated(address token, uint _newTotalStakes);
    event SystemSnapshotsUpdated(uint _totalStakesSnapshot, uint _totalCollateralSnapshot);
    event LTermsUpdated(uint _L_ETH, uint _L_YUSDDebt);
    event TroveSnapshotsUpdated(uint _L_ETH, uint _L_YUSDDebt);
    event TroveIndexUpdated(address _borrower, uint _newIndex);

    // --- Functions ---

    function setAddresses(
        address _borrowerOperationsAddress,
        address _activePoolAddress,
        address _defaultPoolAddress,
        address _stabilityPoolAddress,
        address _gasPoolAddress,
        address _collSurplusPoolAddress,
        address _yusdTokenAddress,
        address _sortedTrovesAddress,
        address _yetiTokenAddress,
        address _sYETIAddress,
        address _whitelistAddress,
        address _troveManagerRedemptionsAddress,
        address _troveManagerLiquidationsAddress
    )
    external;

    function stabilityPool() external view returns (IStabilityPool);
    function yusdToken() external view returns (IYUSDToken);
    function yetiToken() external view returns (IYETIToken);
    function sYETI() external view returns (ISYETI);

    function getTroveOwnersCount() external view returns (uint);

    function getTroveFromTroveOwnersArray(uint _index) external view returns (address);

    function getCurrentICR(address _borrower) external view returns (uint);

    function liquidate(address _borrower) external;

    function batchLiquidateTroves(address[] calldata _troveArray, address _liquidator) external;

    function redeemCollateral(
        uint _YUSDAmount,
        uint _YUSDMaxFee,
        address _firstRedemptionHint,
        address _upperPartialRedemptionHint,
        address _lowerPartialRedemptionHint,
        uint _partialRedemptionHintNICR,
        uint _maxIterations
    ) external;

    function updateStakeAndTotalStakes(address _borrower) external;

    function updateTroveCollTMR(address  _borrower, address[] memory addresses, uint[] memory amounts) external;

    function updateTroveRewardSnapshots(address _borrower) external;

    function addTroveOwnerToArray(address _borrower) external returns (uint index);

    function applyPendingRewards(address _borrower) external;

//    function getPendingETHReward(address _borrower) external view returns (uint);
    function getPendingCollRewards(address _borrower) external view returns (address[] memory, uint[] memory);

    function getPendingYUSDDebtReward(address _borrower) external view returns (uint);

     function hasPendingRewards(address _borrower) external view returns (bool);

//    function getEntireDebtAndColl(address _borrower) external view returns (
//        uint debt,
//        uint coll,
//        uint pendingYUSDDebtReward,
//        uint pendingETHReward
//    );

    function closeTrove(address _borrower) external;

    function removeStake(address _borrower) external;

    function removeStakeTMR(address _borrower) external;
    function updateTroveDebt(address _borrower, uint debt) external;

    function getRedemptionRate() external view returns (uint);
    function getRedemptionRateWithDecay() external view returns (uint);

    function getRedemptionFeeWithDecay(uint _ETHDrawn) external view returns (uint);

    function getBorrowingRate() external view returns (uint);
    function getBorrowingRateWithDecay() external view returns (uint);

    function getBorrowingFee(uint YUSDDebt) external view returns (uint);
    function getBorrowingFeeWithDecay(uint _YUSDDebt) external view returns (uint);

    function decayBaseRateFromBorrowing() external;

    function getTroveStatus(address _borrower) external view returns (uint);

    function isTroveActive(address _borrower) external view returns (bool);

    function getTroveStake(address _borrower, address _token) external view returns (uint);

    function getTotalStake(address _token) external view returns (uint);

    function getTroveDebt(address _borrower) external view returns (uint);

    function getL_Coll(address _token) external view returns (uint);

    function getL_YUSD(address _token) external view returns (uint);

    function getRewardSnapshotColl(address _borrower, address _token) external view returns (uint);

    function getRewardSnapshotYUSD(address _borrower, address _token) external view returns (uint);

    // returns the VC value of a trove
    function getTroveVC(address _borrower) external view returns (uint);

    function getTroveColls(address _borrower) external view returns (address[] memory, uint[] memory);

    function getCurrentTroveState(address _borrower) external view returns (address[] memory, uint[] memory, uint);

    function setTroveStatus(address _borrower, uint num) external;

    function updateTroveColl(address _borrower, address[] memory _tokens, uint[] memory _amounts) external;

    function increaseTroveDebt(address _borrower, uint _debtIncrease) external returns (uint);

    function decreaseTroveDebt(address _borrower, uint _collDecrease) external returns (uint);

    function getTCR() external view returns (uint);

    function checkRecoveryMode() external view returns (bool);

    function closeTroveRedemption(address _borrower) external;

    function closeTroveLiquidation(address _borrower) external;

    function removeStakeTLR(address _borrower) external;

    function updateBaseRate(uint newBaseRate) external;

    function calcDecayedBaseRate() external view returns (uint);

    function redistributeDebtAndColl(IActivePool _activePool, IDefaultPool _defaultPool, uint _debt, address[] memory _tokens, uint[] memory _amounts) external;

    function updateSystemSnapshots_excludeCollRemainder(IActivePool _activePool, address[] memory _tokens, uint[] memory _amounts) external;

    function getEntireDebtAndColls(address _borrower) external view
    returns (uint, address[] memory, uint[] memory, uint, address[] memory, uint[] memory);

    function movePendingTroveRewardsToActivePool(IActivePool _activePool, IDefaultPool _defaultPool, uint _YUSD, address[] memory _tokens, uint[] memory _amounts, address _borrower) external;

    function collSurplusUpdate(address _account, address[] memory _tokens, uint[] memory _amounts) external;

}

File 4 of 26 : IYUSDToken.sol
// SPDX-License-Identifier: UNLICENSED

pragma solidity 0.6.11;

import "../Interfaces/IERC20.sol";
import "../Interfaces/IERC2612.sol";

interface IYUSDToken is IERC20, IERC2612 {
    
    // --- Events ---

    event TroveManagerAddressChanged(address _troveManagerAddress);
    event StabilityPoolAddressChanged(address _newStabilityPoolAddress);
    event BorrowerOperationsAddressChanged(address _newBorrowerOperationsAddress);

    event YUSDTokenBalanceUpdated(address _user, uint _amount);

    // --- Functions ---

    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;
}

File 5 of 26 : ICollSurplusPool.sol
// SPDX-License-Identifier: UNLICENSED

pragma solidity 0.6.11;

import "../Dependencies/YetiCustomBase.sol";
import "./ICollateralReceiver.sol";


interface ICollSurplusPool is ICollateralReceiver {

    // --- Events ---
    
    event BorrowerOperationsAddressChanged(address _newBorrowerOperationsAddress);
    event TroveManagerAddressChanged(address _newTroveManagerAddress);
    event ActivePoolAddressChanged(address _newActivePoolAddress);

    event CollBalanceUpdated(address indexed _account);
    event CollateralSent(address _to);

    // --- Contract setters ---

    function setAddresses(
        address _borrowerOperationsAddress,
        address _troveManagerAddress,
        address _troveManagerRedemptionsAddress,
        address _activePoolAddress,
        address _whitelistAddress
    ) external;

    function getCollVC() external view returns (uint);

    function getAmountClaimable(address _account, address _collateral) external view returns (uint);

    function getCollateral(address _collateral) external view returns (uint);

    function getAllCollateral() external view returns (address[] memory, uint256[] memory);

    function accountSurplus(address _account, address[] memory _tokens, uint[] memory _amounts) external;

    function claimColl(address _account) external;

    function addCollateralType(address _collateral) external;
}

File 6 of 26 : ISortedTroves.sol
// SPDX-License-Identifier: UNLICENSED

pragma solidity 0.6.11;

// Common interface for the SortedTroves Doubly Linked List.
interface ISortedTroves {

    // --- Events ---
    
    event SortedTrovesAddressChanged(address _sortedDoublyLLAddress);
    event BorrowerOperationsAddressChanged(address _borrowerOperationsAddress);
    event NodeAdded(address _id, uint _NICR);
    event NodeRemoved(address _id);

    // --- Functions ---
    
    function setParams(uint256 _size, address _TroveManagerAddress, address _borrowerOperationsAddress, address _troveManagerRedemptionsAddress) external;

    function insert(address _id, uint256 _ICR, address _prevId, address _nextId) external;

    function remove(address _id) external;

    function reInsert(address _id, uint256 _newICR, address _prevId, address _nextId) external;

    function contains(address _id) external view returns (bool);

    function isFull() external view returns (bool);

    function isEmpty() external view returns (bool);

    function getSize() external view returns (uint256);

    function getMaxSize() external view returns (uint256);

    function getFirst() external view returns (address);

    function getLast() external view returns (address);

    function getNext(address _id) external view returns (address);

    function getPrev(address _id) external view returns (address);

    function getOldICR(address _id) external view returns (uint256);

    function validInsertPosition(uint256 _ICR, address _prevId, address _nextId) external view returns (bool);

    function findInsertPosition(uint256 _ICR, address _prevId, address _nextId) external view returns (address, address);
}

File 7 of 26 : ISYETI.sol
// SPDX-License-Identifier: UNLICENSED

pragma solidity 0.6.11;

interface ISYETI {
    /**
     * @dev Returns the amount of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns the amount of tokens owned by `account`.
     */
    function balanceOf(address account) external view returns (uint256);

    /**
     * @dev Moves `amount` tokens from the caller's account to `recipient`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address recipient, uint256 amount) external returns (bool);

    /**
     * @dev Returns the remaining number of tokens that `spender` will be
     * allowed to spend on behalf of `owner` through {transferFrom}. This is
     * zero by default.
     *
     * This value changes when {approve} or {transferFrom} are called.
     */
    function allowance(address owner, address spender) external view returns (uint256);
    function increaseAllowance(address spender, uint256 addedValue) external returns (bool);
    function decreaseAllowance(address spender, uint256 subtractedValue) external returns (bool);

    /**
     * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * IMPORTANT: Beware that changing an allowance with this method brings the risk
     * that someone may use both the old and the new allowance by unfortunate
     * transaction ordering. One possible solution to mitigate this race
     * condition is to first reduce the spender's allowance to 0 and set the
     * desired value afterwards:
     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
     *
     * Emits an {Approval} event.
     */
    function approve(address spender, uint256 amount) external returns (bool);

    /**
     * @dev Moves `amount` tokens from `sender` to `recipient` using the
     * allowance mechanism. `amount` is then deducted from the caller's
     * allowance.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);

    function name() external view returns (string memory);
    function symbol() external view returns (string memory);
    function decimals() external view returns (uint8);

    function mint(uint256 amount) external returns (bool);
    function burn(address to, uint256 shares) external returns (bool);

    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

    /**
     * @dev Emitted when the allowance of a `spender` for an `owner` is set by
     * a call to {approve}. `value` is the new allowance.
     */
    event Approval(address indexed owner, address indexed spender, uint256 value);
}

File 8 of 26 : IWhitelist.sol
// SPDX-License-Identifier: UNLICENSED

pragma solidity 0.6.11;


interface IWhitelist {
    function getValidCollateral() view external returns (address[] memory);

    function setAddresses(
        address _activePoolAddress,
        address _defaultPoolAddress,
        address _stabilityPoolAddress,
        address _collSurplusPoolAddress, 
        address _borrowerOperationsAddress
    ) external;

    function isValidRouter(address _router) external view returns (bool);
    function getOracle(address _collateral) view external returns (address);
    function getRatio(address _collateral) view external returns (uint256);
    function getIsActive(address _collateral) view external returns (bool);
    function getPriceCurve(address _collateral) external view returns (address);
    function getDecimals(address _collateral) external view returns (uint256);
    function getFee(address _collateral, uint _collateralVCInput, uint256 _collateralVCBalancePost, uint256 _totalVCBalancePre, uint256 _totalVCBalancePost) external view returns (uint256 fee);
    function getFeeAndUpdate(address _collateral, uint _collateralVCInput, uint256 _collateralVCBalancePost, uint256 _totalVCBalancePre, uint256 _totalVCBalancePost) external returns (uint256 fee);
    function getIndex(address _collateral) external view returns (uint256);
    function isWrapped(address _collateral) external view returns (bool);
    function setDefaultRouter(address _collateral, address _router) external;

    function getValueVC(address _collateral, uint _amount) view external returns (uint);
    function getValueUSD(address _collateral, uint _amount) view external returns (uint256);
    function getDefaultRouterAddress(address _collateral) external view returns (address);
}

File 9 of 26 : IYetiRouter.sol
// SPDX-License-Identifier: UNLICENSED

pragma solidity 0.6.11;

// Interface which handles routing of tokens to between wrapped versions etc and YUSD or other ERC20s. 
interface IYetiRouter {

    // Goes from some token (YUSD likely) and gives a certain amount of token out.
    // Auto transfers to active pool. 
    // Goes from _startingTokenAddress to _endingTokenAddress, pulling tokens from _fromUser, of _amount, and gets _minSwapAmount out _endingTokenAddress
    function route(address _fromUser, address _startingTokenAddress, address _endingTokenAddress, uint _amount, uint _minSwapAmount) external returns (uint256 _amountOut);

    // Takes the address of the token required in, and gives a certain amount of any token (YUSD likely) out
    // User first withdraws that collateral from the active pool, then performs this swap. Unwraps tokens
    // for the user in that case. 
    // Goes from _startingTokenAddress to _endingTokenAddress, pulling tokens from _fromUser, of _amount, and gets _minSwapAmount out _endingTokenAddress. 
    // Use case: Takes token from trove debt which has been transfered to the owner and then swaps it for YUSD, intended to repay debt. 
    function unRoute(address _fromUser, address _startingTokenAddress, address _endingTokenAddress, uint _amount, uint _minSwapAmount) external returns (uint256 _amountOut);
}

File 10 of 26 : LiquityBase.sol
// SPDX-License-Identifier: UNLICENSED

pragma solidity 0.6.11;

import "./LiquityMath.sol";
import "../Interfaces/IActivePool.sol";
import "../Interfaces/IDefaultPool.sol";
import "../Interfaces/ILiquityBase.sol";
import "../Interfaces/IWhitelist.sol";
import "./YetiCustomBase.sol";


/* 
* Base contract for TroveManager, BorrowerOperations and StabilityPool. Contains global system constants and
* common functions. 
*/
contract LiquityBase is ILiquityBase, YetiCustomBase {

    uint constant public _100pct = 1000000000000000000; // 1e18 == 100%

    uint constant public _110pct = 1100000000000000000; // 1.1e18 == 110%

    // Minimum collateral ratio for individual troves
    uint constant public MCR = 1100000000000000000; // 110%

    // Critical system collateral ratio. If the system's total collateral ratio (TCR) falls below the CCR, Recovery Mode is triggered.
    uint constant public CCR = 1500000000000000000; // 150%

    // Amount of YUSD to be locked in gas pool on opening troves
    uint constant public YUSD_GAS_COMPENSATION = 200e18;

    // Minimum amount of net YUSD debt a must have
    uint constant public MIN_NET_DEBT = 1800e18;
    // uint constant public MIN_NET_DEBT = 0; 

    uint constant public PERCENT_DIVISOR = 200; // dividing by 200 yields 0.5%

    uint constant public BORROWING_FEE_FLOOR = DECIMAL_PRECISION / 1000 * 5; // 0.5%
    uint constant public REDEMPTION_FEE_FLOOR = DECIMAL_PRECISION / 1000 * 5; // 0.5%

    IActivePool public activePool;

    IDefaultPool public defaultPool;

    // --- Gas compensation functions ---

    // Returns the composite debt (drawn debt + gas compensation) of a trove, for the purpose of ICR calculation
    function _getCompositeDebt(uint _debt) internal pure returns (uint) {
        return _debt.add(YUSD_GAS_COMPENSATION);
    }


    function _getNetDebt(uint _debt) internal pure returns (uint) {
        return _debt.sub(YUSD_GAS_COMPENSATION);
    }


    // Return the amount of collateral to be drawn from a trove's collateral and sent as gas compensation.
    function _getCollGasCompensation(newColls memory _coll) internal pure returns (newColls memory) {
        require(_coll.tokens.length == _coll.amounts.length, "_getCollGasCompensation(): Collateral length mismatch");

        uint[] memory amounts = new uint[](_coll.tokens.length);
        for (uint i = 0; i < _coll.tokens.length; i++) {
            amounts[i] = _coll.amounts[i] / PERCENT_DIVISOR;
        }
        return newColls(_coll.tokens, amounts);
    }

    // Return the system's Total Virtual Coin Balance
    // Virtual Coins are a way to keep track of the system collateralization given
    // the collateral ratios of each collateral type
    function getEntireSystemColl() public view returns (uint entireSystemColl) {
        uint activeColl = activePool.getVC();
        uint liquidatedColl = defaultPool.getVC();

        return activeColl.add(liquidatedColl);
    }


    function getEntireSystemDebt() public override view returns (uint entireSystemDebt) {
        uint activeDebt = activePool.getYUSDDebt();
        uint closedDebt = defaultPool.getYUSDDebt();

        return activeDebt.add(closedDebt);
    }


    function _getICRColls(newColls memory _colls, uint _debt) internal view returns (uint ICR) {
        uint totalVC = _getVCColls(_colls);
        ICR = LiquityMath._computeCR(totalVC, _debt);
        return ICR;
    }


    function _getVC(address[] memory _tokens, uint[] memory _amounts) internal view returns (uint totalVC) {
        require(_tokens.length == _amounts.length, "Not same length");
        for (uint i = 0; i < _tokens.length; i++) {
            uint tokenVC = whitelist.getValueVC(_tokens[i], _amounts[i]);
            totalVC = totalVC.add(tokenVC);
        }
        return totalVC;
    }


    function _getVCColls(newColls memory _colls) internal view returns (uint VC) {
        for (uint i = 0; i < _colls.tokens.length; i++) {
            uint valueVC = whitelist.getValueVC(_colls.tokens[i], _colls.amounts[i]);
            VC = VC.add(valueVC);
        }
        return VC;
    }


    function _getUSDColls(newColls memory _colls) internal view returns (uint USDValue) {
        for (uint i = 0; i < _colls.tokens.length; i++) {
            uint valueUSD = whitelist.getValueUSD(_colls.tokens[i], _colls.amounts[i]);
            USDValue = USDValue.add(valueUSD);
        }
        return USDValue;
    }


    function _getTCR() internal view returns (uint TCR) {
        uint entireSystemColl = getEntireSystemColl();
        uint entireSystemDebt = getEntireSystemDebt();
        
        TCR = LiquityMath._computeCR(entireSystemColl, entireSystemDebt);
        return TCR;
    }


    function _checkRecoveryMode() internal view returns (bool) {
        uint TCR = _getTCR();

        return TCR < CCR;
    }

    // fee and amount are denominated in dollar
    function _requireUserAcceptsFee(uint _fee, uint _amount, uint _maxFeePercentage) internal pure {
        uint feePercentage = _fee.mul(DECIMAL_PRECISION).div(_amount);
        require(feePercentage <= _maxFeePercentage, "Fee exceeded provided maximum");
    }


    // get Colls struct for the given tokens and amounts
    function _getColls(address[] memory tokens, uint[] memory amounts) internal view returns (newColls memory coll) {
        require(tokens.length == amounts.length);
        coll.tokens = tokens;
        for (uint i = 0; i < tokens.length; i++) {
            coll.amounts[whitelist.getIndex(tokens[i])] = amounts[i];
        }
        return coll;
    }


    // checks coll has a nonzero balance of at least one token in coll.tokens
    function _CollsIsNonZero(newColls memory coll) internal pure returns (bool) {
        for (uint i = 0; i < coll.tokens.length; i++) {
            if (coll.amounts[i] > 0) {
                return true;
            }
        }
        return false;
    }


    function _sendColl(address _to, newColls memory _coll) internal returns (bool) {
        for (uint i = 0; i < _coll.tokens.length; i++) {
            IERC20 token = IERC20(_coll.tokens[i]);
            if (!token.transfer(_to, _coll.amounts[i])) {
                return false;
            }
        }
        return true;
    }


    // Check whether or not the system *would be* in Recovery Mode, given the entire system coll and debt.
    // returns true if the system would be in recovery mode and false if not
    function _checkPotentialRecoveryMode(uint _entireSystemColl, uint _entireSystemDebt)
    internal
    pure
    returns (bool)
    {
        uint TCR = LiquityMath._computeCR(_entireSystemColl, _entireSystemDebt);

        return TCR < CCR;
    }



}

File 11 of 26 : Ownable.sol
// SPDX-License-Identifier: UNLICENSED

pragma solidity 0.6.11;

/**
 * Based on OpenZeppelin's Ownable contract:
 * https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/access/Ownable.sol
 *
 * @dev Contract module which provides a basic access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * This module is used through inheritance. It will make available the modifier
 * `onlyOwner`, which can be applied to your functions to restrict their use to
 * the owner.
 */
contract Ownable {
    address private _owner;

    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    /**
     * @dev Initializes the contract setting the deployer as the initial owner.
     */
    constructor () internal {
        _owner = msg.sender;
        emit OwnershipTransferred(address(0), msg.sender);
    }

    /**
     * @dev Returns the address of the current owner.
     */
    function owner() public view returns (address) {
        return _owner;
    }

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        require(isOwner(), "Ownable: caller is not the owner");
        _;
    }

    /**
     * @dev Returns true if the caller is the current owner.
     */
    function isOwner() public view returns (bool) {
        return msg.sender == _owner;
    }

    /**
     * @dev Leaves the contract without owner. It will not be possible to call
     * `onlyOwner` functions anymore.
     *
     * NOTE: Renouncing ownership will leave the contract without an owner,
     * thereby removing any functionality that is only available to the owner.
     *
     * NOTE: This function is not safe, as it doesn’t check owner is calling it.
     * Make sure you check it before calling it.
     */
    function _renounceOwnership() internal {
        emit OwnershipTransferred(_owner, address(0));
        _owner = address(0);
    }
}

File 12 of 26 : CheckContract.sol
// SPDX-License-Identifier: UNLICENSED

pragma solidity 0.6.11;


contract CheckContract {
    /**
     * Check that the account is an already deployed non-destroyed contract.
     * See: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/Address.sol#L12
     */
    function checkContract(address _account) internal view {
        require(_account != address(0), "Account cannot be zero address");

        uint256 size;
        // solhint-disable-next-line no-inline-assembly
        assembly { size := extcodesize(_account) }
        require(size > 0, "Account code size cannot be zero");
    }
}

File 13 of 26 : IERC20.sol
// SPDX-License-Identifier: UNLICENSED

pragma solidity 0.6.11;

/**
 * Based on the OpenZeppelin IER20 interface:
 * https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/IERC20.sol
 *
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20 {
    /**
     * @dev Returns the amount of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns the amount of tokens owned by `account`.
     */
    function balanceOf(address account) external view returns (uint256);

    /**
     * @dev Moves `amount` tokens from the caller's account to `recipient`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address recipient, uint256 amount) external returns (bool);

    /**
     * @dev Returns the remaining number of tokens that `spender` will be
     * allowed to spend on behalf of `owner` through {transferFrom}. This is
     * zero by default.
     *
     * This value changes when {approve} or {transferFrom} are called.
     */
    function allowance(address owner, address spender) external view returns (uint256);
    function increaseAllowance(address spender, uint256 addedValue) external returns (bool);
    function decreaseAllowance(address spender, uint256 subtractedValue) external returns (bool);

    /**
     * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * IMPORTANT: Beware that changing an allowance with this method brings the risk
     * that someone may use both the old and the new allowance by unfortunate
     * transaction ordering. One possible solution to mitigate this race
     * condition is to first reduce the spender's allowance to 0 and set the
     * desired value afterwards:
     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
     *
     * Emits an {Approval} event.
     */
    function approve(address spender, uint256 amount) external returns (bool);

    /**
     * @dev Moves `amount` tokens from `sender` to `recipient` using the
     * allowance mechanism. `amount` is then deducted from the caller's
     * allowance.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);

    function name() external view returns (string memory);
    function symbol() external view returns (string memory);
    function decimals() external view returns (uint8);
    
    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

    /**
     * @dev Emitted when the allowance of a `spender` for an `owner` is set by
     * a call to {approve}. `value` is the new allowance.
     */
    event Approval(address indexed owner, address indexed spender, uint256 value);
}

File 14 of 26 : ILiquityBase.sol
// SPDX-License-Identifier: UNLICENSED

pragma solidity 0.6.11;

import "./IPriceFeed.sol";


interface ILiquityBase {

    function getEntireSystemDebt() external view returns (uint entireSystemDebt);
}

File 15 of 26 : IStabilityPool.sol
// SPDX-License-Identifier: UNLICENSED

pragma solidity 0.6.11;

import "./ICollateralReceiver.sol";

/*
 * The Stability Pool holds YUSD tokens deposited by Stability Pool depositors.
 *
 * When a trove is liquidated, then depending on system conditions, some of its YUSD debt gets offset with
 * YUSD in the Stability Pool:  that is, the offset debt evaporates, and an equal amount of YUSD tokens in the Stability Pool is burned.
 *
 * Thus, a liquidation causes each depositor to receive a YUSD loss, in proportion to their deposit as a share of total deposits.
 * They also receive an ETH gain, as the ETH 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 YUSD 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 / ETH gain derivations:
 * https://github.com/liquity/liquity/blob/master/papers/Scalable_Reward_Distribution_with_Compounding_Stakes.pdf
 *
 * --- YETI ISSUANCE TO STABILITY POOL DEPOSITORS ---
 *
 * An YETI issuance event occurs at every deposit operation, and every liquidation.
 *
 * Each deposit is tagged with the address of the front end through which it was made.
 *
 * All deposits earn a share of the issued YETI in proportion to the deposit as a share of total deposits. The YETI earned
 * by a given deposit, is split between the depositor and the front end through which the deposit was made, based on the front end's kickbackRate.
 *
 * Please see the system Readme for an overview:
 * https://github.com/liquity/dev/blob/main/README.md#yeti-issuance-to-stability-providers
 */
interface IStabilityPool is ICollateralReceiver {

    // --- Events ---
    
    event StabilityPoolETHBalanceUpdated(uint _newBalance);
    event StabilityPoolYUSDBalanceUpdated(uint _newBalance);

    event BorrowerOperationsAddressChanged(address _newBorrowerOperationsAddress);
    event TroveManagerAddressChanged(address _newTroveManagerAddress);
    event ActivePoolAddressChanged(address _newActivePoolAddress);
    event DefaultPoolAddressChanged(address _newDefaultPoolAddress);
    event YUSDTokenAddressChanged(address _newYUSDTokenAddress);
    event SortedTrovesAddressChanged(address _newSortedTrovesAddress);
    event PriceFeedAddressChanged(address _newPriceFeedAddress);
    event CommunityIssuanceAddressChanged(address _newCommunityIssuanceAddress);

    event P_Updated(uint _P);
    event S_Updated(uint _S, uint128 _epoch, uint128 _scale);
    event G_Updated(uint _G, uint128 _epoch, uint128 _scale);
    event EpochUpdated(uint128 _currentEpoch);
    event ScaleUpdated(uint128 _currentScale);

    event FrontEndRegistered(address indexed _frontEnd, uint _kickbackRate);
    event FrontEndTagSet(address indexed _depositor, address indexed _frontEnd);

    event DepositSnapshotUpdated(address indexed _depositor, uint _P, uint _S, uint _G);
    event FrontEndSnapshotUpdated(address indexed _frontEnd, uint _P, uint _G);
    event UserDepositChanged(address indexed _depositor, uint _newDeposit);
    event FrontEndStakeChanged(address indexed _frontEnd, uint _newFrontEndStake, address _depositor);

    event ETHGainWithdrawn(address indexed _depositor, uint _ETH, uint _YUSDLoss);
    event YETIPaidToDepositor(address indexed _depositor, uint _YETI);
    event YETIPaidToFrontEnd(address indexed _frontEnd, uint _YETI);
    event EtherSent(address _to, uint _amount);

    // --- Functions ---

    /*
     * Called only once on init, to set addresses of other Liquity contracts
     * Callable only by owner, renounces ownership at the end
     */
    function setAddresses(
        address _borrowerOperationsAddress,
        address _troveManagerAddress,
        address _activePoolAddress,
        address _yusdTokenAddress,
        address _sortedTrovesAddress,
        address _communityIssuanceAddress,
        address _whitelistAddress,
        address _troveManagerLiquidationsAddress
    )
        external;

    /*
     * Initial checks:
     * - Frontend is registered or zero address
     * - Sender is not a registered frontend
     * - _amount is not zero
     * ---
     * - Triggers a YETI issuance, based on time passed since the last issuance. The YETI issuance is shared between *all* depositors and front ends
     * - Tags the deposit with the provided front end tag param, if it's a new deposit
     * - Sends depositor's accumulated gains (YETI, ETH) to depositor
     * - Sends the tagged front end's accumulated YETI gains to the tagged front end
     * - Increases deposit and tagged front end's stake, and takes new snapshots for each.
     */
    function provideToSP(uint _amount, address _frontEndTag) external;

    /*
     * Initial checks:
     * - _amount is zero or there are no under collateralized troves left in the system
     * - User has a non zero deposit
     * ---
     * - Triggers a YETI issuance, based on time passed since the last issuance. The YETI issuance is shared between *all* depositors and front ends
     * - Removes the deposit's front end tag if it is a full withdrawal
     * - Sends all depositor's accumulated gains (YETI, ETH) to depositor
     * - Sends the tagged front end's accumulated YETI gains to the tagged front end
     * - Decreases deposit and tagged front end's stake, and takes new snapshots for each.
     *
     * If _amount > userDeposit, the user withdraws all of their compounded deposit.
     */
    function withdrawFromSP(uint _amount) external;


    /*
     * Initial checks:
     * - Frontend (sender) not already registered
     * - User (sender) has no deposit
     * - _kickbackRate is in the range [0, 100%]
     * ---
     * Front end makes a one-time selection of kickback rate upon registering
     */
    function registerFrontEnd(uint _kickbackRate) external;

    /*
     * Initial checks:
     * - Caller is TroveManager
     * ---
     * Cancels out the specified debt against the YUSD contained in the Stability Pool (as far as possible)
     * and transfers the Trove's ETH collateral from ActivePool to StabilityPool.
     * Only called by liquidation functions in the TroveManager.
     */
    function offset(uint _debt, address[] memory _assets, uint[] memory _amountsAdded) external;

//    /*
//     * Returns the total amount of ETH held by the pool, accounted in an internal variable instead of `balance`,
//     * to exclude edge cases like ETH received from a self-destruct.
//     */
//    function getETH() external view returns (uint);
    
     //*
//     * Calculates and returns the total gains a depositor has accumulated 
//     */
    function  getDepositorGains(address _depositor) external view returns (address[] memory assets, uint[] memory amounts);


    /*
     * Returns the total amount of VC held by the pool, accounted for by multipliying the
     * internal balances of collaterals by the price that is found at the time getVC() is called.
     */
    function getVC() external view returns (uint);

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

    /*
     * Calculate the YETI gain earned by a deposit since its last snapshots were taken.
     * If not tagged with a front end, the depositor gets a 100% cut of what their deposit earned.
     * Otherwise, their cut of the deposit's earnings is equal to the kickbackRate, set by the front end through
     * which they made their deposit.
     */
    function getDepositorYETIGain(address _depositor) external view returns (uint);

    /*
     * Return the YETI gain earned by the front end.
     */
    function getFrontEndYETIGain(address _frontEnd) external view returns (uint);

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

    /*
     * Return the front end's compounded stake.
     *
     * The front end's compounded stake is equal to the sum of its depositors' compounded deposits.
     */
    function getCompoundedFrontEndStake(address _frontEnd) external view returns (uint);

    /*
     * Add collateral type to totalColl 
     */
    function addCollateralType(address _collateral) external;

    function getDepositSnapshotS(address depositor, address collateral) external view returns (uint);

    function getCollateral(address _collateral) external view returns (uint);

    function getAllCollateral() external view returns (address[] memory, uint256[] memory);

}

File 16 of 26 : IYETIToken.sol
// SPDX-License-Identifier: UNLICENSED

pragma solidity 0.6.11;

import "./IERC20.sol";
import "./IERC2612.sol";

interface IYETIToken is IERC20, IERC2612 {

    function sendToSYETI(address _sender, uint256 _amount) external;

    function getDeploymentStartTime() external view returns (uint256);

}

File 17 of 26 : IActivePool.sol
// SPDX-License-Identifier: UNLICENSED

pragma solidity 0.6.11;

import "./IPool.sol";

    
interface IActivePool is IPool {
    // --- Events ---
    event BorrowerOperationsAddressChanged(address _newBorrowerOperationsAddress);
    event TroveManagerAddressChanged(address _newTroveManagerAddress);
    event ActivePoolYUSDDebtUpdated(uint _YUSDDebt);
    event ActivePoolCollateralBalanceUpdated(address _collateral, uint _amount);

    // --- Functions ---
    
    function sendCollaterals(address _to, address[] memory _tokens, uint[] memory _amounts) external returns (bool);
    function sendCollateralsUnwrap(
        address _to,
        address[] memory _tokens,
        uint[] memory _amounts,
        bool _collectRewards) external returns (bool);
    function getCollateralVC(address collateralAddress) external view returns (uint);
    function addCollateralType(address _collateral) external;
}

File 18 of 26 : IDefaultPool.sol
// SPDX-License-Identifier: UNLICENSED

pragma solidity 0.6.11;

import "./IPool.sol";

interface IDefaultPool is IPool {
    // --- Events ---
    event TroveManagerAddressChanged(address _newTroveManagerAddress);
    event DefaultPoolYUSDDebtUpdated(uint _YUSDDebt);
    event DefaultPoolETHBalanceUpdated(uint _ETH);

    // --- Functions ---
    
    function sendCollsToActivePool(address[] memory _collaterals, uint[] memory _amounts, address _borrower) external;
    function addCollateralType(address _collateral) external;
    function getCollateralVC(address collateralAddress) external view returns (uint);
}

File 19 of 26 : IPriceFeed.sol
// SPDX-License-Identifier: UNLICENSED

pragma solidity 0.6.11;

interface IPriceFeed {

    // --- Events ---
    event LastGoodPriceUpdated(uint _lastGoodPrice);

    // --- Function ---
    // function fetchPrice() external returns (uint);

    function fetchPrice_v() view external returns (uint);
}

File 20 of 26 : ICollateralReceiver.sol
// SPDX-License-Identifier: UNLICENSED

pragma solidity 0.6.11;

interface ICollateralReceiver {
    function receiveCollateral(address[] memory _tokens, uint[] memory _amounts) external;
}

File 21 of 26 : IERC2612.sol
// SPDX-License-Identifier: UNLICENSED

pragma solidity 0.6.11;

/**
 * @dev Interface of the ERC2612 standard as defined in the EIP.
 *
 * Adds the {permit} method, which can be used to change one's
 * {IERC20-allowance} without having to send a transaction, by signing a
 * message. This allows users to spend tokens without having to hold Ether.
 *
 * See https://eips.ethereum.org/EIPS/eip-2612.
 * 
 * Code adapted from https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2237/
 */
interface IERC2612 {
    /**
     * @dev Sets `amount` as the allowance of `spender` over `owner`'s tokens,
     * given `owner`'s signed approval.
     *
     * IMPORTANT: The same issues {IERC20-approve} has related to transaction
     * ordering also apply here.
     *
     * Emits an {Approval} event.
     *
     * Requirements:
     *
     * - `owner` cannot be the zero address.
     * - `spender` cannot be the zero address.
     * - `deadline` must be a timestamp in the future.
     * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
     * over the EIP712-formatted function arguments.
     * - the signature must use ``owner``'s current nonce (see {nonces}).
     *
     * For more information on the signature format, see the
     * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
     * section].
     */
    function permit(address owner, address spender, uint256 amount, 
                    uint256 deadline, uint8 v, bytes32 r, bytes32 s) external;
    
    /**
     * @dev Returns the current ERC2612 nonce for `owner`. This value must be
     * included whenever a signature is generated for {permit}.
     *
     * Every successful call to {permit} increases `owner`'s nonce by one. This
     * prevents a signature from being used multiple times.
     *
     * `owner` can limit the time a Permit is valid for by setting `deadline` to 
     * a value in the near future. The deadline argument can be set to uint(-1) to 
     * create Permits that effectively never expire.
     */
    function nonces(address owner) external view returns (uint256);
    
    function version() external view returns (string memory);
    function permitTypeHash() external view returns (bytes32);
    function domainSeparator() external view returns (bytes32);
}

File 22 of 26 : IPool.sol
// SPDX-License-Identifier: UNLICENSED

pragma solidity 0.6.11;

import "./ICollateralReceiver.sol";

// Common interface for the Pools.
interface IPool is ICollateralReceiver {
    
    // --- Events ---
    
    event ETHBalanceUpdated(uint _newBalance);
    event YUSDBalanceUpdated(uint _newBalance);
    event ActivePoolAddressChanged(address _newActivePoolAddress);
    event DefaultPoolAddressChanged(address _newDefaultPoolAddress);
    event StabilityPoolAddressChanged(address _newStabilityPoolAddress);
    event WhitelistAddressChanged(address _newWhitelistAddress);
    event EtherSent(address _to, uint _amount);
    event CollateralSent(address _collateral, address _to, uint _amount);

    // --- Functions ---

    function getVC() external view returns (uint);

    function getCollateral(address collateralAddress) external view returns (uint);

    function getAllCollateral() external view returns (address[] memory, uint256[] memory);

    function getYUSDDebt() external view returns (uint);

    function increaseYUSDDebt(uint _amount) external;

    function decreaseYUSDDebt(uint _amount) external;

}

File 23 of 26 : YetiCustomBase.sol
// SPDX-License-Identifier: UNLICENSED

pragma solidity 0.6.11;

import "./BaseMath.sol";
import "./SafeMath.sol";
import "../Interfaces/IERC20.sol";
import "../Interfaces/IWhitelist.sol";


contract YetiCustomBase is BaseMath {
    using SafeMath for uint256;

    IWhitelist whitelist;

    struct newColls {
        // tokens and amounts should be the same length
        address[] tokens;
        uint256[] amounts;
    }

    // Collateral math

    // gets the sum of _coll1 and _coll2
    function _sumColls(newColls memory _coll1, newColls memory _coll2)
        internal
        view
        returns (newColls memory finalColls)
    {
        newColls memory coll3;

        coll3.tokens = whitelist.getValidCollateral();
        coll3.amounts = new uint256[](coll3.tokens.length);

        uint256 n = 0;
        for (uint256 i = 0; i < _coll1.tokens.length; i++) {
            uint256 tokenIndex = whitelist.getIndex(_coll1.tokens[i]);
            if (_coll1.amounts[i] > 0) {
                n++;
                coll3.amounts[tokenIndex] = _coll1.amounts[i];
            }
        }

        for (uint256 i = 0; i < _coll2.tokens.length; i++) {
            uint256 tokenIndex = whitelist.getIndex(_coll2.tokens[i]);
            if (_coll2.amounts[i] > 0) {
                if (coll3.amounts[tokenIndex] == 0) {
                    n++;
                }
                coll3.amounts[tokenIndex] = coll3.amounts[tokenIndex].add(_coll2.amounts[i]);
            }
        }

        address[] memory sumTokens = new address[](n);
        uint256[] memory sumAmounts = new uint256[](n);
        uint256 j = 0;

        // should only find n amounts over 0
        for (uint256 i = 0; i < coll3.tokens.length; i++) {
            if (coll3.amounts[i] > 0) {
                sumTokens[j] = coll3.tokens[i];
                sumAmounts[j] = coll3.amounts[i];
                j++;
            }
        }
        finalColls.tokens = sumTokens;
        finalColls.amounts = sumAmounts;
    }


    // gets the sum of coll1 with tokens and amounts
    function _sumColls(
        newColls memory _coll1,
        address[] memory tokens,
        uint256[] memory amounts
    ) internal view returns (newColls memory) {
        newColls memory coll2 = newColls(tokens, amounts);
        return _sumColls(_coll1, coll2);
    }


    function _sumColls(
        address[] memory tokens1,
        uint256[] memory amounts1,
        address[] memory tokens2,
        uint256[] memory amounts2
    ) internal view returns (newColls memory) {
        newColls memory coll1 = newColls(tokens1, amounts1);
        return _sumColls(coll1, tokens2, amounts2);
    }


    // Function for summing colls when coll1 includes all the tokens in the whitelist
    // Used in active, default, stability, and surplus pools
    // assumes _coll1.tokens = all whitelisted tokens
    function _leftSumColls(
        newColls memory _coll1,
        address[] memory _tokens,
        uint256[] memory _amounts
    ) internal view returns (uint[] memory) {
        uint[] memory sumAmounts = _getArrayCopy(_coll1.amounts);

        // assumes that sumAmounts length = whitelist tokens length.
        for (uint256 i = 0; i < _tokens.length; i++) {
            uint tokenIndex = whitelist.getIndex(_tokens[i]);
            sumAmounts[tokenIndex] = sumAmounts[tokenIndex].add(_amounts[i]);
        }

        return sumAmounts;
    }


    // Function for summing colls when one list is all tokens. Used in active, default, stability, and surplus pools
    function _leftSubColls(newColls memory _coll1, address[] memory _subTokens, uint[] memory _subAmounts)
        internal
        view
        returns (uint[] memory)
    {
        uint[] memory diffAmounts = _getArrayCopy(_coll1.amounts);

        //assumes that coll1.tokens = whitelist tokens. Keeps all of coll1's tokens, and subtracts coll2's amounts
        for (uint256 i = 0; i < _subTokens.length; i++) {
            uint256 tokenIndex = whitelist.getIndex(_subTokens[i]);
            diffAmounts[tokenIndex] = diffAmounts[tokenIndex].sub(_subAmounts[i]);
        }
        return diffAmounts;
    }
    

    // Returns _coll1 minus _tokens and _amounts
    // will error if _tokens include a token not in _coll1.tokens
    function _subColls(newColls memory _coll1, address[] memory _tokens, uint[] memory _amounts)
        internal
        view
        returns (newColls memory finalColls)
    {
        require(_tokens.length == _amounts.length, "Sub Colls invalid input");

        newColls memory coll3;
        coll3.tokens = whitelist.getValidCollateral();
        coll3.amounts = new uint256[](coll3.tokens.length);
        uint256 n = 0;

        for (uint256 i = 0; i < _coll1.tokens.length; i++) {
            if (_coll1.amounts[i] > 0) {
                uint256 tokenIndex = whitelist.getIndex(_coll1.tokens[i]);
                coll3.amounts[tokenIndex] = _coll1.amounts[i];
                n++;
            }
        }

        for (uint256 i = 0; i < _tokens.length; i++) {
            uint256 tokenIndex = whitelist.getIndex(_tokens[i]);
            require(coll3.amounts[tokenIndex] >= _amounts[i], "illegal sub");
            coll3.amounts[tokenIndex] = coll3.amounts[tokenIndex].sub(_amounts[i]);
            if (coll3.amounts[tokenIndex] == 0) {
                n--;
            }
        }

        address[] memory diffTokens = new address[](n);
        uint256[] memory diffAmounts = new uint256[](n);
        uint256 j = 0;

        for (uint256 i = 0; i < coll3.tokens.length; i++) {
            if (coll3.amounts[i] > 0) {
                diffTokens[j] = coll3.tokens[i];
                diffAmounts[j] = coll3.amounts[i];
                j++;
            }
        }
        finalColls.tokens = diffTokens;
        finalColls.amounts = diffAmounts;
    }

    function _getArrayCopy(uint[] memory _arr) internal pure returns (uint[] memory){
        uint[] memory copy = new uint[](_arr.length);
        for (uint i = 0; i < _arr.length; i++) {
            copy[i] = _arr[i];
        }
        return copy;
    }
}

File 24 of 26 : BaseMath.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.6.11;


contract BaseMath {
    uint constant public DECIMAL_PRECISION = 1e18;
}

File 25 of 26 : SafeMath.sol
// SPDX-License-Identifier: UNLICENSED

pragma solidity 0.6.11;

/**
 * Based on OpenZeppelin's SafeMath:
 * https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/math/SafeMath.sol
 *
 * @dev Wrappers over Solidity's arithmetic operations with added overflow
 * checks.
 *
 * Arithmetic operations in Solidity wrap on overflow. This can easily result
 * in bugs, because programmers usually assume that an overflow raises an
 * error, which is the standard behavior in high level programming languages.
 * `SafeMath` restores this intuition by reverting the transaction when an
 * operation overflows.
 *
 * Using this library instead of the unchecked operations eliminates an entire
 * class of bugs, so it's recommended to use it always.
 */
library SafeMath {
    /**
     * @dev Returns the addition of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `+` operator.
     *
     * Requirements:
     * - Addition cannot overflow.
     */
    function add(uint256 a, uint256 b) internal pure returns (uint256) {
        uint256 c = a + b;
        require(c >= a, "SafeMath: addition overflow");

        return c;
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting on
     * overflow (when the result is negative).
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     * - Subtraction cannot overflow.
     */
    function sub(uint256 a, uint256 b) internal pure returns (uint256) {
        return sub(a, b, "SafeMath: subtraction overflow");
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
     * overflow (when the result is negative).
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     * - Subtraction cannot overflow.
     *
     * _Available since v2.4.0._
     */
    function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b <= a, errorMessage);
        uint256 c = a - b;

        return c;
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `*` operator.
     *
     * Requirements:
     * - Multiplication cannot overflow.
     */
    function mul(uint256 a, uint256 b) internal pure returns (uint256) {
        // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
        // benefit is lost if 'b' is also tested.
        // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
        if (a == 0) {
            return 0;
        }

        uint256 c = a * b;
        require(c / a == b, "SafeMath: multiplication overflow");

        return c;
    }

    /**
     * @dev Returns the integer division of two unsigned integers. Reverts on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator. Note: this function uses a
     * `revert` opcode (which leaves remaining gas untouched) while Solidity
     * uses an invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     * - The divisor cannot be zero.
     */
    function div(uint256 a, uint256 b) internal pure returns (uint256) {
        return div(a, b, "SafeMath: division by zero");
    }

    /**
     * @dev Returns the integer division of two unsigned integers. Reverts with custom message on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator. Note: this function uses a
     * `revert` opcode (which leaves remaining gas untouched) while Solidity
     * uses an invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     * - The divisor cannot be zero.
     *
     * _Available since v2.4.0._
     */
    function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        // Solidity only automatically asserts when dividing by 0
        require(b > 0, errorMessage);
        uint256 c = a / b;
        // assert(a == b * c + a % b); // There is no case in which this doesn't hold

        return c;
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * Reverts when dividing by zero.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     * - The divisor cannot be zero.
     */
    function mod(uint256 a, uint256 b) internal pure returns (uint256) {
        return mod(a, b, "SafeMath: modulo by zero");
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * Reverts with custom message when dividing by zero.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     * - The divisor cannot be zero.
     *
     * _Available since v2.4.0._
     */
    function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b != 0, errorMessage);
        return a % b;
    }
}

File 26 of 26 : LiquityMath.sol
// SPDX-License-Identifier: UNLICENSED

pragma solidity 0.6.11;

import "./SafeMath.sol";

library LiquityMath {
    using SafeMath for uint;

    uint internal constant DECIMAL_PRECISION = 1e18;

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

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

    /* 
    * Multiply two decimal numbers and use normal rounding rules:
    * -round product up if 19'th mantissa digit >= 5
    * -round product down if 19'th mantissa digit < 5
    *
    * Used only inside the exponentiation, _decPow().
    */
    function decMul(uint x, uint y) internal pure returns (uint decProd) {
        uint prod_xy = x.mul(y);

        decProd = prod_xy.add(DECIMAL_PRECISION / 2).div(DECIMAL_PRECISION);
    }

    /* 
    * _decPow: Exponentiation function for 18-digit decimal base, and integer exponent n.
    * 
    * Uses the efficient "exponentiation by squaring" algorithm. O(log(n)) complexity. 
    * 
    * Called by two functions that represent time in units of minutes:
    * 1) TroveManager._calcDecayedBaseRate
    * 2) CommunityIssuance._getCumulativeIssuanceFraction 
    * 
    * The exponent is capped to avoid reverting due to overflow. The cap 525600000 equals
    * "minutes in 1000 years": 60 * 24 * 365 * 1000
    * 
    * If a period of > 1000 years is ever used as an exponent in either of the above functions, the result will be
    * negligibly different from just passing the cap, since: 
    *
    * In function 1), the decayed base rate will be 0 for 1000 years or > 1000 years
    * In function 2), the difference in tokens issued at 1000 years and any time > 1000 years, will be negligible
    */
    function _decPow(uint _base, uint _minutes) internal pure returns (uint) {
       
        if (_minutes > 525600000) {_minutes = 525600000;}  // cap to avoid overflow
    
        if (_minutes == 0) {return DECIMAL_PRECISION;}

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

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

        return decMul(x, y);
  }

    function _getAbsoluteDifference(uint _a, uint _b) internal pure returns (uint) {
        return (_a >= _b) ? _a.sub(_b) : _b.sub(_a);
    }

    //  _coll should be the amount of VC and _debt is debt of YUSD\
    // new collateral ratio is 10**18 times the collateral ratio. (150% => 1.5e18)
    function _computeCR(uint _coll, uint _debt) internal pure returns (uint) {
        if (_debt > 0) {
            uint newCollRatio = _coll.mul(10**18).div(_debt);
            return newCollRatio;
        }
        // Return the maximal value for uint256 if the Trove has a debt of 0. Represents "infinite" CR.
        else { // if (_debt == 0)
            return 2**256 - 1; 
        }
    }

}

Settings
{
  "optimizer": {
    "enabled": true,
    "runs": 100
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "libraries": {}
}

Contract ABI

[{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_activePoolAddress","type":"address"}],"name":"ActivePoolAddressChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_collSurplusPoolAddress","type":"address"}],"name":"CollSurplusPoolAddressChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_defaultPoolAddress","type":"address"}],"name":"DefaultPoolAddressChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_gasPoolAddress","type":"address"}],"name":"GasPoolAddressChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_newPriceFeedAddress","type":"address"}],"name":"PriceFeedAddressChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_sYETIAddress","type":"address"}],"name":"SYETIAddressChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_sortedTrovesAddress","type":"address"}],"name":"SortedTrovesAddressChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_stabilityPoolAddress","type":"address"}],"name":"StabilityPoolAddressChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_borrower","type":"address"},{"indexed":false,"internalType":"uint256","name":"arrayIndex","type":"uint256"}],"name":"TroveCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_newTroveManagerAddress","type":"address"}],"name":"TroveManagerAddressChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_borrower","type":"address"},{"indexed":false,"internalType":"uint256","name":"_debt","type":"uint256"},{"indexed":false,"internalType":"address[]","name":"_tokens","type":"address[]"},{"indexed":false,"internalType":"uint256[]","name":"_amounts","type":"uint256[]"},{"indexed":false,"internalType":"enum BorrowerOperations.BorrowerOperation","name":"operation","type":"uint8"}],"name":"TroveUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_borrower","type":"address"},{"indexed":false,"internalType":"uint256","name":"_debt","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_coll","type":"uint256"},{"indexed":false,"internalType":"uint8","name":"operation","type":"uint8"}],"name":"TroveUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_borrower","type":"address"},{"indexed":false,"internalType":"uint256","name":"_YUSDFee","type":"uint256"}],"name":"YUSDBorrowingFeePaid","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_yusdTokenAddress","type":"address"}],"name":"YUSDTokenAddressChanged","type":"event"},{"inputs":[],"name":"BOOTSTRAP_PERIOD","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"BORROWING_FEE_FLOOR","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"CCR","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DECIMAL_PRECISION","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MCR","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_NET_DEBT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"NAME","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PERCENT_DIVISOR","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"REDEMPTION_FEE_FLOOR","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"YUSD_GAS_COMPENSATION","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"_100pct","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"_110pct","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"activePool","outputs":[{"internalType":"contract IActivePool","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"_collsIn","type":"address[]"},{"internalType":"uint256[]","name":"_amountsIn","type":"uint256[]"},{"internalType":"address","name":"_upperHint","type":"address"},{"internalType":"address","name":"_lowerHint","type":"address"},{"internalType":"uint256","name":"_maxFeePercentage","type":"uint256"}],"name":"addColl","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"_collsIn","type":"address[]"},{"internalType":"uint256[]","name":"_amountsIn","type":"uint256[]"},{"internalType":"address[]","name":"_collsOut","type":"address[]"},{"internalType":"uint256[]","name":"_amountsOut","type":"uint256[]"},{"internalType":"uint256","name":"_YUSDChange","type":"uint256"},{"internalType":"bool","name":"_isDebtIncrease","type":"bool"},{"internalType":"address","name":"_upperHint","type":"address"},{"internalType":"address","name":"_lowerHint","type":"address"},{"internalType":"uint256","name":"_maxFeePercentage","type":"uint256"}],"name":"adjustTrove","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"claimCollateral","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"closeTrove","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"defaultPool","outputs":[{"internalType":"contract IDefaultPool","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_debt","type":"uint256"}],"name":"getCompositeDebt","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"getEntireSystemColl","outputs":[{"internalType":"uint256","name":"entireSystemColl","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getEntireSystemDebt","outputs":[{"internalType":"uint256","name":"entireSystemDebt","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isOwner","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_maxFeePercentage","type":"uint256"},{"internalType":"uint256","name":"_YUSDAmount","type":"uint256"},{"internalType":"address","name":"_upperHint","type":"address"},{"internalType":"address","name":"_lowerHint","type":"address"},{"internalType":"address[]","name":"_colls","type":"address[]"},{"internalType":"uint256[]","name":"_amounts","type":"uint256[]"}],"name":"openTrove","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_YUSDAmount","type":"uint256"},{"internalType":"address","name":"_upperHint","type":"address"},{"internalType":"address","name":"_lowerHint","type":"address"}],"name":"repayYUSD","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"sYETI","outputs":[{"internalType":"contract ISYETI","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"sYETIAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_troveManagerAddress","type":"address"},{"internalType":"address","name":"_activePoolAddress","type":"address"},{"internalType":"address","name":"_defaultPoolAddress","type":"address"},{"internalType":"address","name":"_stabilityPoolAddress","type":"address"},{"internalType":"address","name":"_gasPoolAddress","type":"address"},{"internalType":"address","name":"_collSurplusPoolAddress","type":"address"},{"internalType":"address","name":"_sortedTrovesAddress","type":"address"},{"internalType":"address","name":"_yusdTokenAddress","type":"address"},{"internalType":"address","name":"_sYETIAddress","type":"address"},{"internalType":"address","name":"_whitelistAddress","type":"address"}],"name":"setAddresses","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"sortedTroves","outputs":[{"internalType":"contract ISortedTroves","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"troveManager","outputs":[{"internalType":"contract ITroveManager","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"_collsOut","type":"address[]"},{"internalType":"uint256[]","name":"_amountsOut","type":"uint256[]"},{"internalType":"address","name":"_upperHint","type":"address"},{"internalType":"address","name":"_lowerHint","type":"address"}],"name":"withdrawColl","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_maxFeePercentage","type":"uint256"},{"internalType":"uint256","name":"_YUSDAmount","type":"uint256"},{"internalType":"address","name":"_upperHint","type":"address"},{"internalType":"address","name":"_lowerHint","type":"address"}],"name":"withdrawYUSD","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"yusdToken","outputs":[{"internalType":"contract IYUSDToken","name":"","type":"address"}],"stateMutability":"view","type":"function"}]

608060405234801561001057600080fd5b50600380546001600160a01b031916339081179091556040516000907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908290a3615e7f80620000616000396000f3fe608060405234801561001057600080fd5b50600436106101bb5760003560e01c806372fe25aa116100fa578063a20baee61161009d578063a20baee61461044b578063a2645392146104c9578063a3f4df7e146104d1578063ae9187541461054e578063c35bc55014610556578063c49f843a1461055e578063e63ce3c0146107ac578063f92d3433146101e4578063fe442cff146108e7576101bb565b806372fe25aa1461044b578063794e5724146101ec578063795d26c3146104535780637f7dde4a1461045b57806382fd79f014610463578063887105d31461049d5780638da5cb5b146104a55780638f32d59b146104ad576101bb565b8063499f99d911610162578063499f99d9146103615780634ff8144314610369578063568bcbb2146103865780635733d58f1461038e578063609d67911461039657806363788ac3146103ca5780636c37a4af146103d25780636f0b0c1c14610443576101bb565b80630e704d50146101c05780631bf43555146101ca57806328d28b5b146101e4578063308e9647146101ec5780633cc74225146101f45780633d83908a14610218578063454a7efd146102205780634870dd9a14610359575b600080fd5b6101c8610a2f565b005b6101d2610a43565b60408051918252519081900360200190f35b6101d2610a50565b6101d2610a5b565b6101fc610a67565b604080516001600160a01b039092168252519081900360200190f35b6101fc610a76565b6101c86004803603608081101561023657600080fd5b810190602081018135600160201b81111561025057600080fd5b82018360208201111561026257600080fd5b803590602001918460208302840111600160201b8311171561028357600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295949360208101935035915050600160201b8111156102d257600080fd5b8201836020820111156102e457600080fd5b803590602001918460208302840111600160201b8311171561030557600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250929550506001600160a01b038335811694506020909301359092169150610a859050565b6101d2610ac4565b6101d2610ac9565b6101d26004803603602081101561037f57600080fd5b5035610ad6565b6101fc610ae9565b6101d2610af8565b6101c8600480360360608110156103ac57600080fd5b508035906001600160a01b0360208201358116916040013516610b04565b6101fc610b42565b6101c860048036036101408110156103e957600080fd5b506001600160a01b038135811691602081013582169160408201358116916060810135821691608082013581169160a081013582169160c082013581169160e0810135821691610100820135811691610120013516610b51565b6101c8610ec0565b6101d2610f20565b6101d2610f2c565b6101fc611039565b6101c86004803603608081101561047957600080fd5b508035906020810135906001600160a01b0360408201358116916060013516611048565b6101d2611088565b6101fc611150565b6104b561115f565b604080519115158252519081900360200190f35b6101fc611170565b6104d961117f565b6040805160208082528351818301528351919283929083019185019080838360005b838110156105135781810151838201526020016104fb565b50505050905090810190601f1680156105405780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6101fc6111ad565b6101d26111bc565b6101c8600480360361012081101561057557600080fd5b810190602081018135600160201b81111561058f57600080fd5b8201836020820111156105a157600080fd5b803590602001918460208302840111600160201b831117156105c257600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295949360208101935035915050600160201b81111561061157600080fd5b82018360208201111561062357600080fd5b803590602001918460208302840111600160201b8311171561064457600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295949360208101935035915050600160201b81111561069357600080fd5b8201836020820111156106a557600080fd5b803590602001918460208302840111600160201b831117156106c657600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295949360208101935035915050600160201b81111561071557600080fd5b82018360208201111561072757600080fd5b803590602001918460208302840111600160201b8311171561074857600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295505082359350505060208101351515906001600160a01b036040820135811691606081013590911690608001356111c3565b6101c8600480360360a08110156107c257600080fd5b810190602081018135600160201b8111156107dc57600080fd5b8201836020820111156107ee57600080fd5b803590602001918460208302840111600160201b8311171561080f57600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295949360208101935035915050600160201b81111561085e57600080fd5b82018360208201111561087057600080fd5b803590602001918460208302840111600160201b8311171561089157600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250929550506001600160a01b03833581169450602084013516926040013591506112c99050565b6101c8600480360360c08110156108fd57600080fd5b8135916020810135916001600160a01b03604083013581169260608101359091169181019060a081016080820135600160201b81111561093c57600080fd5b82018360208201111561094e57600080fd5b803590602001918460208302840111600160201b8311171561096f57600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295949360208101935035915050600160201b8111156109be57600080fd5b8201836020820111156109d057600080fd5b803590602001918460208302840111600160201b831117156109f157600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250929550611370945050505050565b610a376157b1565b610a408161141c565b50565b686194049f30f720000081565b6611c37937e0800081565b670f43fc2c04ee000081565b6002546001600160a01b031681565b6004546001600160a01b031681565b610a8d6157db565b60408101859052606081018490526001600160a01b038084166101208301528216610140820152610abd81611c28565b5050505050565b60c881565b680ad78ebc5ac620000081565b6000610ae18261287b565b90505b919050565b600a546001600160a01b031681565b6714d1120d7b16000081565b610b0c6157db565b60a081018490526001600160a01b038084166101208301528216610140820152600060e0820152610b3c81611c28565b50505050565b6009546001600160a01b031681565b610b5961115f565b610baa576040805162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015290519081900360640190fd5b42600b55610bb78a612896565b610bc089612896565b610bc988612896565b610bd287612896565b610bdb86612896565b610be485612896565b610bed84612896565b610bf683612896565b610bff82612896565b610c0881612896565b600480546001600160a01b03199081166001600160a01b038d81169182179093556001805483168d85161790556002805483168c85161790556000805483168585161790556005805483168b85161790556006805483168a8516179055600780548316898516179055600c80548316888516179055600a805483168785161790556009805490921692851692909217905560408051918252517f143219c9e69b09e07e095fcc889b43d8f46ca892bba65f08dc3a0050869a5678916020908290030190a1604080516001600160a01b038b16815290517f78f058b189175430c48dc02699e3a0031ea4ff781536dc2fab847de4babdd8829181900360200190a1604080516001600160a01b038a16815290517f5ee0cae2f063ed938bb55046f6a932fb6ae792bf43624806bb90abe68a50be9b9181900360200190a1604080516001600160a01b038916815290517f82966d27eea39b038ee0fa30cd16532bb24f6e65d31cb58fb227aa5766cdcc7f9181900360200190a1604080516001600160a01b038816815290517fcfb07d791fcafc032b35837b50eb84b74df518cf4cc287e8084f47630fa70fa09181900360200190a1604080516001600160a01b038716815290517fe67f36a6e961157d6eff83b91f3af5a62131ceb6f04954ef74f51c1c05e7f88d9181900360200190a1604080516001600160a01b038616815290517f65f4cf077bc01e4742eb5ad98326f6e95b63548ea24b17f8d5e823111fe788009181900360200190a1604080516001600160a01b038516815290517fc3cd2681391697b6aa2901e9d80dd9dd3218bb54e24e0817c566fa568adeba369181900360200190a1604080516001600160a01b038416815290517f2ea605b72d3979601397bc2b968c2390809927edefe7ec75779d5325fb0ba0799181900360200190a1610eb4612949565b50505050505050505050565b6007546040805163b32beb5b60e01b815233600482015290516001600160a01b039092169163b32beb5b9160248082019260009290919082900301818387803b158015610f0c57600080fd5b505af1158015610b3c573d6000803e3d6000fd5b670de0b6b3a764000081565b600080600160009054906101000a90046001600160a01b03166001600160a01b0316638df709926040518163ffffffff1660e01b815260040160206040518083038186803b158015610f7d57600080fd5b505afa158015610f91573d6000803e3d6000fd5b505050506040513d6020811015610fa757600080fd5b5051600254604080516346fb84c960e11b815290519293506000926001600160a01b0390921691638df7099291600480820192602092909190829003018186803b158015610ff457600080fd5b505afa158015611008573d6000803e3d6000fd5b505050506040513d602081101561101e57600080fd5b50519050611032828263ffffffff61299316565b9250505090565b6001546001600160a01b031681565b6110506157db565b60a0810184905261016081018590526001600160a01b038084166101208301528216610140820152600160e0820152610abd81611c28565b600080600160009054906101000a90046001600160a01b03166001600160a01b03166301d40b636040518163ffffffff1660e01b815260040160206040518083038186803b1580156110d957600080fd5b505afa1580156110ed573d6000803e3d6000fd5b505050506040513d602081101561110357600080fd5b5051600254604080516301d40b6360e01b815290519293506000926001600160a01b03909216916301d40b6391600480820192602092909190829003018186803b158015610ff457600080fd5b6003546001600160a01b031690565b6003546001600160a01b0316331490565b6008546001600160a01b031681565b60405180604001604052806012815260200171426f72726f7765724f7065726174696f6e7360701b81525081565b600c546001600160a01b031681565b6212750081565b6111cd89896129f6565b6111d787876129f6565b6111e18988612b79565b6111ea87612c19565b6111f5338a8a612cbb565b6112305760405162461bcd60e51b8152600401808060200182810382526034815260200180615be06034913960400191505060405180910390fd5b6040805160008152602081019091526112476157db565b6040518061018001604052808c81526020018b81526020018a8152602001898152602001838152602001888152602001600081526020018715158152602001600015158152602001866001600160a01b03168152602001856001600160a01b031681526020018481525090506112bc81611c28565b5050505050505050505050565b6112d16157db565b858152602081018590526001600160a01b038085166101208301528316610140820152610160810182905261130686866129f6565b805161131190612c19565b6113243382600001518360200151612cbb565b61135f5760405162461bcd60e51b8152600401808060200182810382526034815260200180615be06034913960400191505060405180910390fd5b61136881611c28565b505050505050565b80516113b2576040805162461bcd60e51b815260206004820152600c60248201526b0416d6f756e7473203d3d20360a41b604482015290519081900360640190fd5b6113bc82826129f6565b6113c582612c19565b6113d0338383612cbb565b61140b5760405162461bcd60e51b8152600401808060200182810382526030815260200180615d756030913960400191505060405180910390fd5b611368338787600088888888612d35565b611424615852565b50604080516060810182526004546001600160a01b0390811680835260015482166020840152600a54909116928201929092529061146290336135b6565b61146a613673565b805160408051630b07655760e01b815233600482015290516001600160a01b0390921691630b0765579160248082019260009290919082900301818387803b1580156114b557600080fd5b505af11580156114c9573d6000803e3d6000fd5b505082516040805163c617944560e01b81523360048201529051600094506001600160a01b03909216925063c6179445916024808301926020929190829003018186803b15801561151957600080fd5b505afa15801561152d573d6000803e3d6000fd5b505050506040513d602081101561154357600080fd5b505182516040805163265c8de160e21b8152336004820152905192935060609283926001600160a01b0316916399723784916024808301926000929190829003018186803b15801561159457600080fd5b505afa1580156115a8573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160409081528110156115d157600080fd5b8101908080516040519392919084600160201b8211156115f057600080fd5b90830190602082018581111561160557600080fd5b82518660208202830111600160201b8211171561162157600080fd5b82525081516020918201928201910280838360005b8381101561164e578181015183820152602001611636565b5050505090500160405260200180516040519392919084600160201b82111561167657600080fd5b90830190602082018581111561168b57600080fd5b82518660208202830111600160201b821117156116a757600080fd5b82525081516020918201928201910280838360005b838110156116d45781810151838201526020016116bc565b5050505090500160405250505091509150600084600001516001600160a01b031663d66a2553336040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b15801561174157600080fd5b505afa158015611755573d6000803e3d6000fd5b505050506040513d602081101561176b57600080fd5b505160608701519091506000908190156118b95760208088015160405163ab471ec560e01b815233600482018181526001606484018190526080602485019081528b5160848601528b516001600160a01b039096169663ab471ec59694958d958d959392604483019260a40191888201910280838360005b838110156117fb5781810151838201526020016117e3565b50505050905001838103825285818151815260200191508051906020019060200280838360005b8381101561183a578181015183820152602001611822565b505050509050019650505050505050602060405180830381600087803b15801561186357600080fd5b505af1158015611877573d6000803e3d6000fd5b505050506040513d602081101561188d57600080fd5b50600090505b8851518110156118b757886040015181815181106118ad57fe5b5050600101611893565b505b60408701516118e190336118dc86680ad78ebc5ac620000063ffffffff6136b916565b6136fb565b60006118f18760008660006137bb565b90506118fc81613844565b875160408051631fc5750960e31b815233600482015290516001600160a01b039092169163fe2ba8489160248082019260009290919082900301818387803b15801561194757600080fd5b505af115801561195b573d6000803e3d6000fd5b50508951604080516365e89c5760e11b815233600482015290516001600160a01b03909216935063cbd138ae925060248082019260009290919082900301818387803b1580156119aa57600080fd5b505af11580156119be573d6000803e3d6000fd5b50505050606080336001600160a01b0316600080516020615c8f833981519152600084846001604051808581526020018060200180602001846002811115611a0257fe5b60ff168152602001838103835286818151815260200191508051906020019060200280838360005b83811015611a42578181015183820152602001611a2a565b50505050905001838103825285818151815260200191508051906020019060200280838360005b83811015611a81578181015183820152602001611a69565b50505050905001965050505050505060405180910390a260208a015160408b0151611ac6919033611ac18a680ad78ebc5ac620000063ffffffff6136b916565b61388b565b60208a015160408b0151600654611af19291906001600160a01b0316680ad78ebc5ac620000061388b565b8a606001516112bc5789602001516001600160a01b031663ab471ec5338a8a60016040518563ffffffff1660e01b815260040180856001600160a01b03166001600160a01b03168152602001806020018060200184151515158152602001838103835286818151815260200191508051906020019060200280838360005b83811015611b87578181015183820152602001611b6f565b50505050905001838103825285818151815260200191508051906020019060200280838360005b83811015611bc6578181015183820152602001611bae565b505050509050019650505050505050602060405180830381600087803b158015611bef57600080fd5b505af1158015611c03573d6000803e3d6000fd5b505050506040513d6020811015611c1957600080fd5b50505050505050505050505050565b611c30615852565b50604080516060810182526004546001600160a01b03908116825260015481166020830152600a541691810191909152611c68615872565b6000611c72613967565b90508360e0015115611c9a57611c8d84610160015182613982565b611c9a8460a00151613a2e565b611cb1846020015185606001518660a00151613a6d565b8251611cbd90336135b6565b825160408051630b07655760e01b815233600482015290516001600160a01b0390921691630b0765579160248082019260009290919082900301818387803b158015611d0857600080fd5b505af1158015611d1c573d6000803e3d6000fd5b50505060a085015183525083516020850151611d389190613aca565b61020083015260408401516060850151611d529190613aca565b61022083015260e084015115611d8057611d758261020001518560a00151613bfd565b610240830152611d8d565b6102008201516102408301525b8360e001518015611d9c575080155b15611e3157611dc4836000015184604001518660a00151856102400151886101600151613c13565b6101a08301819052610240830151611e1191611dff9190611df390670de0b6b3a764000063ffffffff613d5f16565b9063ffffffff613db816565b6101608601519063ffffffff6136b916565b6101608501526101a08201518251611e2e9163ffffffff61299316565b82525b82516040805163265c8de160e21b815233600482015290516001600160a01b0390921691639972378491602480820192600092909190829003018186803b158015611e7b57600080fd5b505afa158015611e8f573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040908152811015611eb857600080fd5b8101908080516040519392919084600160201b821115611ed757600080fd5b908301906020820185811115611eec57600080fd5b82518660208202830111600160201b82111715611f0857600080fd5b82525081516020918201928201910280838360005b83811015611f35578181015183820152602001611f1d565b5050505090500160405260200180516040519392919084600160201b821115611f5d57600080fd5b908301906020820185811115611f7257600080fd5b82518660208202830111600160201b82111715611f8e57600080fd5b82525081516020918201928201910280838360005b83811015611fbb578181015183820152602001611fa3565b50505050919091016040525050505060e0840181905260c08401829052611fe29190613aca565b8260600181815250506120118260c001518360e001518660000151876020015188604001518960600151613dfa565b6101208401819052610100840182905261202b9190613aca565b6080830181905260608301511060208301819052600060408401521561206e57606082015160808301516120649163ffffffff6136b916565b604083015261208d565b608082015160608301516120879163ffffffff6136b916565b60408301525b82516040805163d66a255360e01b815233600482015290516001600160a01b039092169163d66a255391602480820192602092909190829003018186803b1580156120d757600080fd5b505afa1580156120eb573d6000803e3d6000fd5b505050506040513d602081101561210157600080fd5b505160a0830152835151156121425761213b8460000151856020015184610200015185610220015186610240015189610160015189613e53565b6101c08301525b61215482606001518360a0015161425e565b6101408301526101c082015160a08301516121749163ffffffff61299316565b60a083018190526080830151835160e0870151612192939190614296565b610160830152606084015160e08501516121ae918391856142d1565b8361010001511580156121c357508360e00151155b80156121d3575060008460a00151115b15612226576122016121fc83600001516121f08560a0015161433f565b9063ffffffff6136b916565b61435a565b6122138260a0015183600001516143a2565b61222683604001513384600001516136fb565b83515115612319576020808401518551868301516040805163a7a24edd60e01b8152600481019182528351604482015283516001600160a01b039095169563a7a24edd9583926024810192606490910191878201910280838360005b8381101561229a578181015183820152602001612282565b50505050905001838103825284818151815260200191508051906020019060200280838360005b838110156122d95781810151838201526020016122c1565b50505050905001945050505050600060405180830381600087803b15801561230057600080fd5b505af1158015612314573d6000803e3d6000fd5b505050505b612348836000015133846101000151856101200151866080015187600001518a60e00151896101c001516143f9565b6101e08401526080830152825160408051630c7940bd60e11b815233600482015290516001600160a01b03909216916318f2817a9160248082019260009290919082900301818387803b15801561239e57600080fd5b505af11580156123b2573d6000803e3d6000fd5b5050600c546101608501516101208801516101408901516040805163015f109360e51b815233600482015260248101949094526001600160a01b03928316604485015290821660648401525192169350632be21260925060848082019260009290919082900301818387803b15801561242a57600080fd5b505af115801561243e573d6000803e3d6000fd5b50505050336001600160a01b0316600080516020615c8f833981519152836101e00151846101000151856101200151600260405180858152602001806020018060200184600281111561248d57fe5b60ff168152602001838103835286818151815260200191508051906020019060200280838360005b838110156124cd5781810151838201526020016124b5565b50505050905001838103825285818151815260200191508051906020019060200280838360005b8381101561250c5781810151838201526020016124f4565b50505050905001965050505050505060405180910390a26101a0820151604080519182525133917fce67ef071178b972f4d38b318cc4a8419b7d4c906fb1c6ad94bacc3cf573a324919081900360200190a2836101000151156127185782602001516001600160a01b031663ab471ec5338660400151876060015160016040518563ffffffff1660e01b815260040180856001600160a01b03166001600160a01b03168152602001806020018060200184151515158152602001838103835286818151815260200191508051906020019060200280838360005b838110156125fe5781810151838201526020016125e6565b50505050905001838103825285818151815260200191508051906020019060200280838360005b8381101561263d578181015183820152602001612625565b505050509050019650505050505050602060405180830381600087803b15801561266657600080fd5b505af115801561267a573d6000803e3d6000fd5b505050506040513d602081101561269057600080fd5b50600090505b8460400151518110156126bd57846080015181815181106126b357fe5b5050600101612696565b506126d66121fc8560a001516121f08560a0015161433f565b6126e88260a001518560a001516143a2565b6126fb8360400151338660a001516136fb565b61271383602001518460400151338760a0015161388b565b610b3c565b61274d83602001518460400151336127418860c001518960a001516136b990919063ffffffff16565b60e08901518751614679565b61276883602001518460400151336000866101c0015161469d565b600180546040808701516060880151915163ab471ec560e01b81523360048201818152606483018790526080602484019081528451608485015284516001600160a01b039097169763ab471ec5979396949093604482019160a401906020808901910280838360005b838110156127e95781810151838201526020016127d1565b50505050905001838103825285818151815260200191508051906020019060200280838360005b83811015612828578181015183820152602001612810565b505050509050019650505050505050602060405180830381600087803b15801561285157600080fd5b505af1158015612865573d6000803e3d6000fd5b505050506040513d602081101561136857600080fd5b6000610ae182680ad78ebc5ac620000063ffffffff61299316565b6001600160a01b0381166128f1576040805162461bcd60e51b815260206004820152601e60248201527f4163636f756e742063616e6e6f74206265207a65726f20616464726573730000604482015290519081900360640190fd5b803b80612945576040805162461bcd60e51b815260206004820181905260248201527f4163636f756e7420636f64652073697a652063616e6e6f74206265207a65726f604482015290519081900360640190fd5b5050565b6003546040516000916001600160a01b0316907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908390a3600380546001600160a01b0319169055565b6000828201838110156129ed576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b90505b92915050565b8051825114612a365760405162461bcd60e51b8152600401808060200182810382526029815260200180615a4f6029913960400191505060405180910390fd5b60005b8251811015612b745760005483516001600160a01b03909116906317ae1fc590859084908110612a6557fe5b60200260200101516040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b158015612ab357600080fd5b505afa158015612ac7573d6000803e3d6000fd5b505050506040513d6020811015612add57600080fd5b5051612b1a5760405162461bcd60e51b81526004018080602001828103825260218152602001806159be6021913960400191505060405180910390fd5b6000828281518110612b2857fe5b602002602001015111612b6c5760405162461bcd60e51b815260040180806020018281038252602e815260200180615a78602e913960400191505060405180910390fd5b600101612a39565b505050565b60005b8251811015612b745760005b8251811015612c1057828181518110612b9d57fe5b60200260200101516001600160a01b0316848381518110612bba57fe5b60200260200101516001600160a01b03161415612c085760405162461bcd60e51b815260040180806020018281038252602a815260200180615b88602a913960400191505060405180910390fd5b600101612b88565b50600101612b7c565b60005b815181101561294557600181015b8251811015612cb257828181518110612c3f57fe5b60200260200101516001600160a01b0316838381518110612c5c57fe5b60200260200101516001600160a01b03161415612caa5760405162461bcd60e51b815260040180806020018281038252602a815260200180615b88602a913960400191505060405180910390fd5b600101612c2a565b50600101612c1c565b8051600090815b81811015612d27576000858281518110612cd857fe5b602002602001015190506000858381518110612cf057fe5b602002602001015190506000612d0789848461477a565b905080612d1c57600095505050505050612d2e565b505050600101612cc2565b5060019150505b9392505050565b612d3d615906565b612d45613967565b1515610140820152612d55615852565b50604080516060810182526004546001600160a01b03908116825260015481166020830152600a541691810191909152610140820151612d96908a90613982565b8051612da2908b614814565b60608201889052612db38484613aca565b610100830152610140820151612e1b57612ddd816000015182604001518a8561010001518d613c13565b60408301819052610100830151612e1891612e0b9190611df390670de0b6b3a764000063ffffffff613d5f16565b8a9063ffffffff6136b916565b98505b612e49612e38858585610100015160008761010001518f88613e53565b60408401519063ffffffff61299316565b604083018190526060830151612e649163ffffffff61299316565b60608301819052612e749061435a565b612e81826060015161287b565b60808301819052612e8e57fe5b612ea1826101000151836080015161425e565b60a083015261014082015115612ec357612ebe8260a001516148e8565b612ef8565b612ed08260a0015161492f565b612ee78261010001516001846080015160016137bb565b6101208301819052612ef890613844565b805160408051635d6b480f60e01b81526001600160a01b038d811660048301526001602483015291519190921691635d6b480f91604480830192600092919082900301818387803b158015612f4c57600080fd5b505af1158015612f60573d6000803e3d6000fd5b50508251604051634e9de63560e01b81526001600160a01b038e8116600483019081526060602484019081528a5160648501528a51929094169550634e9de63594508f938a938a936044820191608401906020808801910280838360005b83811015612fd6578181015183820152602001612fbe565b50505050905001838103825284818151815260200191508051906020019060200280838360005b83811015613015578181015183820152602001612ffd565b5050505090500195505050505050600060405180830381600087803b15801561303d57600080fd5b505af1158015613051573d6000803e3d6000fd5b5050505080600001516001600160a01b0316639976cf458b84608001516040518363ffffffff1660e01b815260040180836001600160a01b03166001600160a01b0316815260200182815260200192505050602060405180830381600087803b1580156130bd57600080fd5b505af11580156130d1573d6000803e3d6000fd5b505050506040513d60208110156130e757600080fd5b50508051604080516382fe3eb960e01b81526001600160a01b038d81166004830152915191909216916382fe3eb991602480830192600092919082900301818387803b15801561313657600080fd5b505af115801561314a573d6000803e3d6000fd5b5050505080600001516001600160a01b03166318f2817a8b6040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b03168152602001915050600060405180830381600087803b1580156131aa57600080fd5b505af11580156131be573d6000803e3d6000fd5b50505050600c60009054906101000a90046001600160a01b03166001600160a01b03166346f7cf878b8460a0015189896040518563ffffffff1660e01b815260040180856001600160a01b03166001600160a01b03168152602001848152602001836001600160a01b03166001600160a01b03168152602001826001600160a01b03166001600160a01b03168152602001945050505050600060405180830381600087803b15801561326f57600080fd5b505af1158015613283573d6000803e3d6000fd5b5050505080600001516001600160a01b03166315d549f18b6040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b03168152602001915050602060405180830381600087803b1580156132e357600080fd5b505af11580156132f7573d6000803e3d6000fd5b505050506040513d602081101561330d57600080fd5b505160c0830181905260408051918252516001600160a01b038c16917f59cfd0cd754bc5748b6770e94a4ffa5f678d885cb899dcfadc5734edb97c67ab919081900360200190a280602001516001600160a01b031663a7a24edd85856040518363ffffffff1660e01b8152600401808060200180602001838103835285818151815260200191508051906020019060200280838360005b838110156133bc5781810151838201526020016133a4565b50505050905001838103825284818151815260200191508051906020019060200280838360005b838110156133fb5781810151838201526020016133e3565b50505050905001945050505050600060405180830381600087803b15801561342257600080fd5b505af1158015613436573d6000803e3d6000fd5b5050506020820151604083015161346392508c6134598c8c63ffffffff6136b916565b866060015161469d565b6020810151604082015160065461348f9291906001600160a01b0316680ad78ebc5ac62000008061469d565b896001600160a01b0316600080516020615c8f8339815191528360800151868660006040518085815260200180602001806020018460028111156134cf57fe5b60ff168152602001838103835286818151815260200191508051906020019060200280838360005b8381101561350f5781810151838201526020016134f7565b50505050905001838103825285818151815260200191508051906020019060200280838360005b8381101561354e578181015183820152602001613536565b50505050905001965050505050505060405180910390a2896001600160a01b03167fce67ef071178b972f4d38b318cc4a8419b7d4c906fb1c6ad94bacc3cf573a32483604001516040518082815260200191505060405180910390a250505050505050505050565b816001600160a01b0316633735aa20826040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b15801561360c57600080fd5b505afa158015613620573d6000803e3d6000fd5b505050506040513d602081101561363657600080fd5b50516129455760405162461bcd60e51b815260040180806020018281038252602e815260200180615bb2602e913960400191505060405180910390fd5b61367b613967565b156136b75760405162461bcd60e51b81526004018080602001828103825260398152602001806159df6039913960400191505060405180910390fd5b565b60006129ed83836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250614976565b80836001600160a01b03166370a08231846040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b15801561375257600080fd5b505afa158015613766573d6000803e3d6000fd5b505050506040513d602081101561377c57600080fd5b50511015612b745760405162461bcd60e51b815260040180806020018281038252603d815260200180615c14603d913960400191505060405180910390fd5b6000806137c6611088565b905060006137d2610f2c565b9050856137ee576137e9828863ffffffff6136b916565b6137fe565b6137fe828863ffffffff61299316565b91508361381a57613815818663ffffffff6136b916565b61382a565b61382a818663ffffffff61299316565b90506000613838838361425e565b98975050505050505050565b6714d1120d7b160000811015610a405760405162461bcd60e51b8152600401808060200182810382526049815260200180615b3f6049913960600191505060405180910390fd5b836001600160a01b031663e7b1d678826040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b1580156138d157600080fd5b505af11580156138e5573d6000803e3d6000fd5b50505050826001600160a01b0316639dc29fac83836040518363ffffffff1660e01b815260040180836001600160a01b03166001600160a01b0316815260200182815260200192505050600060405180830381600087803b15801561394957600080fd5b505af115801561395d573d6000803e3d6000fd5b5050505050505050565b600080613972614a0d565b6714d1120d7b1600001191505090565b80156139d457670de0b6b3a76400008211156139cf5760405162461bcd60e51b8152600401808060200182810382526032815260200180615aa66032913960400191505060405180910390fd5b612945565b6611c37937e0800082108015906139f35750670de0b6b3a76400008211155b6129455760405162461bcd60e51b8152600401808060200182810382526030815260200180615da56030913960400191505060405180910390fd5b60008111610a405760405162461bcd60e51b8152600401808060200182810382526037815260200180615dd56037913960400191505060405180910390fd5b613a7683614a30565b80613a855750613a8582614a30565b80613a8f57508015155b612b745760405162461bcd60e51b8152600401808060200182810382526046815260200180615ad86046913960600191505060405180910390fd5b60008151835114613b14576040805162461bcd60e51b815260206004820152600f60248201526e09cdee840e6c2daca40d8cadccee8d608b1b604482015290519081900360640190fd5b60005b8351811015613bf6576000805485516001600160a01b0390911690632e2b1a8890879085908110613b4457fe5b6020026020010151868581518110613b5857fe5b60200260200101516040518363ffffffff1660e01b815260040180836001600160a01b03166001600160a01b031681526020018281526020019250505060206040518083038186803b158015613bad57600080fd5b505afa158015613bc1573d6000803e3d6000fd5b505050506040513d6020811015613bd757600080fd5b50519050613beb838263ffffffff61299316565b925050600101613b17565b5092915050565b6000818311613c0c57816129ed565b5090919050565b6000856001600160a01b0316635dba4c4a6040518163ffffffff1660e01b8152600401600060405180830381600087803b158015613c5057600080fd5b505af1158015613c64573d6000803e3d6000fd5b505050506000866001600160a01b031663631203b0866040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b158015613cae57600080fd5b505afa158015613cc2573d6000803e3d6000fd5b505050506040513d6020811015613cd857600080fd5b50519050613ce7818585614a73565b600954604080516340c10f1960e01b81526001600160a01b039283166004820152602481018490529051918816916340c10f199160448082019260009290919082900301818387803b158015613d3c57600080fd5b505af1158015613d50573d6000803e3d6000fd5b50929998505050505050505050565b600082613d6e575060006129f0565b82820282848281613d7b57fe5b04146129ed5760405162461bcd60e51b8152600401808060200182810382526021815260200180615b1e6021913960400191505060405180910390fd5b60006129ed83836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250614ae8565b606080613e0786866129f6565b613e1184846129f6565b613e1961596b565b613e2589898989614b4d565b9050613e2f61596b565b613e3a828787614b89565b8051602090910151909b909a5098505050505050505050565b600085613e6257506000614253565b613e6a615985565b600254604080516301d40b6360e01b81529051613f56926001600160a01b0316916301d40b63916004808301926020929190829003018186803b158015613eb057600080fd5b505afa158015613ec4573d6000803e3d6000fd5b505050506040513d6020811015613eda57600080fd5b5051602085810151604080516301d40b6360e01b815290516001600160a01b03909216926301d40b6392600480840193829003018186803b158015613f1e57600080fd5b505afa158015613f32573d6000803e3d6000fd5b505050506040513d6020811015613f4857600080fd5b50519063ffffffff61299316565b60608201819052600090613f769088906121f0908b63ffffffff61299316565b90506000805b8b51811015614235578b8181518110613f9157fe5b60209081029190910101516001600160a01b03908116608086018190526000548d51921691632e2b1a8891908e9085908110613fc957fe5b60200260200101516040518363ffffffff1660e01b815260040180836001600160a01b03166001600160a01b031681526020018281526020019250505060206040518083038186803b15801561401e57600080fd5b505afa158015614032573d6000803e3d6000fd5b505050506040513d602081101561404857600080fd5b505160408086019190915260025460808601518251630193854f60e51b81526001600160a01b0391821660048201529251614125939190921691633270a9e091602480820192602092909190829003018186803b1580156140a857600080fd5b505afa1580156140bc573d6000803e3d6000fd5b505050506040513d60208110156140d257600080fd5b5051602088810151608088015160408051630193854f60e51b81526001600160a01b03928316600482015290519190921692633270a9e09260248082019391829003018186803b158015613f1e57600080fd5b60208086018290526000805460808801516040808a015160608b015182516311a7f05360e31b81526001600160a01b0394851660048201526024810192909252604482019790975260648101969096526084860189905251911693638d3f82989360a4808301949193928390030190829087803b1580156141a557600080fd5b505af11580156141b9573d6000803e3d6000fd5b505050506040513d60208110156141cf57600080fd5b505191506141db61513d565b156141f4576141f182662386f26fc1000061515d565b91505b614217670de0b6b3a7640000611df3848760400151613d5f90919063ffffffff16565b80855261422b90869063ffffffff61299316565b9450600101613f7c565b50614241848888614a73565b61424f85604001518561516c565b5050505b979650505050505050565b6000811561428d57600061428483611df386670de0b6b3a764000063ffffffff613d5f16565b91506129f09050565b506000196129f0565b600080826142b3576142ae858563ffffffff6136b916565b6142c3565b6142c3858563ffffffff61299316565b90506000614253878361425e565b8315614308576142e0836151d5565b8115612713576142f48161016001516148e8565b61271381610160015182610140015161521a565b61431681610160015161492f565b61432e816040015182602001518360000151856137bb565b6101808201819052610b3c90613844565b6000610ae182680ad78ebc5ac620000063ffffffff6136b916565b686194049f30f7200000811015610a405760405162461bcd60e51b815260040180806020018281038252603a815260200180615cf8603a913960400191505060405180910390fd5b6143bb82680ad78ebc5ac620000063ffffffff6136b916565b8111156129455760405162461bcd60e51b8152600401808060200182810382526043815260200180615d326043913960600191505060405180910390fd5b60008060008a6001600160a01b0316634e9de6358b8b8b6040518463ffffffff1660e01b815260040180846001600160a01b03166001600160a01b031681526020018060200180602001838103835285818151815260200191508051906020019060200280838360005b8381101561447b578181015183820152602001614463565b50505050905001838103825284818151815260200191508051906020019060200280838360005b838110156144ba5781810151838201526020016144a2565b5050505090500195505050505050600060405180830381600087803b1580156144e257600080fd5b505af11580156144f6573d6000803e3d6000fd5b5050505084156145a2576001600160a01b038b16639976cf458b614520898863ffffffff61299316565b6040518363ffffffff1660e01b815260040180836001600160a01b03166001600160a01b0316815260200182815260200192505050602060405180830381600087803b15801561456f57600080fd5b505af1158015614583573d6000803e3d6000fd5b505050506040513d602081101561459957600080fd5b50519050614668565b838611156145ca576001600160a01b038b166312610e928b614520898863ffffffff6136b916565b6001600160a01b038b16639976cf458b6145ea878a63ffffffff6136b916565b6040518363ffffffff1660e01b815260040180836001600160a01b03166001600160a01b0316815260200182815260200192505050602060405180830381600087803b15801561463957600080fd5b505af115801561464d573d6000803e3d6000fd5b505050506040513d602081101561466357600080fd5b505190505b959a95995094975050505050505050565b81156146915761468c868686868561469d565b611368565b6113688686868661388b565b846001600160a01b031663420429ca826040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b1580156146e357600080fd5b505af11580156146f7573d6000803e3d6000fd5b50505050836001600160a01b03166340c10f1984846040518363ffffffff1660e01b815260040180836001600160a01b03166001600160a01b0316815260200182815260200192505050600060405180830381600087803b15801561475b57600080fd5b505af115801561476f573d6000803e3d6000fd5b505050505050505050565b600154604080516323b872dd60e01b81526001600160a01b038681166004830152928316602482015260448101849052905160009285928492918416916323b872dd9160648082019260209290919082900301818787803b1580156147de57600080fd5b505af11580156147f2573d6000803e3d6000fd5b505050506040513d602081101561480857600080fd5b50519695505050505050565b816001600160a01b0316633735aa20826040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b15801561486a57600080fd5b505afa15801561487e573d6000803e3d6000fd5b505050506040513d602081101561489457600080fd5b505115612945576040805162461bcd60e51b815260206004820152601c60248201527f426f72726f7765724f70733a2054726f76652069732061637469766500000000604482015290519081900360640190fd5b6714d1120d7b160000811015610a405760405162461bcd60e51b8152600401808060200182810382526037815260200180615a186037913960400191505060405180910390fd5b670f43fc2c04ee0000811015610a405760405162461bcd60e51b8152600401808060200182810382526049815260200180615caf6049913960600191505060405180910390fd5b60008184841115614a055760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b838110156149ca5781810151838201526020016149b2565b50505050905090810190601f1680156149f75780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b505050900390565b600080614a18611088565b90506000614a24610f2c565b9050611032828261425e565b6000805b8251811015614a6a57828181518110614a4957fe5b6020026020010151600014614a62576001915050610ae4565b600101614a34565b50600092915050565b6000614a9183611df386670de0b6b3a764000063ffffffff613d5f16565b905081811115610b3c576040805162461bcd60e51b815260206004820152601d60248201527f4665652065786365656465642070726f7669646564206d6178696d756d000000604482015290519081900360640190fd5b60008183614b375760405162461bcd60e51b81526020600482018181528351602484015283519092839260449091019190850190808383600083156149ca5781810151838201526020016149b2565b506000838581614b4357fe5b0495945050505050565b614b5561596b565b614b5d61596b565b6040518060400160405280878152602001868152509050614b7f818585615259565b9695505050505050565b614b9161596b565b8151835114614be1576040805162461bcd60e51b815260206004820152601760248201527614dd588810dbdb1b1cc81a5b9d985b1a59081a5b9c1d5d604a1b604482015290519081900360640190fd5b614be961596b565b6000805460408051634eb5750560e11b815290516001600160a01b0390921692639d6aea0a92600480840193829003018186803b158015614c2957600080fd5b505afa158015614c3d573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526020811015614c6657600080fd5b8101908080516040519392919084600160201b821115614c8557600080fd5b908301906020820185811115614c9a57600080fd5b82518660208202830111600160201b82111715614cb657600080fd5b82525081516020918201928201910280838360005b83811015614ce3578181015183820152602001614ccb565b5050505091909101604052505050818352505167ffffffffffffffff81118015614d0c57600080fd5b50604051908082528060200260200182016040528015614d36578160200160208202803683370190505b5060208201526000805b865151811015614e5157600087602001518281518110614d5c57fe5b60200260200101511115614e495760008054885180516001600160a01b039092169163b31610db919085908110614d8f57fe5b60200260200101516040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b158015614ddd57600080fd5b505afa158015614df1573d6000803e3d6000fd5b505050506040513d6020811015614e0757600080fd5b5051602089015180519192509083908110614e1e57fe5b602002602001015184602001518281518110614e3657fe5b6020908102919091010152506001909101905b600101614d40565b5060005b8551811015614ff8576000805487516001600160a01b039091169063b31610db90899085908110614e8257fe5b60200260200101516040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b158015614ed057600080fd5b505afa158015614ee4573d6000803e3d6000fd5b505050506040513d6020811015614efa57600080fd5b50518651909150869083908110614f0d57fe5b602002602001015184602001518281518110614f2557fe5b60200260200101511015614f6e576040805162461bcd60e51b815260206004820152600b60248201526a34b63632b3b0b61039bab160a91b604482015290519081900360640190fd5b614fab868381518110614f7d57fe5b602002602001015185602001518381518110614f9557fe5b60200260200101516136b990919063ffffffff16565b84602001518281518110614fbb57fe5b60200260200101818152505083602001518181518110614fd757fe5b602002602001015160001415614fef57600019909201915b50600101614e55565b5060608167ffffffffffffffff8111801561501257600080fd5b5060405190808252806020026020018201604052801561503c578160200160208202803683370190505b50905060608267ffffffffffffffff8111801561505857600080fd5b50604051908082528060200260200182016040528015615082578160200160208202803683370190505b5090506000805b855151811015615129576000866020015182815181106150a557fe5b602002602001015111156151215785518051829081106150c157fe5b60200260200101518483815181106150d557fe5b6001600160a01b039092166020928302919091018201528601518051829081106150fb57fe5b602002602001015183838151811061510f57fe5b60209081029190910101526001909101905b600101615089565b505090845260208401525090949350505050565b600b54600090615156906212750063ffffffff61299316565b4210905090565b6000818310613c0c57816129ed565b600954604080516340c10f1960e01b81526001600160a01b039283166004820152602481018490529051918416916340c10f199160448082019260009290919082900301818387803b1580156151c157600080fd5b505af1158015611368573d6000803e3d6000fd5b6151de81614a30565b15610a405760405162461bcd60e51b815260040180806020018281038252603e815260200180615c51603e913960400191505060405180910390fd5b808210156129455760405162461bcd60e51b815260040180806020018281038252603e815260200180615e0c603e913960400191505060405180910390fd5b61526161596b565b61526961596b565b604051806040016040528085815260200184815250905061528a8582615293565b95945050505050565b61529b61596b565b6152a361596b565b6000805460408051634eb5750560e11b815290516001600160a01b0390921692639d6aea0a92600480840193829003018186803b1580156152e357600080fd5b505afa1580156152f7573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052602081101561532057600080fd5b8101908080516040519392919084600160201b82111561533f57600080fd5b90830190602082018581111561535457600080fd5b82518660208202830111600160201b8211171561537057600080fd5b82525081516020918201928201910280838360005b8381101561539d578181015183820152602001615385565b5050505091909101604052505050818352505167ffffffffffffffff811180156153c657600080fd5b506040519080825280602002602001820160405280156153f0578160200160208202803683370190505b5060208201526000805b85515181101561550d5760008054875180516001600160a01b039092169163b31610db91908590811061542957fe5b60200260200101516040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b15801561547757600080fd5b505afa15801561548b573d6000803e3d6000fd5b505050506040513d60208110156154a157600080fd5b505160208801518051919250600091849081106154ba57fe5b602002602001015111156155045760208701518051600190940193839081106154df57fe5b6020026020010151846020015182815181106154f757fe5b6020026020010181815250505b506001016153fa565b5060005b84515181101561566d5760008054865180516001600160a01b039092169163b31610db91908590811061554057fe5b60200260200101516040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b15801561558e57600080fd5b505afa1580156155a2573d6000803e3d6000fd5b505050506040513d60208110156155b857600080fd5b505160208701518051919250600091849081106155d157fe5b6020026020010151111561566457836020015181815181106155ef57fe5b602002602001015160001415615606576001909201915b6156478660200151838151811061561957fe5b60200260200101518560200151838151811061563157fe5b602002602001015161299390919063ffffffff16565b8460200151828151811061565757fe5b6020026020010181815250505b50600101615511565b5060608167ffffffffffffffff8111801561568757600080fd5b506040519080825280602002602001820160405280156156b1578160200160208202803683370190505b50905060608267ffffffffffffffff811180156156cd57600080fd5b506040519080825280602002602001820160405280156156f7578160200160208202803683370190505b5090506000805b85515181101561579e5760008660200151828151811061571a57fe5b6020026020010151111561579657855180518290811061573657fe5b602002602001015184838151811061574a57fe5b6001600160a01b0390921660209283029190910182015286015180518290811061577057fe5b602002602001015183838151811061578457fe5b60209081029190910101526001909101905b6001016156fe565b5050908452602084015250909392505050565b60405180608001604052806060815260200160608152602001606081526020016000151581525090565b6040518061018001604052806060815260200160608152602001606081526020016060815260200160608152602001600081526020016000815260200160001515815260200160001515815260200160006001600160a01b0316815260200160006001600160a01b03168152602001600081525090565b604080516060810182526000808252602082018190529181019190915290565b6040518061026001604052806000815260200160001515815260200160008152602001600081526020016000815260200160008152602001606081526020016060815260200160608152602001606081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b6040518061016001604052806060815260200160608152602001600081526020016000815260200160008152602001600081526020016000815260200160006001600160a01b0316815260200160008152602001600081526020016000151581525090565b604051806040016040528060608152602001606081525090565b6040518060a001604052806000815260200160008152602001600081526020016000815260200160006001600160a01b03168152509056fe424f70733a20436f6c6c61746572616c206e6f7420696e2077686974656c697374426f72726f7765724f70733a204f7065726174696f6e206e6f74207065726d697474656420647572696e67205265636f76657279204d6f6465426f72726f7765724f70733a204f7065726174696f6e206d757374206c656176652074726f7665207769746820494352203e3d204343524c656e677468206f6620636f6c6c61746572616c20617272617973206d75737420626520657175616c424f70733a20436f6c6c61746572616c20616d6f756e74206d7573742062652067726561746572207468616e20304d6178206665652070657263656e74616765206d757374206c657373207468616e206f7220657175616c20746f2031303025426f72726f7765724f70733a205468657265206d75737420626520656974686572206120636f6c6c61746572616c206368616e6765206f7220612064656274206368616e6765536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f77426f72726f7765724f70733a20416e206f7065726174696f6e207468617420776f756c6420726573756c7420696e20544352203c20434352206973206e6f74207065726d6974746564426f72726f7765724f70733a20436f6c6c61746572616c2070617373656420696e206f7665726c617073426f72726f7765724f70733a2054726f766520646f6573206e6f74206578697374206f7220697320636c6f736564424f70733a204661696c656420746f207472616e7366657220636f6c6c61746572616c20696e746f2061637469766520706f6f6c426f72726f7765724f70733a2043616c6c657220646f65736e74206861766520656e6f756768205955534420746f206d616b652072657061796d656e74426f72726f7765724f70733a20436f6c6c61746572616c207769746864726177616c206e6f74207065726d6974746564205265636f76657279204d6f646598c96bbf8d2aa6be678259387225d169084fca483ed9598bde8ea258036bcacf426f72726f7765724f70733a20416e206f7065726174696f6e207468617420776f756c6420726573756c7420696e20494352203c204d4352206973206e6f74207065726d6974746564426f72726f7765724f70733a2054726f76652773206e65742064656274206d7573742062652067726561746572207468616e206d696e696d756d426f72726f7765724f70733a20416d6f756e7420726570616964206d757374206e6f74206265206c6172676572207468616e207468652054726f766527732064656274424f70733a205472616e7366657220636f6c6c61746572616c20696e746f20416374697665506f6f6c206661696c65644d6178206665652070657263656e74616765206d757374206265206265747765656e20302e352520616e642031303025426f72726f7765724f70733a204465627420696e637265617365207265717569726573206e6f6e2d7a65726f20646562744368616e6765426f72726f7765724f70733a2043616e6e6f7420646563726561736520796f75722054726f766527732049435220696e205265636f76657279204d6f6465a264697066735822122062f2cb8afe315bbcd945508e41c98bb3788302c985f890f0080d4b39be23f15b64736f6c634300060b0033

Block Transaction Gas Used Reward
Age Block Fee Address BC Fee Address Voting Power Jailed Incoming
Block Uncle Number Difficulty Gas Used Reward
Loading