ETH Price: $2,580.16 (-2.91%)

Contract

0xCDc3DD86C99b58749de0F697dfc1ABE4bE22216d
 
Transaction Hash
Method
Block
From
To
Withdraw205472332024-08-17 8:44:594 days ago1723884299IN
0xCDc3DD86...4bE22216d
0 ETH0.000285790.89036912
Withdraw205332912024-08-15 9:59:356 days ago1723715975IN
0xCDc3DD86...4bE22216d
0 ETH0.004476113.73242035
Withdraw205327522024-08-15 8:11:236 days ago1723709483IN
0xCDc3DD86...4bE22216d
0 ETH0.000883182.75159384
Withdraw205047062024-08-11 10:14:359 days ago1723371275IN
0xCDc3DD86...4bE22216d
0 ETH0.000302710.9431109
Withdraw202637602024-07-08 19:05:1143 days ago1720465511IN
0xCDc3DD86...4bE22216d
0 ETH0.001372864.2770403
Withdraw200567502024-06-09 20:47:4772 days ago1717966067IN
0xCDc3DD86...4bE22216d
0 ETH0.00302829.80509305
Withdraw200528412024-06-09 7:41:2373 days ago1717918883IN
0xCDc3DD86...4bE22216d
0 ETH0.001352294
Withdraw198841332024-05-16 17:49:3596 days ago1715881775IN
0xCDc3DD86...4bE22216d
0 ETH0.002602378.42695872
Withdraw198830662024-05-16 14:14:5996 days ago1715868899IN
0xCDc3DD86...4bE22216d
0 ETH0.001862455.80253827
Withdraw198530072024-05-12 9:20:23101 days ago1715505623IN
0xCDc3DD86...4bE22216d
0 ETH0.001131853.66472897
Withdraw197452882024-04-27 7:49:23116 days ago1714204163IN
0xCDc3DD86...4bE22216d
0 ETH0.001714095.55010874
Withdraw197048232024-04-21 15:57:59121 days ago1713715079IN
0xCDc3DD86...4bE22216d
0 ETH0.0031799.90427344
Withdraw197033162024-04-21 10:54:59121 days ago1713696899IN
0xCDc3DD86...4bE22216d
0 ETH0.002005246.43527665
Withdraw197032372024-04-21 10:39:11121 days ago1713695951IN
0xCDc3DD86...4bE22216d
0 ETH0.001964026.11897578
Withdraw196377102024-04-12 6:23:11131 days ago1712902991IN
0xCDc3DD86...4bE22216d
0 ETH0.0035460911.4815365
Withdraw196376772024-04-12 6:16:35131 days ago1712902595IN
0xCDc3DD86...4bE22216d
0 ETH0.0039105312.0038747
Withdraw196332632024-04-11 15:26:47131 days ago1712849207IN
0xCDc3DD86...4bE22216d
0 ETH0.0086191727.90712913
Withdraw195534842024-03-31 11:08:47142 days ago1711883327IN
0xCDc3DD86...4bE22216d
0 ETH0.0053511316.67097003
Withdraw195434032024-03-30 1:06:47144 days ago1711760807IN
0xCDc3DD86...4bE22216d
0 ETH0.0055256516.95298237
Withdraw194836462024-03-21 14:31:35152 days ago1711031495IN
0xCDc3DD86...4bE22216d
0 ETH0.0096992230.21820548
Withdraw194757082024-03-20 11:47:59153 days ago1710935279IN
0xCDc3DD86...4bE22216d
0 ETH0.0100395831.27860078
Withdraw193978642024-03-09 13:33:47164 days ago1709991227IN
0xCDc3DD86...4bE22216d
0 ETH0.0170921553.24908354
Withdraw193891802024-03-08 8:13:23166 days ago1709885603IN
0xCDc3DD86...4bE22216d
0 ETH0.0163702351
Withdraw193821702024-03-07 8:42:47167 days ago1709800967IN
0xCDc3DD86...4bE22216d
0 ETH0.0157399849.03649715
Withdraw193405212024-03-01 13:07:59172 days ago1709298479IN
0xCDc3DD86...4bE22216d
0 ETH0.0162634952.65992154
View all transactions

Latest 11 internal transactions

Advanced mode:
Parent Transaction Hash Block From To
171619952023-04-30 23:00:47478 days ago1682895647
0xCDc3DD86...4bE22216d
0 ETH
171572992023-04-30 7:12:23479 days ago1682838743
0xCDc3DD86...4bE22216d
 Contract Creation0 ETH
158548032022-10-29 16:08:11661 days ago1667059691
0xCDc3DD86...4bE22216d
0 ETH
158547772022-10-29 16:02:59661 days ago1667059379
0xCDc3DD86...4bE22216d
 Contract Creation0 ETH
143407652022-03-07 16:23:44897 days ago1646670224
0xCDc3DD86...4bE22216d
0 ETH
142692502022-02-24 14:12:51908 days ago1645711971
0xCDc3DD86...4bE22216d
 Contract Creation0 ETH
136798372021-11-24 22:28:081000 days ago1637792888
0xCDc3DD86...4bE22216d
0 ETH
136760212021-11-24 7:53:091001 days ago1637740389
0xCDc3DD86...4bE22216d
 Contract Creation0 ETH
133963392021-10-11 8:51:131045 days ago1633942273
0xCDc3DD86...4bE22216d
0 ETH
133963352021-10-11 8:50:321045 days ago1633942232
0xCDc3DD86...4bE22216d
 Contract Creation0 ETH
133291902021-09-30 20:24:311055 days ago1633033471
0xCDc3DD86...4bE22216d
 Contract Creation0 ETH
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
PalPoolStkAave

Compiler Version
v0.7.6+commit.7338295f

Optimization Enabled:
Yes with 25000 runs

Other Settings:
default evmVersion
File 1 of 20 : PalPoolStkAave.sol
//██████╗  █████╗ ██╗      █████╗ ██████╗ ██╗███╗   ██╗
//██╔══██╗██╔══██╗██║     ██╔══██╗██╔══██╗██║████╗  ██║
//██████╔╝███████║██║     ███████║██║  ██║██║██╔██╗ ██║
//██╔═══╝ ██╔══██║██║     ██╔══██║██║  ██║██║██║╚██╗██║
//██║     ██║  ██║███████╗██║  ██║██████╔╝██║██║ ╚████║
//╚═╝     ╚═╝  ╚═╝╚══════╝╚═╝  ╚═╝╚═════╝ ╚═╝╚═╝  ╚═══╝
                                                     

pragma solidity ^0.7.6;
pragma abicoder v2;
//SPDX-License-Identifier: MIT

import "../PalPool.sol";
import "../utils/SafeMath.sol";
import "../utils/SafeERC20.sol";
import "../utils/IERC20.sol";
import "../tokens/AAVE/IStakedAave.sol";
import {Errors} from  "../utils/Errors.sol";



/** @title PalPoolStkAave Pool contract  */
/// @author Paladin
contract PalPoolStkAave is PalPool {
    using SafeMath for uint;
    using SafeERC20 for IERC20;

    /** @dev stkAAVE token address */
    address private immutable stkAaveAddress;
    /** @dev AAVE token address */
    address private immutable aaveAddress;
    /** @dev Block number of the last reward claim */
    uint public claimBlockNumber = 0;


    constructor( 
        address _palToken,
        address _controller, 
        address _underlying,
        address _interestModule,
        address _delegator,
        address _palLoanToken,
        address _aaveAddress
    ) PalPool(
            _palToken, 
            _controller,
            _underlying,
            _interestModule,
            _delegator,
            _palLoanToken
        )
    {
        stkAaveAddress = _underlying;
        aaveAddress = _aaveAddress;
    }


    /**
    * @dev Claim AAVE tokens from the AAVE Safety Module and stake them back in the Module
    * @return bool : Success
    */
    function claimFromAave() internal returns(bool) {
        //Load contracts
        IERC20 _aave = IERC20(aaveAddress);
        IStakedAave _stkAave = IStakedAave(stkAaveAddress);

        //Get pending rewards amount
        uint _pendingRewards = _stkAave.getTotalRewardsBalance(address(this));

        //If there is reward to claim
        if(_pendingRewards > 0 && claimBlockNumber != block.number){

            //claim the AAVE tokens
            _stkAave.claimRewards(address(this), _pendingRewards);

            //Stake the AAVE tokens to get stkAAVE tokens
            uint _toStakeAmount = _aave.balanceOf(address(this));
            _aave.safeApprove(stkAaveAddress, _toStakeAmount);
            _stkAave.stake(address(this), _toStakeAmount);

            //update the block number
            claimBlockNumber = block.number;

            return true;
        }
        return true;
    }


    /**
    * @notice Deposit underlying in the Pool
    * @dev Deposit underlying, and mints palToken for the user
    * @param _amount Amount of underlying to deposit
    * @return bool : amount of minted palTokens
    */
    function deposit(uint _amount) public override(PalPool) returns(uint){
        require(claimFromAave());
        return super.deposit(_amount);
    }

    /**
    * @notice Withdraw underliyng token from the Pool
    * @dev Transfer underlying token to the user, and burn the corresponding palToken amount
    * @param _amount Amount of palToken to return
    * @return uint : amount of underlying returned
    */
    function withdraw(uint _amount) public override(PalPool) returns(uint){
        require(claimFromAave());
        return super.withdraw(_amount);
    }

    /**
    * @dev Create a Borrow, deploy a Loan Pool and delegate voting power
    * @param _delegatee Address to delegate the voting power to
    * @param _amount Amount of underlying to borrow
    * @param _feeAmount Amount of fee to pay to start the loan
    * @return uint : amount of paid fees
    */
    function borrow(address _delegatee, uint _amount, uint _feeAmount) public override(PalPool) returns(uint){
        require(claimFromAave());
        return super.borrow(_delegatee, _amount, _feeAmount);
    }

    /**
    * @notice Transfer the new fees to the Loan, and expand the Loan
    * @param _loan Address of the Loan
    * @param _feeAmount New amount of fees to pay
    * @return bool : Amount of fees paid
    */
    function expandBorrow(address _loan, uint _feeAmount) public override(PalPool) returns(uint){
        require(claimFromAave());
        return super.expandBorrow(_loan, _feeAmount);
    }

    /**
    * @notice Close a Loan, and return the non-used fees to the Borrower.
    * If closed before the minimum required length, penalty fees are taken to the non-used fees
    * @dev Close a Loan, and return the non-used fees to the Borrower
    * @param _loan Address of the Loan
    */
    function closeBorrow(address _loan) public override(PalPool) {
        require(claimFromAave());
        super.closeBorrow(_loan);
    }

    /**
    * @notice Kill a non-healthy Loan to collect rewards
    * @dev Kill a non-healthy Loan to collect rewards
    * @param _loan Address of the Loan
    */
    function killBorrow(address _loan) public override(PalPool) {
        require(claimFromAave());
        super.killBorrow(_loan);
    }


    function changeBorrowDelegatee(address _loan, address _newDelegatee) public override(PalPool) {
        require(claimFromAave());
        super.changeBorrowDelegatee(_loan, _newDelegatee);
    }
}

File 2 of 20 : PalPool.sol
//██████╗  █████╗ ██╗      █████╗ ██████╗ ██╗███╗   ██╗
//██╔══██╗██╔══██╗██║     ██╔══██╗██╔══██╗██║████╗  ██║
//██████╔╝███████║██║     ███████║██║  ██║██║██╔██╗ ██║
//██╔═══╝ ██╔══██║██║     ██╔══██║██║  ██║██║██║╚██╗██║
//██║     ██║  ██║███████╗██║  ██║██████╔╝██║██║ ╚████║
//╚═╝     ╚═╝  ╚═╝╚══════╝╚═╝  ╚═╝╚═════╝ ╚═╝╚═╝  ╚═══╝
                                                     

pragma solidity ^0.7.6;
pragma abicoder v2;
//SPDX-License-Identifier: MIT

import "./utils/SafeMath.sol";
import "./utils/SafeERC20.sol";
import "./utils/Clones.sol";
import "./IPalPool.sol";
import "./PalPoolStorage.sol";
import "./IPalLoan.sol";
//import "./PalLoan.sol";
import "./IPalToken.sol";
import "./IPaladinController.sol";
import "./IPalLoanToken.sol";
import "./interests/InterestInterface.sol";
import "./utils/IERC20.sol";
import "./utils/Admin.sol";
import "./utils/ReentrancyGuard.sol";
import {Errors} from  "./utils/Errors.sol";



