Contract 0x7835d976516F82cA8a3Ed2942C4c6F9C4E44bb74 4

 
 
Txn Hash
Method
Block
From
To
Value
0x3aa05b788a8fc3d52b798e67310762091ba2f3f1fda6b09a594a2f00093408aeWithdraw164286812023-01-17 19:42:119 days 12 hrs agoENS Name klickibunti.eth IN  0x7835d976516f82ca8a3ed2942c4c6f9c4e44bb740 Ether0.00376168 22.86652291
0x940a52e2c176d7e74c14fba7064b36ce3efdfb2b9259fa67738c90ad290b3d99Kill Borrow164267952023-01-17 13:23:239 days 19 hrs agoPaladin: Deployer IN  0x7835d976516f82ca8a3ed2942c4c6f9c4e44bb740 Ether0.00789943 19.01444241
0xd530d71c06b535a071016d501763e9dd86d645cdf565226143785abc83313934Withdraw164079922023-01-14 22:20:3512 days 10 hrs ago0xec80b5494e873fd9a7c7bf2368d743b38eb0b9ea IN  0x7835d976516f82ca8a3ed2942c4c6f9c4e44bb740 Ether0.00333812 16.91935132
0x3e660040e0a49f84cbc496071139fdebef14d1a2c79b31dfcf9ad521493b032bWithdraw163107982023-01-01 8:43:2325 days 23 hrs ago0x202d0bec720743e0d41503e19b93298b0dad6531 IN  0x7835d976516f82ca8a3ed2942c4c6f9c4e44bb740 Ether0.00219744 13.35786148
0x5ecb22cbaa15a1497bd2da337513925feefe08b4bbad6b50d81244fc2c5bb1a6Withdraw160720622022-11-29 0:26:2359 days 8 hrs ago0x000158e60c393b51fdfac71b14ce70b70148c326 IN  0x7835d976516f82ca8a3ed2942c4c6f9c4e44bb740 Ether0.00181359 11.02529687
0xed4190e3d2857e51d3fe477443befc3a3b775d003e780f6472c3d9cd225e4dacWithdraw159045092022-11-05 14:47:5982 days 17 hrs ago0x4b6dffa4895610570330880ce370dd764ca67da0 IN  0x7835d976516f82ca8a3ed2942c4c6f9c4e44bb740 Ether0.00173635 11
0xad70ce26d134da54b35f6c48993171c1c4f47cdb823305ff0b675ff652d8770cWithdraw158606242022-10-30 11:37:3588 days 20 hrs ago0x437d69771e4a8e81e5704f4967dc18a323b3fb0e IN  0x7835d976516f82ca8a3ed2942c4c6f9c4e44bb740 Ether0.00119122 7.24124469
0x4a288de4f8aab025b73f317df3fc7e9f8b7aa2f4766ba034b3acbc6bfa820cb3Expand Borrow158546892022-10-29 15:44:5989 days 16 hrs agoENS Name governchaos.eth IN  0x7835d976516f82ca8a3ed2942c4c6f9c4e44bb740 Ether0.00229205 16.12464814
0x3bdb46c9a570e240c6b95ddd00e5b822db49dd8bf1dc3b89ec4cc8852ba37ca4Withdraw158462882022-10-28 11:33:5990 days 20 hrs ago0xe487396fe3b10c67d5293a6cdb5e2cb2f504ca85 IN  0x7835d976516f82ca8a3ed2942c4c6f9c4e44bb740 Ether0.00140206 9.51238897
0xc03b66188ee904f3fea70e2960bc01d55bf6b6346a47647f556dd7e226f96adcWithdraw158415082022-10-27 19:30:3591 days 13 hrs ago0x44ac36d4eac3ff3ddca6cde05b1562d9b67d415e IN  0x7835d976516f82ca8a3ed2942c4c6f9c4e44bb740 Ether0.00425249 25.85006772
0x031dc4e31883a74163e386c8e08f0bd2f4b18795d2e69e0f2a769dd1cd7afbbcWithdraw156015982022-09-24 7:02:59125 days 1 hr ago0x09d18ff5d0c68221df366f79c1cc7a1a7faba118 IN  0x7835d976516f82ca8a3ed2942c4c6f9c4e44bb740 Ether0.00068414.15854098
0x3c7ba7eb53585bc0174567c4735a6e3af3ebab6d27a06b956756e65ab201838cWithdraw153918872022-08-22 18:32:16157 days 13 hrs agoENS Name martingbz.eth IN  0x7835d976516f82ca8a3ed2942c4c6f9c4e44bb740 Ether0.00279381 16.98308405
0xf38c2585deabd4796d13a475cfcd79f3ebb626cf0e2385eff9bafe99ca23a843Withdraw153391872022-08-14 10:23:43165 days 22 hrs ago0xf65f1ec6a0133e8fce4f54b1da8ea7f0cdf7511e IN  0x7835d976516f82ca8a3ed2942c4c6f9c4e44bb740 Ether0.00065802 4
0xe6d41366ae6529230c41943627965177aa1d089a4309aad8635d73a8ae3cd49dWithdraw153257812022-08-12 7:46:43168 days 45 mins ago0xa530bae3707c76450be1a94c59df653a01ed61a6 IN  0x7835d976516f82ca8a3ed2942c4c6f9c4e44bb740 Ether0.00170818 10.38370802
0xc74afd8086b8ade8d86d9a3b7dd2da4277d1115b07701816b48d27b8ce759e90Withdraw153229592022-08-11 21:06:15168 days 11 hrs ago0x8262267b55ab184f6b303e7e1ef260dc5165b5bf IN  0x7835d976516f82ca8a3ed2942c4c6f9c4e44bb740 Ether0.00256629 15.6
0x361603e3612bf2e2a90886270d781b0cbb22c1238dedd34284265765ce104609Withdraw152503742022-07-31 12:59:18179 days 19 hrs ago0xf56036f6a5d9b9991c209dcbc9c40b2c1cd46540 IN  0x7835d976516f82ca8a3ed2942c4c6f9c4e44bb740 Ether0.00087926 4.87980907
0xb33fbb5ec8154dba448c23568bd27fa03aee4545a968901d1ab63027d07d7dc3Borrow152171592022-07-26 8:49:25184 days 23 hrs agoENS Name governchaos.eth IN  0x7835d976516f82ca8a3ed2942c4c6f9c4e44bb740 Ether0.00987649 12.77891736
0x27c5695ee21b012c8854b6844ef452ebe8550d95d8f34a013fa20791e3c40c3aWithdraw152168572022-07-26 7:43:54185 days 48 mins agoENS Name neitsabes.eth IN  0x7835d976516f82ca8a3ed2942c4c6f9c4e44bb740 Ether0.001316048
0xccce69183fa34a4caa5d3b423d1bc91e3ed8f817f72c0dec0ab476b73e7f8194Withdraw152062732022-07-24 16:02:34186 days 16 hrs ago0xee6af57e2882f414ace82957d7102a7afce4c655 IN  0x7835d976516f82ca8a3ed2942c4c6f9c4e44bb740 Ether0.00246587 14.98957026
0x0ab08db119ba89fbe267b476e02cd224145d5fc3ebbad1efbfbef6b21950ae66Withdraw151718382022-07-19 7:56:59192 days 35 mins ago0x0ec07259e0cec1a4894c0c475da711701a03af33 IN  0x7835d976516f82ca8a3ed2942c4c6f9c4e44bb740 Ether0.002035 10.31508177
0x9fa99772f232286015ab8c4209466826c68621526c701fa4fe212fd101033dc3Withdraw151564882022-07-16 22:45:19194 days 9 hrs ago0xe376b0e254ce4751a40114b5c46518aa79a65735 IN  0x7835d976516f82ca8a3ed2942c4c6f9c4e44bb740 Ether0.00236269 16.02851965
0xd7bcb14e09946f9d0140b648ae73b4eb8d4f9aadbb18caca9ef5668926a9ea80Withdraw151321112022-07-13 4:20:44198 days 4 hrs ago0xe7b68e282dfce12b21dca8faa8f50278818a9123 IN  0x7835d976516f82ca8a3ed2942c4c6f9c4e44bb740 Ether0.00170896 11.59357086
0xf8aca4c29f93099938acaf99a8847ec817382182e49282e604974189c735698bWithdraw151109232022-07-09 21:51:48201 days 10 hrs ago0x139776871ee95f55d20b10d9ba5a0385451066cd IN  0x7835d976516f82ca8a3ed2942c4c6f9c4e44bb740 Ether0.00489715 29.76670779
0xae6629e0cb872010a5272b9ad805ce37f86a877f35291b24bfdcef886d2597b8Withdraw151078572022-07-09 10:39:06201 days 21 hrs agoENS Name lambo.eth IN  0x7835d976516f82ca8a3ed2942c4c6f9c4e44bb740 Ether0.0016469 11.17256129
0x0daa6c8b0e7699df46881746a68d0f3e8784c74084a1e5e8c0c48a6f08f449d0Withdraw150947242022-07-07 9:41:18203 days 22 hrs agoENS Name 0x1e51.eth IN  0x7835d976516f82ca8a3ed2942c4c6f9c4e44bb740 Ether0.00209456 11.32440307
[ Download CSV Export 
Latest 25 internal transaction
Parent Txn Hash Block From To Value
0x940a52e2c176d7e74c14fba7064b36ce3efdfb2b9259fa67738c90ad290b3d99164267952023-01-17 13:23:239 days 19 hrs ago 0x0bc8d80cb2276121c727493338370b33f8128bcf 0x7835d976516f82ca8a3ed2942c4c6f9c4e44bb740 Ether
0x04943eb375f077a2fe352aaefe7feb0393261e42f68cc3816f7a7876aca486c9163695442023-01-09 13:28:2317 days 19 hrs ago 0x7835d976516f82ca8a3ed2942c4c6f9c4e44bb74  Contract Creation0 Ether
0xc5db97fa2e6978e977be47548672598c879bca695b59cd59dc7f05bd675db12d152171782022-07-26 8:53:52184 days 23 hrs ago 0x6514398f1c9aa3a867cbaba86de553978b962140 0x7835d976516f82ca8a3ed2942c4c6f9c4e44bb740 Ether
0xb33fbb5ec8154dba448c23568bd27fa03aee4545a968901d1ab63027d07d7dc3152171592022-07-26 8:49:25184 days 23 hrs ago 0x7835d976516f82ca8a3ed2942c4c6f9c4e44bb74  Contract Creation0 Ether
0xc08e02664496ff6168f897f4356fef9d242caf80b547bc109d52d7e41466f0c7144759852022-03-28 17:29:09304 days 15 hrs ago 0xef11cb0eac36644bc1fd2b7c36d8cff35b1e0272 0x7835d976516f82ca8a3ed2942c4c6f9c4e44bb740 Ether
0xdf021dfab0e2de237a8497a6b7b7ea048862fbfa5e836e7bcb84aed9937a46dc144693212022-03-27 16:25:09305 days 16 hrs ago 0x7835d976516f82ca8a3ed2942c4c6f9c4e44bb74  Contract Creation0 Ether
0xe3f6896b7dad6eb5801fe0aaee9001e066644d36bd16b10607db217202578b43140856852022-01-27 5:03:42365 days 3 hrs ago 0x193b9a5a0304e469966d3544b7e3a805edf4f85a 0x7835d976516f82ca8a3ed2942c4c6f9c4e44bb740 Ether
0x2efe30bc3b15c0f72d03ef4f772d45e9024d066d7064b0b740ad472df92b5e06140678372022-01-24 10:36:54367 days 21 hrs ago 0x7835d976516f82ca8a3ed2942c4c6f9c4e44bb74  Contract Creation0 Ether
0x89629d9ec9e5d557dac2a16e5132c196d3df22f3ea81cfe35b22bff22c6baaf1136358232021-11-17 23:15:41435 days 9 hrs ago 0x503470dfb4c7eb31a8593ab8e1bd1d4724a1ea17 0x7835d976516f82ca8a3ed2942c4c6f9c4e44bb740 Ether
0x92ccc3fc7b391e60830905be1189b86dad4437ee6f93ad727b06c559692de682135874402021-11-10 8:32:50442 days 23 hrs ago 0x7835d976516f82ca8a3ed2942c4c6f9c4e44bb74  Contract Creation0 Ether
0x0fa692ba52a41a3647b71751a43c8893bf733d0241f48ec4f7536978ace42702135801232021-11-09 4:41:05444 days 3 hrs ago 0x320ef059f3e3e2155297b7fb41b3c62a75827088 0x7835d976516f82ca8a3ed2942c4c6f9c4e44bb740 Ether
0x0c24079525b23987a7ecb3b48feb8ff596ed9fce6a2268d754e4e627ee09d1a5135759712021-11-08 13:13:13444 days 19 hrs ago 0x7835d976516f82ca8a3ed2942c4c6f9c4e44bb74  Contract Creation0 Ether
0x0eac849818da1eb2f9219c24b2d46256162bf38c1b2ddef2963ec315b0cc3e62135195502021-10-30 16:36:37453 days 15 hrs ago 0xf29011df57d7279a67edf7b6c0a978f0764223ee 0x7835d976516f82ca8a3ed2942c4c6f9c4e44bb740 Ether
0x67e779f6dc650cb6ffc483d5793aebcc0808a09a8a6cc041c243c9ce899fe031135105092021-10-29 6:25:04455 days 2 hrs ago 0x824bf5565603f657d826afeb675ffc325f9daaf9 0x7835d976516f82ca8a3ed2942c4c6f9c4e44bb740 Ether
0x5ac9d0156b691ffccc58c3ae70e5e25782de02afef13528a8e8fdd16a414a25f135104022021-10-29 6:01:10455 days 2 hrs ago 0x7835d976516f82ca8a3ed2942c4c6f9c4e44bb74  Contract Creation0 Ether
0x9cadc761b95a7d42a5c70f67306002aeebfffee4def5f84ace0411b90ae82012134484522021-10-19 13:26:04464 days 19 hrs ago 0x6ce7b68aa8c7885acef8f73d9aa634cf2ff0f60a 0x7835d976516f82ca8a3ed2942c4c6f9c4e44bb740 Ether
0xc7bd454a73cfb2c3b2b5c6f28b21db599160e75d03c3601c576d51d7e136751b134427792021-10-18 16:09:35465 days 16 hrs ago 0x9d8944d57a6bceb9e8a3d08042b8523486234102 0x7835d976516f82ca8a3ed2942c4c6f9c4e44bb740 Ether
0xe6ec22ab2d80fa56b123fd659da9997f37ddd43310d19ef290815f211ff14767134427672021-10-18 16:05:38465 days 16 hrs ago 0x5d7c70d86779b3bd2e791aa3a3a59bb18f715043 0x7835d976516f82ca8a3ed2942c4c6f9c4e44bb740 Ether
0x0be190a279af44f4eb614c956da92f70a4e1a712da97874c95f62d049519cc54134382792021-10-17 23:02:13466 days 9 hrs ago 0x53cac9993ab61f6b0d49903cecfadab3e42751c8 0x7835d976516f82ca8a3ed2942c4c6f9c4e44bb740 Ether
0xe3f4fd425abb7b3be2e7f41a989419970165d2162a68ca69a781f96db4a2b460134172692021-10-14 15:56:55469 days 16 hrs ago 0x7835d976516f82ca8a3ed2942c4c6f9c4e44bb74  Contract Creation0 Ether
0xbd6a83249d01e92f816e0e43f88b5cf3b6141bc60459a10bc03a0d8fdfb5e794134151792021-10-14 8:06:23470 days 25 mins ago 0x7835d976516f82ca8a3ed2942c4c6f9c4e44bb74  Contract Creation0 Ether
0x6908c2ed3d38bdc1eed77b7046b4081c376648d54bedc2dc74ceb36e51f77b48134016032021-10-12 4:41:31472 days 3 hrs ago 0x7835d976516f82ca8a3ed2942c4c6f9c4e44bb74  Contract Creation0 Ether
0xec3a7990bdbbdfe0a7b30ae823097d410979cd5160a2f273bf613b1b76b961e0134015902021-10-12 4:39:37472 days 3 hrs ago 0x7835d976516f82ca8a3ed2942c4c6f9c4e44bb74  Contract Creation0 Ether
0xe3161f863be21dec8a55aab1674abd0f2118a93c95085e8610ea116944d024fe133995552021-10-11 20:59:12472 days 11 hrs ago 0x7835d976516f82ca8a3ed2942c4c6f9c4e44bb74  Contract Creation0 Ether
0x2bd401c3ccc22a2ae1fc98ba4ae2e8946751e932882a7f9f16da00006d8ea299133963412021-10-11 8:51:45472 days 23 hrs ago 0xff4f0a20496f9887ea13aa861cbb4ade566a5431 0x7835d976516f82ca8a3ed2942c4c6f9c4e44bb740 Ether
[ Download CSV Export 
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.

Contract Source Code Verified (Exact Match)

Contract Name:
PalPool

Compiler Version
v0.7.6+commit.7338295f

Optimization Enabled:
Yes with 25000 runs

Other Settings:
default evmVersion
File 1 of 18 : 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 2 of 18 : 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 3 of 18 : 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 4 of 18 : 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 5 of 18 : 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 6 of 18 : 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 7 of 18 : 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 8 of 18 : 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 9 of 18 : 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 10 of 18 : 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 11 of 18 : 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 12 of 18 : 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 13 of 18 : 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 14 of 18 : 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 15 of 18 : 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 16 of 18 : 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 17 of 18 : 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 18 of 18 : 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"}],"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":[{"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"}]

60806040526002805460ff60a01b1916905561b0ea60065567016345785d8a00006007556702c68af0bb1400006008553480156200003c57600080fd5b5060405162005178380380620051788339810160408190526200005f9162000115565b6001601181905560108054336001600160a01b0319918216179091556002805482166001600160a01b03998a16179055600d8054821697891697909717909655805486169487169490941790935543600955600e80548516928616929092179091556ec097ce7bc90715b34b9f1000000000600a55600f8054841691851691909117905560008054909216921691909117905562000195565b80516001600160a01b03811681146200011057600080fd5b919050565b60008060008060008060c087890312156200012e578182fd5b6200013987620000f8565b95506200014960208801620000f8565b94506200015960408801620000f8565b93506200016960608801620000f8565b92506200017960808801620000f8565b91506200018960a08801620000f8565b90509295509295509295565b614fd380620001a56000396000f3fe608060405234801561001057600080fd5b50600436106102f45760003560e01c80637312520211610191578063b6b55f25116100e3578063c7f3b6b111610097578063dd2cc3f311610071578063dd2cc3f314610595578063f77c4791146105a8578063f8f9da28146105b0576102f4565b8063c7f3b6b11461055c578063d4a3109d1461056f578063d5c4a11714610582576102f4565b8063c1bce0b7116100c8578063c1bce0b71461050b578063c1c55d0c1461051e578063c5d40b8a14610531576102f4565b8063b6b55f25146104f0578063bd6d894d14610503576102f4565b80639bdaa5e611610145578063aa5af0fd1161011f578063aa5af0fd146104d8578063ae9d70b0146104e0578063b6331d46146104e8576102f4565b80639bdaa5e6146104aa578063a0187e8a146104bd578063a764804f146104c5576102f4565b80638eec99c8116101765780638eec99c814610471578063935a8b841461048457806393610b8d14610497576102f4565b8063731252021461045657806386a2a4381461045e576102f4565b8063560acbc21161024a5780636558d7b1116101fe5780636f307dc3116101d85780636f307dc31461042857806370a082311461043057806371bfbd4e14610443576102f4565b80636558d7b114610410578063682c2058146104185780636c540baf14610420576102f4565b806359356c5c1161022f57806359356c5c146103d557806359baef40146103dd578063622d2efc146103f0576102f4565b8063560acbc2146103af57806357d1bc96146103c2576102f4565b80634322b714116102ac5780634c19386c116102865780634c19386c1461038c5780634c68df6714610394578063516e2f2a1461039c576102f4565b80634322b7141461035a57806347549903146103625780634b8243c914610377576102f4565b80632d66da9f116102dd5780632d66da9f1461032a5780632e1a7d4d1461033f578063304d5f0714610352576102f4565b8063130cbe5c146102f9578063182df0f514610322575b600080fd5b61030c6103073660046148e4565b6105b8565b6040516103199190614f24565b60405180910390f35b61030c610992565b6103326109a2565b6040516103199190614e4e565b61030c61034d366004614a18565b610a11565b61030c610ddc565b61030c610de2565b61036a610de8565b6040516103199190614a8d565b61038a610385366004614a18565b610e04565b005b61030c610ef6565b61030c610efc565b61038a6103aa366004614874565b610f02565b61038a6103bd366004614a18565b610fb5565b61038a6103d0366004614a18565b611109565b61030c6111cd565b61038a6103eb366004614874565b611274565b6104036103fe3660046148ac565b61134d565b6040516103199190614ea8565b61030c611405565b61030c61140b565b61030c611411565b61036a611417565b61030c61043e366004614874565b611433565b61038a610451366004614874565b6114e2565b610403611c98565b61033261046c366004614874565b611e78565b61038a61047f366004614874565b611f43565b61030c610492366004614874565b612037565b61038a6104a5366004614a6c565b612128565b61030c6104b8366004614874565b612210565b61036a612238565b61038a6104d3366004614874565b612254565b61030c612307565b61030c61230d565b61030c612379565b61030c6104fe366004614a18565b612385565b61030c612691565b61030c61051936600461490f565b6126a4565b61040361052c366004614874565b612f00565b61054461053f366004614874565b613038565b6040516103199c9b9a99989796959493929190614d65565b61038a61056a366004614874565b613230565b61038a61057d3660046148ac565b61395a565b61030c610590366004614a18565b613d5b565b61038a6105a3366004614a48565b613eaa565b61036a614035565b61030c614051565b600060026011541415610612576040805162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015290519081900360640190fd5b6002601181905573ffffffffffffffffffffffffffffffffffffffff84166000908152600b6020908152604091829020600a81015483518085019094529383527f3134000000000000000000000000000000000000000000000000000000000000918301919091529160ff16156106a55760405162461bcd60e51b815260040161069c9190614eb3565b60405180910390fd5b506106b0843361134d565b6040518060400160405280600281526020017f3135000000000000000000000000000000000000000000000000000000000000815250906107045760405162461bcd60e51b815260040161069c9190614eb3565b506000831161071257600080fd5b61071a611c98565b61072357600080fd5b60028101546000805483546040517f6352211e00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9485169490921691636352211e9161078391600401614f24565b60206040518083038186803b15801561079b57600080fd5b505afa1580156107af573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107d39190614890565b60058401549091506107e590866140ba565b600584015560028301546001546108189173ffffffffffffffffffffffffffffffffffffffff918216918491168861411b565b6040517f682904a500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff83169063682904a59061086a908890600401614f24565b602060405180830381600087803b15801561088457600080fd5b505af1158015610898573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108bc91906149f8565b6040518060400160405280600281526020017f3137000000000000000000000000000000000000000000000000000000000000815250906109105760405162461bcd60e51b815260040161069c9190614eb3565b5060018381015490546005850154600286015486546040517f23d5462a0f15711328244c2dee4e7c32ae4c4f8f74faad197b67566f38b021e79561097b95889573ffffffffffffffffffffffffffffffffffffffff9283169591831694309491939092169190614bd4565b60405180910390a150506001601155509092915050565b600061099c6141b6565b90505b90565b6060600c805480602002602001604051908101604052809291908181526020018280548015610a0757602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff1681526001909101906020018083116109dc575b5050505050905090565b600060026011541415610a6b576040805162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015290519081900360640190fd5b6002601155610a78611c98565b610a8157600080fd5b81610a8b33611433565b10156040518060400160405280600281526020017f313000000000000000000000000000000000000000000000000000000000000081525090610ae15760405162461bcd60e51b815260040161069c9190614eb3565b506000610aec6141b6565b90506000610afa84836142bc565b90506000610b1082670de0b6b3a7640000614315565b9050610b1a6111cd565b8111156040518060400160405280600181526020017f390000000000000000000000000000000000000000000000000000000000000081525090610b715760405162461bcd60e51b815260040161069c9190614eb3565b506002546040517f9dc29fac00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff90911690639dc29fac90610bca9033908990600401614aae565b602060405180830381600087803b158015610be457600080fd5b505af1158015610bf8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c1c91906149f8565b6040518060400160405280600281526020017f323100000000000000000000000000000000000000000000000000000000000081525090610c705760405162461bcd60e51b815260040161069c9190614eb3565b50600154610c959073ffffffffffffffffffffffffffffffffffffffff163383614357565b600d546040517f5c0d1b0d00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff90911690635c0d1b0d90610cef90309033908690600401614b2b565b60206040518083038186803b158015610d0757600080fd5b505afa158015610d1b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d3f91906149f8565b6040518060400160405280600281526020017f323400000000000000000000000000000000000000000000000000000000000081525090610d935760405162461bcd60e51b815260040161069c9190614eb3565b507f56c54ba9bd38d8fd62012e42c7ee564519b09763c426d331b3661b537ead19b2338630604051610dc793929190614ad4565b60405180910390a16001601155949350505050565b60075481565b60085481565b60025473ffffffffffffffffffffffffffffffffffffffff1681565b60105473ffffffffffffffffffffffffffffffffffffffff163314610e70576040805162461bcd60e51b815260206004820152600160248201527f3100000000000000000000000000000000000000000000000000000000000000604482015290519081900360640190fd5b610e78611c98565b610e8157600080fd5b600354610e8e90826140ba565b600355601054600154610ebc9173ffffffffffffffffffffffffffffffffffffffff9182169116308461411b565b7fa3e421ddc9810d39cc90c4a3998578420d1c1ebc5b67a3c133c4044a1114de9981604051610eeb9190614f24565b60405180910390a150565b60045481565b60035481565b60105473ffffffffffffffffffffffffffffffffffffffff163314610f6e576040805162461bcd60e51b815260206004820152600160248201527f3100000000000000000000000000000000000000000000000000000000000000604482015290519081900360640190fd5b600f80547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b60105473ffffffffffffffffffffffffffffffffffffffff163314611021576040805162461bcd60e51b815260206004820152600160248201527f3100000000000000000000000000000000000000000000000000000000000000604482015290519081900360640190fd5b611029611c98565b61103257600080fd5b61103a6111cd565b811115801561104b57506003548111155b6040518060400160405280600281526020017f31390000000000000000000000000000000000000000000000000000000000008152509061109f5760405162461bcd60e51b815260040161069c9190614eb3565b506003546110ad90826143e9565b6003556010546001546110da9173ffffffffffffffffffffffffffffffffffffffff918216911683614357565b7ff78dc30da85b5e9540c710154f60a2e296f1461551b7995ef2c7112e3c2be9c381604051610eeb9190614f24565b60105473ffffffffffffffffffffffffffffffffffffffff163314611175576040805162461bcd60e51b815260206004820152600160248201527f3100000000000000000000000000000000000000000000000000000000000000604482015290519081900360640190fd5b60408051808201909152600281527f32380000000000000000000000000000000000000000000000000000000000006020820152816111c75760405162461bcd60e51b815260040161069c9190614eb3565b50600655565b6001546040517f70a0823100000000000000000000000000000000000000000000000000000000815260009173ffffffffffffffffffffffffffffffffffffffff16906370a0823190611224903090600401614a8d565b60206040518083038186803b15801561123c57600080fd5b505afa158015611250573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061099c9190614a30565b60105473ffffffffffffffffffffffffffffffffffffffff163314806112b15750600d5473ffffffffffffffffffffffffffffffffffffffff1633145b6040518060400160405280600281526020017f3239000000000000000000000000000000000000000000000000000000000000815250906113055760405162461bcd60e51b815260040161069c9190614eb3565b50600d80547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b6000805473ffffffffffffffffffffffffffffffffffffffff8084169116632d7254e561137986612210565b6040518263ffffffff1660e01b81526004016113959190614f24565b60206040518083038186803b1580156113ad57600080fd5b505afa1580156113c1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113e59190614890565b73ffffffffffffffffffffffffffffffffffffffff161490505b92915050565b60065481565b60055481565b60095481565b60015473ffffffffffffffffffffffffffffffffffffffff1681565b6002546040517f70a0823100000000000000000000000000000000000000000000000000000000815260009173ffffffffffffffffffffffffffffffffffffffff16906370a082319061148a908590600401614a8d565b60206040518083038186803b1580156114a257600080fd5b505afa1580156114b6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114da9190614a30565b90505b919050565b6002601154141561153a576040805162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015290519081900360640190fd5b6002601181905573ffffffffffffffffffffffffffffffffffffffff82166000908152600b6020908152604091829020600a81015483518085019094529383527f3134000000000000000000000000000000000000000000000000000000000000918301919091529160ff16156115c45760405162461bcd60e51b815260040161069c9190614eb3565b506115cf823361134d565b6040518060400160405280600281526020017f3135000000000000000000000000000000000000000000000000000000000000815250906116235760405162461bcd60e51b815260040161069c9190614eb3565b5061162c611c98565b61163557600080fd5b6000805482546040517f6352211e00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff90921691636352211e9161168c91600401614f24565b60206040518083038186803b1580156116a457600080fd5b505afa1580156116b8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116dc9190614890565b600283015460038401546007850154600a5493945073ffffffffffffffffffffffffffffffffffffffff9092169260009261172e929161172891906117229084906142bc565b90614315565b906143e9565b6006546008860154919250600091839161174891906140ba565b43101561186957600e5460009073ffffffffffffffffffffffffffffffffffffffff1663200d16aa306117796111cd565b600480546003546040517fffffffff0000000000000000000000000000000000000000000000000000000060e088901b1681526117b895949301614de0565b60206040518083038186803b1580156117d057600080fd5b505afa1580156117e4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118089190614a30565b90506000611829436117286006548b600801546140ba90919063ffffffff16565b9050611858670de0b6b3a7640000611722611851858c600301546142bc90919063ffffffff16565b84906142bc565b935061186483856140ba565b925050505b856005015481111561187c575060058501545b600a860180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790556006860181905543600987015560038601546118d2906118c990856140ba565b600454906143e9565b60045560006118e182856143e9565b90506000611906670de0b6b3a7640000611722600754886142bc90919063ffffffff16565b905061193561192c670de0b6b3a7640000611722856008546142bc90919063ffffffff16565b600354906140ba565b60035560085461196a9061195790670de0b6b3a76400009061172290866142bc565b60055461196490846140ba565b906140ba565b6005556040517fd05951a000000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff87169063d05951a0906119bf908690600401614f24565b600060405180830381600087803b1580156119d957600080fd5b505af11580156119ed573d6000803e3d6000fd5b50506000548a546040517f42966c6800000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff90921693506342966c689250611a4791600401614f24565b602060405180830381600087803b158015611a6157600080fd5b505af1158015611a75573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a9991906149f8565b6040518060400160405280600281526020017f333300000000000000000000000000000000000000000000000000000000000081525090611aed5760405162461bcd60e51b815260040161069c9190614eb3565b50600d5460028901546040517f08bc016e00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff928316926308bc016e92611b4d9230928d921690600401614b5c565b60206040518083038186803b158015611b6557600080fd5b505afa158015611b79573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b9d91906149f8565b6040518060400160405280600281526020017f323500000000000000000000000000000000000000000000000000000000000081525090611bf15760405162461bcd60e51b815260040161069c9190614eb3565b507f976725bed73d37e8b46d0d5694646bfa4d33c5b84bae26b3194570f3ad53befb878960010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff168b6003015430888f8f600001546000604051611c8099989796959493929190614cc1565b60405180910390a15050600160115550505050505050565b6009546000904390811415611cb157600191505061099f565b6000611cbb6111cd565b60048054600354600554600a54600e546040517f200d16aa000000000000000000000000000000000000000000000000000000008152969750939592949193909260009273ffffffffffffffffffffffffffffffffffffffff9092169163200d16aa91611d309130918b918b918b9101614de0565b60206040518083038186803b158015611d4857600080fd5b505afa158015611d5c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d809190614a30565b90506000611d99600954896143e990919063ffffffff16565b90506000611da783836142bc565b90506000611dc1670de0b6b3a7640000611722848b6142bc565b90506000611dcf89836140ba565b90506000611dfe611df7670de0b6b3a7640000611722866008546142bc90919063ffffffff16565b8a906140ba565b90506000611e32611df7670de0b6b3a764000061172287611e2c6007546008546143e990919063ffffffff16565b906142bc565b90506000611e4f611df7670de0b6b3a7640000611722898d6142bc565b60049490945550600391909155600555600a555050506009969096555060019550505050505090565b6000546040517f6a22916500000000000000000000000000000000000000000000000000000000815260609173ffffffffffffffffffffffffffffffffffffffff1690636a22916590611ed19085903090600401614b04565b60006040518083038186803b158015611ee957600080fd5b505afa158015611efd573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526114da9190810190614943565b60105473ffffffffffffffffffffffffffffffffffffffff163314611faf576040805162461bcd60e51b815260206004820152600160248201527f3100000000000000000000000000000000000000000000000000000000000000604482015290519081900360640190fd5b6010805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040805191909216808252602082019390935281517ff9ffabca9c8276e99321725bcb43fb076a6c66a54b7f21c4e8146d8519b417dc929181900390910190a15050565b6002546040517f70a08231000000000000000000000000000000000000000000000000000000008152600091829173ffffffffffffffffffffffffffffffffffffffff909116906370a0823190612092908690600401614a8d565b60206040518083038186803b1580156120aa57600080fd5b505afa1580156120be573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120e29190614a30565b9050806120f35760009150506114dd565b60006120fd6141b6565b9050600061210b83836142bc565b905061211f81670de0b6b3a7640000614315565b95945050505050565b60105473ffffffffffffffffffffffffffffffffffffffff163314612194576040805162461bcd60e51b815260206004820152600160248201527f3100000000000000000000000000000000000000000000000000000000000000604482015290519081900360640190fd5b6000821180156121a45750600081115b80156121b05750808210155b6040518060400160405280600281526020017f3238000000000000000000000000000000000000000000000000000000000000815250906122045760405162461bcd60e51b815260040161069c9190614eb3565b50600891909155600755565b73ffffffffffffffffffffffffffffffffffffffff166000908152600b602052604090205490565b60005473ffffffffffffffffffffffffffffffffffffffff1681565b60105473ffffffffffffffffffffffffffffffffffffffff1633146122c0576040805162461bcd60e51b815260206004820152600160248201527f3100000000000000000000000000000000000000000000000000000000000000604482015290519081900360640190fd5b600e80547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b600a5481565b600e5460009073ffffffffffffffffffffffffffffffffffffffff1663e4ef277a306123376111cd565b600480546003546008546040517fffffffff0000000000000000000000000000000000000000000000000000000060e089901b16815261122496959401614e13565b670d2f13f7789f000081565b6000600260115414156123df576040805162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015290519081900360640190fd5b60026011556123ec611c98565b6123f557600080fd5b60006123ff6141b6565b9050600061241584670de0b6b3a76400006142bc565b905060006124238284614315565b60015490915061244b9073ffffffffffffffffffffffffffffffffffffffff1633308861411b565b6002546040517f40c10f1900000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff909116906340c10f19906124a39033908590600401614aae565b602060405180830381600087803b1580156124bd57600080fd5b505af11580156124d1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124f591906149f8565b6040518060400160405280600281526020017f3230000000000000000000000000000000000000000000000000000000000000815250906125495760405162461bcd60e51b815260040161069c9190614eb3565b507fe31c7b8d08ee7db0afa68782e1028ef92305caeea8626633ad44d413e30f6b2f33863060405161257d93929190614ad4565b60405180910390a1600d546040517f806f8ab200000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9091169063806f8ab2906125df90309033908690600401614b2b565b60206040518083038186803b1580156125f757600080fd5b505afa15801561260b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061262f91906149f8565b6040518060400160405280600281526020017f3131000000000000000000000000000000000000000000000000000000000000815250906126835760405162461bcd60e51b815260040161069c9190614eb3565b506001601155949350505050565b600061269b611c98565b5061099c6141b6565b6000600260115414156126fe576040805162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015290519081900360640190fd5b600260115561270b6111cd565b83106040518060400160405280600181526020017f3900000000000000000000000000000000000000000000000000000000000000815250906127615760405162461bcd60e51b815260040161069c9190614eb3565b5060408051808201909152600281527f3232000000000000000000000000000000000000000000000000000000000000602082015273ffffffffffffffffffffffffffffffffffffffff85166127ca5760405162461bcd60e51b815260040161069c9190614eb3565b5060408051808201909152600281527f323700000000000000000000000000000000000000000000000000000000000060208201528361281d5760405162461bcd60e51b815260040161069c9190614eb3565b5061282783613d5b565b8210156040518060400160405280600281526020017f32330000000000000000000000000000000000000000000000000000000000008152509061287e5760405162461bcd60e51b815260040161069c9190614eb3565b50612887611c98565b61289057600080fd5b600454339061289f90856140ba565b600455600f546000906128c79073ffffffffffffffffffffffffffffffffffffffff1661442b565b6001549091506128ee9073ffffffffffffffffffffffffffffffffffffffff168287614357565b6001546129139073ffffffffffffffffffffffffffffffffffffffff1683838761411b565b6001546040517f890dcf5400000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8084169263890dcf549261297492309288929116908c908c908c90600401614c21565b602060405180830381600087803b15801561298e57600080fd5b505af11580156129a2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129c691906149f8565b6040518060400160405280600281526020017f313200000000000000000000000000000000000000000000000000000000000081525090612a1a5760405162461bcd60e51b815260040161069c9190614eb3565b50600c805460018101825560009182527fdf6966c971051c3d54ec59162606531493a51404a002842f56009d7e5cf4a8c70180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff8481169190911790915581546040517f63185c420000000000000000000000000000000000000000000000000000000081529116906363185c4290612ad290869030908790600401614b5c565b602060405180830381600087803b158015612aec57600080fd5b505af1158015612b00573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b249190614a30565b90506040518061018001604052808281526020018873ffffffffffffffffffffffffffffffffffffffff1681526020018373ffffffffffffffffffffffffffffffffffffffff168152602001878152602001600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200186815260200160008152602001600a5481526020014381526020016000815260200160001515815260200160001515815250600b60008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000820151816000015560208201518160010160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060408201518160020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506060820151816003015560808201518160040160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060a0820151816005015560c0820151816006015560e082015181600701556101008201518160080155610120820151816009015561014082015181600a0160006101000a81548160ff02191690831515021790555061016082015181600a0160016101000a81548160ff021916908315150217905550905050600d60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663f5565ddf30858a8a8a886040518763ffffffff1660e01b8152600401612dec96959493929190614d20565b60206040518083038186803b158015612e0457600080fd5b505afa158015612e18573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e3c91906149f8565b6040518060400160405280600281526020017f313300000000000000000000000000000000000000000000000000000000000081525090612e905760405162461bcd60e51b815260040161069c9190614eb3565b506001546040517f8f11691cf96727f419bd99b50853d8351f147118e4778f62bdaa8528ab3e50bb91612ee99186918b9173ffffffffffffffffffffffffffffffffffffffff909116908b903090899089904390614c68565b60405180910390a160016011559695505050505050565b73ffffffffffffffffffffffffffffffffffffffff8082166000908152600b6020908152604080832081516101808101835281548152600182015486169381019390935260028101548516918301919091526003810154606083015260048101549093166080820152600583015460a0820152600683015460c0820152600783015460e08201526008830154610100808301919091526009840154610120830152600a9093015460ff808216158015610140850152949091041615156101608201529091612fd25760009150506114dd565b6000612ffd82606001516117288460e00151611722600a5487606001516142bc90919063ffffffff16565b905060006130248360a00151611722670de0b6b3a7640000856142bc90919063ffffffff16565b670d2f13f7789f0000111595945050505050565b73ffffffffffffffffffffffffffffffffffffffff8082166000908152600b602090815260408083208151610180810183528154808252600183015487169482019490945260028201548616818401526003820154606082015260048083015487166080830152600583015460a0830152600683015460c0830152600783015460e08301526008830154610100808401919091526009840154610120840152600a9093015460ff80821615156101408501529390049092161515610160820152845492517f2d7254e5000000000000000000000000000000000000000000000000000000008152949586958695869586958695869586958695869586958695949190911692632d7254e59261314f92909101614f24565b60206040518083038186803b15801561316757600080fd5b505afa15801561317b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061319f9190614890565b6020820151604083015183516060850151608086015160a08701516101408801516131ea57606088015160e0890151600a546131e59291611728916117229084906142bc565b6131f0565b8760c001515b8861010001518961012001518a61014001518b61016001519c509c509c509c509c509c509c509c509c509c509c509c505091939597999b5091939597999b565b60026011541415613288576040805162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015290519081900360640190fd5b6002601181905573ffffffffffffffffffffffffffffffffffffffff82166000908152600b6020908152604091829020600a81015483518085019094529383527f313400000000000000000000000000000000000000000000000000000000000091830191909152339290919060ff16156133165760405162461bcd60e51b815260040161069c9190614eb3565b50613321838361134d565b156040518060400160405280600281526020017f3136000000000000000000000000000000000000000000000000000000000000815250906133765760405162461bcd60e51b815260040161069c9190614eb3565b5061337f611c98565b61338857600080fd5b6000805482546040517f6352211e00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff90921691636352211e916133df91600401614f24565b60206040518083038186803b1580156133f757600080fd5b505afa15801561340b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061342f9190614890565b9050600061345c83600301546117288560070154611722600a5488600301546142bc90919063ffffffff16565b905060006134838460050154611722670de0b6b3a7640000856142bc90919063ffffffff16565b9050670d2f13f7789f00008110156040518060400160405280600281526020017f3138000000000000000000000000000000000000000000000000000000000000815250906134e55760405162461bcd60e51b815260040161069c9190614eb3565b506002840154600a850180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00909116600117166101001790556005850154600686015543600986015573ffffffffffffffffffffffffffffffffffffffff166000670de0b6b3a764000083111561358d5760058601546135889085906143e9565b613590565b60005b905060006135b9670de0b6b3a76400006117226007548a600501546142bc90919063ffffffff16565b90506135d56118c98689600301546140ba90919063ffffffff16565b600455600854613605906135f890670de0b6b3a7640000906117229086906142bc565b60035461172890846143e9565b60035560075460085461363d9161363491670de0b6b3a7640000916117229161362d916143e9565b86906142bc565b600554906143e9565b6005556007546040517ff8cfe49d00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85169163f8cfe49d91613695918c91600401614aae565b600060405180830381600087803b1580156136af57600080fd5b505af11580156136c3573d6000803e3d6000fd5b505060005489546040517f42966c6800000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff90921693506342966c68925061371d91600401614f24565b602060405180830381600087803b15801561373757600080fd5b505af115801561374b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061376f91906149f8565b6040518060400160405280600281526020017f3333000000000000000000000000000000000000000000000000000000000000815250906137c35760405162461bcd60e51b815260040161069c9190614eb3565b50600d5460028801546040517f716e257f00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9283169263716e257f926138239230928e921690600401614b5c565b60206040518083038186803b15801561383b57600080fd5b505afa15801561384f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061387391906149f8565b6040518060400160405280600281526020017f3236000000000000000000000000000000000000000000000000000000000000815250906138c75760405162461bcd60e51b815260040161069c9190614eb3565b507f976725bed73d37e8b46d0d5694646bfa4d33c5b84bae26b3194570f3ad53befb868860010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff168a60030154308c600501548f8e600001546001604051611c8099989796959493929190614cc1565b600260115414156139b2576040805162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015290519081900360640190fd5b6002601181905573ffffffffffffffffffffffffffffffffffffffff83166000908152600b6020908152604091829020600a81015483518085019094529383527f3134000000000000000000000000000000000000000000000000000000000000918301919091529160ff1615613a3c5760405162461bcd60e51b815260040161069c9190614eb3565b5060408051808201909152600281527f3232000000000000000000000000000000000000000000000000000000000000602082015273ffffffffffffffffffffffffffffffffffffffff8316613aa55760405162461bcd60e51b815260040161069c9190614eb3565b50613ab0833361134d565b6040518060400160405280600281526020017f313500000000000000000000000000000000000000000000000000000000000081525090613b045760405162461bcd60e51b815260040161069c9190614eb3565b50613b0d611c98565b613b1657600080fd5b60028101546001820180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff858116919091179091556040517f10187c7500000000000000000000000000000000000000000000000000000000815291169081906310187c7590613ba1908690600401614a8d565b602060405180830381600087803b158015613bbb57600080fd5b505af1158015613bcf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613bf391906149f8565b6040518060400160405280600281526020017f333200000000000000000000000000000000000000000000000000000000000081525090613c475760405162461bcd60e51b815260040161069c9190614eb3565b5060005482546040517f6352211e0000000000000000000000000000000000000000000000000000000081527f0495d9ab17c89a5018a45652488d3006feedcac9a14e348e939ffdab147057249273ffffffffffffffffffffffffffffffffffffffff1691636352211e91613cbf9190600401614f24565b60206040518083038186803b158015613cd757600080fd5b505afa158015613ceb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613d0f9190614890565b60015460028501548554604051613d489493899373ffffffffffffffffffffffffffffffffffffffff9182169330939290911691614b8c565b60405180910390a1505060016011555050565b6000613d656111cd565b82106040518060400160405280600181526020017f390000000000000000000000000000000000000000000000000000000000000081525090613dbb5760405162461bcd60e51b815260040161069c9190614eb3565b50600e5460009073ffffffffffffffffffffffffffffffffffffffff1663200d16aa30613dea866117286111cd565b600454613df790886140ba565b6003546040518563ffffffff1660e01b8152600401613e199493929190614de0565b60206040518083038186803b158015613e3157600080fd5b505afa158015613e45573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613e699190614a30565b90506000613e8f670de0b6b3a7640000611722613e8687866142bc565b600654906142bc565b905060008111613ea0576001613ea2565b805b949350505050565b60105473ffffffffffffffffffffffffffffffffffffffff16331480613ee75750600d5473ffffffffffffffffffffffffffffffffffffffff1633145b6040518060400160405280600281526020017f323900000000000000000000000000000000000000000000000000000000000081525090613f3b5760405162461bcd60e51b815260040161069c9190614eb3565b50613f44611c98565b613f4d57600080fd5b6005548211158015613f6157506003548211155b6040518060400160405280600281526020017f333400000000000000000000000000000000000000000000000000000000000081525090613fb55760405162461bcd60e51b815260040161069c9190614eb3565b50600554613fc390836143e9565b600555600354613fd390836143e9565b600355600154613ffa9073ffffffffffffffffffffffffffffffffffffffff168284614357565b7f835862a12039ab712842887f732f62f9ba4e46c8a157b8f2ece290bb03cb6229826040516140299190614f24565b60405180910390a15050565b600d5473ffffffffffffffffffffffffffffffffffffffff1681565b600e5460009073ffffffffffffffffffffffffffffffffffffffff1663200d16aa3061407b6111cd565b600480546003546040517fffffffff0000000000000000000000000000000000000000000000000000000060e088901b16815261122495949301614de0565b600082820183811015614114576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b9392505050565b6040805173ffffffffffffffffffffffffffffffffffffffff80861660248301528416604482015260648082018490528251808303909101815260849091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f23b872dd000000000000000000000000000000000000000000000000000000001790526141b09085906144f3565b50505050565b600080600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b15801561422157600080fd5b505afa158015614235573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906142599190614a30565b90508061427157670de0b6b3a764000091505061099f565b600061427b6111cd565b9050600061429a600354611728600454856140ba90919063ffffffff16565b90506142b28361172283670de0b6b3a76400006142bc565b935050505061099f565b6000826142cb575060006113ff565b828202828482816142d857fe5b04146141145760405162461bcd60e51b8152600401808060200182810382526021815260200180614f536021913960400191505060405180910390fd5b600061411483836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f0000000000008152506145b1565b6040805173ffffffffffffffffffffffffffffffffffffffff8416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb000000000000000000000000000000000000000000000000000000001790526143e49084906144f3565b505050565b600061411483836040518060400160405280601f81526020017f536166654d6174683a207375627472616374696f6e20756e646572666c6f7700815250614653565b60006040517f3d602d80600a3d3981f3363d3d373d3d3d363d7300000000000000000000000081528260601b60148201527f5af43d82803e903d91602b57fd5bf3000000000000000000000000000000000060288201526037816000f091505073ffffffffffffffffffffffffffffffffffffffff81166114dd576040805162461bcd60e51b815260206004820152601660248201527f455243313136373a20637265617465206661696c656400000000000000000000604482015290519081900360640190fd5b6000614555826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff166146ad9092919063ffffffff16565b8051909150156143e45780806020019051602081101561457457600080fd5b50516143e45760405162461bcd60e51b815260040180806020018281038252602a815260200180614f74602a913960400191505060405180910390fd5b6000818361463d5760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b838110156146025781810151838201526020016145ea565b50505050905090810190601f16801561462f5780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b50600083858161464957fe5b0495945050505050565b600081848411156146a55760405162461bcd60e51b81526020600482018181528351602484015283519092839260449091019190850190808383600083156146025781810151838201526020016145ea565b505050900390565b6060613ea28484600085856146c1856147fd565b614712576040805162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015290519081900360640190fd5b6000808673ffffffffffffffffffffffffffffffffffffffff1685876040518082805190602001908083835b6020831061477b57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0909201916020918201910161473e565b6001836020036101000a03801982511681845116808217855250505050505090500191505060006040518083038185875af1925050503d80600081146147dd576040519150601f19603f3d011682016040523d82523d6000602084013e6147e2565b606091505b50915091506147f2828286614803565b979650505050505050565b3b151590565b60608315614812575081614114565b8251156148225782518084602001fd5b60405162461bcd60e51b81526020600482018181528451602484015284518593919283926044019190850190808383600083156146025781810151838201526020016145ea565b80516114dd81614f2d565b600060208284031215614885578081fd5b813561411481614f2d565b6000602082840312156148a1578081fd5b815161411481614f2d565b600080604083850312156148be578081fd5b82356148c981614f2d565b915060208301356148d981614f2d565b809150509250929050565b600080604083850312156148f6578182fd5b823561490181614f2d565b946020939093013593505050565b600080600060608486031215614923578081fd5b833561492e81614f2d565b95602085013595506040909401359392505050565b60006020808385031215614955578182fd5b825167ffffffffffffffff8082111561496c578384fd5b818501915085601f83011261497f578384fd5b81518181111561498b57fe5b838102604051858282010181811085821117156149a457fe5b604052828152858101935084860182860187018a10156149c2578788fd5b8795505b838610156149eb576149d781614869565b8552600195909501949386019386016149c6565b5098975050505050505050565b600060208284031215614a09578081fd5b81518015158114614114578182fd5b600060208284031215614a29578081fd5b5035919050565b600060208284031215614a41578081fd5b5051919050565b60008060408385031215614a5a578182fd5b8235915060208301356148d981614f2d565b60008060408385031215614a7e578182fd5b50508035926020909101359150565b73ffffffffffffffffffffffffffffffffffffffff91909116815260200190565b73ffffffffffffffffffffffffffffffffffffffff929092168252602082015260400190565b73ffffffffffffffffffffffffffffffffffffffff93841681526020810192909252909116604082015260600190565b73ffffffffffffffffffffffffffffffffffffffff92831681529116602082015260400190565b73ffffffffffffffffffffffffffffffffffffffff9384168152919092166020820152604081019190915260600190565b73ffffffffffffffffffffffffffffffffffffffff93841681529183166020830152909116604082015260600190565b73ffffffffffffffffffffffffffffffffffffffff9687168152948616602086015292851660408501529084166060840152909216608082015260a081019190915260c00190565b73ffffffffffffffffffffffffffffffffffffffff9788168152958716602087015293861660408601529185166060850152608084015290921660a082015260c081019190915260e00190565b73ffffffffffffffffffffffffffffffffffffffff96871681529486166020860152928516604085015293166060830152608082019290925260a081019190915260c00190565b73ffffffffffffffffffffffffffffffffffffffff9889168152968816602088015294871660408701526060860193909352908516608085015290931660a083015260c082019290925260e08101919091526101000190565b73ffffffffffffffffffffffffffffffffffffffff998a168152978916602089015295881660408801526060870194909452918616608086015260a085015290931660c083015260e08201929092529015156101008201526101200190565b73ffffffffffffffffffffffffffffffffffffffff9687168152948616602086015292851660408501526060840191909152608083015290911660a082015260c00190565b73ffffffffffffffffffffffffffffffffffffffff9c8d1681529a8c1660208c0152988b1660408b015260608a019790975260808901959095529290971660a087015260c086015260e08501959095526101008401949094526101208301939093529115156101408201529015156101608201526101800190565b73ffffffffffffffffffffffffffffffffffffffff94909416845260208401929092526040830152606082015260800190565b73ffffffffffffffffffffffffffffffffffffffff959095168552602085019390935260408401919091526060830152608082015260a00190565b6020808252825182820181905260009190848201906040850190845b81811015614e9c57835173ffffffffffffffffffffffffffffffffffffffff1683529284019291840191600101614e6a565b50909695505050505050565b901515815260200190565b6000602080835283518082850152825b81811015614edf57858101830151858201604001528201614ec3565b81811115614ef05783604083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016929092016040019392505050565b90815260200190565b73ffffffffffffffffffffffffffffffffffffffff81168114614f4f57600080fd5b5056fe536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f775361666545524332303a204552433230206f7065726174696f6e20646964206e6f742073756363656564a26469706673582212203e45d090c628521bd5bdc8acd4a6582d11213dd4a48700c25c752082e171295a64736f6c634300070600330000000000000000000000007ffad0da714f4595fc9c48fe789d76b9137d7245000000000000000000000000bbfa3b05b2dae65fb4c05ec7f1598793a4bc06230000000000000000000000001f9840a85d5af5bf1d1762f925bdaddc4201f984000000000000000000000000076d4cf37e48b9265e05d57f280eff562b17747600000000000000000000000012cb3f4e80b795bc77090a7c412b1f804ee085a800000000000000000000000055da1cbd77b1c3b2d8bfe0f5fdf63d684b49f8a5

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

0000000000000000000000007ffad0da714f4595fc9c48fe789d76b9137d7245000000000000000000000000bbfa3b05b2dae65fb4c05ec7f1598793a4bc06230000000000000000000000001f9840a85d5af5bf1d1762f925bdaddc4201f984000000000000000000000000076d4cf37e48b9265e05d57f280eff562b17747600000000000000000000000012cb3f4e80b795bc77090a7c412b1f804ee085a800000000000000000000000055da1cbd77b1c3b2d8bfe0f5fdf63d684b49f8a5

-----Decoded View---------------
Arg [0] : _palToken (address): 0x7fFad0dA714f4595fC9c48FE789d76b9137D7245
Arg [1] : _controller (address): 0xbBFA3b05b2dAe65Fb4C05Ec7F1598793a4Bc0623
Arg [2] : _underlying (address): 0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984
Arg [3] : _interestModule (address): 0x076D4cf37E48B9265E05D57f280EfF562b177476
Arg [4] : _delegator (address): 0x12Cb3F4e80b795bc77090A7c412B1f804Ee085a8
Arg [5] : _palLoanToken (address): 0x55DA1CBD77B1c3b2d8Bfe0F5fDF63d684b49F8A5

-----Encoded View---------------
6 Constructor Arguments found :
Arg [0] : 0000000000000000000000007ffad0da714f4595fc9c48fe789d76b9137d7245
Arg [1] : 000000000000000000000000bbfa3b05b2dae65fb4c05ec7f1598793a4bc0623
Arg [2] : 0000000000000000000000001f9840a85d5af5bf1d1762f925bdaddc4201f984
Arg [3] : 000000000000000000000000076d4cf37e48b9265e05d57f280eff562b177476
Arg [4] : 00000000000000000000000012cb3f4e80b795bc77090a7c412b1f804ee085a8
Arg [5] : 00000000000000000000000055da1cbd77b1c3b2d8bfe0f5fdf63d684b49f8a5


Block Transaction Difficulty Gas Used Reward
Block Uncle Number Difficulty Gas Used Reward
Loading
Loading
Make sure to use the "Vote Down" button for any spammy posts, and the "Vote Up" for interesting conversations.

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.