/** @title PalPool contract  */
/// @author Paladin
contract PalPool is IPalPool, PalPoolStorage, Admin, ReentrancyGuard {
    using SafeMath for uint;
    using SafeERC20 for IERC20;


    modifier controllerOnly() {
        //allows only the Controller and the admin to call the function
        require(msg.sender == admin || msg.sender == address(controller), Errors.CALLER_NOT_CONTROLLER);
        _;
    }



    //Functions

    constructor(
        address _palToken,
        address _controller, 
        address _underlying,
        address _interestModule,
        address _delegator,
        address _palLoanToken
    ){
        //Set admin
        admin = msg.sender;

        //Set inital values & modules
        palToken = IPalToken(_palToken);
        controller = IPaladinController(_controller);
        underlying = IERC20(_underlying);
        accrualBlockNumber = block.number;
        interestModule = InterestInterface(_interestModule);
        borrowIndex = 1e36;
        delegator = _delegator;
        palLoanToken = IPalLoanToken(_palLoanToken);
    }

    /**
    * @notice Get the underlying balance for this Pool
    * @dev Get the underlying balance of this Pool
    * @return uint : balance of this pool in the underlying token
    */
    function underlyingBalance() public view returns(uint){
        //Return the balance of this contract for the underlying asset
        return underlying.balanceOf(address(this));
    }

    /**
    * @notice Deposit underlying in the Pool
    * @dev Deposit underlying, and mints palToken for the user
    * @param _amount Amount of underlying to deposit
    * @return bool : amount of minted palTokens
    */
    function deposit(uint _amount) public virtual override nonReentrant returns(uint){
        require(_updateInterest());

        //Retrieve the current exchange rate palToken:underlying
        uint _exchRate = _exchangeRate();


        //Find the amount to mint depending on the amount to transfer
        uint _num = _amount.mul(mantissaScale);
        uint _toMint = _num.div(_exchRate);

        //Transfer the underlying to this contract
        //The amount of underlying needs to be approved before
        underlying.safeTransferFrom(msg.sender, address(this), _amount);

        //Mint the palToken
        require(palToken.mint(msg.sender, _toMint), Errors.FAIL_MINT);

        //Emit the Deposit event
        emit Deposit(msg.sender, _amount, address(this));

        //Use the controller to check if the minting was successfull
        require(controller.depositVerify(address(this), msg.sender, _toMint), Errors.FAIL_DEPOSIT);

        return _toMint;
    }

    /**
    * @notice Withdraw underliyng token from the Pool
    * @dev Transfer underlying token to the user, and burn the corresponding palToken amount
    * @param _amount Amount of palToken to return
    * @return uint : amount of underlying returned
    */
    function withdraw(uint _amount) public virtual override nonReentrant returns(uint){
        require(_updateInterest());
        require(balanceOf(msg.sender) >= _amount, Errors.INSUFFICIENT_BALANCE);

        //Retrieve the current exchange rate palToken:underlying
        uint _exchRate = _exchangeRate();

        //Find the amount to return depending on the amount of palToken to burn
        uint _num = _amount.mul(_exchRate);
        uint _toReturn = _num.div(mantissaScale);

        //Check if the pool has enough underlying to return
        require(_toReturn <= underlyingBalance(), Errors.INSUFFICIENT_CASH);

        //Burn the corresponding palToken amount
        require(palToken.burn(msg.sender, _amount), Errors.FAIL_BURN);

        //Make the underlying transfer
        underlying.safeTransfer(msg.sender, _toReturn);

        //Use the controller to check if the burning was successfull
        require(controller.withdrawVerify(address(this), msg.sender, _toReturn), Errors.FAIL_WITHDRAW);

        //Emit the Withdraw event
        emit Withdraw(msg.sender, _amount, address(this));

        return _toReturn;
    }

    /**
    * @dev Create a Borrow, deploy a Loan Pool and delegate voting power
    * @param _delegatee Address to delegate the voting power to
    * @param _amount Amount of underlying to borrow
    * @param _feeAmount Amount of fee to pay to start the loan
    * @return uint : new PalLoanToken Id
    */
    function borrow(address _delegatee, uint _amount, uint _feeAmount) public virtual override nonReentrant returns(uint){
        //Need the pool to have enough liquidity, and the interests to be up to date
        require(_amount < underlyingBalance(), Errors.INSUFFICIENT_CASH);
        require(_delegatee != address(0), Errors.ZERO_ADDRESS);
        require(_amount > 0, Errors.ZERO_BORROW);
        require(_feeAmount >= minBorrowFees(_amount), Errors.BORROW_INSUFFICIENT_FEES);
        require(_updateInterest());

        address _borrower = msg.sender;

        //Update Total Borrowed
        totalBorrowed = totalBorrowed.add(_amount);

        IPalLoan _newLoan = IPalLoan(Clones.clone(delegator));

        //Send the borrowed amount of underlying tokens to the Loan
        underlying.safeTransfer(address(_newLoan), _amount);

        //And transfer the fees from the Borrower to the Loan
        underlying.safeTransferFrom(_borrower, address(_newLoan), _feeAmount);

        //Start the Loan (and delegate voting power)
        require(_newLoan.initiate(
            address(this),
            _borrower,
            address(underlying),
            _delegatee,
            _amount,
            _feeAmount
        ), Errors.FAIL_LOAN_INITIATE);

        //Add the new Loan to mappings
        loans.push(address(_newLoan));

        //Mint the palLoanToken linked to this new Loan
        uint256 _newTokenId = palLoanToken.mint(_borrower, address(this), address(_newLoan));

        //New Borrow struct for this Loan
        loanToBorrow[address(_newLoan)] = Borrow(
            _newTokenId,
            _delegatee,
            address(_newLoan),
            _amount,
            address(underlying),
            _feeAmount,
            0,
            borrowIndex,
            block.number,
            0,
            false,
            false
        );

        //Check the borrow succeeded
        require(
            controller.borrowVerify(address(this), _borrower, _delegatee, _amount, _feeAmount, address(_newLoan)), 
            Errors.FAIL_BORROW
        );

        //Emit the NewLoan Event
        emit NewLoan(
            _borrower,
            _delegatee,
            address(underlying),
            _amount,
            address(this),
            address(_newLoan),
            _newTokenId,
            block.number
        );

        //Return the PalLoanToken Id
        return _newTokenId;
    }

    /**
    * @notice Transfer the new fees to the Loan, and expand the Loan
    * @param _loan Address of the Loan
    * @param _feeAmount New amount of fees to pay
    * @return bool : Amount of fees paid
    */
    function expandBorrow(address _loan, uint _feeAmount) public virtual override nonReentrant returns(uint){
        //Fetch the corresponding Borrow
        //And check that the caller is the Borrower, and the Loan is still active
        Borrow storage _borrow = loanToBorrow[_loan];
        require(!_borrow.closed, Errors.LOAN_CLOSED);
        require(isLoanOwner(_loan, msg.sender), Errors.NOT_LOAN_OWNER);
        require(_feeAmount > 0);
        require(_updateInterest());
        
        //Load the Loan Pool contract & get Loan owner
        IPalLoan _palLoan = IPalLoan(_borrow.loan);

        address _loanOwner = palLoanToken.ownerOf(_borrow.tokenId);

        _borrow.feesAmount = _borrow.feesAmount.add(_feeAmount);

        //Transfer the new fees to the Loan
        //If success, call the expand function of the Loan
        underlying.safeTransferFrom(_loanOwner, _borrow.loan, _feeAmount);

        require(_palLoan.expand(_feeAmount), Errors.FAIL_LOAN_EXPAND);

        emit ExpandLoan(
            _loanOwner,
            _borrow.delegatee,
            address(underlying),
            address(this),
            _borrow.feesAmount,
            _borrow.loan,
            _borrow.tokenId
        );

        return _feeAmount;
    }

    /**
    * @notice Close a Loan, and return the non-used fees to the Borrower.
    * If closed before the minimum required length, penalty fees are taken to the non-used fees
    * @dev Close a Loan, and return the non-used fees to the Borrower
    * @param _loan Address of the Loan
    */
    function closeBorrow(address _loan) public virtual override nonReentrant {
        //Fetch the corresponding Borrow
        //And check that the caller is the Borrower, and the Loan is still active
        Borrow storage _borrow = loanToBorrow[_loan];
        require(!_borrow.closed, Errors.LOAN_CLOSED);
        require(isLoanOwner(_loan, msg.sender), Errors.NOT_LOAN_OWNER);
        require(_updateInterest());

        //Get Loan owner from the ERC721 contract
        address _loanOwner = palLoanToken.ownerOf(_borrow.tokenId);

        //Load the Loan contract
        IPalLoan _palLoan = IPalLoan(_borrow.loan);

        //Calculates the amount of fees used
        uint _feesUsed = (_borrow.amount.mul(borrowIndex).div(_borrow.borrowIndex)).sub(_borrow.amount);
        uint _penaltyFees = 0;
        uint _totalFees = _feesUsed;

        //If the Borrow is closed before the minimum length, calculates the penalty fees to pay
        // -> Number of block remaining to complete the minimum length * current Borrow Rate
        if(block.number < (_borrow.startBlock.add(minBorrowLength))){
            uint _currentBorrowRate = interestModule.getBorrowRate(address(this), underlyingBalance(), totalBorrowed, totalReserve);
            uint _missingBlocks = (_borrow.startBlock.add(minBorrowLength)).sub(block.number);
            _penaltyFees = _missingBlocks.mul(_borrow.amount.mul(_currentBorrowRate)).div(mantissaScale);
            _totalFees = _totalFees.add(_penaltyFees);
        }
    
        //Security so the Borrow can be closed if there are no more fees
        //(if the Borrow wasn't Killed yet, or the loan is closed before minimum time, and already paid fees aren't enough)
        if(_totalFees > _borrow.feesAmount){
            _totalFees = _borrow.feesAmount;
        }

        //Set the Borrow as closed
        _borrow.closed = true;
        _borrow.feesUsed = _totalFees;
        _borrow.closeBlock = block.number;

        //Remove the borrowed tokens + fees from the TotalBorrowed
        //Add to the Reserve the reserveFactor of Penalty Fees (if there is Penalty Fees)
        //And add the fees counted as potential Killer Fees to the Accrued Fees, since no killing was necessary
        totalBorrowed = totalBorrowed.sub((_borrow.amount).add(_feesUsed));
        uint _realPenaltyFees = _totalFees.sub(_feesUsed);
        uint _killerFees = _feesUsed.mul(killerRatio).div(mantissaScale);
        totalReserve = totalReserve.add(reserveFactor.mul(_realPenaltyFees).div(mantissaScale));
        accruedFees = accruedFees.add(_killerFees).add(reserveFactor.mul(_realPenaltyFees).div(mantissaScale));
        
        //Close and destroy the loan
        _palLoan.closeLoan(_totalFees);

        //Burn the palLoanToken for this Loan
        require(palLoanToken.burn(_borrow.tokenId), Errors.FAIL_LOAN_TOKEN_BURN);

        require(controller.closeBorrowVerify(address(this), _loanOwner, _borrow.loan), Errors.FAIL_CLOSE_BORROW);

        //Emit the CloseLoan Event
        emit CloseLoan(
            _loanOwner,
            _borrow.delegatee,
            address(underlying),
            _borrow.amount,
            address(this),
            _totalFees,
            _loan,
            _borrow.tokenId,
            false
        );
    }

    /**
    * @notice Kill a non-healthy Loan to collect rewards
    * @dev Kill a non-healthy Loan to collect rewards
    * @param _loan Address of the Loan
    */
    function killBorrow(address _loan) public virtual override nonReentrant {
        address killer = msg.sender;
        //Fetch the corresponding Borrow
        //And check that the killer is not the Borrower, and the Loan is still active
        Borrow storage _borrow = loanToBorrow[_loan];
        require(!_borrow.closed, Errors.LOAN_CLOSED);
        require(!isLoanOwner(_loan, killer), Errors.LOAN_OWNER);
        require(_updateInterest());

        //Get the owner of the Loan through the ERC721 contract
        address _loanOwner = palLoanToken.ownerOf(_borrow.tokenId);

        //Calculate the amount of fee used, and check if the Loan is killable
        uint _feesUsed = (_borrow.amount.mul(borrowIndex).div(_borrow.borrowIndex)).sub(_borrow.amount);
        uint _loanHealthFactor = _feesUsed.mul(uint(1e18)).div(_borrow.feesAmount);
        require(_loanHealthFactor >= killFactor, Errors.NOT_KILLABLE);

        //Load the Loan
        IPalLoan _palLoan = IPalLoan(_borrow.loan);

        //Close the Loan, and update storage variables
        _borrow.closed = true;
        _borrow.killed = true;
        _borrow.feesUsed = _borrow.feesAmount;
        _borrow.closeBlock = block.number;

        //Remove the borrowed tokens + fees from the TotalBorrowed
        //Remove the amount paid as killer fees from the Reserve, and any over accrued interest in the Reserve & AccruedFees
        uint _overAccruedInterest = _loanHealthFactor <= mantissaScale ? 0 : _feesUsed.sub(_borrow.feesAmount);
        uint _killerFees = (_borrow.feesAmount).mul(killerRatio).div(mantissaScale);
        totalBorrowed = totalBorrowed.sub((_borrow.amount).add(_feesUsed));
        totalReserve = totalReserve.sub(_killerFees).sub(_overAccruedInterest.mul(reserveFactor).div(mantissaScale));
        accruedFees = accruedFees.sub(_overAccruedInterest.mul(reserveFactor.sub(killerRatio)).div(mantissaScale));

        //Kill the Loan
        _palLoan.killLoan(killer, killerRatio);

        //Burn the palLoanToken for this Loan
        require(palLoanToken.burn(_borrow.tokenId), Errors.FAIL_LOAN_TOKEN_BURN);

        require(controller.killBorrowVerify(address(this), killer, _borrow.loan), Errors.FAIL_KILL_BORROW);

        //Emit the CloseLoan Event
        emit CloseLoan(
            _loanOwner,
            _borrow.delegatee,
            address(underlying),
            _borrow.amount,
            address(this),
            _borrow.feesAmount,
            _loan,
            _borrow.tokenId,
            true
        );
    }



    /**
    * @notice Change the delegatee of a Loan, and delegate him the voting power
    * @dev Change the delegatee in the Borrow struct and in the palLoan, then change the voting power delegation recipient
    * @param _loan Address of the Loan
    * @param _newDelegatee Address of the new voting power recipient
    */
    function changeBorrowDelegatee(address _loan, address _newDelegatee) public virtual override nonReentrant {
        //Fetch the corresponding Borrow
        //And check that the caller is the Borrower, and the Loan is still active
        Borrow storage _borrow = loanToBorrow[_loan];
        require(!_borrow.closed, Errors.LOAN_CLOSED);
        require(_newDelegatee != address(0), Errors.ZERO_ADDRESS);
        require(isLoanOwner(_loan, msg.sender), Errors.NOT_LOAN_OWNER);
        require(_updateInterest());

        //Load the Loan Pool contract
        IPalLoan _palLoan = IPalLoan(_borrow.loan);

        //Update storage data
        _borrow.delegatee = _newDelegatee;

        //Call the delegation logic in the palLoan to change the votong power recipient
        require(_palLoan.changeDelegatee(_newDelegatee), Errors.FAIL_LOAN_DELEGATEE_CHANGE);

        //Emit the Event
        emit ChangeLoanDelegatee(
            palLoanToken.ownerOf(_borrow.tokenId),
            _newDelegatee,
            address(underlying),
            address(this),
            _borrow.loan,
            _borrow.tokenId
        );

    }


    /**
    * @notice Return the user's palToken balance
    * @dev Links the PalToken balanceOf() method
    * @param _account User address
    * @return uint256 : user palToken balance (in wei)
    */
    function balanceOf(address _account) public view override returns(uint){
        return palToken.balanceOf(_account);
    }


    /**
    * @notice Return the corresponding balance of the pool underlying token depending on the user's palToken balance
    * @param _account User address
    * @return uint256 : corresponding balance in the underlying token (in wei)
    */
    function underlyingBalanceOf(address _account) external view override returns(uint){
        uint _balance = palToken.balanceOf(_account);
        if(_balance == 0){
            return 0;
        }
        uint _exchRate = _exchangeRate();
        uint _num = _balance.mul(_exchRate);
        return _num.div(mantissaScale);
    }


    /**
    * @notice Return true is the given address is the owner of the palLoanToken for the given palLoan
    * @param _loanAddress Address of the Loan
    * @param _user User address
    * @return bool : true if owner
    */
    function isLoanOwner(address _loanAddress, address _user) public view override returns(bool){
        return palLoanToken.allOwnerOf(idOfLoan(_loanAddress)) == _user;
    }


    /**
    * @notice Return the token Id of the palLoanToken linked to this palLoan
    * @param _loanAddress Address of the Loan
    * @return uint256 : palLoanToken token Id
    */
    function idOfLoan(address _loanAddress) public view override returns(uint256){
        return loanToBorrow[_loanAddress].tokenId;
    }



    /**
    * @notice Return the list of all Loans for this Pool (closed and active)
    * @return address[] : list of Loans
    */
    function getLoansPools() external view override returns(address [] memory){
        //Return the addresses of all loans (old ones and active ones)
        return loans;
    }
    
    /**
    * @notice Return all the Loans for a given address
    * @param _borrower Address of the user
    * @return address : list of Loans
    */
    function getLoansByBorrower(address _borrower) external view override returns(address [] memory){
        return palLoanToken.allLoansOfForPool(_borrower, address(this));
    }

    
    /**
    * @notice Return the stored Borrow data for a given Loan
    * @dev Return the Borrow data for a given Loan
    * @param _loanAddress Address of the palLoan
    * Composants of a Borrow struct
    */
    function getBorrowData(address _loanAddress) external view override returns(
        address _borrower,
        address _delegatee,
        address _loan,
        uint256 _palLoanTokenId,
        uint _amount,
        address _underlying,
        uint _feesAmount,
        uint _feesUsed,
        uint _startBlock,
        uint _closeBlock,
        bool _closed,
        bool _killed
    ){
        //Return the data inside a Borrow struct
        Borrow memory _borrow = loanToBorrow[_loanAddress];
        return (
            //Get the Loan owner through the ERC721 contract
            palLoanToken.allOwnerOf(_borrow.tokenId),
            _borrow.delegatee,
            _borrow.loan,
            _borrow.tokenId,
            _borrow.amount,
            _borrow.underlying,
            _borrow.feesAmount,
            //Calculate amount of fees used
            _borrow.closed ? _borrow.feesUsed : (_borrow.amount.mul(borrowIndex).div(_borrow.borrowIndex)).sub(_borrow.amount),
            _borrow.startBlock,
            _borrow.closeBlock,
            _borrow.closed,
            _borrow.killed
        );

    }
    
    /**
    * @notice Get the Borrow Rate for this Pool
    * @dev Get the Borrow Rate from the Interest Module
    * @return uint : Borrow Rate (scale 1e18)
    */
    function borrowRatePerBlock() external view override returns (uint){
        return interestModule.getBorrowRate(address(this), underlyingBalance(), totalBorrowed, totalReserve);
    }
    
    /**
    * @notice Get the Supply Rate for this Pool
    * @dev Get the Supply Rate from the Interest Module
    * @return uint : Supply Rate (scale 1e18)
    */
    function supplyRatePerBlock() external view override returns (uint){
        return interestModule.getSupplyRate(address(this), underlyingBalance(), totalBorrowed, totalReserve, reserveFactor);
    }

    
    /**
    * @dev Calculates the current exchange rate
    * @return uint : current exchange rate (scale 1e18)
    */
    function _exchangeRate() internal view returns (uint){
        uint _totalSupply = palToken.totalSupply();
        //If no palTokens where minted, use the initial exchange rate
        if(_totalSupply == 0){
            return initialExchangeRate;
        }
        else{
            // Exchange Rate = (Cash + Borrows - Reserve) / Supply
            uint _cash = underlyingBalance();
            uint _availableCash = _cash.add(totalBorrowed).sub(totalReserve);
            return _availableCash.mul(1e18).div(_totalSupply);
        }
    }

    /**
    * @notice Get the current exchange rate for the palToken
    * @dev Updates interest & Calls internal function _exchangeRate
    * @return uint : current exchange rate (scale 1e18)
    */
    function exchangeRateCurrent() external override returns (uint){
        _updateInterest();
        return _exchangeRate();
    }
    
    /**
    * @notice Get the stored exchange rate for the palToken
    * @dev Calls internal function _exchangeRate
    * @return uint : current exchange rate (scale 1e18)
    */
    function exchangeRateStored() external view override returns (uint){
        return _exchangeRate();
    }

    /**
    * @notice Return the minimum of fees to pay to borrow
    * @dev Fees to pay for a Borrow (for the minimum borrow length)
    * @return uint : minimum amount (in wei)
    */
    function minBorrowFees(uint _amount) public view override returns (uint){
        require(_amount < underlyingBalance(), Errors.INSUFFICIENT_CASH);
        //Future Borrow Rate with the amount to borrow counted as already borrowed
        uint _borrowRate = interestModule.getBorrowRate(address(this), underlyingBalance().sub(_amount), totalBorrowed.add(_amount), totalReserve);
        uint _minFees = minBorrowLength.mul(_amount.mul(_borrowRate)).div(mantissaScale);
        return _minFees > 0 ? _minFees : 1;
    }

    function isKillable(address _loan) external view override returns(bool){
        Borrow memory __borrow = loanToBorrow[_loan];
        if(__borrow.closed){
            return false;
        }

        //Calculate the amount of fee used, and check if the Loan is killable
        uint _feesUsed = (__borrow.amount.mul(borrowIndex).div(__borrow.borrowIndex)).sub(__borrow.amount);
        uint _loanHealthFactor = _feesUsed.mul(uint(1e18)).div(__borrow.feesAmount);
        return _loanHealthFactor >= killFactor;
    }

    /**
    * @dev Updates Inetrest and variables for this Pool
    * @return bool : Update success
    */
    function _updateInterest() public returns (bool){
        //Get the current block
        //Check if the Pool has already been updated this block
        uint _currentBlock = block.number;
        if(_currentBlock == accrualBlockNumber){
            return true;
        }

        //Get Pool variables from Storage
        uint _cash = underlyingBalance();
        uint _borrows = totalBorrowed;
        uint _reserves = totalReserve;
        uint _accruedFees = accruedFees;
        uint _oldBorrowIndex = borrowIndex;

        //Get the Borrow Rate from the Interest Module
        uint _borrowRate = interestModule.getBorrowRate(address(this), _cash, _borrows, _reserves);

        //Delta of blocks since the last update
        uint _ellapsedBlocks = _currentBlock.sub(accrualBlockNumber);

        /*
        Interest Factor = Borrow Rate * Ellapsed Blocks
        Accumulated Interests = Interest Factor * Borrows
        Total Borrows = Borrows + Accumulated Interests
        Total Reserve = Reserve + Accumulated Interests * Reserve Factor
        Accrued Fees = Accrued Fees + Accumulated Interests * (Reserve Factor - Killer Ratio) -> (available fees should not count potential fees to send to killers)
        Borrow Index = old Borrow Index + old Borrow Index * Interest Factor 
        */
        uint _interestFactor = _borrowRate.mul(_ellapsedBlocks);
        uint _accumulatedInterest = _interestFactor.mul(_borrows).div(mantissaScale);
        uint _newBorrows = _borrows.add(_accumulatedInterest);
        uint _newReserve = _reserves.add(reserveFactor.mul(_accumulatedInterest).div(mantissaScale));
        uint _newAccruedFees = _accruedFees.add((reserveFactor.sub(killerRatio)).mul(_accumulatedInterest).div(mantissaScale));
        uint _newBorrowIndex = _oldBorrowIndex.add(_interestFactor.mul(_oldBorrowIndex).div(1e18));

        //Update storage
        totalBorrowed = _newBorrows;
        totalReserve = _newReserve;
        accruedFees = _newAccruedFees;
        borrowIndex = _newBorrowIndex;
        accrualBlockNumber = _currentBlock;

        return true;
    }

    


    // Admin Functions

    /**
    * @notice Set a new Controller
    * @dev Loads the new Controller for the Pool
    * @param  _newController address of the new Controller
    */
    function setNewController(address _newController) external override controllerOnly {
        controller = IPaladinController(_newController);
    }

    /**
    * @notice Set a new Interest Module
    * @dev Load a new Interest Module
    * @param _interestModule address of the new Interest Module
    */
    function setNewInterestModule(address _interestModule) external override adminOnly {
        interestModule = InterestInterface(_interestModule);
    }

    /**
    * @notice Set a new Delegator
    * @dev Change Delegator address
    * @param _delegator address of the new Delegator
    */
    function setNewDelegator(address _delegator) external override adminOnly {
        delegator = _delegator;
    }


    /**
    * @notice Set a new Minimum Borrow Length
    * @dev Change Minimum Borrow Length value
    * @param _length new Minimum Borrow Length
    */
    function updateMinBorrowLength(uint _length) external override adminOnly {
        require(_length > 0, Errors.INVALID_PARAMETERS);
        minBorrowLength = _length;
    }


    /**
    * @notice Update the Pool Reserve Factor & Killer Ratio
    * @dev Change Reserve Factor value & Killer Ratio value
    * @param _reserveFactor new % of fees to set as Reserve
    * @param _killerRatio new Ratio of Fees to pay the killer
    */
    function updatePoolFactors(uint _reserveFactor, uint _killerRatio) external override adminOnly {
        require(_reserveFactor > 0 && _killerRatio > 0 && _reserveFactor >= _killerRatio, 
            Errors.INVALID_PARAMETERS
        );
        reserveFactor = _reserveFactor;
        killerRatio = _killerRatio;
    }


    /**
    * @notice Add underlying in the Pool Reserve
    * @dev Transfer underlying token from the admin to the Pool
    * @param _amount Amount of underlying to transfer
    */
    function addReserve(uint _amount) external override adminOnly {
        require(_updateInterest());

        totalReserve = totalReserve.add(_amount);

        //Transfer from the admin to the Pool
        underlying.safeTransferFrom(admin, address(this), _amount);

        emit AddReserve(_amount);
    }

    /**
    * @notice Remove underlying from the Pool Reserve
    * @dev Transfer underlying token from the Pool to the admin
    * @param _amount Amount of underlying to transfer
    */
    function removeReserve(uint _amount) external override adminOnly {
        //Check if there is enough in the reserve
        require(_updateInterest());
        require(_amount <= underlyingBalance() && _amount <= totalReserve, Errors.RESERVE_FUNDS_INSUFFICIENT);

        totalReserve = totalReserve.sub(_amount);

        //Transfer underlying to the admin
        underlying.safeTransfer(admin, _amount);

        emit RemoveReserve(_amount);
    }

    /**
    * @notice Method to allow the Controller (or admin) to withdraw protocol fees
    * @dev Transfer underlying token from the Pool to the controller (or admin)
    * @param _amount Amount of underlying to transfer
    * @param _recipient Address to receive the token
    */
    function withdrawFees(uint _amount, address _recipient) external override controllerOnly {
        //Check if there is enough in the reserve
        require(_updateInterest());
        require(_amount<= accruedFees && _amount <= totalReserve, Errors.FEES_ACCRUED_INSUFFICIENT);

        //Substract from accruedFees (to track how much fees the Controller can withdraw since last time)
        //And also from the REserve, since the fees are part of the Reserve
        accruedFees = accruedFees.sub(_amount);
        totalReserve = totalReserve.sub(_amount);

        //Transfer fees to the recipient
        underlying.safeTransfer(_recipient, _amount);

        emit WithdrawFees(_amount);
    }

}

File 3 of 20 : SafeMath.sol
pragma solidity ^0.7.6;
//SPDX-License-Identifier: MIT

// From https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/math/Math.sol
// Subject to the MIT license.

/**
 * @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 addition of two unsigned integers, reverting with custom message on overflow.
     *
     * Counterpart to Solidity's `+` operator.
     *
     * Requirements:
     * - Addition cannot overflow.
     */
    function add(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        uint256 c = a + b;
        require(c >= a, errorMessage);

        return c;
    }

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

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting with custom message on underflow (when the result is negative).
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     * - Subtraction cannot underflow.
     */
    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 multiplication of two unsigned integers, reverting on overflow.
     *
     * Counterpart to Solidity's `*` operator.
     *
     * Requirements:
     * - Multiplication cannot overflow.
     */
    function mul(uint256 a, uint256 b, string memory errorMessage) 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, errorMessage);

        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.
     */
    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.
     */
    function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b != 0, errorMessage);
        return a % b;
    }
}

File 4 of 20 : SafeERC20.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.7.6;

import "./IERC20.sol";
import "./SafeMath.sol";
import "./Address.sol";

/**
 * @title SafeERC20
 * @dev Wrappers around ERC20 operations that throw on failure (when the token
 * contract returns false). Tokens that return no value (and instead revert or
 * throw on failure) are also supported, non-reverting calls are assumed to be
 * successful.
 * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
 * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
 */
library SafeERC20 {
    using SafeMath for uint256;
    using Address for address;

    function safeTransfer(IERC20 token, address to, uint256 value) internal {
        _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
    }

    function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
        _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
    }

    /**
     * @dev Deprecated. This function has issues similar to the ones found in
     * {IERC20-approve}, and its usage is discouraged.
     *
     * Whenever possible, use {safeIncreaseAllowance} and
     * {safeDecreaseAllowance} instead.
     */
    function safeApprove(IERC20 token, address spender, uint256 value) internal {
        // safeApprove should only be called when setting an initial allowance,
        // or when resetting it to zero. To increase and decrease it, use
        // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
        // solhint-disable-next-line max-line-length
        require((value == 0) || (token.allowance(address(this), spender) == 0),
            "SafeERC20: approve from non-zero to non-zero allowance"
        );
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
    }

    function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
        uint256 newAllowance = token.allowance(address(this), spender).add(value);
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
    }

    function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
        uint256 newAllowance = token.allowance(address(this), spender).sub(value, "SafeERC20: decreased allowance below zero");
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
    }

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     */
    function _callOptionalReturn(IERC20 token, bytes memory data) private {
        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
        // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that
        // the target address contains contract code and also asserts for success in the low-level call.

        bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
        if (returndata.length > 0) { // Return data is optional
            // solhint-disable-next-line max-line-length
            require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
        }
    }
}

File 5 of 20 : IERC20.sol
// SPDX-License-Identifier: agpl-3.0
pragma solidity ^0.7.6;

/**
 * @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);

  /**
   * @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);

  /**
   * @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 6 of 20 : IStakedAave.sol
// SPDX-License-Identifier: agpl-3.0
pragma solidity ^0.7.5;

interface IStakedAave {
  function stake(address to, uint256 amount) external;

  function redeem(address to, uint256 amount) external;

  function cooldown() external;

  function claimRewards(address to, uint256 amount) external;

  function getTotalRewardsBalance(address staker) external view returns (uint256);
}

File 7 of 20 : Errors.sol
//██████╗  █████╗ ██╗      █████╗ ██████╗ ██╗███╗   ██╗
//██╔══██╗██╔══██╗██║     ██╔══██╗██╔══██╗██║████╗  ██║
//██████╔╝███████║██║     ███████║██║  ██║██║██╔██╗ ██║
//██╔═══╝ ██╔══██║██║     ██╔══██║██║  ██║██║██║╚██╗██║
//██║     ██║  ██║███████╗██║  ██║██████╔╝██║██║ ╚████║
//╚═╝     ╚═╝  ╚═╝╚══════╝╚═╝  ╚═╝╚═════╝ ╚═╝╚═╝  ╚═══╝
                                                     

pragma solidity ^0.7.6;
//SPDX-License-Identifier: MIT

library Errors {
    // Admin error
    string public constant CALLER_NOT_ADMIN = '1'; // 'The caller must be the admin'
    string public constant CALLER_NOT_CONTROLLER = '29'; // 'The caller must be the admin or the controller'
    string public constant CALLER_NOT_ALLOWED_POOL = '30';  // 'The caller must be a palPool listed in the controller'
    string public constant CALLER_NOT_MINTER = '31';

    // ERC20 type errors
    string public constant FAIL_TRANSFER = '2';
    string public constant FAIL_TRANSFER_FROM = '3';
    string public constant BALANCE_TOO_LOW = '4';
    string public constant ALLOWANCE_TOO_LOW = '5';
    string public constant SELF_TRANSFER = '6';

    // PalPool errors
    string public constant INSUFFICIENT_CASH = '9';
    string public constant INSUFFICIENT_BALANCE = '10';
    string public constant FAIL_DEPOSIT = '11';
    string public constant FAIL_LOAN_INITIATE = '12';
    string public constant FAIL_BORROW = '13';
    string public constant ZERO_BORROW = '27';
    string public constant BORROW_INSUFFICIENT_FEES = '23';
    string public constant LOAN_CLOSED = '14';
    string public constant NOT_LOAN_OWNER = '15';
    string public constant LOAN_OWNER = '16';
    string public constant FAIL_LOAN_EXPAND = '17';
    string public constant NOT_KILLABLE = '18';
    string public constant RESERVE_FUNDS_INSUFFICIENT = '19';
    string public constant FAIL_MINT = '20';
    string public constant FAIL_BURN = '21';
    string public constant FAIL_WITHDRAW = '24';
    string public constant FAIL_CLOSE_BORROW = '25';
    string public constant FAIL_KILL_BORROW = '26';
    string public constant ZERO_ADDRESS = '22';
    string public constant INVALID_PARAMETERS = '28'; 
    string public constant FAIL_LOAN_DELEGATEE_CHANGE = '32';
    string public constant FAIL_LOAN_TOKEN_BURN = '33';
    string public constant FEES_ACCRUED_INSUFFICIENT = '34';

}

File 8 of 20 : Clones.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <0.8.0;

/**
 * @dev https://eips.ethereum.org/EIPS/eip-1167[EIP 1167] is a standard for
 * deploying minimal proxy contracts, also known as "clones".
 *
 * > To simply and cheaply clone contract functionality in an immutable way, this standard specifies
 * > a minimal bytecode implementation that delegates all calls to a known, fixed address.
 *
 * The library includes functions to deploy a proxy using either `create` (traditional deployment) or `create2`
 * (salted deterministic deployment). It also includes functions to predict the addresses of clones deployed using the
 * deterministic method.
 *
 * _Available since v3.4._
 */
library Clones {
    /**
     * @dev Deploys and returns the address of a clone that mimics the behaviour of `master`.
     *
     * This function uses the create opcode, which should never revert.
     */
    function clone(address master) internal returns (address instance) {
        // solhint-disable-next-line no-inline-assembly
        assembly {
            let ptr := mload(0x40)
            mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000)
            mstore(add(ptr, 0x14), shl(0x60, master))
            mstore(add(ptr, 0x28), 0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000)
            instance := create(0, ptr, 0x37)
        }
        require(instance != address(0), "ERC1167: create failed");
    }

    /**
     * @dev Deploys and returns the address of a clone that mimics the behaviour of `master`.
     *
     * This function uses the create2 opcode and a `salt` to deterministically deploy
     * the clone. Using the same `master` and `salt` multiple time will revert, since
     * the clones cannot be deployed twice at the same address.
     */
    function cloneDeterministic(address master, bytes32 salt) internal returns (address instance) {
        // solhint-disable-next-line no-inline-assembly
        assembly {
            let ptr := mload(0x40)
            mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000)
            mstore(add(ptr, 0x14), shl(0x60, master))
            mstore(add(ptr, 0x28), 0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000)
            instance := create2(0, ptr, 0x37, salt)
        }
        require(instance != address(0), "ERC1167: create2 failed");
    }

    /**
     * @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}.
     */
    function predictDeterministicAddress(address master, bytes32 salt, address deployer) internal pure returns (address predicted) {
        // solhint-disable-next-line no-inline-assembly
        assembly {
            let ptr := mload(0x40)
            mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000)
            mstore(add(ptr, 0x14), shl(0x60, master))
            mstore(add(ptr, 0x28), 0x5af43d82803e903d91602b57fd5bf3ff00000000000000000000000000000000)
            mstore(add(ptr, 0x38), shl(0x60, deployer))
            mstore(add(ptr, 0x4c), salt)
            mstore(add(ptr, 0x6c), keccak256(ptr, 0x37))
            predicted := keccak256(add(ptr, 0x37), 0x55)
        }
    }

    /**
     * @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}.
     */
    function predictDeterministicAddress(address master, bytes32 salt) internal view returns (address predicted) {
        return predictDeterministicAddress(master, salt, address(this));
    }
}

File 9 of 20 : IPalPool.sol
//██████╗  █████╗ ██╗      █████╗ ██████╗ ██╗███╗   ██╗
//██╔══██╗██╔══██╗██║     ██╔══██╗██╔══██╗██║████╗  ██║
//██████╔╝███████║██║     ███████║██║  ██║██║██╔██╗ ██║
//██╔═══╝ ██╔══██║██║     ██╔══██║██║  ██║██║██║╚██╗██║
//██║     ██║  ██║███████╗██║  ██║██████╔╝██║██║ ╚████║
//╚═╝     ╚═╝  ╚═╝╚══════╝╚═╝  ╚═╝╚═════╝ ╚═╝╚═╝  ╚═══╝
                                                     

pragma solidity ^0.7.6;
pragma abicoder v2;
//SPDX-License-Identifier: MIT

/** @title palPool Interface  */
/// @author Paladin
interface IPalPool {

    //Events
    /** @notice Event when an user deposit tokens in the pool */
    event Deposit(address user, uint amount, address palPool);
    /** @notice Event when an user withdraw tokens from the pool */
    event Withdraw(address user, uint amount, address palPool);
    /** @notice Event when a loan is started */
    event NewLoan(
        address borrower,
        address delegatee,
        address underlying,
        uint amount,
        address palPool,
        address loanAddress,
        uint256 palLoanTokenId,
        uint startBlock);
    /** @notice Event when the fee amount in the loan is updated */
    event ExpandLoan(
        address borrower,
        address delegatee,
        address underlying,
        address palPool,
        uint newFeesAmount,
        address loanAddress,
        uint256 palLoanTokenId
    );
    /** @notice Event when the delegatee of the loan is updated */
    event ChangeLoanDelegatee(
        address borrower,
        address newDelegatee,
        address underlying,
        address palPool,
        address loanAddress,
        uint256 palLoanTokenId
    );
    /** @notice Event when a loan is ended */
    event CloseLoan(
        address borrower,
        address delegatee,
        address underlying,
        uint amount,
        address palPool,
        uint usedFees,
        address loanAddress,
        uint256 palLoanTokenId,
        bool wasKilled
    );

    /** @notice Reserve Events */
    event AddReserve(uint amount);
    event RemoveReserve(uint amount);
    event WithdrawFees(uint amount);


    //Functions
    function deposit(uint _amount) external returns(uint);
    function withdraw(uint _amount) external returns(uint);
    
    function borrow(address _delegatee, uint _amount, uint _feeAmount) external returns(uint);
    function expandBorrow(address _loanPool, uint _feeAmount) external returns(uint);
    function closeBorrow(address _loanPool) external;
    function killBorrow(address _loanPool) external;
    function changeBorrowDelegatee(address _loanPool, address _newDelegatee) external;

    function balanceOf(address _account) external view returns(uint);
    function underlyingBalanceOf(address _account) external view returns(uint);

    function isLoanOwner(address _loanAddress, address _user) external view returns(bool);
    function idOfLoan(address _loanAddress) external view returns(uint256);

    function getLoansPools() external view returns(address [] memory);
    function getLoansByBorrower(address _borrower) external view returns(address [] memory);
    function getBorrowData(address _loanAddress) external view returns(
        address _borrower,
        address _delegatee,
        address _loanPool,
        uint256 _palLoanTokenId,
        uint _amount,
        address _underlying,
        uint _feesAmount,
        uint _feesUsed,
        uint _startBlock,
        uint _closeBlock,
        bool _closed,
        bool _killed
    );

    function borrowRatePerBlock() external view returns (uint);
    function supplyRatePerBlock() external view returns (uint);

    function exchangeRateCurrent() external returns (uint);
    function exchangeRateStored() external view returns (uint);

    function minBorrowFees(uint _amount) external view returns (uint);

    function isKillable(address _loan) external view returns(bool);

    //Admin functions : 
    function setNewController(address _newController) external;
    function setNewInterestModule(address _interestModule) external;
    function setNewDelegator(address _delegator) external;

    function updateMinBorrowLength(uint _length) external;
    function updatePoolFactors(uint _reserveFactor, uint _killerRatio) external;

    function addReserve(uint _amount) external;
    function removeReserve(uint _amount) external;
    function withdrawFees(uint _amount, address _recipient) external;

}

File 10 of 20 : PalPoolStorage.sol
//██████╗  █████╗ ██╗      █████╗ ██████╗ ██╗███╗   ██╗
//██╔══██╗██╔══██╗██║     ██╔══██╗██╔══██╗██║████╗  ██║
//██████╔╝███████║██║     ███████║██║  ██║██║██╔██╗ ██║
//██╔═══╝ ██╔══██║██║     ██╔══██║██║  ██║██║██║╚██╗██║
//██║     ██║  ██║███████╗██║  ██║██████╔╝██║██║ ╚████║
//╚═╝     ╚═╝  ╚═╝╚══════╝╚═╝  ╚═╝╚═════╝ ╚═╝╚═╝  ╚═══╝
                                                     

pragma solidity ^0.7.6;
//SPDX-License-Identifier: MIT

import "./IPaladinController.sol";
import "./IPalLoanToken.sol";
import "./interests/InterestInterface.sol";
import "./IPalPool.sol";
import "./IPalToken.sol";
import "./utils/IERC20.sol";

/** @title palPool Storage contract  */
/// @author Paladin
contract PalPoolStorage {

    /** @notice Struct of a Borrow */
    struct Borrow {
        //id of the palLoanToken
        uint256 tokenId;
        //address of the delegatee
        address delegatee;
        //address of the Loan Pool contract holding the loan
        address loan;
        //amount of the loan
        uint amount;
        //address of the underlying for this loan
        address underlying;
        //amount of fees (in the underlying token) paid by the borrower
        uint feesAmount;
        //amount of fees (in the underlying token) already used
        uint feesUsed;
        //borrow index at the loan creation
        uint borrowIndex;
        //start block for the Borrow
        uint startBlock;
        //block where the Borrow was closed
        uint closeBlock;
        //false if the loan is active, true if loan was closed or killed
        bool closed;
        //false when the loan is active, true if the loan was killed
        bool killed;
    }

    //palPool variables & Mappings

    /** @notice ERC721 palLoanToken */
    IPalLoanToken public palLoanToken;

    /** @notice Underlying ERC20 token of this Pool */
    IERC20 public underlying;

    /** @notice ERC20 palToken for this Pool */
    IPalToken public palToken;

    /** @dev Boolean to prevent reentry in some functions */
    bool internal entered = false;

    /** @notice Total of the current Reserve */
    uint public totalReserve;
    /** @notice Total of underlying tokens "borrowed" (in Loan Pool contracts) */
    uint public totalBorrowed;
    /** @notice Total fees accrued since last withdraw */
    /** (this amount id part of the Reserve : we should always have totalReserve >= accruedFees) */
    uint public accruedFees;

    /** @notice Minimum duration of a Borrow (in blocks) */
    uint public minBorrowLength = 45290;
    

    /** @dev Health Factor to kill a loan */
    uint public constant killFactor = 0.95e18;
    /** @dev Ratio of the borrow fees to pay the killer of a loan */
    uint public killerRatio = 0.1e18;

    /** @dev Base value to mint palTokens */
    uint internal constant initialExchangeRate = 1e18;
    /** @notice Part of the borrows interest to set as Reserves */
    uint public reserveFactor = 0.2e18;
    /** @notice Last block where the interest where updated for this pool */
    uint public accrualBlockNumber;
    /** @notice Borrow Index : increase at each interest update to represent borrows interests increasing (scaled 1e36) */
    uint public borrowIndex;

    /** @dev Scale used to represent decimal values */
    uint constant internal mantissaScale = 1e18;

    /** @dev Mapping of Loan Pool contract address to Borrow struct */
    mapping (address => Borrow) internal loanToBorrow;
    /** @dev List of all loans (current & closed) */
    address[] internal loans;


    //Modules

    /** @notice Paladin Controller contract */
    IPaladinController public controller;
    /** @dev Current Inetrest Module */
    InterestInterface internal interestModule;

    /** @dev Delegator for the underlying governance token */
    address internal delegator;
    
}

File 11 of 20 : IPalLoan.sol
//██████╗  █████╗ ██╗      █████╗ ██████╗ ██╗███╗   ██╗
//██╔══██╗██╔══██╗██║     ██╔══██╗██╔══██╗██║████╗  ██║
//██████╔╝███████║██║     ███████║██║  ██║██║██╔██╗ ██║
//██╔═══╝ ██╔══██║██║     ██╔══██║██║  ██║██║██║╚██╗██║
//██║     ██║  ██║███████╗██║  ██║██████╔╝██║██║ ╚████║
//╚═╝     ╚═╝  ╚═╝╚══════╝╚═╝  ╚═╝╚═════╝ ╚═╝╚═╝  ╚═══╝
                                                     

pragma solidity ^0.7.6;
//SPDX-License-Identifier: MIT

/** @title Interface for PalLoan contract  */
/// @author Paladin
interface IPalLoan {

    // Variables
    function underlying() external view returns(address);
    function amount() external view returns(uint);
    function borrower() external view returns(address);
    function delegatee() external view returns(address);
    function motherPool() external view returns(address);
    function feesAmount() external view returns(uint);

    // Functions
    function initiate(
        address _motherPool,
        address _borrower,
        address _underlying,
        address _delegatee,
        uint _amount,
        uint _feesAmount
    ) external returns(bool);
    function expand(uint _newFeesAmount) external returns(bool);
    function closeLoan(uint _usedAmount) external;
    function killLoan(address _killer, uint _killerRatio) external;
    function changeDelegatee(address _delegatee) external returns(bool);
}

File 12 of 20 : IPalToken.sol
//██████╗  █████╗ ██╗      █████╗ ██████╗ ██╗███╗   ██╗
//██╔══██╗██╔══██╗██║     ██╔══██╗██╔══██╗██║████╗  ██║
//██████╔╝███████║██║     ███████║██║  ██║██║██╔██╗ ██║
//██╔═══╝ ██╔══██║██║     ██╔══██║██║  ██║██║██║╚██╗██║
//██║     ██║  ██║███████╗██║  ██║██████╔╝██║██║ ╚████║
//╚═╝     ╚═╝  ╚═╝╚══════╝╚═╝  ╚═╝╚═════╝ ╚═╝╚═╝  ╚═══╝
                                                     

pragma solidity ^0.7.6;
//SPDX-License-Identifier: MIT


/** @title simple PalToken Interface to be used inside the PalPool contract  */
/// @author Paladin
interface IPalToken {

    function mint(address _user, uint _toMint) external returns(bool);

    function burn(address _user, uint _toBurn) external returns(bool);

    function balanceOf(address owner) external view returns(uint);

    function totalSupply() external view returns (uint256);

}

File 13 of 20 : IPaladinController.sol
//██████╗  █████╗ ██╗      █████╗ ██████╗ ██╗███╗   ██╗
//██╔══██╗██╔══██╗██║     ██╔══██╗██╔══██╗██║████╗  ██║
//██████╔╝███████║██║     ███████║██║  ██║██║██╔██╗ ██║
//██╔═══╝ ██╔══██║██║     ██╔══██║██║  ██║██║██║╚██╗██║
//██║     ██║  ██║███████╗██║  ██║██████╔╝██║██║ ╚████║
//╚═╝     ╚═╝  ╚═╝╚══════╝╚═╝  ╚═╝╚═════╝ ╚═╝╚═╝  ╚═══╝
                                                     

pragma solidity ^0.7.6;
//SPDX-License-Identifier: MIT

/** @title Paladin Controller Interface  */
/// @author Paladin
interface IPaladinController {
    
    //Events

    /** @notice Event emitted when a new token & pool are added to the list */
    event NewPalPool(address palPool, address palToken);
    /** @notice Event emitted when a token & pool are removed from the list */
    event RemovePalPool(address palPool, address palToken);


    //Functions
    function isPalPool(address pool) external view returns(bool);
    function getPalTokens() external view returns(address[] memory);
    function getPalPools() external view returns(address[] memory);
    function setInitialPools(address[] memory palTokens, address[] memory palPools) external returns(bool);
    function addNewPool(address palToken, address palPool) external returns(bool);
    function removePool(address _palPool) external returns(bool);

    function withdrawPossible(address palPool, uint amount) external view returns(bool);
    function borrowPossible(address palPool, uint amount) external view returns(bool);

    function depositVerify(address palPool, address dest, uint amount) external view returns(bool);
    function withdrawVerify(address palPool, address dest, uint amount) external view returns(bool);
    function borrowVerify(address palPool, address borrower, address delegatee, uint amount, uint feesAmount, address loanAddress) external view returns(bool);
    function expandBorrowVerify(address palPool, address loanAddress, uint newFeesAmount) external view returns(bool);
    function closeBorrowVerify(address palPool, address borrower, address loanAddress) external view returns(bool);
    function killBorrowVerify(address palPool, address killer, address loanAddress) external view returns(bool);

    //Admin functions
    function setPoolsNewController(address _newController) external returns(bool);
    function withdrawFromPool(address _pool, uint _amount, address _recipient) external returns(bool);

}

File 14 of 20 : IPalLoanToken.sol
//██████╗  █████╗ ██╗      █████╗ ██████╗ ██╗███╗   ██╗
//██╔══██╗██╔══██╗██║     ██╔══██╗██╔══██╗██║████╗  ██║
//██████╔╝███████║██║     ███████║██║  ██║██║██╔██╗ ██║
//██╔═══╝ ██╔══██║██║     ██╔══██║██║  ██║██║██║╚██╗██║
//██║     ██║  ██║███████╗██║  ██║██████╔╝██║██║ ╚████║
//╚═╝     ╚═╝  ╚═╝╚══════╝╚═╝  ╚═╝╚═════╝ ╚═╝╚═╝  ╚═══╝
                                                     

pragma solidity ^0.7.6;
pragma abicoder v2;
//SPDX-License-Identifier: MIT

import "./utils/IERC721.sol";

/** @title palLoanToken Interface  */
/// @author Paladin
interface IPalLoanToken is IERC721 {

    //Events

    /** @notice Event when a new Loan Token is minted */
    event NewLoanToken(address palPool, address indexed owner, address indexed palLoan, uint256 indexed tokenId);
    /** @notice Event when a Loan Token is burned */
    event BurnLoanToken(address palPool, address indexed owner, address indexed palLoan, uint256 indexed tokenId);


    //Functions
    function mint(address to, address palPool, address palLoan) external returns(uint256);
    function burn(uint256 tokenId) external returns(bool);

    function tokenURI(uint256 tokenId) external view returns (string memory);

    function tokenOfByIndex(address owner, uint256 tokenIdex) external view returns (uint256);
    function loanOf(uint256 tokenId) external view returns(address);
    function poolOf(uint256 tokenId) external view returns(address);
    function loansOf(address owner) external view returns(address[] memory);
    function tokensOf(address owner) external view returns(uint256[] memory);
    function loansOfForPool(address owner, address palPool) external view returns(address[] memory);
    function allTokensOf(address owner) external view returns(uint256[] memory);
    function allLoansOf(address owner) external view returns(address[] memory);
    function allLoansOfForPool(address owner, address palPool) external view returns(address[] memory);
    function allOwnerOf(uint256 tokenId) external view returns(address);

    function isBurned(uint256 tokenId) external view returns(bool);

    //Admin functions
    function setNewController(address _newController) external;
    function setNewBaseURI(string memory _newBaseURI) external;

}

File 15 of 20 : InterestInterface.sol
//██████╗  █████╗ ██╗      █████╗ ██████╗ ██╗███╗   ██╗
//██╔══██╗██╔══██╗██║     ██╔══██╗██╔══██╗██║████╗  ██║
//██████╔╝███████║██║     ███████║██║  ██║██║██╔██╗ ██║
//██╔═══╝ ██╔══██║██║     ██╔══██║██║  ██║██║██║╚██╗██║
//██║     ██║  ██║███████╗██║  ██║██████╔╝██║██║ ╚████║
//╚═╝     ╚═╝  ╚═╝╚══════╝╚═╝  ╚═╝╚═════╝ ╚═╝╚═╝  ╚═══╝
                                                     

pragma solidity ^0.7.6;
//SPDX-License-Identifier: MIT

/** @title Interest Module Interface  */
/// @author Paladin
interface InterestInterface {

    function getSupplyRate(address palPool, uint cash, uint borrows, uint reserves, uint reserveFactor) external view returns(uint);
    function getBorrowRate(address palPool, uint cash, uint borrows, uint reserves) external view returns(uint);
}

File 16 of 20 : Admin.sol
pragma solidity ^0.7.6;
//SPDX-License-Identifier: MIT


/** @title Admin contract  */
/// @author Paladin
contract Admin {

    /** @notice (Admin) Event when the contract admin is updated */
    event NewAdmin(address oldAdmin, address newAdmin);

    /** @dev Admin address for this contract */
    address payable internal admin;
    
    modifier adminOnly() {
        //allows only the admin of this contract to call the function
        require(msg.sender == admin, '1');
        _;
    }

        /**
    * @notice Set a new Admin
    * @dev Changes the address for the admin parameter
    * @param _newAdmin address of the new Controller Admin
    */
    function setNewAdmin(address payable _newAdmin) external adminOnly {
        address _oldAdmin = admin;
        admin = _newAdmin;

        emit NewAdmin(_oldAdmin, _newAdmin);
    }
}

File 17 of 20 : ReentrancyGuard.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.7.0;

/**
 * @dev Contract module that helps prevent reentrant calls to a function.
 *
 * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
 * available, which can be applied to functions to make sure there are no nested
 * (reentrant) calls to them.
 *
 * Note that because there is a single `nonReentrant` guard, functions marked as
 * `nonReentrant` may not call one another. This can be worked around by making
 * those functions `private`, and then adding `external` `nonReentrant` entry
 * points to them.
 *
 * TIP: If you would like to learn more about reentrancy and alternative ways
 * to protect against it, check out our blog post
 * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
 */
abstract contract ReentrancyGuard {
    // Booleans are more expensive than uint256 or any type that takes up a full
    // word because each write operation emits an extra SLOAD to first read the
    // slot's contents, replace the bits taken up by the boolean, and then write
    // back. This is the compiler's defense against contract upgrades and
    // pointer aliasing, and it cannot be disabled.

    // The values being non-zero value makes deployment a bit more expensive,
    // but in exchange the refund on every call to nonReentrant will be lower in
    // amount. Since refunds are capped to a percentage of the total
    // transaction's gas, it is best to keep them low in cases like this one, to
    // increase the likelihood of the full refund coming into effect.
    uint256 private constant _NOT_ENTERED = 1;
    uint256 private constant _ENTERED = 2;

    uint256 private _status;

    constructor () {
        _status = _NOT_ENTERED;
    }

    /**
     * @dev Prevents a contract from calling itself, directly or indirectly.
     * Calling a `nonReentrant` function from another `nonReentrant`
     * function is not supported. It is possible to prevent this from happening
     * by making the `nonReentrant` function external, and make it call a
     * `private` function that does the actual work.
     */
    modifier nonReentrant() {
        // On the first call to nonReentrant, _notEntered will be true
        require(_status != _ENTERED, "ReentrancyGuard: reentrant call");

        // Any calls to nonReentrant after this point will fail
        _status = _ENTERED;

        _;

        // By storing the original value once again, a refund is triggered (see
        // https://eips.ethereum.org/EIPS/eip-2200)
        _status = _NOT_ENTERED;
    }
}

File 18 of 20 : Address.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.7.6;
/**
 * @dev Collection of functions related to the address type
 */
library Address {
    /**
     * @dev Returns true if `account` is a contract.
     *
     * [IMPORTANT]
     * ====
     * It is unsafe to assume that an address for which this function returns
     * false is an externally-owned account (EOA) and not a contract.
     *
     * Among others, `isContract` will return false for the following
     * types of addresses:
     *
     *  - an externally-owned account
     *  - a contract in construction
     *  - an address where a contract will be created
     *  - an address where a contract lived, but was destroyed
     * ====
     */
    function isContract(address account) internal view returns (bool) {
        // This method relies on extcodesize, which returns 0 for contracts in
        // construction, since the code is only stored at the end of the
        // constructor execution.

        uint256 size;
        // solhint-disable-next-line no-inline-assembly
        assembly { size := extcodesize(account) }
        return size > 0;
    }

    /**
     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
     * `recipient`, forwarding all available gas and reverting on errors.
     *
     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
     * of certain opcodes, possibly making contracts go over the 2300 gas limit
     * imposed by `transfer`, making them unable to receive funds via
     * `transfer`. {sendValue} removes this limitation.
     *
     * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
     *
     * IMPORTANT: because control is transferred to `recipient`, care must be
     * taken to not create reentrancy vulnerabilities. Consider using
     * {ReentrancyGuard} or the
     * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
     */
    function sendValue(address payable recipient, uint256 amount) internal {
        require(address(this).balance >= amount, "Address: insufficient balance");

        // solhint-disable-next-line avoid-low-level-calls, avoid-call-value
        (bool success, ) = recipient.call{ value: amount }("");
        require(success, "Address: unable to send value, recipient may have reverted");
    }

    /**
     * @dev Performs a Solidity function call using a low level `call`. A
     * plain`call` is an unsafe replacement for a function call: use this
     * function instead.
     *
     * If `target` reverts with a revert reason, it is bubbled up by this
     * function (like regular Solidity function calls).
     *
     * Returns the raw returned data. To convert to the expected return value,
     * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
     *
     * Requirements:
     *
     * - `target` must be a contract.
     * - calling `target` with `data` must not revert.
     *
     * _Available since v3.1._
     */
    function functionCall(address target, bytes memory data) internal returns (bytes memory) {
      return functionCall(target, data, "Address: low-level call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
     * `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but also transferring `value` wei to `target`.
     *
     * Requirements:
     *
     * - the calling contract must have an ETH balance of at least `value`.
     * - the called Solidity function must be `payable`.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
        return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
    }

    /**
     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
     * with `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) {
        require(address(this).balance >= value, "Address: insufficient balance for call");
        require(isContract(target), "Address: call to non-contract");

        // solhint-disable-next-line avoid-low-level-calls
        (bool success, bytes memory returndata) = target.call{ value: value }(data);
        return _verifyCallResult(success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
        return functionStaticCall(target, data, "Address: low-level static call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(address target, bytes memory data, string memory errorMessage) internal view returns (bytes memory) {
        require(isContract(target), "Address: static call to non-contract");

        // solhint-disable-next-line avoid-low-level-calls
        (bool success, bytes memory returndata) = target.staticcall(data);
        return _verifyCallResult(success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionDelegateCall(target, data, "Address: low-level delegate call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {
        require(isContract(target), "Address: delegate call to non-contract");

        // solhint-disable-next-line avoid-low-level-calls
        (bool success, bytes memory returndata) = target.delegatecall(data);
        return _verifyCallResult(success, returndata, errorMessage);
    }

    function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private pure returns(bytes memory) {
        if (success) {
            return returndata;
        } else {
            // Look for revert reason and bubble it up if present
            if (returndata.length > 0) {
                // The easiest way to bubble the revert reason is using memory via assembly

                // solhint-disable-next-line no-inline-assembly
                assembly {
                    let returndata_size := mload(returndata)
                    revert(add(32, returndata), returndata_size)
                }
            } else {
                revert(errorMessage);
            }
        }
    }
}

File 19 of 20 : IERC721.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.7.6;

import "./IERC165.sol";

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

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

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

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

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

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

    /**
     * @dev Transfers `tokenId` token from `from` to `to`.
     *
     * WARNING: Usage of this method is discouraged, use {safeTransferFrom} whenever possible.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must be owned by `from`.
     * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(
        address from,
        address to,
        uint256 tokenId
    ) external;

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

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

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

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

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

File 20 of 20 : IERC165.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.7.6;

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

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

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"address","name":"_palToken","type":"address"},{"internalType":"address","name":"_controller","type":"address"},{"internalType":"address","name":"_underlying","type":"address"},{"internalType":"address","name":"_interestModule","type":"address"},{"internalType":"address","name":"_delegator","type":"address"},{"internalType":"address","name":"_palLoanToken","type":"address"},{"internalType":"address","name":"_aaveAddress","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"AddReserve","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"borrower","type":"address"},{"indexed":false,"internalType":"address","name":"newDelegatee","type":"address"},{"indexed":false,"internalType":"address","name":"underlying","type":"address"},{"indexed":false,"internalType":"address","name":"palPool","type":"address"},{"indexed":false,"internalType":"address","name":"loanAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"palLoanTokenId","type":"uint256"}],"name":"ChangeLoanDelegatee","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"borrower","type":"address"},{"indexed":false,"internalType":"address","name":"delegatee","type":"address"},{"indexed":false,"internalType":"address","name":"underlying","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"address","name":"palPool","type":"address"},{"indexed":false,"internalType":"uint256","name":"usedFees","type":"uint256"},{"indexed":false,"internalType":"address","name":"loanAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"palLoanTokenId","type":"uint256"},{"indexed":false,"internalType":"bool","name":"wasKilled","type":"bool"}],"name":"CloseLoan","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"address","name":"palPool","type":"address"}],"name":"Deposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"borrower","type":"address"},{"indexed":false,"internalType":"address","name":"delegatee","type":"address"},{"indexed":false,"internalType":"address","name":"underlying","type":"address"},{"indexed":false,"internalType":"address","name":"palPool","type":"address"},{"indexed":false,"internalType":"uint256","name":"newFeesAmount","type":"uint256"},{"indexed":false,"internalType":"address","name":"loanAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"palLoanTokenId","type":"uint256"}],"name":"ExpandLoan","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldAdmin","type":"address"},{"indexed":false,"internalType":"address","name":"newAdmin","type":"address"}],"name":"NewAdmin","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"borrower","type":"address"},{"indexed":false,"internalType":"address","name":"delegatee","type":"address"},{"indexed":false,"internalType":"address","name":"underlying","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"address","name":"palPool","type":"address"},{"indexed":false,"internalType":"address","name":"loanAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"palLoanTokenId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"startBlock","type":"uint256"}],"name":"NewLoan","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"RemoveReserve","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"address","name":"palPool","type":"address"}],"name":"Withdraw","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"WithdrawFees","type":"event"},{"inputs":[],"name":"_updateInterest","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"accrualBlockNumber","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"accruedFees","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"addReserve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_delegatee","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"uint256","name":"_feeAmount","type":"uint256"}],"name":"borrow","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"borrowIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"borrowRatePerBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_loan","type":"address"},{"internalType":"address","name":"_newDelegatee","type":"address"}],"name":"changeBorrowDelegatee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"claimBlockNumber","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_loan","type":"address"}],"name":"closeBorrow","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"controller","outputs":[{"internalType":"contract IPaladinController","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"deposit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"exchangeRateCurrent","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"exchangeRateStored","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_loan","type":"address"},{"internalType":"uint256","name":"_feeAmount","type":"uint256"}],"name":"expandBorrow","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_loanAddress","type":"address"}],"name":"getBorrowData","outputs":[{"internalType":"address","name":"_borrower","type":"address"},{"internalType":"address","name":"_delegatee","type":"address"},{"internalType":"address","name":"_loan","type":"address"},{"internalType":"uint256","name":"_palLoanTokenId","type":"uint256"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"address","name":"_underlying","type":"address"},{"internalType":"uint256","name":"_feesAmount","type":"uint256"},{"internalType":"uint256","name":"_feesUsed","type":"uint256"},{"internalType":"uint256","name":"_startBlock","type":"uint256"},{"internalType":"uint256","name":"_closeBlock","type":"uint256"},{"internalType":"bool","name":"_closed","type":"bool"},{"internalType":"bool","name":"_killed","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_borrower","type":"address"}],"name":"getLoansByBorrower","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLoansPools","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_loanAddress","type":"address"}],"name":"idOfLoan","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_loan","type":"address"}],"name":"isKillable","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_loanAddress","type":"address"},{"internalType":"address","name":"_user","type":"address"}],"name":"isLoanOwner","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_loan","type":"address"}],"name":"killBorrow","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"killFactor","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"killerRatio","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"minBorrowFees","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minBorrowLength","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"palLoanToken","outputs":[{"internalType":"contract IPalLoanToken","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"palToken","outputs":[{"internalType":"contract IPalToken","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"removeReserve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"reserveFactor","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address payable","name":"_newAdmin","type":"address"}],"name":"setNewAdmin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_newController","type":"address"}],"name":"setNewController","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_delegator","type":"address"}],"name":"setNewDelegator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_interestModule","type":"address"}],"name":"setNewInterestModule","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"supplyRatePerBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalBorrowed","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalReserve","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"underlying","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"underlyingBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"underlyingBalanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_length","type":"uint256"}],"name":"updateMinBorrowLength","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_reserveFactor","type":"uint256"},{"internalType":"uint256","name":"_killerRatio","type":"uint256"}],"name":"updatePoolFactors","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"withdraw","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"address","name":"_recipient","type":"address"}],"name":"withdrawFees","outputs":[],"stateMutability":"nonpayable","type":"function"}]

60c06040526002805460ff60a01b1916905561b0ea60065567016345785d8a00006007556702c68af0bb14000060085560006012553480156200004157600080fd5b506040516200514738038062005147833981016040819052620000649162000133565b6001601181905560108054336001600160a01b0319918216179091556002805482166001600160a01b039a8b16179055600d80548216988a16989098179097558054871686891617905543600955600e80548716948816949094179093556ec097ce7bc90715b34b9f1000000000600a55600f805486169287169290921790915560008054909416941693909317909155606090811b6001600160601b031990811660805291901b1660a052620001c7565b80516001600160a01b03811681146200012e57600080fd5b919050565b600080600080600080600060e0888a0312156200014e578283fd5b620001598862000116565b9650620001696020890162000116565b9550620001796040890162000116565b9450620001896060890162000116565b9350620001996080890162000116565b9250620001a960a0890162000116565b9150620001b960c0890162000116565b905092959891949750929550565b60805160601c60a05160601c614f51620001f660003980611a2b525080611a4d5280611c195250614f516000f3fe608060405234801561001057600080fd5b50600436106102ff5760003560e01c806371bfbd4e1161019c578063b6331d46116100ee578063c7f3b6b111610097578063dd2cc3f311610071578063dd2cc3f3146105a8578063f77c4791146105bb578063f8f9da28146105c3576102ff565b8063c7f3b6b11461056f578063d4a3109d14610582578063d5c4a11714610595576102ff565b8063c1bce0b7116100c8578063c1bce0b71461051e578063c1c55d0c14610531578063c5d40b8a14610544576102ff565b8063b6331d46146104fb578063b6b55f2514610503578063bd6d894d14610516576102ff565b806393610b8d11610150578063a764804f1161012a578063a764804f146104d8578063aa5af0fd146104eb578063ae9d70b0146104f3576102ff565b806393610b8d146104aa5780639bdaa5e6146104bd578063a0187e8a146104d0576102ff565b806386a2a4381161018157806386a2a438146104715780638eec99c814610484578063935a8b8414610497576102ff565b806371bfbd4e146104565780637312520214610469576102ff565b8063516e2f2a11610255578063622d2efc116102095780636c540baf116101e35780636c540baf146104335780636f307dc31461043b57806370a0823114610443576102ff565b8063622d2efc146104035780636558d7b114610423578063682c20581461042b576102ff565b806357d1bc961161023a57806357d1bc96146103d557806359356c5c146103e857806359baef40146103f0576102ff565b8063516e2f2a146103af578063560acbc2146103c2576102ff565b8063304d5f07116102b75780634b8243c9116102915780634b8243c91461038a5780634c19386c1461039f5780634c68df67146103a7576102ff565b8063304d5f07146103655780634322b7141461036d5780634754990314610375576102ff565b80631e348629116102e85780631e348629146103355780632d66da9f1461033d5780632e1a7d4d14610352576102ff565b8063130cbe5c14610304578063182df0f51461032d575b600080fd5b61031761031236600461490c565b6105cb565b6040516103249190614e7c565b60405180910390f35b6103176105f1565b610317610601565b610345610607565b6040516103249190614db3565b610317610360366004614a40565b610669565b61031761068d565b610317610693565b61037d610699565b6040516103249190614ab5565b61039d610398366004614a40565b6106a8565b005b610317610780565b610317610786565b61039d6103bd36600461489c565b61078c565b61039d6103d0366004614a40565b610825565b61039d6103e3366004614a40565b610968565b610317610a1f565b61039d6103fe36600461489c565b610ab9565b6104166104113660046148d4565b610b6b565b6040516103249190614e00565b610317610c07565b610317610c0d565b610317610c13565b61037d610c19565b61031761045136600461489c565b610c28565b61039d61046436600461489c565b610cc2565b610416610cdf565b61034561047f36600461489c565b610eb8565b61039d61049236600461489c565b610f76565b6103176104a536600461489c565b611050565b61039d6104b8366004614a94565b611134565b6103176104cb36600461489c565b61120f565b61037d61122a565b61039d6104e636600461489c565b611239565b6103176112d2565b6103176112d8565b610317611337565b610317610511366004614a40565b611343565b61031761135f565b61031761052c366004614937565b611372565b61041661053f36600461489c565b61139a565b61055761055236600461489c565b6114cb565b6040516103249c9b9a99989796959493929190614cf1565b61039d61057d36600461489c565b6116b6565b61039d6105903660046148d4565b6116d0565b6103176105a3366004614a40565b6116ef565b61039d6105b6366004614a70565b611831565b61037d611995565b6103176119a4565b60006105d5611a00565b6105de57600080fd5b6105e88383611cd3565b90505b92915050565b60006105fb612063565b90505b90565b60125481565b6060600c80548060200260200160405190810160405280929190818152602001828054801561065f57602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311610641575b5050505050905090565b6000610673611a00565b61067c57600080fd5b6106858261214f565b90505b919050565b60075481565b60085481565b6002546001600160a01b031681565b6010546001600160a01b03163314610707576040805162461bcd60e51b815260206004820152600160248201527f3100000000000000000000000000000000000000000000000000000000000000604482015290519081900360640190fd5b61070f610cdf565b61071857600080fd5b60035461072590826124f3565b600355601054600154610746916001600160a01b039182169116308461254d565b7fa3e421ddc9810d39cc90c4a3998578420d1c1ebc5b67a3c133c4044a1114de99816040516107759190614e7c565b60405180910390a150565b60045481565b60035481565b6010546001600160a01b031633146107eb576040805162461bcd60e51b815260206004820152600160248201527f3100000000000000000000000000000000000000000000000000000000000000604482015290519081900360640190fd5b600f80547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0392909216919091179055565b6010546001600160a01b03163314610884576040805162461bcd60e51b815260206004820152600160248201527f3100000000000000000000000000000000000000000000000000000000000000604482015290519081900360640190fd5b61088c610cdf565b61089557600080fd5b61089d610a1f565b81111580156108ae57506003548111155b6040518060400160405280600281526020017f31390000000000000000000000000000000000000000000000000000000000008152509061090b5760405162461bcd60e51b81526004016109029190614e0b565b60405180910390fd5b5060035461091990826125db565b600355601054600154610939916001600160a01b0391821691168361261d565b7ff78dc30da85b5e9540c710154f60a2e296f1461551b7995ef2c7112e3c2be9c3816040516107759190614e7c565b6010546001600160a01b031633146109c7576040805162461bcd60e51b815260206004820152600160248201527f3100000000000000000000000000000000000000000000000000000000000000604482015290519081900360640190fd5b60408051808201909152600281527f3238000000000000000000000000000000000000000000000000000000000000602082015281610a195760405162461bcd60e51b81526004016109029190614e0b565b50600655565b6001546040517f70a082310000000000000000000000000000000000000000000000000000000081526000916001600160a01b0316906370a0823190610a69903090600401614ab5565b60206040518083038186803b158015610a8157600080fd5b505afa158015610a95573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105fb9190614a58565b6010546001600160a01b0316331480610adc5750600d546001600160a01b031633145b6040518060400160405280600281526020017f323900000000000000000000000000000000000000000000000000000000000081525090610b305760405162461bcd60e51b81526004016109029190614e0b565b50600d80547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0392909216919091179055565b600080546001600160a01b038084169116632d7254e5610b8a8661120f565b6040518263ffffffff1660e01b8152600401610ba69190614e7c565b60206040518083038186803b158015610bbe57600080fd5b505afa158015610bd2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bf691906148b8565b6001600160a01b0316149392505050565b60065481565b60055481565b60095481565b6001546001600160a01b031681565b6002546040517f70a082310000000000000000000000000000000000000000000000000000000081526000916001600160a01b0316906370a0823190610c72908590600401614ab5565b60206040518083038186803b158015610c8a57600080fd5b505afa158015610c9e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106859190614a58565b610cca611a00565b610cd357600080fd5b610cdc816126a2565b50565b6009546000904390811415610cf85760019150506105fe565b6000610d02610a1f565b60048054600354600554600a54600e546040517f200d16aa00000000000000000000000000000000000000000000000000000000815296975093959294919390926000926001600160a01b039092169163200d16aa91610d6a9130918b918b918b9101614d5f565b60206040518083038186803b158015610d8257600080fd5b505afa158015610d96573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610dba9190614a58565b90506000610dd3600954896125db90919063ffffffff16565b90506000610de18383612dd7565b90506000610e01670de0b6b3a7640000610dfb848b612dd7565b90612e30565b90506000610e0f89836124f3565b90506000610e3e610e37670de0b6b3a7640000610dfb86600854612dd790919063ffffffff16565b8a906124f3565b90506000610e72610e37670de0b6b3a7640000610dfb87610e6c6007546008546125db90919063ffffffff16565b90612dd7565b90506000610e8f610e37670de0b6b3a7640000610dfb898d612dd7565b60049490945550600391909155600555600a555050506009969096555060019550505050505090565b6000546040517f6a2291650000000000000000000000000000000000000000000000000000000081526060916001600160a01b031690636a22916590610f049085903090600401614b05565b60006040518083038186803b158015610f1c57600080fd5b505afa158015610f30573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052610685919081019061496b565b6010546001600160a01b03163314610fd5576040805162461bcd60e51b815260206004820152600160248201527f3100000000000000000000000000000000000000000000000000000000000000604482015290519081900360640190fd5b601080546001600160a01b038381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040805191909216808252602082019390935281517ff9ffabca9c8276e99321725bcb43fb076a6c66a54b7f21c4e8146d8519b417dc929181900390910190a15050565b6002546040517f70a0823100000000000000000000000000000000000000000000000000000000815260009182916001600160a01b03909116906370a082319061109e908690600401614ab5565b60206040518083038186803b1580156110b657600080fd5b505afa1580156110ca573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110ee9190614a58565b9050806110ff576000915050610688565b6000611109612063565b905060006111178383612dd7565b905061112b81670de0b6b3a7640000612e30565b95945050505050565b6010546001600160a01b03163314611193576040805162461bcd60e51b815260206004820152600160248201527f3100000000000000000000000000000000000000000000000000000000000000604482015290519081900360640190fd5b6000821180156111a35750600081115b80156111af5750808210155b6040518060400160405280600281526020017f3238000000000000000000000000000000000000000000000000000000000000815250906112035760405162461bcd60e51b81526004016109029190614e0b565b50600891909155600755565b6001600160a01b03166000908152600b602052604090205490565b6000546001600160a01b031681565b6010546001600160a01b03163314611298576040805162461bcd60e51b815260206004820152600160248201527f3100000000000000000000000000000000000000000000000000000000000000604482015290519081900360640190fd5b600e80547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0392909216919091179055565b600a5481565b600e546000906001600160a01b031663e4ef277a306112f5610a1f565b600480546003546008546040517fffffffff0000000000000000000000000000000000000000000000000000000060e089901b168152610a6996959401614d85565b670d2f13f7789f000081565b600061134d611a00565b61135657600080fd5b61068582612e72565b6000611369610cdf565b506105fb612063565b600061137c611a00565b61138557600080fd5b611390848484613157565b90505b9392505050565b6001600160a01b038082166000908152600b6020908152604080832081516101808101835281548152600182015486169381019390935260028101548516918301919091526003810154606083015260048101549093166080820152600583015460a0820152600683015460c0820152600783015460e08201526008830154610100808301919091526009840154610120830152600a9093015460ff80821615801561014085015294909104161515610160820152909161145f576000915050610688565b6000611490826060015161148a8460e00151610dfb600a548760600151612dd790919063ffffffff16565b906125db565b905060006114b78360a00151610dfb670de0b6b3a764000085612dd790919063ffffffff16565b670d2f13f7789f0000111595945050505050565b6001600160a01b038082166000908152600b602090815260408083208151610180810183528154808252600183015487169482019490945260028201548616818401526003820154606082015260048083015487166080830152600583015460a0830152600683015460c0830152600783015460e08301526008830154610100808401919091526009840154610120840152600a9093015460ff80821615156101408501529390049092161515610160820152845492517f2d7254e5000000000000000000000000000000000000000000000000000000008152949586958695869586958695869586958695869586958695949190911692632d7254e5926115d592909101614e7c565b60206040518083038186803b1580156115ed57600080fd5b505afa158015611601573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061162591906148b8565b6020820151604083015183516060850151608086015160a087015161014088015161167057606088015160e0890151600a5461166b929161148a91610dfb908490612dd7565b611676565b8760c001515b8861010001518961012001518a61014001518b61016001519c509c509c509c509c509c509c509c509c509c509c509c505091939597999b5091939597999b565b6116be611a00565b6116c757600080fd5b610cdc816138a2565b6116d8611a00565b6116e157600080fd5b6116eb8282613f64565b5050565b60006116f9610a1f565b82106040518060400160405280600181526020017f39000000000000000000000000000000000000000000000000000000000000008152509061174f5760405162461bcd60e51b81526004016109029190614e0b565b50600e546000906001600160a01b031663200d16aa306117718661148a610a1f565b60045461177e90886124f3565b6003546040518563ffffffff1660e01b81526004016117a09493929190614d5f565b60206040518083038186803b1580156117b857600080fd5b505afa1580156117cc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117f09190614a58565b90506000611816670de0b6b3a7640000610dfb61180d8786612dd7565b60065490612dd7565b905060008111611827576001611829565b805b949350505050565b6010546001600160a01b03163314806118545750600d546001600160a01b031633145b6040518060400160405280600281526020017f3239000000000000000000000000000000000000000000000000000000000000815250906118a85760405162461bcd60e51b81526004016109029190614e0b565b506118b1610cdf565b6118ba57600080fd5b60055482111580156118ce57506003548211155b6040518060400160405280600281526020017f3334000000000000000000000000000000000000000000000000000000000000815250906119225760405162461bcd60e51b81526004016109029190614e0b565b5060055461193090836125db565b60055560035461194090836125db565b60035560015461195a906001600160a01b0316828461261d565b7f835862a12039ab712842887f732f62f9ba4e46c8a157b8f2ece290bb03cb6229826040516119899190614e7c565b60405180910390a15050565b600d546001600160a01b031681565b600e546000906001600160a01b031663200d16aa306119c1610a1f565b600480546003546040517fffffffff0000000000000000000000000000000000000000000000000000000060e088901b168152610a6995949301614d5f565b6040517f8dbefee20000000000000000000000000000000000000000000000000000000081526000907f0000000000000000000000000000000000000000000000000000000000000000907f00000000000000000000000000000000000000000000000000000000000000009083906001600160a01b03831690638dbefee290611a8e903090600401614ab5565b60206040518083038186803b158015611aa657600080fd5b505afa158015611aba573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ade9190614a58565b9050600081118015611af257504360125414155b15611cc9576040517f9a99b4f00000000000000000000000000000000000000000000000000000000081526001600160a01b03831690639a99b4f090611b3e9030908590600401614ac9565b600060405180830381600087803b158015611b5857600080fd5b505af1158015611b6c573d6000803e3d6000fd5b50506040517f70a08231000000000000000000000000000000000000000000000000000000008152600092506001600160a01b03861691506370a0823190611bb8903090600401614ab5565b60206040518083038186803b158015611bd057600080fd5b505afa158015611be4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c089190614a58565b9050611c3e6001600160a01b0385167f000000000000000000000000000000000000000000000000000000000000000083614324565b6040517fadc9772e0000000000000000000000000000000000000000000000000000000081526001600160a01b0384169063adc9772e90611c859030908590600401614ac9565b600060405180830381600087803b158015611c9f57600080fd5b505af1158015611cb3573d6000803e3d6000fd5b50504360125550600195506105fe945050505050565b6001935050505090565b600060026011541415611d2d576040805162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015290519081900360640190fd5b600260118190556001600160a01b0384166000908152600b6020908152604091829020600a81015483518085019094529383527f3134000000000000000000000000000000000000000000000000000000000000918301919091529160ff1615611daa5760405162461bcd60e51b81526004016109029190614e0b565b50611db58433610b6b565b6040518060400160405280600281526020017f313500000000000000000000000000000000000000000000000000000000000081525090611e095760405162461bcd60e51b81526004016109029190614e0b565b5060008311611e1757600080fd5b611e1f610cdf565b611e2857600080fd5b60028101546000805483546040517f6352211e0000000000000000000000000000000000000000000000000000000081526001600160a01b039485169490921691636352211e91611e7b91600401614e7c565b60206040518083038186803b158015611e9357600080fd5b505afa158015611ea7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ecb91906148b8565b6005840154909150611edd90866124f3565b60058401556002830154600154611f03916001600160a01b03918216918491168861254d565b6040517f682904a50000000000000000000000000000000000000000000000000000000081526001600160a01b0383169063682904a590611f48908890600401614e7c565b602060405180830381600087803b158015611f6257600080fd5b505af1158015611f76573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f9a9190614a20565b6040518060400160405280600281526020017f313700000000000000000000000000000000000000000000000000000000000081525090611fee5760405162461bcd60e51b81526004016109029190614e0b565b5060018381015490546005850154600286015486546040517f23d5462a0f15711328244c2dee4e7c32ae4c4f8f74faad197b67566f38b021e79561204c9588956001600160a01b039283169591831694309491939092169190614ba1565b60405180910390a150506001601155509092915050565b600080600260009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b1580156120b457600080fd5b505afa1580156120c8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120ec9190614a58565b90508061210457670de0b6b3a76400009150506105fe565b600061210e610a1f565b9050600061212d60035461148a600454856124f390919063ffffffff16565b905061214583610dfb83670de0b6b3a7640000612dd7565b93505050506105fe565b6000600260115414156121a9576040805162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015290519081900360640190fd5b60026011556121b6610cdf565b6121bf57600080fd5b816121c933610c28565b10156040518060400160405280600281526020017f31300000000000000000000000000000000000000000000000000000000000008152509061221f5760405162461bcd60e51b81526004016109029190614e0b565b50600061222a612063565b905060006122388483612dd7565b9050600061224e82670de0b6b3a7640000612e30565b9050612258610a1f565b8111156040518060400160405280600181526020017f3900000000000000000000000000000000000000000000000000000000000000815250906122af5760405162461bcd60e51b81526004016109029190614e0b565b506002546040517f9dc29fac0000000000000000000000000000000000000000000000000000000081526001600160a01b0390911690639dc29fac906122fb9033908990600401614ac9565b602060405180830381600087803b15801561231557600080fd5b505af1158015612329573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061234d9190614a20565b6040518060400160405280600281526020017f3231000000000000000000000000000000000000000000000000000000000000815250906123a15760405162461bcd60e51b81526004016109029190614e0b565b506001546123b9906001600160a01b0316338361261d565b600d546040517f5c0d1b0d0000000000000000000000000000000000000000000000000000000081526001600160a01b0390911690635c0d1b0d9061240690309033908690600401614b1f565b60206040518083038186803b15801561241e57600080fd5b505afa158015612432573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124569190614a20565b6040518060400160405280600281526020017f3234000000000000000000000000000000000000000000000000000000000000815250906124aa5760405162461bcd60e51b81526004016109029190614e0b565b507f56c54ba9bd38d8fd62012e42c7ee564519b09763c426d331b3661b537ead19b23386306040516124de93929190614ae2565b60405180910390a16001601155949350505050565b6000828201838110156105e8576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b604080516001600160a01b0380861660248301528416604482015260648082018490528251808303909101815260849091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f23b872dd000000000000000000000000000000000000000000000000000000001790526125d590859061447a565b50505050565b60006105e883836040518060400160405280601f81526020017f536166654d6174683a207375627472616374696f6e20756e646572666c6f770081525061452b565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb0000000000000000000000000000000000000000000000000000000017905261269d90849061447a565b505050565b600260115414156126fa576040805162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015290519081900360640190fd5b600260118190556001600160a01b0382166000908152600b6020908152604091829020600a81015483518085019094529383527f3134000000000000000000000000000000000000000000000000000000000000918301919091529160ff16156127775760405162461bcd60e51b81526004016109029190614e0b565b506127828233610b6b565b6040518060400160405280600281526020017f3135000000000000000000000000000000000000000000000000000000000000815250906127d65760405162461bcd60e51b81526004016109029190614e0b565b506127df610cdf565b6127e857600080fd5b6000805482546040517f6352211e0000000000000000000000000000000000000000000000000000000081526001600160a01b0390921691636352211e9161283291600401614e7c565b60206040518083038186803b15801561284a57600080fd5b505afa15801561285e573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061288291906148b8565b600283015460038401546007850154600a549394506001600160a01b03909216926000926128bb929161148a9190610dfb908490612dd7565b600654600886015491925060009183916128d591906124f3565b4310156129e957600e546000906001600160a01b031663200d16aa306128f9610a1f565b600480546003546040517fffffffff0000000000000000000000000000000000000000000000000000000060e088901b16815261293895949301614d5f565b60206040518083038186803b15801561295057600080fd5b505afa158015612964573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129889190614a58565b905060006129a94361148a6006548b600801546124f390919063ffffffff16565b90506129d8670de0b6b3a7640000610dfb6129d1858c60030154612dd790919063ffffffff16565b8490612dd7565b93506129e483856124f3565b925050505b85600501548111156129fc575060058501545b600a860180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055600686018190554360098701556003860154612a5290612a4990856124f3565b600454906125db565b6004556000612a6182856125db565b90506000612a86670de0b6b3a7640000610dfb60075488612dd790919063ffffffff16565b9050612ab5612aac670de0b6b3a7640000610dfb85600854612dd790919063ffffffff16565b600354906124f3565b600355600854612aea90612ad790670de0b6b3a764000090610dfb9086612dd7565b600554612ae490846124f3565b906124f3565b6005556040517fd05951a00000000000000000000000000000000000000000000000000000000081526001600160a01b0387169063d05951a090612b32908690600401614e7c565b600060405180830381600087803b158015612b4c57600080fd5b505af1158015612b60573d6000803e3d6000fd5b50506000548a546040517f42966c680000000000000000000000000000000000000000000000000000000081526001600160a01b0390921693506342966c689250612bad91600401614e7c565b602060405180830381600087803b158015612bc757600080fd5b505af1158015612bdb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612bff9190614a20565b6040518060400160405280600281526020017f333300000000000000000000000000000000000000000000000000000000000081525090612c535760405162461bcd60e51b81526004016109029190614e0b565b50600d5460028901546040517f08bc016e0000000000000000000000000000000000000000000000000000000081526001600160a01b03928316926308bc016e92612ca69230928d921690600401614b43565b60206040518083038186803b158015612cbe57600080fd5b505afa158015612cd2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612cf69190614a20565b6040518060400160405280600281526020017f323500000000000000000000000000000000000000000000000000000000000081525090612d4a5760405162461bcd60e51b81526004016109029190614e0b565b507f976725bed73d37e8b46d0d5694646bfa4d33c5b84bae26b3194570f3ad53befb878960010160009054906101000a90046001600160a01b0316600160009054906101000a90046001600160a01b03168b6003015430888f8f600001546000604051612dbf99989796959493929190614c67565b60405180910390a15050600160115550505050505050565b600082612de6575060006105eb565b82820282848281612df357fe5b04146105e85760405162461bcd60e51b8152600401808060200182810382526021815260200180614e9b6021913960400191505060405180910390fd5b60006105e883836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f0000000000008152506145c2565b600060026011541415612ecc576040805162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015290519081900360640190fd5b6002601155612ed9610cdf565b612ee257600080fd5b6000612eec612063565b90506000612f0284670de0b6b3a7640000612dd7565b90506000612f108284612e30565b600154909150612f2b906001600160a01b031633308861254d565b6002546040517f40c10f190000000000000000000000000000000000000000000000000000000081526001600160a01b03909116906340c10f1990612f769033908590600401614ac9565b602060405180830381600087803b158015612f9057600080fd5b505af1158015612fa4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612fc89190614a20565b6040518060400160405280600281526020017f32300000000000000000000000000000000000000000000000000000000000008152509061301c5760405162461bcd60e51b81526004016109029190614e0b565b507fe31c7b8d08ee7db0afa68782e1028ef92305caeea8626633ad44d413e30f6b2f33863060405161305093929190614ae2565b60405180910390a1600d546040517f806f8ab20000000000000000000000000000000000000000000000000000000081526001600160a01b039091169063806f8ab2906130a590309033908690600401614b1f565b60206040518083038186803b1580156130bd57600080fd5b505afa1580156130d1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130f59190614a20565b6040518060400160405280600281526020017f3131000000000000000000000000000000000000000000000000000000000000815250906131495760405162461bcd60e51b81526004016109029190614e0b565b506001601155949350505050565b6000600260115414156131b1576040805162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015290519081900360640190fd5b60026011556131be610a1f565b83106040518060400160405280600181526020017f3900000000000000000000000000000000000000000000000000000000000000815250906132145760405162461bcd60e51b81526004016109029190614e0b565b5060408051808201909152600281527f323200000000000000000000000000000000000000000000000000000000000060208201526001600160a01b0385166132705760405162461bcd60e51b81526004016109029190614e0b565b5060408051808201909152600281527f32370000000000000000000000000000000000000000000000000000000000006020820152836132c35760405162461bcd60e51b81526004016109029190614e0b565b506132cd836116ef565b8210156040518060400160405280600281526020017f3233000000000000000000000000000000000000000000000000000000000000815250906133245760405162461bcd60e51b81526004016109029190614e0b565b5061332d610cdf565b61333657600080fd5b600454339061334590856124f3565b600455600f54600090613360906001600160a01b0316614627565b60015490915061337a906001600160a01b0316828761261d565b600154613392906001600160a01b031683838761254d565b6001546040517f890dcf540000000000000000000000000000000000000000000000000000000081526001600160a01b038084169263890dcf54926133e692309288929116908c908c908c90600401614be1565b602060405180830381600087803b15801561340057600080fd5b505af1158015613414573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134389190614a20565b6040518060400160405280600281526020017f31320000000000000000000000000000000000000000000000000000000000008152509061348c5760405162461bcd60e51b81526004016109029190614e0b565b50600c805460018101825560009182527fdf6966c971051c3d54ec59162606531493a51404a002842f56009d7e5cf4a8c70180547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b038481169190911790915581546040517f63185c420000000000000000000000000000000000000000000000000000000081529116906363185c429061353790869030908790600401614b43565b602060405180830381600087803b15801561355157600080fd5b505af1158015613565573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135899190614a58565b9050604051806101800160405280828152602001886001600160a01b03168152602001836001600160a01b03168152602001878152602001600160009054906101000a90046001600160a01b03166001600160a01b0316815260200186815260200160008152602001600a5481526020014381526020016000815260200160001515815260200160001515815250600b6000846001600160a01b03166001600160a01b031681526020019081526020016000206000820151816000015560208201518160010160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555060408201518160020160006101000a8154816001600160a01b0302191690836001600160a01b031602179055506060820151816003015560808201518160040160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555060a0820151816005015560c0820151816006015560e082015181600701556101008201518160080155610120820151816009015561014082015181600a0160006101000a81548160ff02191690831515021790555061016082015181600a0160016101000a81548160ff021916908315150217905550905050600d60009054906101000a90046001600160a01b03166001600160a01b031663f5565ddf30858a8a8a886040518763ffffffff1660e01b815260040161379b96959493929190614cb9565b60206040518083038186803b1580156137b357600080fd5b505afa1580156137c7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137eb9190614a20565b6040518060400160405280600281526020017f31330000000000000000000000000000000000000000000000000000000000008152509061383f5760405162461bcd60e51b81526004016109029190614e0b565b506001546040517f8f11691cf96727f419bd99b50853d8351f147118e4778f62bdaa8528ab3e50bb9161388b9186918b916001600160a01b03909116908b903090899089904390614c1b565b60405180910390a160016011559695505050505050565b600260115414156138fa576040805162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015290519081900360640190fd5b600260118190556001600160a01b0382166000908152600b6020908152604091829020600a81015483518085019094529383527f313400000000000000000000000000000000000000000000000000000000000091830191909152339290919060ff161561397b5760405162461bcd60e51b81526004016109029190614e0b565b506139868383610b6b565b156040518060400160405280600281526020017f3136000000000000000000000000000000000000000000000000000000000000815250906139db5760405162461bcd60e51b81526004016109029190614e0b565b506139e4610cdf565b6139ed57600080fd5b6000805482546040517f6352211e0000000000000000000000000000000000000000000000000000000081526001600160a01b0390921691636352211e91613a3791600401614e7c565b60206040518083038186803b158015613a4f57600080fd5b505afa158015613a63573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613a8791906148b8565b90506000613ab4836003015461148a8560070154610dfb600a548860030154612dd790919063ffffffff16565b90506000613adb8460050154610dfb670de0b6b3a764000085612dd790919063ffffffff16565b9050670d2f13f7789f00008110156040518060400160405280600281526020017f313800000000000000000000000000000000000000000000000000000000000081525090613b3d5760405162461bcd60e51b81526004016109029190614e0b565b506002840154600a850180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0090911660011716610100179055600585015460068601554360098601556001600160a01b03166000670de0b6b3a7640000831115613bd8576005860154613bd39085906125db565b613bdb565b60005b90506000613c04670de0b6b3a7640000610dfb6007548a60050154612dd790919063ffffffff16565b9050613c20612a498689600301546124f390919063ffffffff16565b600455600854613c5090613c4390670de0b6b3a764000090610dfb908690612dd7565b60035461148a90846125db565b600355600754600854613c8891613c7f91670de0b6b3a764000091610dfb91613c78916125db565b8690612dd7565b600554906125db565b6005556007546040517ff8cfe49d0000000000000000000000000000000000000000000000000000000081526001600160a01b0385169163f8cfe49d91613cd3918c91600401614ac9565b600060405180830381600087803b158015613ced57600080fd5b505af1158015613d01573d6000803e3d6000fd5b505060005489546040517f42966c680000000000000000000000000000000000000000000000000000000081526001600160a01b0390921693506342966c689250613d4e91600401614e7c565b602060405180830381600087803b158015613d6857600080fd5b505af1158015613d7c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613da09190614a20565b6040518060400160405280600281526020017f333300000000000000000000000000000000000000000000000000000000000081525090613df45760405162461bcd60e51b81526004016109029190614e0b565b50600d5460028801546040517f716e257f0000000000000000000000000000000000000000000000000000000081526001600160a01b039283169263716e257f92613e479230928e921690600401614b43565b60206040518083038186803b158015613e5f57600080fd5b505afa158015613e73573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613e979190614a20565b6040518060400160405280600281526020017f323600000000000000000000000000000000000000000000000000000000000081525090613eeb5760405162461bcd60e51b81526004016109029190614e0b565b507f976725bed73d37e8b46d0d5694646bfa4d33c5b84bae26b3194570f3ad53befb868860010160009054906101000a90046001600160a01b0316600160009054906101000a90046001600160a01b03168a60030154308c600501548f8e600001546001604051612dbf99989796959493929190614c67565b60026011541415613fbc576040805162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015290519081900360640190fd5b600260118190556001600160a01b0383166000908152600b6020908152604091829020600a81015483518085019094529383527f3134000000000000000000000000000000000000000000000000000000000000918301919091529160ff16156140395760405162461bcd60e51b81526004016109029190614e0b565b5060408051808201909152600281527f323200000000000000000000000000000000000000000000000000000000000060208201526001600160a01b0383166140955760405162461bcd60e51b81526004016109029190614e0b565b506140a08333610b6b565b6040518060400160405280600281526020017f3135000000000000000000000000000000000000000000000000000000000000815250906140f45760405162461bcd60e51b81526004016109029190614e0b565b506140fd610cdf565b61410657600080fd5b60028101546001820180547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b03858116919091179091556040517f10187c7500000000000000000000000000000000000000000000000000000000815291169081906310187c7590614184908690600401614ab5565b602060405180830381600087803b15801561419e57600080fd5b505af11580156141b2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906141d69190614a20565b6040518060400160405280600281526020017f33320000000000000000000000000000000000000000000000000000000000008152509061422a5760405162461bcd60e51b81526004016109029190614e0b565b5060005482546040517f6352211e0000000000000000000000000000000000000000000000000000000081527f0495d9ab17c89a5018a45652488d3006feedcac9a14e348e939ffdab14705724926001600160a01b031691636352211e916142959190600401614e7c565b60206040518083038186803b1580156142ad57600080fd5b505afa1580156142c1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906142e591906148b8565b60015460028501548554604051614311949389936001600160a01b039182169330939290911691614b66565b60405180910390a1505060016011555050565b8015806143c35750604080517fdd62ed3e0000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b03848116602483015291519185169163dd62ed3e91604480820192602092909190829003018186803b15801561439557600080fd5b505afa1580156143a9573d6000803e3d6000fd5b505050506040513d60208110156143bf57600080fd5b5051155b6143fe5760405162461bcd60e51b8152600401808060200182810382526036815260200180614ee66036913960400191505060405180910390fd5b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f095ea7b30000000000000000000000000000000000000000000000000000000017905261269d9084905b60006144cf826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166146e29092919063ffffffff16565b80519091501561269d578080602001905160208110156144ee57600080fd5b505161269d5760405162461bcd60e51b815260040180806020018281038252602a815260200180614ebc602a913960400191505060405180910390fd5b600081848411156145ba5760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b8381101561457f578181015183820152602001614567565b50505050905090810190601f1680156145ac5780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b505050900390565b600081836146115760405162461bcd60e51b815260206004820181815283516024840152835190928392604490910191908501908083836000831561457f578181015183820152602001614567565b50600083858161461d57fe5b0495945050505050565b60006040517f3d602d80600a3d3981f3363d3d373d3d3d363d7300000000000000000000000081528260601b60148201527f5af43d82803e903d91602b57fd5bf3000000000000000000000000000000000060288201526037816000f09150506001600160a01b038116610688576040805162461bcd60e51b815260206004820152601660248201527f455243313136373a20637265617465206661696c656400000000000000000000604482015290519081900360640190fd5b60606113908484600085856146f685614825565b614747576040805162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015290519081900360640190fd5b600080866001600160a01b031685876040518082805190602001908083835b602083106147a357805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101614766565b6001836020036101000a03801982511681845116808217855250505050505090500191505060006040518083038185875af1925050503d8060008114614805576040519150601f19603f3d011682016040523d82523d6000602084013e61480a565b606091505b509150915061481a82828661482b565b979650505050505050565b3b151590565b6060831561483a575081611393565b82511561484a5782518084602001fd5b60405162461bcd60e51b815260206004820181815284516024840152845185939192839260440191908501908083836000831561457f578181015183820152602001614567565b805161068881614e85565b6000602082840312156148ad578081fd5b81356105e881614e85565b6000602082840312156148c9578081fd5b81516105e881614e85565b600080604083850312156148e6578081fd5b82356148f181614e85565b9150602083013561490181614e85565b809150509250929050565b6000806040838503121561491e578182fd5b823561492981614e85565b946020939093013593505050565b60008060006060848603121561494b578081fd5b833561495681614e85565b95602085013595506040909401359392505050565b6000602080838503121561497d578182fd5b825167ffffffffffffffff80821115614994578384fd5b818501915085601f8301126149a7578384fd5b8151818111156149b357fe5b838102604051858282010181811085821117156149cc57fe5b604052828152858101935084860182860187018a10156149ea578788fd5b8795505b83861015614a13576149ff81614891565b8552600195909501949386019386016149ee565b5098975050505050505050565b600060208284031215614a31578081fd5b815180151581146105e8578182fd5b600060208284031215614a51578081fd5b5035919050565b600060208284031215614a69578081fd5b5051919050565b60008060408385031215614a82578182fd5b82359150602083013561490181614e85565b60008060408385031215614aa6578182fd5b50508035926020909101359150565b6001600160a01b0391909116815260200190565b6001600160a01b03929092168252602082015260400190565b6001600160a01b0393841681526020810192909252909116604082015260600190565b6001600160a01b0392831681529116602082015260400190565b6001600160a01b039384168152919092166020820152604081019190915260600190565b6001600160a01b0393841681529183166020830152909116604082015260600190565b6001600160a01b039687168152948616602086015292851660408501529084166060840152909216608082015260a081019190915260c00190565b6001600160a01b039788168152958716602087015293861660408601529185166060850152608084015290921660a082015260c081019190915260e00190565b6001600160a01b0396871681529486166020860152928516604085015293166060830152608082019290925260a081019190915260c00190565b6001600160a01b039889168152968816602088015294871660408701526060860193909352908516608085015290931660a083015260c082019290925260e08101919091526101000190565b6001600160a01b03998a168152978916602089015295881660408801526060870194909452918616608086015260a085015290931660c083015260e08201929092529015156101008201526101200190565b6001600160a01b039687168152948616602086015292851660408501526060840191909152608083015290911660a082015260c00190565b6001600160a01b039c8d1681529a8c1660208c0152988b1660408b015260608a019790975260808901959095529290971660a087015260c086015260e08501959095526101008401949094526101208301939093529115156101408201529015156101608201526101800190565b6001600160a01b0394909416845260208401929092526040830152606082015260800190565b6001600160a01b03959095168552602085019390935260408401919091526060830152608082015260a00190565b6020808252825182820181905260009190848201906040850190845b81811015614df45783516001600160a01b031683529284019291840191600101614dcf565b50909695505050505050565b901515815260200190565b6000602080835283518082850152825b81811015614e3757858101830151858201604001528201614e1b565b81811115614e485783604083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016929092016040019392505050565b90815260200190565b6001600160a01b0381168114610cdc57600080fdfe536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f775361666545524332303a204552433230206f7065726174696f6e20646964206e6f7420737563636565645361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f20746f206e6f6e2d7a65726f20616c6c6f77616e6365a2646970667358221220be08c056d801186983217449e435e2d3b835fb2e672440a1d5a63b03a552b59064736f6c6343000706003300000000000000000000000024e79e946dea5482212c38aab2d0782f04cdb0e0000000000000000000000000bbfa3b05b2dae65fb4c05ec7f1598793a4bc06230000000000000000000000004da27a545c0c5b758a6ba100e3a049001de870f5000000000000000000000000076d4cf37e48b9265e05d57f280eff562b177476000000000000000000000000a35c7681655811ad3befd76b45c3b2920f0c613c00000000000000000000000055da1cbd77b1c3b2d8bfe0f5fdf63d684b49f8a50000000000000000000000007fc66500c84a76ad7e9c93437bfc5ac33e2ddae9

Deployed Bytecode

0x608060405234801561001057600080fd5b50600436106102ff5760003560e01c806371bfbd4e1161019c578063b6331d46116100ee578063c7f3b6b111610097578063dd2cc3f311610071578063dd2cc3f3146105a8578063f77c4791146105bb578063f8f9da28146105c3576102ff565b8063c7f3b6b11461056f578063d4a3109d14610582578063d5c4a11714610595576102ff565b8063c1bce0b7116100c8578063c1bce0b71461051e578063c1c55d0c14610531578063c5d40b8a14610544576102ff565b8063b6331d46146104fb578063b6b55f2514610503578063bd6d894d14610516576102ff565b806393610b8d11610150578063a764804f1161012a578063a764804f146104d8578063aa5af0fd146104eb578063ae9d70b0146104f3576102ff565b806393610b8d146104aa5780639bdaa5e6146104bd578063a0187e8a146104d0576102ff565b806386a2a4381161018157806386a2a438146104715780638eec99c814610484578063935a8b8414610497576102ff565b806371bfbd4e146104565780637312520214610469576102ff565b8063516e2f2a11610255578063622d2efc116102095780636c540baf116101e35780636c540baf146104335780636f307dc31461043b57806370a0823114610443576102ff565b8063622d2efc146104035780636558d7b114610423578063682c20581461042b576102ff565b806357d1bc961161023a57806357d1bc96146103d557806359356c5c146103e857806359baef40146103f0576102ff565b8063516e2f2a146103af578063560acbc2146103c2576102ff565b8063304d5f07116102b75780634b8243c9116102915780634b8243c91461038a5780634c19386c1461039f5780634c68df67146103a7576102ff565b8063304d5f07146103655780634322b7141461036d5780634754990314610375576102ff565b80631e348629116102e85780631e348629146103355780632d66da9f1461033d5780632e1a7d4d14610352576102ff565b8063130cbe5c14610304578063182df0f51461032d575b600080fd5b61031761031236600461490c565b6105cb565b6040516103249190614e7c565b60405180910390f35b6103176105f1565b610317610601565b610345610607565b6040516103249190614db3565b610317610360366004614a40565b610669565b61031761068d565b610317610693565b61037d610699565b6040516103249190614ab5565b61039d610398366004614a40565b6106a8565b005b610317610780565b610317610786565b61039d6103bd36600461489c565b61078c565b61039d6103d0366004614a40565b610825565b61039d6103e3366004614a40565b610968565b610317610a1f565b61039d6103fe36600461489c565b610ab9565b6104166104113660046148d4565b610b6b565b6040516103249190614e00565b610317610c07565b610317610c0d565b610317610c13565b61037d610c19565b61031761045136600461489c565b610c28565b61039d61046436600461489c565b610cc2565b610416610cdf565b61034561047f36600461489c565b610eb8565b61039d61049236600461489c565b610f76565b6103176104a536600461489c565b611050565b61039d6104b8366004614a94565b611134565b6103176104cb36600461489c565b61120f565b61037d61122a565b61039d6104e636600461489c565b611239565b6103176112d2565b6103176112d8565b610317611337565b610317610511366004614a40565b611343565b61031761135f565b61031761052c366004614937565b611372565b61041661053f36600461489c565b61139a565b61055761055236600461489c565b6114cb565b6040516103249c9b9a99989796959493929190614cf1565b61039d61057d36600461489c565b6116b6565b61039d6105903660046148d4565b6116d0565b6103176105a3366004614a40565b6116ef565b61039d6105b6366004614a70565b611831565b61037d611995565b6103176119a4565b60006105d5611a00565b6105de57600080fd5b6105e88383611cd3565b90505b92915050565b60006105fb612063565b90505b90565b60125481565b6060600c80548060200260200160405190810160405280929190818152602001828054801561065f57602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311610641575b5050505050905090565b6000610673611a00565b61067c57600080fd5b6106858261214f565b90505b919050565b60075481565b60085481565b6002546001600160a01b031681565b6010546001600160a01b03163314610707576040805162461bcd60e51b815260206004820152600160248201527f3100000000000000000000000000000000000000000000000000000000000000604482015290519081900360640190fd5b61070f610cdf565b61071857600080fd5b60035461072590826124f3565b600355601054600154610746916001600160a01b039182169116308461254d565b7fa3e421ddc9810d39cc90c4a3998578420d1c1ebc5b67a3c133c4044a1114de99816040516107759190614e7c565b60405180910390a150565b60045481565b60035481565b6010546001600160a01b031633146107eb576040805162461bcd60e51b815260206004820152600160248201527f3100000000000000000000000000000000000000000000000000000000000000604482015290519081900360640190fd5b600f80547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0392909216919091179055565b6010546001600160a01b03163314610884576040805162461bcd60e51b815260206004820152600160248201527f3100000000000000000000000000000000000000000000000000000000000000604482015290519081900360640190fd5b61088c610cdf565b61089557600080fd5b61089d610a1f565b81111580156108ae57506003548111155b6040518060400160405280600281526020017f31390000000000000000000000000000000000000000000000000000000000008152509061090b5760405162461bcd60e51b81526004016109029190614e0b565b60405180910390fd5b5060035461091990826125db565b600355601054600154610939916001600160a01b0391821691168361261d565b7ff78dc30da85b5e9540c710154f60a2e296f1461551b7995ef2c7112e3c2be9c3816040516107759190614e7c565b6010546001600160a01b031633146109c7576040805162461bcd60e51b815260206004820152600160248201527f3100000000000000000000000000000000000000000000000000000000000000604482015290519081900360640190fd5b60408051808201909152600281527f3238000000000000000000000000000000000000000000000000000000000000602082015281610a195760405162461bcd60e51b81526004016109029190614e0b565b50600655565b6001546040517f70a082310000000000000000000000000000000000000000000000000000000081526000916001600160a01b0316906370a0823190610a69903090600401614ab5565b60206040518083038186803b158015610a8157600080fd5b505afa158015610a95573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105fb9190614a58565b6010546001600160a01b0316331480610adc5750600d546001600160a01b031633145b6040518060400160405280600281526020017f323900000000000000000000000000000000000000000000000000000000000081525090610b305760405162461bcd60e51b81526004016109029190614e0b565b50600d80547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0392909216919091179055565b600080546001600160a01b038084169116632d7254e5610b8a8661120f565b6040518263ffffffff1660e01b8152600401610ba69190614e7c565b60206040518083038186803b158015610bbe57600080fd5b505afa158015610bd2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bf691906148b8565b6001600160a01b0316149392505050565b60065481565b60055481565b60095481565b6001546001600160a01b031681565b6002546040517f70a082310000000000000000000000000000000000000000000000000000000081526000916001600160a01b0316906370a0823190610c72908590600401614ab5565b60206040518083038186803b158015610c8a57600080fd5b505afa158015610c9e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106859190614a58565b610cca611a00565b610cd357600080fd5b610cdc816126a2565b50565b6009546000904390811415610cf85760019150506105fe565b6000610d02610a1f565b60048054600354600554600a54600e546040517f200d16aa00000000000000000000000000000000000000000000000000000000815296975093959294919390926000926001600160a01b039092169163200d16aa91610d6a9130918b918b918b9101614d5f565b60206040518083038186803b158015610d8257600080fd5b505afa158015610d96573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610dba9190614a58565b90506000610dd3600954896125db90919063ffffffff16565b90506000610de18383612dd7565b90506000610e01670de0b6b3a7640000610dfb848b612dd7565b90612e30565b90506000610e0f89836124f3565b90506000610e3e610e37670de0b6b3a7640000610dfb86600854612dd790919063ffffffff16565b8a906124f3565b90506000610e72610e37670de0b6b3a7640000610dfb87610e6c6007546008546125db90919063ffffffff16565b90612dd7565b90506000610e8f610e37670de0b6b3a7640000610dfb898d612dd7565b60049490945550600391909155600555600a555050506009969096555060019550505050505090565b6000546040517f6a2291650000000000000000000000000000000000000000000000000000000081526060916001600160a01b031690636a22916590610f049085903090600401614b05565b60006040518083038186803b158015610f1c57600080fd5b505afa158015610f30573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052610685919081019061496b565b6010546001600160a01b03163314610fd5576040805162461bcd60e51b815260206004820152600160248201527f3100000000000000000000000000000000000000000000000000000000000000604482015290519081900360640190fd5b601080546001600160a01b038381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040805191909216808252602082019390935281517ff9ffabca9c8276e99321725bcb43fb076a6c66a54b7f21c4e8146d8519b417dc929181900390910190a15050565b6002546040517f70a0823100000000000000000000000000000000000000000000000000000000815260009182916001600160a01b03909116906370a082319061109e908690600401614ab5565b60206040518083038186803b1580156110b657600080fd5b505afa1580156110ca573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110ee9190614a58565b9050806110ff576000915050610688565b6000611109612063565b905060006111178383612dd7565b905061112b81670de0b6b3a7640000612e30565b95945050505050565b6010546001600160a01b03163314611193576040805162461bcd60e51b815260206004820152600160248201527f3100000000000000000000000000000000000000000000000000000000000000604482015290519081900360640190fd5b6000821180156111a35750600081115b80156111af5750808210155b6040518060400160405280600281526020017f3238000000000000000000000000000000000000000000000000000000000000815250906112035760405162461bcd60e51b81526004016109029190614e0b565b50600891909155600755565b6001600160a01b03166000908152600b602052604090205490565b6000546001600160a01b031681565b6010546001600160a01b03163314611298576040805162461bcd60e51b815260206004820152600160248201527f3100000000000000000000000000000000000000000000000000000000000000604482015290519081900360640190fd5b600e80547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0392909216919091179055565b600a5481565b600e546000906001600160a01b031663e4ef277a306112f5610a1f565b600480546003546008546040517fffffffff0000000000000000000000000000000000000000000000000000000060e089901b168152610a6996959401614d85565b670d2f13f7789f000081565b600061134d611a00565b61135657600080fd5b61068582612e72565b6000611369610cdf565b506105fb612063565b600061137c611a00565b61138557600080fd5b611390848484613157565b90505b9392505050565b6001600160a01b038082166000908152600b6020908152604080832081516101808101835281548152600182015486169381019390935260028101548516918301919091526003810154606083015260048101549093166080820152600583015460a0820152600683015460c0820152600783015460e08201526008830154610100808301919091526009840154610120830152600a9093015460ff80821615801561014085015294909104161515610160820152909161145f576000915050610688565b6000611490826060015161148a8460e00151610dfb600a548760600151612dd790919063ffffffff16565b906125db565b905060006114b78360a00151610dfb670de0b6b3a764000085612dd790919063ffffffff16565b670d2f13f7789f0000111595945050505050565b6001600160a01b038082166000908152600b602090815260408083208151610180810183528154808252600183015487169482019490945260028201548616818401526003820154606082015260048083015487166080830152600583015460a0830152600683015460c0830152600783015460e08301526008830154610100808401919091526009840154610120840152600a9093015460ff80821615156101408501529390049092161515610160820152845492517f2d7254e5000000000000000000000000000000000000000000000000000000008152949586958695869586958695869586958695869586958695949190911692632d7254e5926115d592909101614e7c565b60206040518083038186803b1580156115ed57600080fd5b505afa158015611601573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061162591906148b8565b6020820151604083015183516060850151608086015160a087015161014088015161167057606088015160e0890151600a5461166b929161148a91610dfb908490612dd7565b611676565b8760c001515b8861010001518961012001518a61014001518b61016001519c509c509c509c509c509c509c509c509c509c509c509c505091939597999b5091939597999b565b6116be611a00565b6116c757600080fd5b610cdc816138a2565b6116d8611a00565b6116e157600080fd5b6116eb8282613f64565b5050565b60006116f9610a1f565b82106040518060400160405280600181526020017f39000000000000000000000000000000000000000000000000000000000000008152509061174f5760405162461bcd60e51b81526004016109029190614e0b565b50600e546000906001600160a01b031663200d16aa306117718661148a610a1f565b60045461177e90886124f3565b6003546040518563ffffffff1660e01b81526004016117a09493929190614d5f565b60206040518083038186803b1580156117b857600080fd5b505afa1580156117cc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117f09190614a58565b90506000611816670de0b6b3a7640000610dfb61180d8786612dd7565b60065490612dd7565b905060008111611827576001611829565b805b949350505050565b6010546001600160a01b03163314806118545750600d546001600160a01b031633145b6040518060400160405280600281526020017f3239000000000000000000000000000000000000000000000000000000000000815250906118a85760405162461bcd60e51b81526004016109029190614e0b565b506118b1610cdf565b6118ba57600080fd5b60055482111580156118ce57506003548211155b6040518060400160405280600281526020017f3334000000000000000000000000000000000000000000000000000000000000815250906119225760405162461bcd60e51b81526004016109029190614e0b565b5060055461193090836125db565b60055560035461194090836125db565b60035560015461195a906001600160a01b0316828461261d565b7f835862a12039ab712842887f732f62f9ba4e46c8a157b8f2ece290bb03cb6229826040516119899190614e7c565b60405180910390a15050565b600d546001600160a01b031681565b600e546000906001600160a01b031663200d16aa306119c1610a1f565b600480546003546040517fffffffff0000000000000000000000000000000000000000000000000000000060e088901b168152610a6995949301614d5f565b6040517f8dbefee20000000000000000000000000000000000000000000000000000000081526000907f0000000000000000000000007fc66500c84a76ad7e9c93437bfc5ac33e2ddae9907f0000000000000000000000004da27a545c0c5b758a6ba100e3a049001de870f59083906001600160a01b03831690638dbefee290611a8e903090600401614ab5565b60206040518083038186803b158015611aa657600080fd5b505afa158015611aba573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ade9190614a58565b9050600081118015611af257504360125414155b15611cc9576040517f9a99b4f00000000000000000000000000000000000000000000000000000000081526001600160a01b03831690639a99b4f090611b3e9030908590600401614ac9565b600060405180830381600087803b158015611b5857600080fd5b505af1158015611b6c573d6000803e3d6000fd5b50506040517f70a08231000000000000000000000000000000000000000000000000000000008152600092506001600160a01b03861691506370a0823190611bb8903090600401614ab5565b60206040518083038186803b158015611bd057600080fd5b505afa158015611be4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c089190614a58565b9050611c3e6001600160a01b0385167f0000000000000000000000004da27a545c0c5b758a6ba100e3a049001de870f583614324565b6040517fadc9772e0000000000000000000000000000000000000000000000000000000081526001600160a01b0384169063adc9772e90611c859030908590600401614ac9565b600060405180830381600087803b158015611c9f57600080fd5b505af1158015611cb3573d6000803e3d6000fd5b50504360125550600195506105fe945050505050565b6001935050505090565b600060026011541415611d2d576040805162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015290519081900360640190fd5b600260118190556001600160a01b0384166000908152600b6020908152604091829020600a81015483518085019094529383527f3134000000000000000000000000000000000000000000000000000000000000918301919091529160ff1615611daa5760405162461bcd60e51b81526004016109029190614e0b565b50611db58433610b6b565b6040518060400160405280600281526020017f313500000000000000000000000000000000000000000000000000000000000081525090611e095760405162461bcd60e51b81526004016109029190614e0b565b5060008311611e1757600080fd5b611e1f610cdf565b611e2857600080fd5b60028101546000805483546040517f6352211e0000000000000000000000000000000000000000000000000000000081526001600160a01b039485169490921691636352211e91611e7b91600401614e7c565b60206040518083038186803b158015611e9357600080fd5b505afa158015611ea7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ecb91906148b8565b6005840154909150611edd90866124f3565b60058401556002830154600154611f03916001600160a01b03918216918491168861254d565b6040517f682904a50000000000000000000000000000000000000000000000000000000081526001600160a01b0383169063682904a590611f48908890600401614e7c565b602060405180830381600087803b158015611f6257600080fd5b505af1158015611f76573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f9a9190614a20565b6040518060400160405280600281526020017f313700000000000000000000000000000000000000000000000000000000000081525090611fee5760405162461bcd60e51b81526004016109029190614e0b565b5060018381015490546005850154600286015486546040517f23d5462a0f15711328244c2dee4e7c32ae4c4f8f74faad197b67566f38b021e79561204c9588956001600160a01b039283169591831694309491939092169190614ba1565b60405180910390a150506001601155509092915050565b600080600260009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b1580156120b457600080fd5b505afa1580156120c8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120ec9190614a58565b90508061210457670de0b6b3a76400009150506105fe565b600061210e610a1f565b9050600061212d60035461148a600454856124f390919063ffffffff16565b905061214583610dfb83670de0b6b3a7640000612dd7565b93505050506105fe565b6000600260115414156121a9576040805162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015290519081900360640190fd5b60026011556121b6610cdf565b6121bf57600080fd5b816121c933610c28565b10156040518060400160405280600281526020017f31300000000000000000000000000000000000000000000000000000000000008152509061221f5760405162461bcd60e51b81526004016109029190614e0b565b50600061222a612063565b905060006122388483612dd7565b9050600061224e82670de0b6b3a7640000612e30565b9050612258610a1f565b8111156040518060400160405280600181526020017f3900000000000000000000000000000000000000000000000000000000000000815250906122af5760405162461bcd60e51b81526004016109029190614e0b565b506002546040517f9dc29fac0000000000000000000000000000000000000000000000000000000081526001600160a01b0390911690639dc29fac906122fb9033908990600401614ac9565b602060405180830381600087803b15801561231557600080fd5b505af1158015612329573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061234d9190614a20565b6040518060400160405280600281526020017f3231000000000000000000000000000000000000000000000000000000000000815250906123a15760405162461bcd60e51b81526004016109029190614e0b565b506001546123b9906001600160a01b0316338361261d565b600d546040517f5c0d1b0d0000000000000000000000000000000000000000000000000000000081526001600160a01b0390911690635c0d1b0d9061240690309033908690600401614b1f565b60206040518083038186803b15801561241e57600080fd5b505afa158015612432573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124569190614a20565b6040518060400160405280600281526020017f3234000000000000000000000000000000000000000000000000000000000000815250906124aa5760405162461bcd60e51b81526004016109029190614e0b565b507f56c54ba9bd38d8fd62012e42c7ee564519b09763c426d331b3661b537ead19b23386306040516124de93929190614ae2565b60405180910390a16001601155949350505050565b6000828201838110156105e8576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b604080516001600160a01b0380861660248301528416604482015260648082018490528251808303909101815260849091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f23b872dd000000000000000000000000000000000000000000000000000000001790526125d590859061447a565b50505050565b60006105e883836040518060400160405280601f81526020017f536166654d6174683a207375627472616374696f6e20756e646572666c6f770081525061452b565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb0000000000000000000000000000000000000000000000000000000017905261269d90849061447a565b505050565b600260115414156126fa576040805162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015290519081900360640190fd5b600260118190556001600160a01b0382166000908152600b6020908152604091829020600a81015483518085019094529383527f3134000000000000000000000000000000000000000000000000000000000000918301919091529160ff16156127775760405162461bcd60e51b81526004016109029190614e0b565b506127828233610b6b565b6040518060400160405280600281526020017f3135000000000000000000000000000000000000000000000000000000000000815250906127d65760405162461bcd60e51b81526004016109029190614e0b565b506127df610cdf565b6127e857600080fd5b6000805482546040517f6352211e0000000000000000000000000000000000000000000000000000000081526001600160a01b0390921691636352211e9161283291600401614e7c565b60206040518083038186803b15801561284a57600080fd5b505afa15801561285e573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061288291906148b8565b600283015460038401546007850154600a549394506001600160a01b03909216926000926128bb929161148a9190610dfb908490612dd7565b600654600886015491925060009183916128d591906124f3565b4310156129e957600e546000906001600160a01b031663200d16aa306128f9610a1f565b600480546003546040517fffffffff0000000000000000000000000000000000000000000000000000000060e088901b16815261293895949301614d5f565b60206040518083038186803b15801561295057600080fd5b505afa158015612964573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129889190614a58565b905060006129a94361148a6006548b600801546124f390919063ffffffff16565b90506129d8670de0b6b3a7640000610dfb6129d1858c60030154612dd790919063ffffffff16565b8490612dd7565b93506129e483856124f3565b925050505b85600501548111156129fc575060058501545b600a860180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055600686018190554360098701556003860154612a5290612a4990856124f3565b600454906125db565b6004556000612a6182856125db565b90506000612a86670de0b6b3a7640000610dfb60075488612dd790919063ffffffff16565b9050612ab5612aac670de0b6b3a7640000610dfb85600854612dd790919063ffffffff16565b600354906124f3565b600355600854612aea90612ad790670de0b6b3a764000090610dfb9086612dd7565b600554612ae490846124f3565b906124f3565b6005556040517fd05951a00000000000000000000000000000000000000000000000000000000081526001600160a01b0387169063d05951a090612b32908690600401614e7c565b600060405180830381600087803b158015612b4c57600080fd5b505af1158015612b60573d6000803e3d6000fd5b50506000548a546040517f42966c680000000000000000000000000000000000000000000000000000000081526001600160a01b0390921693506342966c689250612bad91600401614e7c565b602060405180830381600087803b158015612bc757600080fd5b505af1158015612bdb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612bff9190614a20565b6040518060400160405280600281526020017f333300000000000000000000000000000000000000000000000000000000000081525090612c535760405162461bcd60e51b81526004016109029190614e0b565b50600d5460028901546040517f08bc016e0000000000000000000000000000000000000000000000000000000081526001600160a01b03928316926308bc016e92612ca69230928d921690600401614b43565b60206040518083038186803b158015612cbe57600080fd5b505afa158015612cd2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612cf69190614a20565b6040518060400160405280600281526020017f323500000000000000000000000000000000000000000000000000000000000081525090612d4a5760405162461bcd60e51b81526004016109029190614e0b565b507f976725bed73d37e8b46d0d5694646bfa4d33c5b84bae26b3194570f3ad53befb878960010160009054906101000a90046001600160a01b0316600160009054906101000a90046001600160a01b03168b6003015430888f8f600001546000604051612dbf99989796959493929190614c67565b60405180910390a15050600160115550505050505050565b600082612de6575060006105eb565b82820282848281612df357fe5b04146105e85760405162461bcd60e51b8152600401808060200182810382526021815260200180614e9b6021913960400191505060405180910390fd5b60006105e883836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f0000000000008152506145c2565b600060026011541415612ecc576040805162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015290519081900360640190fd5b6002601155612ed9610cdf565b612ee257600080fd5b6000612eec612063565b90506000612f0284670de0b6b3a7640000612dd7565b90506000612f108284612e30565b600154909150612f2b906001600160a01b031633308861254d565b6002546040517f40c10f190000000000000000000000000000000000000000000000000000000081526001600160a01b03909116906340c10f1990612f769033908590600401614ac9565b602060405180830381600087803b158015612f9057600080fd5b505af1158015612fa4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612fc89190614a20565b6040518060400160405280600281526020017f32300000000000000000000000000000000000000000000000000000000000008152509061301c5760405162461bcd60e51b81526004016109029190614e0b565b507fe31c7b8d08ee7db0afa68782e1028ef92305caeea8626633ad44d413e30f6b2f33863060405161305093929190614ae2565b60405180910390a1600d546040517f806f8ab20000000000000000000000000000000000000000000000000000000081526001600160a01b039091169063806f8ab2906130a590309033908690600401614b1f565b60206040518083038186803b1580156130bd57600080fd5b505afa1580156130d1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130f59190614a20565b6040518060400160405280600281526020017f3131000000000000000000000000000000000000000000000000000000000000815250906131495760405162461bcd60e51b81526004016109029190614e0b565b506001601155949350505050565b6000600260115414156131b1576040805162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015290519081900360640190fd5b60026011556131be610a1f565b83106040518060400160405280600181526020017f3900000000000000000000000000000000000000000000000000000000000000815250906132145760405162461bcd60e51b81526004016109029190614e0b565b5060408051808201909152600281527f323200000000000000000000000000000000000000000000000000000000000060208201526001600160a01b0385166132705760405162461bcd60e51b81526004016109029190614e0b565b5060408051808201909152600281527f32370000000000000000000000000000000000000000000000000000000000006020820152836132c35760405162461bcd60e51b81526004016109029190614e0b565b506132cd836116ef565b8210156040518060400160405280600281526020017f3233000000000000000000000000000000000000000000000000000000000000815250906133245760405162461bcd60e51b81526004016109029190614e0b565b5061332d610cdf565b61333657600080fd5b600454339061334590856124f3565b600455600f54600090613360906001600160a01b0316614627565b60015490915061337a906001600160a01b0316828761261d565b600154613392906001600160a01b031683838761254d565b6001546040517f890dcf540000000000000000000000000000000000000000000000000000000081526001600160a01b038084169263890dcf54926133e692309288929116908c908c908c90600401614be1565b602060405180830381600087803b15801561340057600080fd5b505af1158015613414573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134389190614a20565b6040518060400160405280600281526020017f31320000000000000000000000000000000000000000000000000000000000008152509061348c5760405162461bcd60e51b81526004016109029190614e0b565b50600c805460018101825560009182527fdf6966c971051c3d54ec59162606531493a51404a002842f56009d7e5cf4a8c70180547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b038481169190911790915581546040517f63185c420000000000000000000000000000000000000000000000000000000081529116906363185c429061353790869030908790600401614b43565b602060405180830381600087803b15801561355157600080fd5b505af1158015613565573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135899190614a58565b9050604051806101800160405280828152602001886001600160a01b03168152602001836001600160a01b03168152602001878152602001600160009054906101000a90046001600160a01b03166001600160a01b0316815260200186815260200160008152602001600a5481526020014381526020016000815260200160001515815260200160001515815250600b6000846001600160a01b03166001600160a01b031681526020019081526020016000206000820151816000015560208201518160010160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555060408201518160020160006101000a8154816001600160a01b0302191690836001600160a01b031602179055506060820151816003015560808201518160040160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555060a0820151816005015560c0820151816006015560e082015181600701556101008201518160080155610120820151816009015561014082015181600a0160006101000a81548160ff02191690831515021790555061016082015181600a0160016101000a81548160ff021916908315150217905550905050600d60009054906101000a90046001600160a01b03166001600160a01b031663f5565ddf30858a8a8a886040518763ffffffff1660e01b815260040161379b96959493929190614cb9565b60206040518083038186803b1580156137b357600080fd5b505afa1580156137c7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137eb9190614a20565b6040518060400160405280600281526020017f31330000000000000000000000000000000000000000000000000000000000008152509061383f5760405162461bcd60e51b81526004016109029190614e0b565b506001546040517f8f11691cf96727f419bd99b50853d8351f147118e4778f62bdaa8528ab3e50bb9161388b9186918b916001600160a01b03909116908b903090899089904390614c1b565b60405180910390a160016011559695505050505050565b600260115414156138fa576040805162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015290519081900360640190fd5b600260118190556001600160a01b0382166000908152600b6020908152604091829020600a81015483518085019094529383527f313400000000000000000000000000000000000000000000000000000000000091830191909152339290919060ff161561397b5760405162461bcd60e51b81526004016109029190614e0b565b506139868383610b6b565b156040518060400160405280600281526020017f3136000000000000000000000000000000000000000000000000000000000000815250906139db5760405162461bcd60e51b81526004016109029190614e0b565b506139e4610cdf565b6139ed57600080fd5b6000805482546040517f6352211e0000000000000000000000000000000000000000000000000000000081526001600160a01b0390921691636352211e91613a3791600401614e7c565b60206040518083038186803b158015613a4f57600080fd5b505afa158015613a63573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613a8791906148b8565b90506000613ab4836003015461148a8560070154610dfb600a548860030154612dd790919063ffffffff16565b90506000613adb8460050154610dfb670de0b6b3a764000085612dd790919063ffffffff16565b9050670d2f13f7789f00008110156040518060400160405280600281526020017f313800000000000000000000000000000000000000000000000000000000000081525090613b3d5760405162461bcd60e51b81526004016109029190614e0b565b506002840154600a850180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0090911660011716610100179055600585015460068601554360098601556001600160a01b03166000670de0b6b3a7640000831115613bd8576005860154613bd39085906125db565b613bdb565b60005b90506000613c04670de0b6b3a7640000610dfb6007548a60050154612dd790919063ffffffff16565b9050613c20612a498689600301546124f390919063ffffffff16565b600455600854613c5090613c4390670de0b6b3a764000090610dfb908690612dd7565b60035461148a90846125db565b600355600754600854613c8891613c7f91670de0b6b3a764000091610dfb91613c78916125db565b8690612dd7565b600554906125db565b6005556007546040517ff8cfe49d0000000000000000000000000000000000000000000000000000000081526001600160a01b0385169163f8cfe49d91613cd3918c91600401614ac9565b600060405180830381600087803b158015613ced57600080fd5b505af1158015613d01573d6000803e3d6000fd5b505060005489546040517f42966c680000000000000000000000000000000000000000000000000000000081526001600160a01b0390921693506342966c689250613d4e91600401614e7c565b602060405180830381600087803b158015613d6857600080fd5b505af1158015613d7c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613da09190614a20565b6040518060400160405280600281526020017f333300000000000000000000000000000000000000000000000000000000000081525090613df45760405162461bcd60e51b81526004016109029190614e0b565b50600d5460028801546040517f716e257f0000000000000000000000000000000000000000000000000000000081526001600160a01b039283169263716e257f92613e479230928e921690600401614b43565b60206040518083038186803b158015613e5f57600080fd5b505afa158015613e73573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613e979190614a20565b6040518060400160405280600281526020017f323600000000000000000000000000000000000000000000000000000000000081525090613eeb5760405162461bcd60e51b81526004016109029190614e0b565b507f976725bed73d37e8b46d0d5694646bfa4d33c5b84bae26b3194570f3ad53befb868860010160009054906101000a90046001600160a01b0316600160009054906101000a90046001600160a01b03168a60030154308c600501548f8e600001546001604051612dbf99989796959493929190614c67565b60026011541415613fbc576040805162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015290519081900360640190fd5b600260118190556001600160a01b0383166000908152600b6020908152604091829020600a81015483518085019094529383527f3134000000000000000000000000000000000000000000000000000000000000918301919091529160ff16156140395760405162461bcd60e51b81526004016109029190614e0b565b5060408051808201909152600281527f323200000000000000000000000000000000000000000000000000000000000060208201526001600160a01b0383166140955760405162461bcd60e51b81526004016109029190614e0b565b506140a08333610b6b565b6040518060400160405280600281526020017f3135000000000000000000000000000000000000000000000000000000000000815250906140f45760405162461bcd60e51b81526004016109029190614e0b565b506140fd610cdf565b61410657600080fd5b60028101546001820180547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b03858116919091179091556040517f10187c7500000000000000000000000000000000000000000000000000000000815291169081906310187c7590614184908690600401614ab5565b602060405180830381600087803b15801561419e57600080fd5b505af11580156141b2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906141d69190614a20565b6040518060400160405280600281526020017f33320000000000000000000000000000000000000000000000000000000000008152509061422a5760405162461bcd60e51b81526004016109029190614e0b565b5060005482546040517f6352211e0000000000000000000000000000000000000000000000000000000081527f0495d9ab17c89a5018a45652488d3006feedcac9a14e348e939ffdab14705724926001600160a01b031691636352211e916142959190600401614e7c565b60206040518083038186803b1580156142ad57600080fd5b505afa1580156142c1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906142e591906148b8565b60015460028501548554604051614311949389936001600160a01b039182169330939290911691614b66565b60405180910390a1505060016011555050565b8015806143c35750604080517fdd62ed3e0000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b03848116602483015291519185169163dd62ed3e91604480820192602092909190829003018186803b15801561439557600080fd5b505afa1580156143a9573d6000803e3d6000fd5b505050506040513d60208110156143bf57600080fd5b5051155b6143fe5760405162461bcd60e51b8152600401808060200182810382526036815260200180614ee66036913960400191505060405180910390fd5b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f095ea7b30000000000000000000000000000000000000000000000000000000017905261269d9084905b60006144cf826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166146e29092919063ffffffff16565b80519091501561269d578080602001905160208110156144ee57600080fd5b505161269d5760405162461bcd60e51b815260040180806020018281038252602a815260200180614ebc602a913960400191505060405180910390fd5b600081848411156145ba5760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b8381101561457f578181015183820152602001614567565b50505050905090810190601f1680156145ac5780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b505050900390565b600081836146115760405162461bcd60e51b815260206004820181815283516024840152835190928392604490910191908501908083836000831561457f578181015183820152602001614567565b50600083858161461d57fe5b0495945050505050565b60006040517f3d602d80600a3d3981f3363d3d373d3d3d363d7300000000000000000000000081528260601b60148201527f5af43d82803e903d91602b57fd5bf3000000000000000000000000000000000060288201526037816000f09150506001600160a01b038116610688576040805162461bcd60e51b815260206004820152601660248201527f455243313136373a20637265617465206661696c656400000000000000000000604482015290519081900360640190fd5b60606113908484600085856146f685614825565b614747576040805162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015290519081900360640190fd5b600080866001600160a01b031685876040518082805190602001908083835b602083106147a357805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101614766565b6001836020036101000a03801982511681845116808217855250505050505090500191505060006040518083038185875af1925050503d8060008114614805576040519150601f19603f3d011682016040523d82523d6000602084013e61480a565b606091505b509150915061481a82828661482b565b979650505050505050565b3b151590565b6060831561483a575081611393565b82511561484a5782518084602001fd5b60405162461bcd60e51b815260206004820181815284516024840152845185939192839260440191908501908083836000831561457f578181015183820152602001614567565b805161068881614e85565b6000602082840312156148ad578081fd5b81356105e881614e85565b6000602082840312156148c9578081fd5b81516105e881614e85565b600080604083850312156148e6578081fd5b82356148f181614e85565b9150602083013561490181614e85565b809150509250929050565b6000806040838503121561491e578182fd5b823561492981614e85565b946020939093013593505050565b60008060006060848603121561494b578081fd5b833561495681614e85565b95602085013595506040909401359392505050565b6000602080838503121561497d578182fd5b825167ffffffffffffffff80821115614994578384fd5b818501915085601f8301126149a7578384fd5b8151818111156149b357fe5b838102604051858282010181811085821117156149cc57fe5b604052828152858101935084860182860187018a10156149ea578788fd5b8795505b83861015614a13576149ff81614891565b8552600195909501949386019386016149ee565b5098975050505050505050565b600060208284031215614a31578081fd5b815180151581146105e8578182fd5b600060208284031215614a51578081fd5b5035919050565b600060208284031215614a69578081fd5b5051919050565b60008060408385031215614a82578182fd5b82359150602083013561490181614e85565b60008060408385031215614aa6578182fd5b50508035926020909101359150565b6001600160a01b0391909116815260200190565b6001600160a01b03929092168252602082015260400190565b6001600160a01b0393841681526020810192909252909116604082015260600190565b6001600160a01b0392831681529116602082015260400190565b6001600160a01b039384168152919092166020820152604081019190915260600190565b6001600160a01b0393841681529183166020830152909116604082015260600190565b6001600160a01b039687168152948616602086015292851660408501529084166060840152909216608082015260a081019190915260c00190565b6001600160a01b039788168152958716602087015293861660408601529185166060850152608084015290921660a082015260c081019190915260e00190565b6001600160a01b0396871681529486166020860152928516604085015293166060830152608082019290925260a081019190915260c00190565b6001600160a01b039889168152968816602088015294871660408701526060860193909352908516608085015290931660a083015260c082019290925260e08101919091526101000190565b6001600160a01b03998a168152978916602089015295881660408801526060870194909452918616608086015260a085015290931660c083015260e08201929092529015156101008201526101200190565b6001600160a01b039687168152948616602086015292851660408501526060840191909152608083015290911660a082015260c00190565b6001600160a01b039c8d1681529a8c1660208c0152988b1660408b015260608a019790975260808901959095529290971660a087015260c086015260e08501959095526101008401949094526101208301939093529115156101408201529015156101608201526101800190565b6001600160a01b0394909416845260208401929092526040830152606082015260800190565b6001600160a01b03959095168552602085019390935260408401919091526060830152608082015260a00190565b6020808252825182820181905260009190848201906040850190845b81811015614df45783516001600160a01b031683529284019291840191600101614dcf565b50909695505050505050565b901515815260200190565b6000602080835283518082850152825b81811015614e3757858101830151858201604001528201614e1b565b81811115614e485783604083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016929092016040019392505050565b90815260200190565b6001600160a01b0381168114610cdc57600080fdfe536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f775361666545524332303a204552433230206f7065726174696f6e20646964206e6f7420737563636565645361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f20746f206e6f6e2d7a65726f20616c6c6f77616e6365a2646970667358221220be08c056d801186983217449e435e2d3b835fb2e672440a1d5a63b03a552b59064736f6c63430007060033

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

00000000000000000000000024e79e946dea5482212c38aab2d0782f04cdb0e0000000000000000000000000bbfa3b05b2dae65fb4c05ec7f1598793a4bc06230000000000000000000000004da27a545c0c5b758a6ba100e3a049001de870f5000000000000000000000000076d4cf37e48b9265e05d57f280eff562b177476000000000000000000000000a35c7681655811ad3befd76b45c3b2920f0c613c00000000000000000000000055da1cbd77b1c3b2d8bfe0f5fdf63d684b49f8a50000000000000000000000007fc66500c84a76ad7e9c93437bfc5ac33e2ddae9

-----Decoded View---------------
Arg [0] : _palToken (address): 0x24E79e946dEa5482212c38aaB2D0782F04cdB0E0
Arg [1] : _controller (address): 0xbBFA3b05b2dAe65Fb4C05Ec7F1598793a4Bc0623
Arg [2] : _underlying (address): 0x4da27a545c0c5B758a6BA100e3a049001de870f5
Arg [3] : _interestModule (address): 0x076D4cf37E48B9265E05D57f280EfF562b177476
Arg [4] : _delegator (address): 0xA35C7681655811Ad3BefD76B45c3B2920F0C613C
Arg [5] : _palLoanToken (address): 0x55DA1CBD77B1c3b2d8Bfe0F5fDF63d684b49F8A5
Arg [6] : _aaveAddress (address): 0x7Fc66500c84A76Ad7e9c93437bFc5Ac33E2DDaE9

-----Encoded View---------------
7 Constructor Arguments found :
Arg [0] : 00000000000000000000000024e79e946dea5482212c38aab2d0782f04cdb0e0
Arg [1] : 000000000000000000000000bbfa3b05b2dae65fb4c05ec7f1598793a4bc0623
Arg [2] : 0000000000000000000000004da27a545c0c5b758a6ba100e3a049001de870f5
Arg [3] : 000000000000000000000000076d4cf37e48b9265e05d57f280eff562b177476
Arg [4] : 000000000000000000000000a35c7681655811ad3befd76b45c3b2920f0c613c
Arg [5] : 00000000000000000000000055da1cbd77b1c3b2d8bfe0f5fdf63d684b49f8a5
Arg [6] : 0000000000000000000000007fc66500c84a76ad7e9c93437bfc5ac33e2ddae9


Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

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

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading
[ Download: CSV Export  ]
[ Download: CSV Export  ]

A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.