ETH Price: $2,623.44 (+7.27%)

Contract

0x9aa024D3fd962701ED17F76c17CaB22d3dc9D92d
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Un Pause177841542023-07-27 11:38:47445 days ago1690457927IN
0x9aa024D3...d3dc9D92d
0 ETH0.0007348121.98408298
Set Vault Versio...177696602023-07-25 10:57:59447 days ago1690282679IN
0x9aa024D3...d3dc9D92d
0 ETH0.0005829422.74099571
Un Pause176696302023-07-11 9:57:59461 days ago1689069479IN
0x9aa024D3...d3dc9D92d
0 ETH0.0005790517.32142695
Update Interest ...176645302023-07-10 16:45:47462 days ago1689007547IN
0x9aa024D3...d3dc9D92d
0 ETH0.0025506932.40537382
Set Interest Con...176640342023-07-10 15:04:59462 days ago1689001499IN
0x9aa024D3...d3dc9D92d
0 ETH0.0014672358.24212995
Update Interest ...169767432023-04-04 16:37:11559 days ago1680626231IN
0x9aa024D3...d3dc9D92d
0 ETH0.0032210338.60389355
Set Interest Con...169767152023-04-04 16:31:35559 days ago1680625895IN
0x9aa024D3...d3dc9D92d
0 ETH0.001017633.67309089
Do Action With L...168775992023-03-21 17:50:11572 days ago1679421011IN
0x9aa024D3...d3dc9D92d
0 ETH0.0174432125.31568545
Do Action With L...168774842023-03-21 17:26:35573 days ago1679419595IN
0x9aa024D3...d3dc9D92d
0 ETH0.0180241429.69812172
Do Action With L...168774792023-03-21 17:25:35573 days ago1679419535IN
0x9aa024D3...d3dc9D92d
0 ETH0.0170622630.02898835
Set Interest Con...168768002023-03-21 15:07:47573 days ago1679411267IN
0x9aa024D3...d3dc9D92d
0 ETH0.0009360234.1066347
Set Borrow Cap168767982023-03-21 15:07:23573 days ago1679411243IN
0x9aa024D3...d3dc9D92d
0 ETH0.0016980936.16810953
Set Interest Con...168350342023-03-15 18:20:23578 days ago1678904423IN
0x9aa024D3...d3dc9D92d
0 ETH0.0011659238.55053233
Set Borrow Cap168296972023-03-15 0:17:47579 days ago1678839467IN
0x9aa024D3...d3dc9D92d
0 ETH0.000789931.59371178
Set Vault Versio...168296972023-03-15 0:17:47579 days ago1678839467IN
0x9aa024D3...d3dc9D92d
0 ETH0.0015021531.59371178
Set Supply Cap167921972023-03-09 17:41:23584 days ago1678383683IN
0x9aa024D3...d3dc9D92d
0 ETH0.0018558562.08535217
Change Guardian167790122023-03-07 21:12:11586 days ago1678223531IN
0x9aa024D3...d3dc9D92d
0 ETH0.0016309734.1187161
Set Supply Cap167774622023-03-07 15:58:11587 days ago1678204691IN
0x9aa024D3...d3dc9D92d
0 ETH0.0011418438.19894038
Set Treasury167773532023-03-07 15:36:11587 days ago1678203371IN
0x9aa024D3...d3dc9D92d
0 ETH0.0013114845.16288137
Set Interest Con...167771472023-03-07 14:54:59587 days ago1678200899IN
0x9aa024D3...d3dc9D92d
0 ETH0.0018524439.13724263
Set Borrow Cap167771472023-03-07 14:54:59587 days ago1678200899IN
0x9aa024D3...d3dc9D92d
0 ETH0.0018360839.13724263
Set Supply Cap167771472023-03-07 14:54:59587 days ago1678200899IN
0x9aa024D3...d3dc9D92d
0 ETH0.0011684839.13724263
Set Treasury Liq...167771472023-03-07 14:54:59587 days ago1678200899IN
0x9aa024D3...d3dc9D92d
0 ETH0.0011859339.13724263
Set Treasury Int...167771472023-03-07 14:54:59587 days ago1678200899IN
0x9aa024D3...d3dc9D92d
0 ETH0.0011854239.13724263
Add Tranche167771472023-03-07 14:54:59587 days ago1678200899IN
0x9aa024D3...d3dc9D92d
0 ETH0.0055576839.13724263
View all transactions

View more zero value Internal Transactions in Advanced View mode

Advanced mode:
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
LendingPool

Compiler Version
v0.8.17+commit.8df45f5f

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion
File 1 of 18 : LendingPool.sol
/**
 * Created by Pragma Labs
 * SPDX-License-Identifier: BUSL-1.1
 */
pragma solidity ^0.8.13;

import { SafeTransferLib } from "../lib/solmate/src/utils/SafeTransferLib.sol";
import { SafeCastLib } from "../lib/solmate/src/utils/SafeCastLib.sol";
import { FixedPointMathLib } from "../lib/solmate/src/utils/FixedPointMathLib.sol";
import { LogExpMath } from "./utils/LogExpMath.sol";
import { ITranche } from "./interfaces/ITranche.sol";
import { IFactory } from "./interfaces/IFactory.sol";
import { IVault } from "./interfaces/IVault.sol";
import { ILiquidator } from "./interfaces/ILiquidator.sol";
import { ILendingPool } from "./interfaces/ILendingPool.sol";
import { TrustedCreditor } from "./TrustedCreditor.sol";
import { ERC20, ERC4626, DebtToken } from "./DebtToken.sol";
import { InterestRateModule } from "./InterestRateModule.sol";
import { Guardian } from "./security/Guardian.sol";

/**
 * @title Arcadia LendingPool.
 * @author Pragma Labs
 * @notice The Lending pool contains the main logic to provide liquidity and take or repay loans for a certain asset
 * and does the accounting of the debtTokens (ERC4626).
 * @dev Implementation not vulnerable to ERC4626 inflation attacks,
 * since totalAssets() cannot be manipulated by the first minter.
 * For more information, see https://github.com/OpenZeppelin/openzeppelin-contracts/issues/3706
 */
contract LendingPool is Guardian, TrustedCreditor, DebtToken, InterestRateModule, ILendingPool {
    using SafeTransferLib for ERC20;
    using FixedPointMathLib for uint256;

    /* //////////////////////////////////////////////////////////////
                                STORAGE
    ////////////////////////////////////////////////////////////// */

    // Seconds per year, leap years ignored.
    uint256 public constant YEARLY_SECONDS = 31_536_000;
    // Contract address of the Arcadia Vault Factory.
    address public immutable vaultFactory;
    // Contract address of the Liquidator contract.
    address public immutable liquidator;

    // Last timestamp that interests were realized.
    uint32 public lastSyncedTimestamp;
    // Origination fee, 4 decimals precision (10 equals 0.001 or 0.1%), capped at 255 (2.55%).
    uint8 public originationFee;
    // Sum of all the interest weights of the tranches + treasury.
    uint24 public totalInterestWeight;
    // Fraction (interestWeightTreasury / totalInterestWeight) of the interest fees that go to the treasury.
    uint16 public interestWeightTreasury;
    // Sum of the liquidation weights of the tranches + treasury.
    uint24 public totalLiquidationWeight;
    // Fraction (liquidationWeightTreasury / totalLiquidationWeight) of the liquidation fees that goes to the treasury.
    uint16 public liquidationWeightTreasury;

    // Total amount of `underlying asset` that is claimable by the LPs. Does not take into account pending interests.
    uint128 public totalRealisedLiquidity;
    // Maximum amount of `underlying asset` that can be supplied to the pool.
    uint128 public supplyCap;
    // Conservative estimate of the maximal gas cost to liquidate a position (fixed cost, independent of openDebt).
    uint96 public fixedLiquidationCost;
    // Maximum amount of `underlying asset` that is paid as fee to the initiator of a liquidation.
    uint80 public maxInitiatorFee;
    // Number of auctions that are currently in progress.
    uint16 public auctionsInProgress;
    // Address of the protocol treasury.
    address public treasury;

    // Array of the interest weights of each Tranche.
    // Fraction (interestWeightTranches[i] / totalInterestWeight) of the interest fees that go to Tranche i.
    uint16[] public interestWeightTranches;
    // Array of the liquidation weights of each Tranche.
    // Fraction (liquidationWeightTranches[i] / totalLiquidationWeight) of the liquidation fees that go to Tranche i.
    uint16[] public liquidationWeightTranches;
    // Array of the contract addresses of the Tranches.
    address[] public tranches;

    // Map tranche => status.
    mapping(address => bool) public isTranche;
    // Map tranche => interestWeight.
    // Fraction (interestWeightTranches[i] / totalInterestWeight) of the interest fees that go to Tranche i.
    mapping(address => uint256) public interestWeight;
    // Map tranche => realisedLiquidity.
    // Amount of `underlying asset` that is claimable by the Tranche. Does not take into account pending interests.
    mapping(address => uint256) public realisedLiquidityOf;
    // Map vault => initiator.
    // Stores the address of the initiator of an auction, used to pay out the initiation fee after auction is ended.
    mapping(address => address) public liquidationInitiator;
    // Map vault => owner => beneficiary => amount.
    // Stores the credit allowances for a beneficiary per Vault and per Owner.
    mapping(address => mapping(address => mapping(address => uint256))) public creditAllowance;

    /* //////////////////////////////////////////////////////////////
                                EVENTS
    ////////////////////////////////////////////////////////////// */

    event TrancheAdded(address indexed tranche, uint8 indexed index, uint16 interestWeight, uint16 liquidationWeight);
    event InterestWeightSet(uint256 indexed index, uint16 weight);
    event LiquidationWeightSet(uint256 indexed index, uint16 weight);
    event MaxInitiatorFeeSet(uint80 maxInitiatorFee);
    event TranchePopped(address tranche);
    event TreasuryInterestWeightSet(uint16 weight);
    event TreasuryLiquidationWeightSet(uint16 weight);
    event OriginationFeeSet(uint8 originationFee);
    event BorrowCapSet(uint128 borrowCap);
    event SupplyCapSet(uint128 supplyCap);
    event CreditApproval(address indexed vault, address indexed owner, address indexed beneficiary, uint256 amount);
    event Borrow(
        address indexed vault, address indexed by, address to, uint256 amount, uint256 fee, bytes3 indexed referrer
    );
    event Repay(address indexed vault, address indexed from, uint256 amount);
    event FixedLiquidationCostSet(uint96 fixedLiquidationCost);
    event VaultVersionSet(uint256 indexed vaultVersion, bool valid);

    error supplyCapExceeded();

    /* //////////////////////////////////////////////////////////////
                                MODIFIERS
    ////////////////////////////////////////////////////////////// */

    modifier onlyLiquidator() {
        require(liquidator == msg.sender, "LP: Only liquidator");
        _;
    }

    modifier onlyTranche() {
        require(isTranche[msg.sender], "LP: Only tranche");
        _;
    }

    modifier processInterests() {
        _syncInterests();
        _;
        //_updateInterestRate() modifies the state (effect), but can safely be called after interactions.
        //Cannot be exploited by re-entrancy attack.
        _updateInterestRate(realisedDebt, totalRealisedLiquidity);
    }

    /* //////////////////////////////////////////////////////////////
                                CONSTRUCTOR
    ////////////////////////////////////////////////////////////// */

    /**
     * @notice The constructor for a lending pool.
     * @param asset_ The underlying ERC-20 token of the Lending Pool.
     * @param treasury_ The address of the protocol treasury.
     * @param vaultFactory_ The address of the Vault Factory.
     * @param liquidator_ The address of the Liquidator.
     * @dev The name and symbol of the DebtToken are automatically generated, based on the name and symbol of the underlying token.
     */
    constructor(ERC20 asset_, address treasury_, address vaultFactory_, address liquidator_)
        Guardian()
        TrustedCreditor()
        DebtToken(asset_)
    {
        treasury = treasury_;
        vaultFactory = vaultFactory_;
        liquidator = liquidator_;
    }

    /* //////////////////////////////////////////////////////////////
                            TRANCHES LOGIC
    ////////////////////////////////////////////////////////////// */

    /**
     * @notice Adds a tranche to the Lending Pool.
     * @param tranche The address of the Tranche.
     * @param interestWeight_ The interestWeight of the specific Tranche.
     * @param liquidationWeight The liquidationWeight of the specific Tranche.
     * @dev The order of the tranches is important, the most senior tranche is added first at index 0, the most junior at the last index.
     * @dev Each Tranche is an ERC-4626 contract.
     * @dev The interestWeight of each Tranche determines the relative share of the yield (interest payments) that goes to its Liquidity providers.
     * @dev The liquidationWeight of each Tranche determines the relative share of the liquidation fee that goes to its Liquidity providers.
     */
    function addTranche(address tranche, uint16 interestWeight_, uint16 liquidationWeight) external onlyOwner {
        require(!isTranche[tranche], "TR_AD: Already exists");
        totalInterestWeight += interestWeight_;
        interestWeightTranches.push(interestWeight_);
        interestWeight[tranche] = interestWeight_;

        totalLiquidationWeight += liquidationWeight;
        liquidationWeightTranches.push(liquidationWeight);

        tranches.push(tranche);
        isTranche[tranche] = true;

        emit TrancheAdded(tranche, uint8(tranches.length - 1), interestWeight_, liquidationWeight);
    }

    /**
     * @notice Changes the interestWeight of a specific Tranche.
     * @param index The index of the Tranche for which a new interestWeight is being set.
     * @param weight The new interestWeight of the Tranche at the index.
     * @dev The interestWeight of each Tranche determines the relative share yield (interest payments) that goes to its Liquidity providers.
     */
    function setInterestWeight(uint256 index, uint16 weight) external onlyOwner {
        require(index < tranches.length, "TR_SIW: Non Existing Tranche");
        totalInterestWeight = totalInterestWeight - interestWeightTranches[index] + weight;
        interestWeightTranches[index] = weight;
        interestWeight[tranches[index]] = weight;

        emit InterestWeightSet(index, weight);
    }

    /**
     * @notice Changes the liquidationWeight of a specific tranche.
     * @param index The index of the Tranche for which a new liquidationWeight is being set.
     * @param weight The new liquidationWeight of the Tranche at the index.
     * @dev The liquidationWeight determines the relative share of the liquidation fee that goes to its Liquidity providers.
     */
    function setLiquidationWeight(uint256 index, uint16 weight) external onlyOwner {
        require(index < tranches.length, "TR_SLW: Non Existing Tranche");
        totalLiquidationWeight = totalLiquidationWeight - liquidationWeightTranches[index] + weight;
        liquidationWeightTranches[index] = weight;

        emit LiquidationWeightSet(index, weight);
    }

    /**
     * @notice Removes the Tranche at the last index (most junior).
     * @param index The index of the last Tranche.
     * @param tranche The address of the last Tranche.
     * @dev This function can only be called by the function _processDefault(uint256 assets),
     * when there is a default as big as (or bigger than) the complete principal of the most junior tranche.
     * @dev Passing the input parameters to the function saves gas compared to reading the address and index of the last tranche from memory.
     * No need to check if index and Tranche are indeed of the last tranche since function is only called by _processDefault.
     */
    function _popTranche(uint256 index, address tranche) internal {
        totalInterestWeight -= interestWeightTranches[index];
        totalLiquidationWeight -= liquidationWeightTranches[index];
        isTranche[tranche] = false;
        interestWeightTranches.pop();
        liquidationWeightTranches.pop();
        tranches.pop();

        emit TranchePopped(tranche);
    }

    /* ///////////////////////////////////////////////////////////////
                    TREASURY FEE CONFIGURATION
    ////////////////////////////////////////////////////////////// */

    /**
     * @notice Changes the fraction of the interest payments that go to the treasury.
     * @param interestWeightTreasury_ The new interestWeight of the treasury.
     * @dev The interestWeight determines the relative share of the yield (interest payments) that goes to the protocol treasury.
     * @dev Setting interestWeightTreasury to a very high value will cause the treasury to collect all interest fees from that moment on.
     * Although this will affect the future profits of liquidity providers, no funds nor realized interest are at risk for LPs.
     */
    function setTreasuryInterestWeight(uint16 interestWeightTreasury_) external onlyOwner {
        totalInterestWeight = totalInterestWeight - interestWeightTreasury + interestWeightTreasury_;
        interestWeightTreasury = interestWeightTreasury_;

        emit TreasuryInterestWeightSet(interestWeightTreasury_);
    }

    /**
     * @notice Changes the fraction of the liquidation fees that go to the treasury.
     * @param liquidationWeightTreasury_ The new liquidationWeight of the liquidation fee fee.
     * @dev The liquidationWeight determines the relative share of the liquidation fee that goes to the protocol treasury.
     * @dev Setting liquidationWeightTreasury to a very high value will cause the treasury to collect all liquidation fees from that moment on.
     * Although this will affect the future profits of liquidity providers in the Jr tranche, no funds nor realized interest are at risk for LPs.
     */
    function setTreasuryLiquidationWeight(uint16 liquidationWeightTreasury_) external onlyOwner {
        totalLiquidationWeight = totalLiquidationWeight - liquidationWeightTreasury + liquidationWeightTreasury_;
        liquidationWeightTreasury = liquidationWeightTreasury_;

        emit TreasuryLiquidationWeightSet(liquidationWeightTreasury_);
    }

    /**
     * @notice Sets new treasury address.
     * @param treasury_ The new address of the treasury.
     */
    function setTreasury(address treasury_) external onlyOwner {
        treasury = treasury_;
    }

    /**
     * @notice Sets the new origination fee.
     * @param originationFee_ The new origination fee.
     * @dev originationFee is limited by being a uint8 -> max value is 2.55%
     * 4 decimal precision (10 = 0.1%).
     */
    function setOriginationFee(uint8 originationFee_) external onlyOwner {
        originationFee = originationFee_;

        emit OriginationFeeSet(originationFee_);
    }

    /* //////////////////////////////////////////////////////////////
                         PROTOCOL CAP LOGIC
    ////////////////////////////////////////////////////////////// */
    /**
     * @notice Sets the maximum amount of assets that can be borrowed per Vault.
     * @param borrowCap_ The new maximum amount that can be borrowed.
     * @dev The borrowCap is the maximum amount of assets that can be borrowed per Vault.
     * @dev If it is set to 0, there is no borrow cap.
     */
    function setBorrowCap(uint128 borrowCap_) external onlyOwner {
        borrowCap = borrowCap_;

        emit BorrowCapSet(borrowCap_);
    }

    /**
     * @notice Sets the maximum amount of assets that can be deposited in the pool.
     * @param supplyCap_ The new maximum amount of assets that can be deposited.
     * @dev The supplyCap is the maximum amount of assets that can be deposited in the pool at any given time.
     * @dev If it is set to 0, there is no supply cap.
     */
    function setSupplyCap(uint128 supplyCap_) external onlyOwner {
        supplyCap = supplyCap_;

        emit SupplyCapSet(supplyCap_);
    }

    /* //////////////////////////////////////////////////////////////
                        DEPOSIT/WITHDRAWAL LOGIC
    ////////////////////////////////////////////////////////////// */

    /**
     * @notice Deposit assets in the Lending Pool.
     * @param assets The amount of assets of the underlying ERC-20 tokens being deposited.
     * @param from The address of the Liquidity Provider who deposits the underlying ERC-20 token via a Tranche.
     * @dev This function can only be called by Tranches.
     */

    function depositInLendingPool(uint256 assets, address from)
        external
        whenDepositNotPaused
        onlyTranche
        processInterests
    {
        if (supplyCap > 0) {
            if (totalRealisedLiquidity + assets > supplyCap) revert supplyCapExceeded();
        }
        // Need to transfer before minting or ERC777s could reenter.
        // Address(this) is trusted -> no risk on re-entrancy attack after transfer.
        asset.safeTransferFrom(from, address(this), assets);

        unchecked {
            realisedLiquidityOf[msg.sender] += assets;
            totalRealisedLiquidity += SafeCastLib.safeCastTo128(assets);
        }

        //Event emitted by Tranche.
    }

    /**
     * @notice Donate assets to the Lending Pool.
     * @param trancheIndex The index of the tranche to donate to.
     * @param assets The amount of assets of the underlying ERC-20 tokens being deposited.
     * @dev Can be used by anyone to donate assets to the Lending Pool.
     * It is supposed to serve as a way to compensate the jrTranche after an
     * auction didn't get sold and was manually Liquidated by the Protocol.
     * @dev First minter of a tranche could abuse this function by mining only 1 share,
     * frontrun next minter by calling this function and inflate the share price.
     * This is mitigated by checking that there are at least 10 ** decimals shares outstanding.
     */
    function donateToTranche(uint256 trancheIndex, uint256 assets) external whenDepositNotPaused processInterests {
        require(assets > 0, "LP_DTT: Amount is 0");

        if (supplyCap > 0) {
            if (totalRealisedLiquidity + assets > supplyCap) revert supplyCapExceeded();
        }

        address tranche = tranches[trancheIndex];
        //Mitigate share manipulation, where first Liquidity Provider mints just 1 share.
        //See https://github.com/OpenZeppelin/openzeppelin-contracts/issues/3706 for more information.
        require(ERC4626(tranche).totalSupply() >= 10 ** decimals, "LP_DTT: Insufficient shares");

        asset.safeTransferFrom(msg.sender, address(this), assets);

        unchecked {
            realisedLiquidityOf[tranche] += assets; //[̲̅$̲̅(̲̅ ͡° ͜ʖ ͡°̲̅)̲̅$̲̅]
            totalRealisedLiquidity += SafeCastLib.safeCastTo128(assets);
        }
    }

    /**
     * @notice Withdraw assets from the Lending Pool.
     * @param assets The amount of assets of the underlying ERC-20 tokens being withdrawn.
     * @param receiver The address of the receiver of the underlying ERC-20 tokens.
     * @dev This function can be called by anyone with an open balance (realisedLiquidityOf[address] bigger than 0),
     * which can be both Tranches as other address (treasury, Liquidation Initiators, Liquidated Vault Owner...).
     */
    function withdrawFromLendingPool(uint256 assets, address receiver)
        external
        whenWithdrawNotPaused
        processInterests
    {
        require(realisedLiquidityOf[msg.sender] >= assets, "LP_WFLP: Amount exceeds balance");

        unchecked {
            realisedLiquidityOf[msg.sender] -= assets;
        }
        totalRealisedLiquidity -= SafeCastLib.safeCastTo128(assets);

        asset.safeTransfer(receiver, assets);

        //Event emitted by Tranche.
    }

    /* //////////////////////////////////////////////////////////////
                            LENDING LOGIC
    ////////////////////////////////////////////////////////////// */

    /**
     * @notice Approve a beneficiary to take out a loan against an Arcadia Vault.
     * @param beneficiary The address of the beneficiary who can take out a loan backed by an Arcadia Vault.
     * @param amount The amount of underlying ERC-20 tokens to be lent out.
     * @param vault The address of the Arcadia Vault backing the loan.
     */
    function approveBeneficiary(address beneficiary, uint256 amount, address vault) external {
        //If vault is not an actual address of a vault, ownerOfVault(address) will return the zero address.
        require(IFactory(vaultFactory).ownerOfVault(vault) == msg.sender, "LP_AB: UNAUTHORIZED");

        creditAllowance[vault][msg.sender][beneficiary] = amount;

        emit CreditApproval(vault, msg.sender, beneficiary, amount);
    }

    /**
     * @notice Takes out a loan backed by collateral in an Arcadia Vault.
     * @param amount The amount of underlying ERC-20 tokens to be lent out.
     * @param vault The address of the Arcadia Vault backing the loan.
     * @param to The address who receives the lent out underlying tokens.
     * @param referrer A unique identifier of the referrer, who will receive part of the fees generated by this transaction.
     * @dev The sender might be different than the owner if they have the proper allowances.
     */
    function borrow(uint256 amount, address vault, address to, bytes3 referrer)
        external
        whenBorrowNotPaused
        processInterests
    {
        //If vault is not an actual address of a vault, ownerOfVault(address) will return the zero address.
        address vaultOwner = IFactory(vaultFactory).ownerOfVault(vault);
        require(vaultOwner != address(0), "LP_B: Not a vault");

        uint256 amountWithFee = amount + (amount * originationFee) / 10_000;

        //Check allowances to take debt.
        if (vaultOwner != msg.sender) {
            uint256 allowed = creditAllowance[vault][vaultOwner][msg.sender];
            if (allowed != type(uint256).max) {
                creditAllowance[vault][vaultOwner][msg.sender] = allowed - amountWithFee;
            }
        }

        //Mint debt tokens to the vault.
        _deposit(amountWithFee, vault);

        //Add origination fee to the treasury.
        unchecked {
            totalRealisedLiquidity += SafeCastLib.safeCastTo128(amountWithFee - amount);
            realisedLiquidityOf[treasury] += amountWithFee - amount;
        }

        //Call vault to check if it is still healthy after the debt is increased with amountWithFee.
        (bool isHealthy, address trustedCreditor, uint256 vaultVersion) =
            IVault(vault).isVaultHealthy(0, maxWithdraw(vault));
        require(isHealthy && trustedCreditor == address(this) && isValidVersion[vaultVersion], "LP_B: Reverted");

        //Transfer fails if there is insufficient liquidity in the pool.
        asset.safeTransfer(to, amount);

        emit Borrow(vault, msg.sender, to, amount, amountWithFee - amount, referrer);
    }

    /**
     * @notice Repays a loan.
     * @param amount The amount of underlying ERC-20 tokens to be repaid.
     * @param vault The address of the Arcadia Vault backing the loan.
     * @dev if Vault is not an actual address of a Vault, maxWithdraw(vault) will always return 0.
     * Function will not revert, but transferAmount is always 0.
     * @dev Anyone (EOAs and contracts) can repay debt in the name of a vault.
     */
    function repay(uint256 amount, address vault) external whenRepayNotPaused processInterests {
        uint256 vaultDebt = maxWithdraw(vault);
        uint256 transferAmount = vaultDebt > amount ? amount : vaultDebt;

        // Need to transfer before burning debt or ERC777s could reenter.
        // Address(this) is trusted -> no risk on re-entrancy attack after transfer.
        asset.safeTransferFrom(msg.sender, address(this), transferAmount);

        _withdraw(transferAmount, vault, vault);

        emit Repay(vault, msg.sender, transferAmount);
    }

    /* //////////////////////////////////////////////////////////////
                        LEVERAGED ACTIONS LOGIC
    ////////////////////////////////////////////////////////////// */

    /**
     * @notice Execute and interact with external logic on leverage.
     * @param amountBorrowed The amount of underlying ERC-20 tokens to be lent out.
     * @param vault The address of the Arcadia Vault backing the loan.
     * @param actionHandler the address of the action handler to call.
     * @param actionData a bytes object containing two actionAssetData structs, an address array and a bytes array.
     * @param referrer A unique identifier of the referrer, who will receive part of the fees generated by this transaction.
     * @dev The sender might be different than the owner if they have the proper allowances.
     * @dev vaultManagementAction() works similar to flash loans, this function optimistically calls external logic and checks for the vault state at the very end.
     */
    function doActionWithLeverage(
        uint256 amountBorrowed,
        address vault,
        address actionHandler,
        bytes calldata actionData,
        bytes3 referrer
    ) external whenBorrowNotPaused processInterests {
        //If vault is not an actual address of a vault, ownerOfVault(address) will return the zero address.
        address vaultOwner = IFactory(vaultFactory).ownerOfVault(vault);
        require(vaultOwner != address(0), "LP_DAWL: Not a vault");

        uint256 amountBorrowedWithFee = amountBorrowed + (amountBorrowed * originationFee) / 10_000;

        //Check allowances to take debt.
        if (vaultOwner != msg.sender) {
            //Since calling vaultManagementAction() gives the sender full control over all assets in the vault,
            //Only Beneficiaries with maximum allowance can call the doActionWithLeverage function.
            require(creditAllowance[vault][vaultOwner][msg.sender] == type(uint256).max, "LP_DAWL: UNAUTHORIZED");
        }

        //Mint debt tokens to the vault, debt must be minted Before the actions in the vault are performed.
        _deposit(amountBorrowedWithFee, vault);

        //Add origination fee to the treasury.
        unchecked {
            totalRealisedLiquidity += SafeCastLib.safeCastTo128(amountBorrowedWithFee - amountBorrowed);
            realisedLiquidityOf[treasury] += amountBorrowedWithFee - amountBorrowed;
        }

        //Send Borrowed funds to the actionHandler.
        asset.safeTransfer(actionHandler, amountBorrowed);

        //The actionHandler will use the borrowed funds (optionally with additional assets withdrawn from the Vault)
        //to execute one or more actions (swap, deposit, mint...).
        //Next the actionHandler will deposit any of the remaining funds or any of the recipient token
        //resulting from the actions back into the vault.
        //As last step, after all assets are deposited back into the vault a final health check is done:
        //The Collateral Value of all assets in the vault is bigger than the total liabilities against the vault (including the margin taken during this function).
        (address trustedCreditor, uint256 vaultVersion) = IVault(vault).vaultManagementAction(actionHandler, actionData);
        require(trustedCreditor == address(this) && isValidVersion[vaultVersion], "LP_DAWL: Reverted");

        emit Borrow(vault, msg.sender, actionHandler, amountBorrowed, amountBorrowedWithFee - amountBorrowed, referrer);
    }

    /* //////////////////////////////////////////////////////////////
                            ACCOUNTING LOGIC
    ////////////////////////////////////////////////////////////// */

    /**
     * @notice Returns the total amount of outstanding debt in the underlying asset.
     * @return totalDebt The total debt in underlying assets.
     */
    function totalAssets() public view override returns (uint256 totalDebt) {
        // Avoid a second calculation of unrealised debt (expensive)
        // if interests are already synced this block.
        if (lastSyncedTimestamp != uint32(block.timestamp)) {
            totalDebt = realisedDebt + calcUnrealisedDebt();
        } else {
            totalDebt = realisedDebt;
        }
    }

    /**
     * @notice Returns the redeemable amount of liquidity in the underlying asset of an address.
     * @param owner_ The address of the liquidity provider.
     * @return assets The redeemable amount of liquidity in the underlying asset.
     * @dev This function syncs the interests to prevent calculating UnrealisedDebt twice when depositing/withdrawing through the Tranches.
     * @dev After calling this function, the interest rate will not be updated until the next processInterests() call.
     */
    function liquidityOfAndSync(address owner_) external returns (uint256 assets) {
        _syncInterests();
        assets = realisedLiquidityOf[owner_];
    }

    /**
     * @notice Returns the redeemable amount of liquidity in the underlying asset of an address.
     * @param owner_ The address of the liquidity provider.
     * @return assets The redeemable amount of liquidity in the underlying asset.
     */
    function liquidityOf(address owner_) external view returns (uint256 assets) {
        // Avoid a second calculation of unrealised debt (expensive).
        // if interests are already synced this block.
        if (lastSyncedTimestamp != uint32(block.timestamp)) {
            // The total liquidity of a tranche equals the sum of the realised liquidity
            // of the tranche, and its pending interests.
            uint256 interest = calcUnrealisedDebt().mulDivUp(interestWeight[owner_], totalInterestWeight);
            unchecked {
                assets = realisedLiquidityOf[owner_] + interest;
            }
        } else {
            assets = realisedLiquidityOf[owner_];
        }
    }

    /**
     * @notice Skims any surplus funds in the LendingPool to the treasury.
     * @dev In normal conditions (when there are no ongoing auctions), the total Claimable Liquidity should be equal
     * to the sum of the available funds (the balanceOf() the underlying asset) in the pool and the total open debt.
     * In practice the actual sum of available funds and total open debt will always be bigger than the total Claimable Liquidity.
     * This because of the rounding errors of the ERC4626 calculations (conversions between assets and shares),
     * or because someone accidentally sent funds directly to the pool instead of depositing via a Tranche.
     * This functions makes the surplus available to the Treasury (otherwise they would be lost forever).
     * @dev In case you accidentally sent funds to the pool, contact the current treasury manager.
     */
    function skim() external processInterests {
        //During auctions, debt tokens are burned at start of the auction, while auctions proceeds are only returned
        //at the end of the auction -> skim function must be blocked during auctions.
        require(auctionsInProgress == 0, "LP_S: Auctions Ongoing");

        //Pending interests are synced via the processInterests modifier.
        uint256 delta = asset.balanceOf(address(this)) + realisedDebt - totalRealisedLiquidity;

        //Add difference to the treasury.
        unchecked {
            totalRealisedLiquidity += SafeCastLib.safeCastTo128(delta);
            realisedLiquidityOf[treasury] += delta;
        }
    }

    /* //////////////////////////////////////////////////////////////
                            INTERESTS LOGIC
    ////////////////////////////////////////////////////////////// */

    /**
     * @notice Syncs all unrealised debt (= interest for LP and treasury).
     * @dev Calculates the unrealised debt since last sync, and realises it by minting an equal amount of
     * debt tokens to all debt holders and interests to LPs and the treasury.
     */
    function _syncInterests() internal {
        // Only Sync interests once per block.
        if (lastSyncedTimestamp != uint32(block.timestamp)) {
            uint256 unrealisedDebt = calcUnrealisedDebt();
            lastSyncedTimestamp = uint32(block.timestamp);

            //Sync interests for borrowers.
            unchecked {
                realisedDebt += unrealisedDebt;
            }

            //Sync interests for LPs and Protocol Treasury.
            _syncInterestsToLiquidityProviders(unrealisedDebt);
        }
    }

    /**
     * @notice Calculates the unrealised debt (interests).
     * @return unrealisedDebt The unrealised debt.
     * @dev To Find the unrealised debt over an amount of time, you need to calculate D[(1+r)^x-1].
     * The base of the exponential: 1 + r, is a 18 decimals fixed point number
     * with r the yearly interest rate.
     * The exponent of the exponential: x, is a 18 decimals fixed point number.
     * The exponent x is calculated as: the amount of seconds passed since last sync timestamp divided by the average of
     * seconds per year. _yearlyInterestRate = 1 + r expressed as 18 decimals fixed point number.
     */
    function calcUnrealisedDebt() public view returns (uint256 unrealisedDebt) {
        uint256 base;
        uint256 exponent;

        unchecked {
            //gas: Can't overflow for reasonable interest rates.
            base = 1e18 + interestRate;

            //gas: Only overflows when (block.timestamp - lastSyncedBlockTimestamp) > 1e59
            //in practice: exponent in LogExpMath lib is limited to 130e18,
            //Corresponding to a delta of timestamps of 4099680000 (or 130 years),
            //much bigger than any realistic time difference between two syncs.
            exponent = ((block.timestamp - lastSyncedTimestamp) * 1e18) / YEARLY_SECONDS;

            //gas: Taking an imaginary worst-case scenario with max interest of 1000%
            //over a period of 5 years.
            //This won't overflow as long as openDebt < 3402823669209384912995114146594816
            //which is 3.4 million billion *10**18 decimals.
            unrealisedDebt = (realisedDebt * (LogExpMath.pow(base, exponent) - 1e18)) / 1e18;
        }

        return SafeCastLib.safeCastTo128(unrealisedDebt);
    }

    /**
     * @notice Syncs interest payments to the Lending providers and the treasury.
     * @param assets The total amount of underlying assets to be paid out as interests.
     * @dev The interestWeight of each Tranche determines the relative share yield (interest payments) that goes to its Liquidity providers.
     */
    function _syncInterestsToLiquidityProviders(uint256 assets) internal {
        uint256 remainingAssets = assets;

        uint256 trancheShare;
        for (uint256 i; i < tranches.length;) {
            trancheShare = assets.mulDivDown(interestWeightTranches[i], totalInterestWeight);
            unchecked {
                realisedLiquidityOf[tranches[i]] += trancheShare;
                remainingAssets -= trancheShare;
                ++i;
            }
        }
        unchecked {
            totalRealisedLiquidity += SafeCastLib.safeCastTo128(assets);

            // Add the remainingAssets to the treasury balance.
            realisedLiquidityOf[treasury] += remainingAssets;
        }
    }

    /* //////////////////////////////////////////////////////////////
                        INTEREST RATE LOGIC
    ////////////////////////////////////////////////////////////// */

    /**
     * @notice Set's the configuration parameters of InterestRateConfiguration struct.
     * @param newConfig New set of configuration parameters.
     */
    function setInterestConfig(InterestRateConfiguration calldata newConfig) external onlyOwner {
        _setInterestConfig(newConfig);
    }

    /**
     * @notice Updates the interest rate.
     * @dev Any address can call this, it will sync unrealised interests and update the interest rate.
     */
    function updateInterestRate() external processInterests { }

    /* //////////////////////////////////////////////////////////////
                        LIQUIDATION LOGIC
    ////////////////////////////////////////////////////////////// */

    /**
     * @notice Sets the maxInitiatorFee.
     * @param maxInitiatorFee_ The maximum fee that is paid to the initiator of a liquidation.
     * @dev The liquidator sets the % of the debt that is paid to the initiator of a liquidation.
     * This fee is capped by the maxInitiatorFee.
     */
    function setMaxInitiatorFee(uint80 maxInitiatorFee_) external onlyOwner {
        maxInitiatorFee = maxInitiatorFee_;

        emit MaxInitiatorFeeSet(maxInitiatorFee_);
    }

    /**
     * @notice Sets the estimated max gas cost to liquidate a position, denominated in baseCurrency.
     * @param fixedLiquidationCost_ The new fixedLiquidationCost.
     * @dev Conservative estimate of the maximal gas cost to liquidate a position (fixed cost, independent of openDebt).
     * The fixedLiquidationCost prevents dusting attacks, and ensures that upon Liquidations positions are big enough to cover.
     * gas costs of the Liquidator without resulting in badDebt.
     */
    function setFixedLiquidationCost(uint96 fixedLiquidationCost_) external onlyOwner {
        fixedLiquidationCost = fixedLiquidationCost_;

        emit FixedLiquidationCostSet(fixedLiquidationCost_);
    }

    /**
     * @notice Starts liquidation of a Vault.
     * @param vault The vault address.
     * @dev At the start of the liquidation the debt tokens are burned,
     * as such interests are not accrued during the liquidation.
     */

    function liquidateVault(address vault) external whenLiquidationNotPaused processInterests {
        //Only Vaults can have debt, and debtTokens are non-transferrable.
        //Hence by checking that the balance of the address passed as vault is not 0, we know the address
        //passed as vault is indeed a vault and has debt.
        uint256 openDebt = maxWithdraw(vault);
        require(openDebt != 0, "LP_LV: Not a Vault with debt");

        //Store liquidation initiator to pay out initiator reward when auction is finished.
        liquidationInitiator[vault] = msg.sender;

        //Start the auction of the collateralised assets to repay debt.
        ILiquidator(liquidator).startAuction(vault, openDebt, maxInitiatorFee);

        //Hook to the most junior Tranche, to inform that auctions are ongoing,
        //already done if there are other auctions in progress (auctionsInProgress > O).
        if (auctionsInProgress == 0) {
            ITranche(tranches[tranches.length - 1]).setAuctionInProgress(true);
        }
        unchecked {
            ++auctionsInProgress;
        }

        //Remove debt from Vault (burn DebtTokens).
        _withdraw(openDebt, vault, vault);

        //Event emitted by Liquidator.
    }

    /**
     * @notice Settles the liquidation after the auction is finished and pays out Creditor, Original owner and Service providers.
     * @param vault The contract address of the vault.
     * @param originalOwner The original owner of the vault before the auction.
     * @param badDebt The amount of liabilities that was not recouped by the auction.
     * @param liquidationInitiatorReward The Reward for the Liquidation Initiator.
     * @param liquidationFee The additional fee the `originalOwner` has to pay to the protocol.
     * @param remainder Any funds remaining after the auction are returned back to the `originalOwner`.
     * @dev This function is called by the Liquidator after a liquidation is finished.
     * @dev The liquidator will transfer the auction proceeds (the underlying asset)
     * back to the liquidity pool after liquidation, before calling this function.
     */

    function settleLiquidation(
        address vault,
        address originalOwner,
        uint256 badDebt,
        uint256 liquidationInitiatorReward,
        uint256 liquidationFee,
        uint256 remainder
    ) external onlyLiquidator processInterests {
        //Make Initiator rewards claimable for liquidationInitiator[vault].
        realisedLiquidityOf[liquidationInitiator[vault]] += liquidationInitiatorReward;

        if (badDebt > 0) {
            //Collateral was auctioned for less than the liabilities (openDebt + Liquidation Initiator Reward)
            //-> Default event, deduct badDebt from LPs, starting with most Junior Tranche.
            totalRealisedLiquidity =
                SafeCastLib.safeCastTo128(uint256(totalRealisedLiquidity) + liquidationInitiatorReward - badDebt);
            _processDefault(badDebt);
        } else {
            //Collateral was auctioned for more than the liabilities
            //-> Pay out the Liquidation Fee to treasury and Tranches.
            _syncLiquidationFeeToLiquidityProviders(liquidationFee);
            totalRealisedLiquidity = SafeCastLib.safeCastTo128(
                uint256(totalRealisedLiquidity) + liquidationInitiatorReward + liquidationFee + remainder
            );

            //Any remaining assets after paying off liabilities and the fee go back to the original Vault Owner.
            if (remainder > 0) {
                //Make remainder claimable by originalOwner.
                realisedLiquidityOf[originalOwner] += remainder;
            }
        }

        unchecked {
            --auctionsInProgress;
        }
        //Hook to the most junior Tranche to inform that there are no ongoing auctions.
        if (auctionsInProgress == 0 && tranches.length > 0) {
            ITranche(tranches[tranches.length - 1]).setAuctionInProgress(false);
        }

        //Event emitted by Liquidator.
    }

    /**
     * @notice Handles the bookkeeping in case of bad debt (Vault became undercollateralised).
     * @param badDebt The total amount of underlying assets that need to be written off as bad debt.
     * @dev The order of the Tranches is important, the most senior tranche is at index 0, the most junior at the last index.
     * @dev The most junior tranche will lose its underlying assets first. If all liquidity of a certain Tranche is written off,
     * the complete tranche is locked and removed. If there is still remaining bad debt, the next Tranche starts losing capital.
     */
    function _processDefault(uint256 badDebt) internal {
        address tranche;
        uint256 maxBurnable;
        for (uint256 i = tranches.length; i > 0;) {
            unchecked {
                --i;
            }
            tranche = tranches[i];
            maxBurnable = realisedLiquidityOf[tranche];
            if (badDebt < maxBurnable) {
                //Deduct badDebt from the balance of the most junior Tranche.
                unchecked {
                    realisedLiquidityOf[tranche] -= badDebt;
                }
                break;
            } else {
                //Unhappy flow, should never occur in practice!
                //badDebt is bigger than balance most junior Tranche -> tranche is completely wiped out
                //and temporarily locked (no new deposits or withdraws possible).
                //DAO or insurance might refund (Part of) the losses, and add Tranche back.
                realisedLiquidityOf[tranche] = 0;
                _popTranche(i, tranche);
                unchecked {
                    badDebt -= maxBurnable;
                }
                ITranche(tranche).lock();
                //Hook to the new most junior Tranche to inform that auctions are ongoing.
                if (i != 0) ITranche(tranches[i - 1]).setAuctionInProgress(true);
            }
        }
    }

    /**
     * @notice Syncs liquidation penalties to the Lending providers and the treasury.
     * @param assets The total amount of underlying assets to be paid out as liquidation fee.
     * @dev The liquidationWeight of each Tranche determines the relative share yield (interest payments) that goes to its Liquidity providers.
     */
    function _syncLiquidationFeeToLiquidityProviders(uint256 assets) internal {
        uint256 remainingAssets = assets;

        uint256 trancheShare;
        uint256 weightOfTranche;
        for (uint256 i; i < tranches.length;) {
            weightOfTranche = liquidationWeightTranches[i];

            if (weightOfTranche != 0) {
                //skip if weight is zero, which is the case for Sr tranche.
                trancheShare = assets.mulDivDown(weightOfTranche, totalLiquidationWeight);
                unchecked {
                    realisedLiquidityOf[tranches[i]] += trancheShare;
                    remainingAssets -= trancheShare;
                }
            }

            unchecked {
                ++i;
            }
        }

        unchecked {
            // Add the remainingAssets to the treasury balance.
            realisedLiquidityOf[treasury] += remainingAssets;
        }
    }

    /* //////////////////////////////////////////////////////////////
                            VAULT LOGIC
    ////////////////////////////////////////////////////////////// */

    /**
     * @notice Enables or disables a certain Vault version to be used as margin account.
     * @param vaultVersion The Vault version to be enabled/disabled.
     * @param valid The validity of the respective vaultVersion.
     */
    function setVaultVersion(uint256 vaultVersion, bool valid) external onlyOwner {
        _setVaultVersion(vaultVersion, valid);

        emit VaultVersionSet(vaultVersion, valid);
    }

    /**
     * @inheritdoc TrustedCreditor
     */
    function openMarginAccount(uint256 vaultVersion)
        external
        view
        override
        returns (bool success, address baseCurrency, address liquidator_, uint256 fixedLiquidationCost_)
    {
        if (isValidVersion[vaultVersion]) {
            success = true;
            baseCurrency = address(asset);
            liquidator_ = liquidator;
            fixedLiquidationCost_ = fixedLiquidationCost;
        }
    }

    /**
     * @inheritdoc TrustedCreditor
     */
    function getOpenPosition(address vault) external view override returns (uint256 openPosition) {
        openPosition = maxWithdraw(vault);
    }
}

File 2 of 18 : Owned.sol
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;

/// @notice Simple single owner authorization mixin.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/auth/Owned.sol)
abstract contract Owned {
    /*//////////////////////////////////////////////////////////////
                                 EVENTS
    //////////////////////////////////////////////////////////////*/

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

    /*//////////////////////////////////////////////////////////////
                            OWNERSHIP STORAGE
    //////////////////////////////////////////////////////////////*/

    address public owner;

    modifier onlyOwner() virtual {
        require(msg.sender == owner, "UNAUTHORIZED");

        _;
    }

    /*//////////////////////////////////////////////////////////////
                               CONSTRUCTOR
    //////////////////////////////////////////////////////////////*/

    constructor(address _owner) {
        owner = _owner;

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

    /*//////////////////////////////////////////////////////////////
                             OWNERSHIP LOGIC
    //////////////////////////////////////////////////////////////*/

    function transferOwnership(address newOwner) public virtual onlyOwner {
        owner = newOwner;

        emit OwnershipTransferred(msg.sender, newOwner);
    }
}

File 3 of 18 : ERC4626.sol
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;

import {ERC20} from "../tokens/ERC20.sol";
import {SafeTransferLib} from "../utils/SafeTransferLib.sol";
import {FixedPointMathLib} from "../utils/FixedPointMathLib.sol";

/// @notice Minimal ERC4626 tokenized Vault implementation.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/mixins/ERC4626.sol)
abstract contract ERC4626 is ERC20 {
    using SafeTransferLib for ERC20;
    using FixedPointMathLib for uint256;

    /*//////////////////////////////////////////////////////////////
                                 EVENTS
    //////////////////////////////////////////////////////////////*/

    event Deposit(address indexed caller, address indexed owner, uint256 assets, uint256 shares);

    event Withdraw(
        address indexed caller,
        address indexed receiver,
        address indexed owner,
        uint256 assets,
        uint256 shares
    );

    /*//////////////////////////////////////////////////////////////
                               IMMUTABLES
    //////////////////////////////////////////////////////////////*/

    ERC20 public immutable asset;

    constructor(
        ERC20 _asset,
        string memory _name,
        string memory _symbol
    ) ERC20(_name, _symbol, _asset.decimals()) {
        asset = _asset;
    }

    /*//////////////////////////////////////////////////////////////
                        DEPOSIT/WITHDRAWAL LOGIC
    //////////////////////////////////////////////////////////////*/

    function deposit(uint256 assets, address receiver) public virtual returns (uint256 shares) {
        // Check for rounding error since we round down in previewDeposit.
        require((shares = previewDeposit(assets)) != 0, "ZERO_SHARES");

        // Need to transfer before minting or ERC777s could reenter.
        asset.safeTransferFrom(msg.sender, address(this), assets);

        _mint(receiver, shares);

        emit Deposit(msg.sender, receiver, assets, shares);

        afterDeposit(assets, shares);
    }

    function mint(uint256 shares, address receiver) public virtual returns (uint256 assets) {
        assets = previewMint(shares); // No need to check for rounding error, previewMint rounds up.

        // Need to transfer before minting or ERC777s could reenter.
        asset.safeTransferFrom(msg.sender, address(this), assets);

        _mint(receiver, shares);

        emit Deposit(msg.sender, receiver, assets, shares);

        afterDeposit(assets, shares);
    }

    function withdraw(
        uint256 assets,
        address receiver,
        address owner
    ) public virtual returns (uint256 shares) {
        shares = previewWithdraw(assets); // No need to check for rounding error, previewWithdraw rounds up.

        if (msg.sender != owner) {
            uint256 allowed = allowance[owner][msg.sender]; // Saves gas for limited approvals.

            if (allowed != type(uint256).max) allowance[owner][msg.sender] = allowed - shares;
        }

        beforeWithdraw(assets, shares);

        _burn(owner, shares);

        emit Withdraw(msg.sender, receiver, owner, assets, shares);

        asset.safeTransfer(receiver, assets);
    }

    function redeem(
        uint256 shares,
        address receiver,
        address owner
    ) public virtual returns (uint256 assets) {
        if (msg.sender != owner) {
            uint256 allowed = allowance[owner][msg.sender]; // Saves gas for limited approvals.

            if (allowed != type(uint256).max) allowance[owner][msg.sender] = allowed - shares;
        }

        // Check for rounding error since we round down in previewRedeem.
        require((assets = previewRedeem(shares)) != 0, "ZERO_ASSETS");

        beforeWithdraw(assets, shares);

        _burn(owner, shares);

        emit Withdraw(msg.sender, receiver, owner, assets, shares);

        asset.safeTransfer(receiver, assets);
    }

    /*//////////////////////////////////////////////////////////////
                            ACCOUNTING LOGIC
    //////////////////////////////////////////////////////////////*/

    function totalAssets() public view virtual returns (uint256);

    function convertToShares(uint256 assets) public view virtual returns (uint256) {
        uint256 supply = totalSupply; // Saves an extra SLOAD if totalSupply is non-zero.

        return supply == 0 ? assets : assets.mulDivDown(supply, totalAssets());
    }

    function convertToAssets(uint256 shares) public view virtual returns (uint256) {
        uint256 supply = totalSupply; // Saves an extra SLOAD if totalSupply is non-zero.

        return supply == 0 ? shares : shares.mulDivDown(totalAssets(), supply);
    }

    function previewDeposit(uint256 assets) public view virtual returns (uint256) {
        return convertToShares(assets);
    }

    function previewMint(uint256 shares) public view virtual returns (uint256) {
        uint256 supply = totalSupply; // Saves an extra SLOAD if totalSupply is non-zero.

        return supply == 0 ? shares : shares.mulDivUp(totalAssets(), supply);
    }

    function previewWithdraw(uint256 assets) public view virtual returns (uint256) {
        uint256 supply = totalSupply; // Saves an extra SLOAD if totalSupply is non-zero.

        return supply == 0 ? assets : assets.mulDivUp(supply, totalAssets());
    }

    function previewRedeem(uint256 shares) public view virtual returns (uint256) {
        return convertToAssets(shares);
    }

    /*//////////////////////////////////////////////////////////////
                     DEPOSIT/WITHDRAWAL LIMIT LOGIC
    //////////////////////////////////////////////////////////////*/

    function maxDeposit(address) public view virtual returns (uint256) {
        return type(uint256).max;
    }

    function maxMint(address) public view virtual returns (uint256) {
        return type(uint256).max;
    }

    function maxWithdraw(address owner) public view virtual returns (uint256) {
        return convertToAssets(balanceOf[owner]);
    }

    function maxRedeem(address owner) public view virtual returns (uint256) {
        return balanceOf[owner];
    }

    /*//////////////////////////////////////////////////////////////
                          INTERNAL HOOKS LOGIC
    //////////////////////////////////////////////////////////////*/

    function beforeWithdraw(uint256 assets, uint256 shares) internal virtual {}

    function afterDeposit(uint256 assets, uint256 shares) internal virtual {}
}

File 4 of 18 : ERC20.sol
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;

/// @notice Modern and gas efficient ERC20 + EIP-2612 implementation.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC20.sol)
/// @author Modified from Uniswap (https://github.com/Uniswap/uniswap-v2-core/blob/master/contracts/UniswapV2ERC20.sol)
/// @dev Do not manually set balances without updating totalSupply, as the sum of all user balances must not exceed it.
abstract contract ERC20 {
    /*//////////////////////////////////////////////////////////////
                                 EVENTS
    //////////////////////////////////////////////////////////////*/

    event Transfer(address indexed from, address indexed to, uint256 amount);

    event Approval(address indexed owner, address indexed spender, uint256 amount);

    /*//////////////////////////////////////////////////////////////
                            METADATA STORAGE
    //////////////////////////////////////////////////////////////*/

    string public name;

    string public symbol;

    uint8 public immutable decimals;

    /*//////////////////////////////////////////////////////////////
                              ERC20 STORAGE
    //////////////////////////////////////////////////////////////*/

    uint256 public totalSupply;

    mapping(address => uint256) public balanceOf;

    mapping(address => mapping(address => uint256)) public allowance;

    /*//////////////////////////////////////////////////////////////
                            EIP-2612 STORAGE
    //////////////////////////////////////////////////////////////*/

    uint256 internal immutable INITIAL_CHAIN_ID;

    bytes32 internal immutable INITIAL_DOMAIN_SEPARATOR;

    mapping(address => uint256) public nonces;

    /*//////////////////////////////////////////////////////////////
                               CONSTRUCTOR
    //////////////////////////////////////////////////////////////*/

    constructor(
        string memory _name,
        string memory _symbol,
        uint8 _decimals
    ) {
        name = _name;
        symbol = _symbol;
        decimals = _decimals;

        INITIAL_CHAIN_ID = block.chainid;
        INITIAL_DOMAIN_SEPARATOR = computeDomainSeparator();
    }

    /*//////////////////////////////////////////////////////////////
                               ERC20 LOGIC
    //////////////////////////////////////////////////////////////*/

    function approve(address spender, uint256 amount) public virtual returns (bool) {
        allowance[msg.sender][spender] = amount;

        emit Approval(msg.sender, spender, amount);

        return true;
    }

    function transfer(address to, uint256 amount) public virtual returns (bool) {
        balanceOf[msg.sender] -= amount;

        // Cannot overflow because the sum of all user
        // balances can't exceed the max uint256 value.
        unchecked {
            balanceOf[to] += amount;
        }

        emit Transfer(msg.sender, to, amount);

        return true;
    }

    function transferFrom(
        address from,
        address to,
        uint256 amount
    ) public virtual returns (bool) {
        uint256 allowed = allowance[from][msg.sender]; // Saves gas for limited approvals.

        if (allowed != type(uint256).max) allowance[from][msg.sender] = allowed - amount;

        balanceOf[from] -= amount;

        // Cannot overflow because the sum of all user
        // balances can't exceed the max uint256 value.
        unchecked {
            balanceOf[to] += amount;
        }

        emit Transfer(from, to, amount);

        return true;
    }

    /*//////////////////////////////////////////////////////////////
                             EIP-2612 LOGIC
    //////////////////////////////////////////////////////////////*/

    function permit(
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) public virtual {
        require(deadline >= block.timestamp, "PERMIT_DEADLINE_EXPIRED");

        // Unchecked because the only math done is incrementing
        // the owner's nonce which cannot realistically overflow.
        unchecked {
            address recoveredAddress = ecrecover(
                keccak256(
                    abi.encodePacked(
                        "\x19\x01",
                        DOMAIN_SEPARATOR(),
                        keccak256(
                            abi.encode(
                                keccak256(
                                    "Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"
                                ),
                                owner,
                                spender,
                                value,
                                nonces[owner]++,
                                deadline
                            )
                        )
                    )
                ),
                v,
                r,
                s
            );

            require(recoveredAddress != address(0) && recoveredAddress == owner, "INVALID_SIGNER");

            allowance[recoveredAddress][spender] = value;
        }

        emit Approval(owner, spender, value);
    }

    function DOMAIN_SEPARATOR() public view virtual returns (bytes32) {
        return block.chainid == INITIAL_CHAIN_ID ? INITIAL_DOMAIN_SEPARATOR : computeDomainSeparator();
    }

    function computeDomainSeparator() internal view virtual returns (bytes32) {
        return
            keccak256(
                abi.encode(
                    keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"),
                    keccak256(bytes(name)),
                    keccak256("1"),
                    block.chainid,
                    address(this)
                )
            );
    }

    /*//////////////////////////////////////////////////////////////
                        INTERNAL MINT/BURN LOGIC
    //////////////////////////////////////////////////////////////*/

    function _mint(address to, uint256 amount) internal virtual {
        totalSupply += amount;

        // Cannot overflow because the sum of all user
        // balances can't exceed the max uint256 value.
        unchecked {
            balanceOf[to] += amount;
        }

        emit Transfer(address(0), to, amount);
    }

    function _burn(address from, uint256 amount) internal virtual {
        balanceOf[from] -= amount;

        // Cannot underflow because a user's balance
        // will never be larger than the total supply.
        unchecked {
            totalSupply -= amount;
        }

        emit Transfer(from, address(0), amount);
    }
}

File 5 of 18 : FixedPointMathLib.sol
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;

/// @notice Arithmetic library with operations for fixed-point numbers.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/FixedPointMathLib.sol)
/// @author Inspired by USM (https://github.com/usmfum/USM/blob/master/contracts/WadMath.sol)
library FixedPointMathLib {
    /*//////////////////////////////////////////////////////////////
                    SIMPLIFIED FIXED POINT OPERATIONS
    //////////////////////////////////////////////////////////////*/

    uint256 internal constant MAX_UINT256 = 2**256 - 1;

    uint256 internal constant WAD = 1e18; // The scalar of ETH and most ERC20s.

    function mulWadDown(uint256 x, uint256 y) internal pure returns (uint256) {
        return mulDivDown(x, y, WAD); // Equivalent to (x * y) / WAD rounded down.
    }

    function mulWadUp(uint256 x, uint256 y) internal pure returns (uint256) {
        return mulDivUp(x, y, WAD); // Equivalent to (x * y) / WAD rounded up.
    }

    function divWadDown(uint256 x, uint256 y) internal pure returns (uint256) {
        return mulDivDown(x, WAD, y); // Equivalent to (x * WAD) / y rounded down.
    }

    function divWadUp(uint256 x, uint256 y) internal pure returns (uint256) {
        return mulDivUp(x, WAD, y); // Equivalent to (x * WAD) / y rounded up.
    }

    /*//////////////////////////////////////////////////////////////
                    LOW LEVEL FIXED POINT OPERATIONS
    //////////////////////////////////////////////////////////////*/

    function mulDivDown(
        uint256 x,
        uint256 y,
        uint256 denominator
    ) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            // Equivalent to require(denominator != 0 && (y == 0 || x <= type(uint256).max / y))
            if iszero(mul(denominator, iszero(mul(y, gt(x, div(MAX_UINT256, y)))))) {
                revert(0, 0)
            }

            // Divide x * y by the denominator.
            z := div(mul(x, y), denominator)
        }
    }

    function mulDivUp(
        uint256 x,
        uint256 y,
        uint256 denominator
    ) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            // Equivalent to require(denominator != 0 && (y == 0 || x <= type(uint256).max / y))
            if iszero(mul(denominator, iszero(mul(y, gt(x, div(MAX_UINT256, y)))))) {
                revert(0, 0)
            }

            // If x * y modulo the denominator is strictly greater than 0,
            // 1 is added to round up the division of x * y by the denominator.
            z := add(gt(mod(mul(x, y), denominator), 0), div(mul(x, y), denominator))
        }
    }

    function rpow(
        uint256 x,
        uint256 n,
        uint256 scalar
    ) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            switch x
            case 0 {
                switch n
                case 0 {
                    // 0 ** 0 = 1
                    z := scalar
                }
                default {
                    // 0 ** n = 0
                    z := 0
                }
            }
            default {
                switch mod(n, 2)
                case 0 {
                    // If n is even, store scalar in z for now.
                    z := scalar
                }
                default {
                    // If n is odd, store x in z for now.
                    z := x
                }

                // Shifting right by 1 is like dividing by 2.
                let half := shr(1, scalar)

                for {
                    // Shift n right by 1 before looping to halve it.
                    n := shr(1, n)
                } n {
                    // Shift n right by 1 each iteration to halve it.
                    n := shr(1, n)
                } {
                    // Revert immediately if x ** 2 would overflow.
                    // Equivalent to iszero(eq(div(xx, x), x)) here.
                    if shr(128, x) {
                        revert(0, 0)
                    }

                    // Store x squared.
                    let xx := mul(x, x)

                    // Round to the nearest number.
                    let xxRound := add(xx, half)

                    // Revert if xx + half overflowed.
                    if lt(xxRound, xx) {
                        revert(0, 0)
                    }

                    // Set x to scaled xxRound.
                    x := div(xxRound, scalar)

                    // If n is even:
                    if mod(n, 2) {
                        // Compute z * x.
                        let zx := mul(z, x)

                        // If z * x overflowed:
                        if iszero(eq(div(zx, x), z)) {
                            // Revert if x is non-zero.
                            if iszero(iszero(x)) {
                                revert(0, 0)
                            }
                        }

                        // Round to the nearest number.
                        let zxRound := add(zx, half)

                        // Revert if zx + half overflowed.
                        if lt(zxRound, zx) {
                            revert(0, 0)
                        }

                        // Return properly scaled zxRound.
                        z := div(zxRound, scalar)
                    }
                }
            }
        }
    }

    /*//////////////////////////////////////////////////////////////
                        GENERAL NUMBER UTILITIES
    //////////////////////////////////////////////////////////////*/

    function sqrt(uint256 x) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            let y := x // We start y at x, which will help us make our initial estimate.

            z := 181 // The "correct" value is 1, but this saves a multiplication later.

            // This segment is to get a reasonable initial estimate for the Babylonian method. With a bad
            // start, the correct # of bits increases ~linearly each iteration instead of ~quadratically.

            // We check y >= 2^(k + 8) but shift right by k bits
            // each branch to ensure that if x >= 256, then y >= 256.
            if iszero(lt(y, 0x10000000000000000000000000000000000)) {
                y := shr(128, y)
                z := shl(64, z)
            }
            if iszero(lt(y, 0x1000000000000000000)) {
                y := shr(64, y)
                z := shl(32, z)
            }
            if iszero(lt(y, 0x10000000000)) {
                y := shr(32, y)
                z := shl(16, z)
            }
            if iszero(lt(y, 0x1000000)) {
                y := shr(16, y)
                z := shl(8, z)
            }

            // Goal was to get z*z*y within a small factor of x. More iterations could
            // get y in a tighter range. Currently, we will have y in [256, 256*2^16).
            // We ensured y >= 256 so that the relative difference between y and y+1 is small.
            // That's not possible if x < 256 but we can just verify those cases exhaustively.

            // Now, z*z*y <= x < z*z*(y+1), and y <= 2^(16+8), and either y >= 256, or x < 256.
            // Correctness can be checked exhaustively for x < 256, so we assume y >= 256.
            // Then z*sqrt(y) is within sqrt(257)/sqrt(256) of sqrt(x), or about 20bps.

            // For s in the range [1/256, 256], the estimate f(s) = (181/1024) * (s+1) is in the range
            // (1/2.84 * sqrt(s), 2.84 * sqrt(s)), with largest error when s = 1 and when s = 256 or 1/256.

            // Since y is in [256, 256*2^16), let a = y/65536, so that a is in [1/256, 256). Then we can estimate
            // sqrt(y) using sqrt(65536) * 181/1024 * (a + 1) = 181/4 * (y + 65536)/65536 = 181 * (y + 65536)/2^18.

            // There is no overflow risk here since y < 2^136 after the first branch above.
            z := shr(18, mul(z, add(y, 65536))) // A mul() is saved from starting z at 181.

            // Given the worst case multiplicative error of 2.84 above, 7 iterations should be enough.
            z := shr(1, add(z, div(x, z)))
            z := shr(1, add(z, div(x, z)))
            z := shr(1, add(z, div(x, z)))
            z := shr(1, add(z, div(x, z)))
            z := shr(1, add(z, div(x, z)))
            z := shr(1, add(z, div(x, z)))
            z := shr(1, add(z, div(x, z)))

            // If x+1 is a perfect square, the Babylonian method cycles between
            // floor(sqrt(x)) and ceil(sqrt(x)). This statement ensures we return floor.
            // See: https://en.wikipedia.org/wiki/Integer_square_root#Using_only_integer_division
            // Since the ceil is rare, we save gas on the assignment and repeat division in the rare case.
            // If you don't care whether the floor or ceil square root is returned, you can remove this statement.
            z := sub(z, lt(div(x, z), z))
        }
    }

    function unsafeMod(uint256 x, uint256 y) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            // Mod x by y. Note this will return
            // 0 instead of reverting if y is zero.
            z := mod(x, y)
        }
    }

    function unsafeDiv(uint256 x, uint256 y) internal pure returns (uint256 r) {
        /// @solidity memory-safe-assembly
        assembly {
            // Divide x by y. Note this will return
            // 0 instead of reverting if y is zero.
            r := div(x, y)
        }
    }

    function unsafeDivUp(uint256 x, uint256 y) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            // Add 1 to x * y if x % y > 0. Note this will
            // return 0 instead of reverting if y is zero.
            z := add(gt(mod(x, y), 0), div(x, y))
        }
    }
}

File 6 of 18 : SafeCastLib.sol
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;

/// @notice Safe unsigned integer casting library that reverts on overflow.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/SafeCastLib.sol)
/// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/math/SafeCast.sol)
library SafeCastLib {
    function safeCastTo248(uint256 x) internal pure returns (uint248 y) {
        require(x < 1 << 248);

        y = uint248(x);
    }

    function safeCastTo224(uint256 x) internal pure returns (uint224 y) {
        require(x < 1 << 224);

        y = uint224(x);
    }

    function safeCastTo192(uint256 x) internal pure returns (uint192 y) {
        require(x < 1 << 192);

        y = uint192(x);
    }

    function safeCastTo160(uint256 x) internal pure returns (uint160 y) {
        require(x < 1 << 160);

        y = uint160(x);
    }

    function safeCastTo128(uint256 x) internal pure returns (uint128 y) {
        require(x < 1 << 128);

        y = uint128(x);
    }

    function safeCastTo96(uint256 x) internal pure returns (uint96 y) {
        require(x < 1 << 96);

        y = uint96(x);
    }

    function safeCastTo64(uint256 x) internal pure returns (uint64 y) {
        require(x < 1 << 64);

        y = uint64(x);
    }

    function safeCastTo32(uint256 x) internal pure returns (uint32 y) {
        require(x < 1 << 32);

        y = uint32(x);
    }

    function safeCastTo24(uint256 x) internal pure returns (uint24 y) {
        require(x < 1 << 24);

        y = uint24(x);
    }

    function safeCastTo16(uint256 x) internal pure returns (uint16 y) {
        require(x < 1 << 16);

        y = uint16(x);
    }

    function safeCastTo8(uint256 x) internal pure returns (uint8 y) {
        require(x < 1 << 8);

        y = uint8(x);
    }
}

File 7 of 18 : SafeTransferLib.sol
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;

import {ERC20} from "../tokens/ERC20.sol";

/// @notice Safe ETH and ERC20 transfer library that gracefully handles missing return values.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/SafeTransferLib.sol)
/// @dev Use with caution! Some functions in this library knowingly create dirty bits at the destination of the free memory pointer.
/// @dev Note that none of the functions in this library check that a token has code at all! That responsibility is delegated to the caller.
library SafeTransferLib {
    /*//////////////////////////////////////////////////////////////
                             ETH OPERATIONS
    //////////////////////////////////////////////////////////////*/

    function safeTransferETH(address to, uint256 amount) internal {
        bool success;

        /// @solidity memory-safe-assembly
        assembly {
            // Transfer the ETH and store if it succeeded or not.
            success := call(gas(), to, amount, 0, 0, 0, 0)
        }

        require(success, "ETH_TRANSFER_FAILED");
    }

    /*//////////////////////////////////////////////////////////////
                            ERC20 OPERATIONS
    //////////////////////////////////////////////////////////////*/

    function safeTransferFrom(
        ERC20 token,
        address from,
        address to,
        uint256 amount
    ) internal {
        bool success;

        /// @solidity memory-safe-assembly
        assembly {
            // Get a pointer to some free memory.
            let freeMemoryPointer := mload(0x40)

            // Write the abi-encoded calldata into memory, beginning with the function selector.
            mstore(freeMemoryPointer, 0x23b872dd00000000000000000000000000000000000000000000000000000000)
            mstore(add(freeMemoryPointer, 4), from) // Append the "from" argument.
            mstore(add(freeMemoryPointer, 36), to) // Append the "to" argument.
            mstore(add(freeMemoryPointer, 68), amount) // Append the "amount" argument.

            success := and(
                // Set success to whether the call reverted, if not we check it either
                // returned exactly 1 (can't just be non-zero data), or had no return data.
                or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())),
                // We use 100 because the length of our calldata totals up like so: 4 + 32 * 3.
                // We use 0 and 32 to copy up to 32 bytes of return data into the scratch space.
                // Counterintuitively, this call must be positioned second to the or() call in the
                // surrounding and() call or else returndatasize() will be zero during the computation.
                call(gas(), token, 0, freeMemoryPointer, 100, 0, 32)
            )
        }

        require(success, "TRANSFER_FROM_FAILED");
    }

    function safeTransfer(
        ERC20 token,
        address to,
        uint256 amount
    ) internal {
        bool success;

        /// @solidity memory-safe-assembly
        assembly {
            // Get a pointer to some free memory.
            let freeMemoryPointer := mload(0x40)

            // Write the abi-encoded calldata into memory, beginning with the function selector.
            mstore(freeMemoryPointer, 0xa9059cbb00000000000000000000000000000000000000000000000000000000)
            mstore(add(freeMemoryPointer, 4), to) // Append the "to" argument.
            mstore(add(freeMemoryPointer, 36), amount) // Append the "amount" argument.

            success := and(
                // Set success to whether the call reverted, if not we check it either
                // returned exactly 1 (can't just be non-zero data), or had no return data.
                or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())),
                // We use 68 because the length of our calldata totals up like so: 4 + 32 * 2.
                // We use 0 and 32 to copy up to 32 bytes of return data into the scratch space.
                // Counterintuitively, this call must be positioned second to the or() call in the
                // surrounding and() call or else returndatasize() will be zero during the computation.
                call(gas(), token, 0, freeMemoryPointer, 68, 0, 32)
            )
        }

        require(success, "TRANSFER_FAILED");
    }

    function safeApprove(
        ERC20 token,
        address to,
        uint256 amount
    ) internal {
        bool success;

        /// @solidity memory-safe-assembly
        assembly {
            // Get a pointer to some free memory.
            let freeMemoryPointer := mload(0x40)

            // Write the abi-encoded calldata into memory, beginning with the function selector.
            mstore(freeMemoryPointer, 0x095ea7b300000000000000000000000000000000000000000000000000000000)
            mstore(add(freeMemoryPointer, 4), to) // Append the "to" argument.
            mstore(add(freeMemoryPointer, 36), amount) // Append the "amount" argument.

            success := and(
                // Set success to whether the call reverted, if not we check it either
                // returned exactly 1 (can't just be non-zero data), or had no return data.
                or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())),
                // We use 68 because the length of our calldata totals up like so: 4 + 32 * 2.
                // We use 0 and 32 to copy up to 32 bytes of return data into the scratch space.
                // Counterintuitively, this call must be positioned second to the or() call in the
                // surrounding and() call or else returndatasize() will be zero during the computation.
                call(gas(), token, 0, freeMemoryPointer, 68, 0, 32)
            )
        }

        require(success, "APPROVE_FAILED");
    }
}

File 8 of 18 : DebtToken.sol
/**
 * Created by Pragma Labs
 * SPDX-License-Identifier: BUSL-1.1
 */
pragma solidity ^0.8.13;

import { ERC20, ERC4626 } from "../lib/solmate/src/mixins/ERC4626.sol";
import { FixedPointMathLib } from "../lib/solmate/src/utils/FixedPointMathLib.sol";

/**
 * @title Debt Token.
 * @author Pragma Labs
 * @notice The Logic to do the debt accounting for a lending pool for a certain ERC20 token.
 * @dev Protocol is according the ERC4626 standard, with a certain ERC20 as underlying.
 * @dev Implementation not vulnerable to ERC4626 inflation attacks,
 * since totalAssets() cannot be manipulated by first minter when total amount of shares are low.
 * For more information, see https://github.com/OpenZeppelin/openzeppelin-contracts/issues/3706.
 */
abstract contract DebtToken is ERC4626 {
    using FixedPointMathLib for uint256;

    /* //////////////////////////////////////////////////////////////
                                STORAGE
    ////////////////////////////////////////////////////////////// */

    // Total amount of `underlying asset` that debtors have in debt, does not take into account pending interests.
    uint256 public realisedDebt;
    // Maximum amount of `underlying asset` in debt that a single debtor can take.
    uint128 public borrowCap;

    error FunctionNotImplemented();

    /* //////////////////////////////////////////////////////////////
                                CONSTRUCTOR
    ////////////////////////////////////////////////////////////// */

    /**
     * @notice The constructor for the debt token.
     * @param asset_ The underlying ERC-20 token in which the debt is denominated.
     */
    constructor(ERC20 asset_)
        ERC4626(
            asset_,
            string(abi.encodePacked("Arcadia ", asset_.name(), " Debt")),
            string(abi.encodePacked("darc", asset_.symbol()))
        )
    { }

    /*//////////////////////////////////////////////////////////////
                            ACCOUNTING LOGIC
    //////////////////////////////////////////////////////////////*/

    /**
     * @notice Returns the total amount of outstanding debt in the underlying asset.
     * @return totalDebt The total debt in underlying assets.
     * @dev Implementation overwritten in LendingPool.sol which inherits DebtToken.sol.
     * Implementation not vulnerable to ERC4626 inflation attacks,
     * totaLAssets() does not rely on balanceOf call.
     */
    function totalAssets() public view virtual override returns (uint256) { }

    /*//////////////////////////////////////////////////////////////
                        DEPOSIT/WITHDRAWAL LOGIC
    //////////////////////////////////////////////////////////////*/

    /**
     * @notice Modification of the standard ERC-4626 deposit implementation.
     * @dev No public deposit allowed.
     */
    function deposit(uint256, address) public pure override returns (uint256) {
        revert FunctionNotImplemented();
    }

    /**
     * @notice Modification of the standard ERC-4626 deposit implementation.
     * @param assets The amount of assets of the underlying ERC-20 token being loaned out.
     * @param receiver The Arcadia vault with collateral covering the loan.
     * @return shares The corresponding amount of debt shares minted.
     * @dev Only the Lending Pool (which inherits this contract) can issue debt.
     */
    function _deposit(uint256 assets, address receiver) internal returns (uint256 shares) {
        shares = previewDeposit(assets); // No need to check for rounding error, previewDeposit rounds up.
        if (borrowCap > 0) require(maxWithdraw(receiver) + assets <= borrowCap, "DT_D: BORROW_CAP_EXCEEDED");

        _mint(receiver, shares);

        realisedDebt += assets;

        emit Deposit(msg.sender, receiver, assets, shares);
    }

    /**
     * @notice Modification of the standard ERC-4626 deposit implementation.
     * @dev No public mint allowed.
     */
    function mint(uint256, address) public pure override returns (uint256) {
        revert FunctionNotImplemented();
    }

    /**
     * @notice Modification of the standard ERC-4626 withdraw implementation.
     * @dev No public withdraw allowed.
     */
    function withdraw(uint256, address, address) public pure override returns (uint256) {
        revert FunctionNotImplemented();
    }

    /**
     * @notice Modification of the standard ERC-4626 withdraw implementation.
     * @param assets The amount of assets of the underlying ERC-20 token being paid back.
     * @param receiver Will always be the Lending Pool.
     * @param owner_ The Arcadia vault with collateral covering the loan.
     * @return shares The corresponding amount of debt shares redeemed.
     * @dev Only the Lending Pool (which inherits this contract) can issue debt.
     */
    function _withdraw(uint256 assets, address receiver, address owner_) internal returns (uint256 shares) {
        // Check for rounding error since we round down in previewWithdraw.
        require((shares = previewWithdraw(assets)) != 0, "DT_W: ZERO_SHARES");

        _burn(owner_, shares);

        realisedDebt -= assets;

        emit Withdraw(msg.sender, receiver, owner_, assets, shares);
    }

    /**
     * @notice Modification of the standard ERC-4626 redeem implementation.
     * @dev No public redeem allowed.
     */
    function redeem(uint256, address, address) public pure override returns (uint256) {
        revert FunctionNotImplemented();
    }

    /*//////////////////////////////////////////////////////////////
                            ACCOUNTING LOGIC
    //////////////////////////////////////////////////////////////*/

    /**
     * @notice Modification of the standard ERC-4626 convertToShares implementation.
     * @dev Since debt is a liability instead of an asset, roundUp and roundDown are inverted compared to the standard implementation.
     */
    function convertToShares(uint256 assets) public view override returns (uint256) {
        uint256 supply = totalSupply; // Saves an extra SLOAD if totalSupply is non-zero.

        return supply == 0 ? assets : assets.mulDivUp(supply, totalAssets());
    }

    /**
     * @notice Modification of the standard ERC-4626 convertToShares implementation.
     * @dev Since debt is a liability instead of an asset, roundUp and roundDown are inverted compared to the standard implementation.
     */
    function convertToAssets(uint256 shares) public view override returns (uint256) {
        uint256 supply = totalSupply; // Saves an extra SLOAD if totalSupply is non-zero.

        return supply == 0 ? shares : shares.mulDivUp(totalAssets(), supply);
    }

    /**
     * @notice Modification of the standard ERC-4626 previewMint implementation.
     * @dev Since debt is a liability instead of an asset, roundUp and roundDown are inverted compared to the standard implementation.
     */
    function previewMint(uint256 shares) public view override returns (uint256) {
        uint256 supply = totalSupply; // Saves an extra SLOAD if totalSupply is non-zero.

        return supply == 0 ? shares : shares.mulDivDown(totalAssets(), supply);
    }

    /**
     * @notice Modification of the standard ERC-4626 previewWithdraw implementation.
     * @dev Since debt is a liability instead of an asset, roundUp and roundDown are inverted compared to the standard implementation.
     */
    function previewWithdraw(uint256 assets) public view override returns (uint256) {
        uint256 supply = totalSupply; // Saves an extra SLOAD if totalSupply is non-zero.

        return supply == 0 ? assets : assets.mulDivDown(supply, totalAssets());
    }

    /*//////////////////////////////////////////////////////////////
                            TRANSFER LOGIC
    //////////////////////////////////////////////////////////////*/

    /**
     * @notice Modification of the standard ERC-4626 approve implementation.
     * @dev No public approve allowed.
     */
    function approve(address, uint256) public pure override returns (bool) {
        revert FunctionNotImplemented();
    }

    /**
     * @notice Modification of the standard ERC-4626 transfer implementation.
     * @dev No public transfer allowed.
     */
    function transfer(address, uint256) public pure override returns (bool) {
        revert FunctionNotImplemented();
    }

    /**
     * @notice Modification of the standard ERC-4626 transferFrom implementation.
     * @dev No public transferFrom allowed.
     */
    function transferFrom(address, address, uint256) public pure override returns (bool) {
        revert FunctionNotImplemented();
    }

    /**
     * @notice Modification of the standard ERC-4626 permit implementation.
     * @dev No public permit allowed.
     */
    function permit(address, address, uint256, uint256, uint8, bytes32, bytes32) public pure override {
        revert FunctionNotImplemented();
    }
}

File 9 of 18 : InterestRateModule.sol
/**
 * Created by Pragma Labs
 * SPDX-License-Identifier: BUSL-1.1
 */
pragma solidity ^0.8.13;

/**
 * @title Interest Rate Module.
 * @author Pragma Labs
 * @notice The Logic to calculate and store the interest rate of the Lending Pool.
 */
contract InterestRateModule {
    /* //////////////////////////////////////////////////////////////
                                STORAGE
    ////////////////////////////////////////////////////////////// */

    // The current interest rate, 18 decimals precision.
    uint256 public interestRate;

    // A struct with the configuration of the interest rate curves,
    // which give the interest rate in function of the utilisation of the Lending Pool.
    InterestRateConfiguration public interestRateConfig;

    /**
     * A struct with the set of interest rate configuration parameters:
     * - baseRatePerYear The interest rate when utilisation is 0.
     * - lowSlopePerYear The slope of the first curve, defined as the delta in interest rate for a delta in utilisation of 100%.
     * - highSlopePerYear The slope of the second curve, defined as the delta in interest rate for a delta in utilisation of 100%.
     * - utilisationThreshold the optimal utilisation, where we go from the flat first curve to the steeper second curve.
     */
    struct InterestRateConfiguration {
        uint72 baseRatePerYear; //18 decimals precision.
        uint72 lowSlopePerYear; //18 decimals precision.
        uint72 highSlopePerYear; //18 decimals precision.
        uint40 utilisationThreshold; //5 decimal precision.
    }

    /* //////////////////////////////////////////////////////////////
                                EVENTS
    ////////////////////////////////////////////////////////////// */

    event InterestRate(uint80 interestRate);

    /* //////////////////////////////////////////////////////////////
                        INTEREST RATE LOGIC
    ////////////////////////////////////////////////////////////// */

    /**
     * @notice Sets the configuration parameters of InterestRateConfiguration struct.
     * @param newConfig A struct with a new set of interest rate configuration parameters:
     * - baseRatePerYear The interest rate when utilisation is 0, 18 decimals precision.
     * - lowSlopePerYear The slope of the first curve, defined as the delta in interest rate for a delta in utilisation of 100%,
     *   18 decimals precision.
     * - highSlopePerYear The slope of the second curve, defined as the delta in interest rate for a delta in utilisation of 100%,
     *   18 decimals precision.
     * - utilisationThreshold the optimal utilisation, where we go from the flat first curve to the steeper second curve,
     *   5 decimal precision.
     */
    function _setInterestConfig(InterestRateConfiguration calldata newConfig) internal {
        interestRateConfig = newConfig;
    }

    /**
     * @notice Calculates the interest rate.
     * @param utilisation Utilisation rate, 5 decimal precision.
     * @return interestRate The current interest rate, 18 decimal precision.
     * @dev The interest rate is a function of the utilisation of the Lending Pool.
     * We use two linear curves: a flat one below the optimal utilisation and a steep one above.
     */
    function _calculateInterestRate(uint256 utilisation) internal view returns (uint256) {
        unchecked {
            if (utilisation >= interestRateConfig.utilisationThreshold) {
                // 1e23 = uT (1e5) * ls (1e18).
                uint256 lowSlopeInterest =
                    uint256(interestRateConfig.utilisationThreshold) * interestRateConfig.lowSlopePerYear;
                // 1e23 = (uT - u) (1e5) * hs (e18).
                uint256 highSlopeInterest = uint256((utilisation - interestRateConfig.utilisationThreshold))
                    * interestRateConfig.highSlopePerYear;
                // 1e18 = bs (1e18) + (lsIR (e23) + hsIR (1e23)) / 1e5.
                return uint256(interestRateConfig.baseRatePerYear) + ((lowSlopeInterest + highSlopeInterest) / 100_000);
            } else {
                // 1e18 = br (1e18) + (ls (1e18) * u (1e5)) / 1e5.
                return uint256(
                    uint256(interestRateConfig.baseRatePerYear)
                        + ((uint256(interestRateConfig.lowSlopePerYear) * utilisation) / 100_000)
                );
            }
        }
    }

    /**
     * @notice Updates the interest rate.
     * @param totalDebt Total amount of debt.
     * @param totalLiquidity Total amount of Liquidity (sum of borrowed out assets and assets still available in the Lending Pool).
     * @dev This function is only be called by the function _updateInterestRate(uint256 realisedDebt_, uint256 totalRealisedLiquidity_),
     * calculates the interest rate, if the totalRealisedLiquidity_ is zero then utilisation is zero.
     */
    function _updateInterestRate(uint256 totalDebt, uint256 totalLiquidity) internal {
        uint256 utilisation; // 5 decimals precision
        if (totalLiquidity > 0) {
            utilisation = (100_000 * totalDebt) / totalLiquidity;
        }

        //Calculates and stores interestRate as a uint256, emits interestRate as a uint80 (interestRate is maximally equal to uint72 + uint72).
        //_updateInterestRate() will be called a lot, saves a read from from storage or a write+read from memory.
        emit InterestRate(uint80(interestRate = _calculateInterestRate(utilisation)));
    }
}

File 10 of 18 : TrustedCreditor.sol
/**
 * Created by Pragma Labs
 * SPDX-License-Identifier: BUSL-1.1
 */
pragma solidity ^0.8.13;

/**
 * @title Trusted Creditor implementation.
 * @author Pragma Labs
 * @notice This contract contains the minimum functionality a Trusted Creditor, interacting with Arcadia Vaults, needs to implement.
 * @dev For the implementation of Arcadia Vaults, see: https://github.com/arcadia-finance/arcadia-vaults.
 */
abstract contract TrustedCreditor {
    /* //////////////////////////////////////////////////////////////
                                STORAGE
    ////////////////////////////////////////////////////////////// */

    // Map vaultVersion => status.
    mapping(uint256 => bool) public isValidVersion;

    /* //////////////////////////////////////////////////////////////
                            VAULT LOGIC
    ////////////////////////////////////////////////////////////// */

    /**
     * @notice Sets the validity of vault version to valid.
     * @param vaultVersion The version current version of the vault.
     * @param valid The validity of the respective vaultVersion.
     */
    function _setVaultVersion(uint256 vaultVersion, bool valid) internal {
        isValidVersion[vaultVersion] = valid;
    }

    /**
     * @notice Checks if vault fulfills all requirements and returns application settings.
     * @param vaultVersion The current version of the vault.
     * @return success Bool indicating if all requirements are met.
     * @return baseCurrency The base currency of the application.
     * @return liquidator The liquidator of the application.
     * @return fixedLiquidationCost Estimated fixed costs (independent of size of debt) to liquidate a position.
     */
    function openMarginAccount(uint256 vaultVersion)
        external
        virtual
        returns (bool success, address baseCurrency, address liquidator, uint256 fixedLiquidationCost);

    /**
     * @notice Returns the open position of the vault.
     * @param vault The vault address.
     * @return openPosition The open position of the vault.
     */
    function getOpenPosition(address vault) external view virtual returns (uint256 openPosition);
}

File 11 of 18 : IFactory.sol
/**
 * Created by Pragma Labs
 * SPDX-License-Identifier: MIT
 */
pragma solidity ^0.8.13;

interface IFactory {
    /**
     * @notice View function returning if an address is a vault.
     * @param vault The address to be checked.
     * @return bool Whether the address is a vault or not.
     */
    function isVault(address vault) external view returns (bool);

    /**
     * @notice Returns the owner of a vault.
     * @param vault The Vault address.
     * @return owner The Vault owner.
     */
    function ownerOfVault(address vault) external view returns (address);
}

File 12 of 18 : ILendingPool.sol
/**
 * Created by Pragma Labs
 * SPDX-License-Identifier: MIT
 */
pragma solidity ^0.8.13;

import { ERC20 } from "../../lib/solmate/src/tokens/ERC20.sol";

interface ILendingPool {
    /**
     * @notice returns the supply cap of the Lending Pool.
     * @return supplyCap The supply cap of the Lending Pool.
     */
    function supplyCap() external view returns (uint128);

    /**
     * @notice returns the total realised liquidity of the Lending Pool.
     * @return totalRealisedLiquidity The total realised liquidity of the Lending Pool.
     */
    function totalRealisedLiquidity() external view returns (uint128);

    /**
     * @notice Deposit assets in the Lending Pool.
     * @param assets The amount of assets of the underlying ERC-20 token being deposited.
     * @param from The address of the Liquidity Provider who deposits the underlying ERC-20 token via a Tranche.
     */
    function depositInLendingPool(uint256 assets, address from) external;

    /**
     * @notice Withdraw assets from the Lending Pool.
     * @param assets The amount of assets of the underlying ERC-20 tokens being withdrawn.
     * @param receiver The address of the receiver of the underlying ERC-20 tokens.
     */
    function withdrawFromLendingPool(uint256 assets, address receiver) external;

    /**
     * @notice Returns the redeemable amount of liquidity in the underlying asset of an address.
     * @param owner The address of the liquidity provider.
     * @return assets The redeemable amount of liquidity in the underlying asset.
     */
    function liquidityOf(address owner) external view returns (uint256);

    /**
     * @notice liquidityOf, but syncs the unrealised interest first.
     * @param owner The address of the liquidity provider.
     * @return assets The redeemable amount of liquidity in the underlying asset.
     */
    function liquidityOfAndSync(address owner) external returns (uint256);

    /**
     * @notice Calculates the unrealised debt (interests).
     * @return unrealisedDebt The unrealised debt.
     */
    function calcUnrealisedDebt() external view returns (uint256);
}

File 13 of 18 : ILiquidator.sol
/**
 * Created by Pragma Labs
 * SPDX-License-Identifier: MIT
 */
pragma solidity ^0.8.13;

interface ILiquidator {
    /**
     * @notice Called by a Creditor to start an auction to liquidate collateral of a vault.
     * @param vault The contract address of the Vault to liquidate.
     * @param openDebt The open debt taken by `originalOwner`.
     * @param maxInitiatorFee The maximum fee that is paid to the initiator of a liquidation.
     */
    function startAuction(address vault, uint256 openDebt, uint80 maxInitiatorFee) external;
}

File 14 of 18 : ITranche.sol
/**
 * Created by Pragma Labs
 * SPDX-License-Identifier: MIT
 */
pragma solidity ^0.8.13;

interface ITranche {
    /**
     * @notice Locks the tranche in case all liquidity of the tranche is written of due to bad debt.
     */
    function lock() external;

    /**
     * @notice Locks the tranche while an auction is in progress.
     * @param auctionInProgress Flag indicating if there are auctions in progress.
     */
    function setAuctionInProgress(bool auctionInProgress) external;
}

File 15 of 18 : IVault.sol
/**
 * Created by Pragma Labs
 * SPDX-License-Identifier: MIT
 */
pragma solidity ^0.8.13;

interface IVault {
    /**
     * @notice Returns the address of the owner of the Vault.
     */
    function owner() external view returns (address);

    /**
     * @notice Checks if the Vault is healthy and still has free margin.
     * @param amount The amount with which the position is increased.
     * @param totalOpenDebt The total open Debt against the Vault.
     * @return success Boolean indicating if there is sufficient margin to back a certain amount of Debt.
     * @return trustedCreditor_ The contract address of the trusted creditor.
     * @return vaultVersion_ The vault version.
     * @dev Only one of the values can be non-zero, or we check on a certain increase of debt, or we check on a total amount of debt.
     */
    function isVaultHealthy(uint256 amount, uint256 totalOpenDebt) external view returns (bool, address, uint256);

    /**
     * @notice Calls external action handler to execute and interact with external logic.
     * @param actionHandler The address of the action handler.
     * @param actionData A bytes object containing two actionAssetData structs, an address array and a bytes array.
     * @return trustedCreditor_ The contract address of the trusted creditor.
     * @return vaultVersion_ The vault version.
     */
    function vaultManagementAction(address actionHandler, bytes calldata actionData)
        external
        returns (address, uint256);
}

File 16 of 18 : Guardian.sol
/**
 * Created by Pragma Labs
 * SPDX-License-Identifier: BUSL-1.1
 */

pragma solidity ^0.8.13;

import { Owned } from "../../lib/solmate/src/auth/Owned.sol";

/**
 * @title Guardian
 * @author Pragma Labs
 * @notice This module provides the logic that allows authorized accounts to trigger an emergency stop.
 */
abstract contract Guardian is Owned {
    /* //////////////////////////////////////////////////////////////
                                STORAGE
    ////////////////////////////////////////////////////////////// */

    // Address of the Guardian.
    address public guardian;
    // Flag indicating if the repay() function is paused.
    bool public repayPaused;
    // Flag indicating if the withdraw() function is paused.
    bool public withdrawPaused;
    // Flag indicating if the borrow() function is paused.
    bool public borrowPaused;
    // Flag indicating if the deposit() function is paused.
    bool public depositPaused;
    // Flag indicating if the liquidation() function is paused.
    bool public liquidationPaused;
    // Last timestamp an emergency stop was triggered.
    uint256 public pauseTimestamp;

    /* //////////////////////////////////////////////////////////////
                                EVENTS
    ////////////////////////////////////////////////////////////// */

    event GuardianChanged(address indexed oldGuardian, address indexed newGuardian);
    event PauseUpdate(
        bool repayPauseUpdate,
        bool withdrawPauseUpdate,
        bool borrowPauseUpdate,
        bool supplyPauseUpdate,
        bool liquidationPauseUpdate
    );

    /* //////////////////////////////////////////////////////////////
                                ERRORS
    ////////////////////////////////////////////////////////////// */

    error FunctionIsPaused();

    /* //////////////////////////////////////////////////////////////
                                MODIFIERS
    ////////////////////////////////////////////////////////////// */

    /**
     * @dev Throws if called by any account other than the guardian.
     */
    modifier onlyGuardian() {
        require(msg.sender == guardian, "Guardian: Only guardian");
        _;
    }

    /**
     * @dev This modifier is used to restrict access to certain functions when the contract is paused for repay.
     * It throws if repay is paused.
     */
    modifier whenRepayNotPaused() {
        if (repayPaused) revert FunctionIsPaused();
        _;
    }

    /**
     * @dev This modifier is used to restrict access to certain functions when the contract is paused for withdraw.
     * It throws if withdraw is paused.
     */
    modifier whenWithdrawNotPaused() {
        if (withdrawPaused) revert FunctionIsPaused();
        _;
    }

    /**
     * @dev This modifier is used to restrict access to certain functions when the contract is paused for borrow.
     * It throws if borrow is paused.
     */
    modifier whenBorrowNotPaused() {
        if (borrowPaused) revert FunctionIsPaused();
        _;
    }

    /**
     * @dev This modifier is used to restrict access to certain functions when the contract is paused for deposit.
     * It throws if deposit is paused.
     */
    modifier whenDepositNotPaused() {
        if (depositPaused) revert FunctionIsPaused();
        _;
    }

    /**
     * @dev This modifier is used to restrict access to certain functions when the contract is paused for liquidation.
     * It throws if liquidation is paused.
     */
    modifier whenLiquidationNotPaused() {
        if (liquidationPaused) revert FunctionIsPaused();
        _;
    }

    /* //////////////////////////////////////////////////////////////
                                CONSTRUCTOR
    ////////////////////////////////////////////////////////////// */

    constructor() Owned(msg.sender) { }

    /* //////////////////////////////////////////////////////////////
                            GUARDIAN LOGIC
    ////////////////////////////////////////////////////////////// */

    /**
     * @notice This function is used to set the guardian address.
     * @param guardian_ The address of the new guardian.
     * @dev Allows onlyOwner to change the guardian address.
     */
    function changeGuardian(address guardian_) external onlyOwner {
        emit GuardianChanged(guardian, guardian_);

        guardian = guardian_;
    }

    /* //////////////////////////////////////////////////////////////
                            PAUSING LOGIC
    ////////////////////////////////////////////////////////////// */

    /**
     * @notice This function is used to pause all the flags of the contract.
     * @dev This function can be called by the guardian to pause all functionality in the event of an emergency.
     * This function pauses repay, withdraw, borrow, deposit and liquidation.
     * This function can only be called by the guardian.
     * The guardian can only pause the protocol again after 32 days have past since the last pause.
     * This is to prevent that a malicious guardian can take user-funds hostage for an indefinite time.
     * @dev After the guardian has paused the protocol, the owner has 30 days to find potential problems,
     * find a solution and unpause the protocol. If the protocol is not unpaused after 30 days,
     * an emergency procedure can be started by any user to unpause the protocol.
     * All users have now at least a two-day window to withdraw assets and close positions before
     * the protocol can again be paused (after 32 days).
     */
    function pause() external onlyGuardian {
        require(block.timestamp > pauseTimestamp + 32 days, "G_P: Cannot pause");
        repayPaused = true;
        withdrawPaused = true;
        borrowPaused = true;
        depositPaused = true;
        liquidationPaused = true;
        pauseTimestamp = block.timestamp;

        emit PauseUpdate(true, true, true, true, true);
    }

    /**
     * @notice This function is used to unpause one or more flags.
     * @param repayPaused_ false when repay functionality should be unPaused.
     * @param withdrawPaused_ false when withdraw functionality should be unPaused.
     * @param borrowPaused_ false when borrow functionality should be unPaused.
     * @param depositPaused_ false when deposit functionality should be unPaused.
     * @param liquidationPaused_ false when liquidation functionality should be unPaused.
     * @dev This function can unPause repay, withdraw, borrow, and deposit individually.
     * @dev Can only update flags from paused (true) to unPaused (false), cannot be used the other way around
     * (to set unPaused flags to paused).
     */
    function unPause(
        bool repayPaused_,
        bool withdrawPaused_,
        bool borrowPaused_,
        bool depositPaused_,
        bool liquidationPaused_
    ) external onlyOwner {
        repayPaused = repayPaused && repayPaused_;
        withdrawPaused = withdrawPaused && withdrawPaused_;
        borrowPaused = borrowPaused && borrowPaused_;
        depositPaused = depositPaused && depositPaused_;
        liquidationPaused = liquidationPaused && liquidationPaused_;

        emit PauseUpdate(repayPaused, withdrawPaused, borrowPaused, depositPaused, liquidationPaused);
    }

    /**
     * @notice This function is used to unPause all flags.
     * @dev If the protocol is not unpaused after 30 days, any user can unpause the protocol.
     * This ensures that no rogue owner or guardian can lock user funds for an indefinite amount of time.
     * All users have now at least a two-day window to withdraw assets and close positions before
     * the protocol can again be paused (after 32 days).
     */
    function unPause() external {
        require(block.timestamp > pauseTimestamp + 30 days, "G_UP: Cannot unPause");
        if (repayPaused || withdrawPaused || borrowPaused || depositPaused || liquidationPaused) {
            repayPaused = false;
            withdrawPaused = false;
            borrowPaused = false;
            depositPaused = false;
            liquidationPaused = false;

            emit PauseUpdate(false, false, false, false, false);
        }
    }
}

File 17 of 18 : BalancerErrors.sol
// SPDX-License-Identifier: GPL-3.0-or-later
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

pragma solidity ^0.8.13;

// solhint-disable

/**
 * @dev Reverts if `condition` is false, with a revert reason containing `errorCode`. Only codes up to 999 are
 * supported.
 */
function _require(bool condition, uint256 errorCode) pure {
    if (!condition) {
        _revert(errorCode);
    }
}

/**
 * @dev Reverts with a revert reason containing `errorCode`. Only codes up to 999 are supported.
 */
function _revert(uint256 errorCode) pure {
    // We're going to dynamically create a revert string based on the error code, with the following format:
    // 'BAL#{errorCode}'
    // where the code is left-padded with zeroes to three digits (so they range from 000 to 999).
    //
    // We don't have revert strings embedded in the contract to save bytecode size: it takes much less space to store a
    // number (8 to 16 bits) than the individual string characters.
    //
    // The dynamic string creation algorithm that follows could be implemented in Solidity, but assembly allows for a
    // much denser implementation, again saving bytecode size. Given this function unconditionally reverts, this is a
    // safe place to rely on it without worrying about how its usage might affect e.g. memory contents.
    assembly {
        // First, we need to compute the ASCII representation of the error code. We assume that it is in the 0-999
        // range, so we only need to convert three digits. To convert the digits to ASCII, we add 0x30, the value for
        // the '0' character.

        let units := add(mod(errorCode, 10), 0x30)

        errorCode := div(errorCode, 10)
        let tenths := add(mod(errorCode, 10), 0x30)

        errorCode := div(errorCode, 10)
        let hundreds := add(mod(errorCode, 10), 0x30)

        // With the individual characters, we can now construct the full string. The "BAL#" part is a known constant
        // (0x42414c23): we simply shift this by 24 (to provide space for the 3 bytes of the error code), and add the
        // characters to it, each shifted by a multiple of 8.
        // The revert reason is then shifted left by 200 bits (256 minus the length of the string, 7 characters * 8 bits
        // per character = 56) to locate it in the most significant part of the 256 slot (the beginning of a byte
        // array).

        let revertReason := shl(200, add(0x42414c23000000, add(add(units, shl(8, tenths)), shl(16, hundreds))))

        // We can now encode the reason in memory, which can be safely overwritten as we're about to revert. The encoded
        // message will have the following layout:
        // [ revert reason identifier ] [ string location offset ] [ string length ] [ string contents ]

        // The Solidity revert reason identifier is 0x08c739a0, the function selector of the Error(string) function. We
        // also write zeroes to the next 28 bytes of memory, but those are about to be overwritten.
        mstore(0x0, 0x08c379a000000000000000000000000000000000000000000000000000000000)
        // Next is the offset to the location of the string, which will be placed immediately after (20 bytes away).
        mstore(0x04, 0x0000000000000000000000000000000000000000000000000000000000000020)
        // The string length is fixed: 7 characters.
        mstore(0x24, 7)
        // Finally, the string itself is stored.
        mstore(0x44, revertReason)

        // Even if the string is only 7 bytes long, we need to return a full 32 byte slot containing it. The length of
        // the encoded message is therefore 4 + 32 + 32 + 32 = 100.
        revert(0, 100)
    }
}

library Errors {
    // Math
    uint256 internal constant ADD_OVERFLOW = 0;
    uint256 internal constant SUB_OVERFLOW = 1;
    uint256 internal constant SUB_UNDERFLOW = 2;
    uint256 internal constant MUL_OVERFLOW = 3;
    uint256 internal constant ZERO_DIVISION = 4;
    uint256 internal constant DIV_INTERNAL = 5;
    uint256 internal constant X_OUT_OF_BOUNDS = 6;
    uint256 internal constant Y_OUT_OF_BOUNDS = 7;
    uint256 internal constant PRODUCT_OUT_OF_BOUNDS = 8;
    uint256 internal constant INVALID_EXPONENT = 9;

    // Input
    uint256 internal constant OUT_OF_BOUNDS = 100;
    uint256 internal constant UNSORTED_ARRAY = 101;
    uint256 internal constant UNSORTED_TOKENS = 102;
    uint256 internal constant INPUT_LENGTH_MISMATCH = 103;
    uint256 internal constant ZERO_TOKEN = 104;

    // Shared pools
    uint256 internal constant MIN_TOKENS = 200;
    uint256 internal constant MAX_TOKENS = 201;
    uint256 internal constant MAX_SWAP_FEE_PERCENTAGE = 202;
    uint256 internal constant MIN_SWAP_FEE_PERCENTAGE = 203;
    uint256 internal constant MINIMUM_BPT = 204;
    uint256 internal constant CALLER_NOT_VAULT = 205;
    uint256 internal constant UNINITIALIZED = 206;
    uint256 internal constant BPT_IN_MAX_AMOUNT = 207;
    uint256 internal constant BPT_OUT_MIN_AMOUNT = 208;
    uint256 internal constant EXPIRED_PERMIT = 209;

    // Pools
    uint256 internal constant MIN_AMP = 300;
    uint256 internal constant MAX_AMP = 301;
    uint256 internal constant MIN_WEIGHT = 302;
    uint256 internal constant MAX_STABLE_TOKENS = 303;
    uint256 internal constant MAX_IN_RATIO = 304;
    uint256 internal constant MAX_OUT_RATIO = 305;
    uint256 internal constant MIN_BPT_IN_FOR_TOKEN_OUT = 306;
    uint256 internal constant MAX_OUT_BPT_FOR_TOKEN_IN = 307;
    uint256 internal constant NORMALIZED_WEIGHT_INVARIANT = 308;
    uint256 internal constant INVALID_TOKEN = 309;
    uint256 internal constant UNHANDLED_JOIN_KIND = 310;
    uint256 internal constant ZERO_INVARIANT = 311;
    uint256 internal constant ORACLE_INVALID_SECONDS_QUERY = 312;
    uint256 internal constant ORACLE_NOT_INITIALIZED = 313;
    uint256 internal constant ORACLE_QUERY_TOO_OLD = 314;
    uint256 internal constant ORACLE_INVALID_INDEX = 315;
    uint256 internal constant ORACLE_BAD_SECS = 316;

    // Lib
    uint256 internal constant REENTRANCY = 400;
    uint256 internal constant SENDER_NOT_ALLOWED = 401;
    uint256 internal constant PAUSED = 402;
    uint256 internal constant PAUSE_WINDOW_EXPIRED = 403;
    uint256 internal constant MAX_PAUSE_WINDOW_DURATION = 404;
    uint256 internal constant MAX_BUFFER_PERIOD_DURATION = 405;
    uint256 internal constant INSUFFICIENT_BALANCE = 406;
    uint256 internal constant INSUFFICIENT_ALLOWANCE = 407;
    uint256 internal constant ERC20_TRANSFER_FROM_ZERO_ADDRESS = 408;
    uint256 internal constant ERC20_TRANSFER_TO_ZERO_ADDRESS = 409;
    uint256 internal constant ERC20_MINT_TO_ZERO_ADDRESS = 410;
    uint256 internal constant ERC20_BURN_FROM_ZERO_ADDRESS = 411;
    uint256 internal constant ERC20_APPROVE_FROM_ZERO_ADDRESS = 412;
    uint256 internal constant ERC20_APPROVE_TO_ZERO_ADDRESS = 413;
    uint256 internal constant ERC20_TRANSFER_EXCEEDS_ALLOWANCE = 414;
    uint256 internal constant ERC20_DECREASED_ALLOWANCE_BELOW_ZERO = 415;
    uint256 internal constant ERC20_TRANSFER_EXCEEDS_BALANCE = 416;
    uint256 internal constant ERC20_BURN_EXCEEDS_ALLOWANCE = 417;
    uint256 internal constant SAFE_ERC20_CALL_FAILED = 418;
    uint256 internal constant ADDRESS_INSUFFICIENT_BALANCE = 419;
    uint256 internal constant ADDRESS_CANNOT_SEND_VALUE = 420;
    uint256 internal constant SAFE_CAST_VALUE_CANT_FIT_INT256 = 421;
    uint256 internal constant GRANT_SENDER_NOT_ADMIN = 422;
    uint256 internal constant REVOKE_SENDER_NOT_ADMIN = 423;
    uint256 internal constant RENOUNCE_SENDER_NOT_ALLOWED = 424;
    uint256 internal constant BUFFER_PERIOD_EXPIRED = 425;

    // Vault
    uint256 internal constant INVALID_POOL_ID = 500;
    uint256 internal constant CALLER_NOT_POOL = 501;
    uint256 internal constant SENDER_NOT_ASSET_MANAGER = 502;
    uint256 internal constant USER_DOESNT_ALLOW_RELAYER = 503;
    uint256 internal constant INVALID_SIGNATURE = 504;
    uint256 internal constant EXIT_BELOW_MIN = 505;
    uint256 internal constant JOIN_ABOVE_MAX = 506;
    uint256 internal constant SWAP_LIMIT = 507;
    uint256 internal constant SWAP_DEADLINE = 508;
    uint256 internal constant CANNOT_SWAP_SAME_TOKEN = 509;
    uint256 internal constant UNKNOWN_AMOUNT_IN_FIRST_SWAP = 510;
    uint256 internal constant MALCONSTRUCTED_MULTIHOP_SWAP = 511;
    uint256 internal constant INTERNAL_BALANCE_OVERFLOW = 512;
    uint256 internal constant INSUFFICIENT_INTERNAL_BALANCE = 513;
    uint256 internal constant INVALID_ETH_INTERNAL_BALANCE = 514;
    uint256 internal constant INVALID_POST_LOAN_BALANCE = 515;
    uint256 internal constant INSUFFICIENT_ETH = 516;
    uint256 internal constant UNALLOCATED_ETH = 517;
    uint256 internal constant ETH_TRANSFER = 518;
    uint256 internal constant CANNOT_USE_ETH_SENTINEL = 519;
    uint256 internal constant TOKENS_MISMATCH = 520;
    uint256 internal constant TOKEN_NOT_REGISTERED = 521;
    uint256 internal constant TOKEN_ALREADY_REGISTERED = 522;
    uint256 internal constant TOKENS_ALREADY_SET = 523;
    uint256 internal constant TOKENS_LENGTH_MUST_BE_2 = 524;
    uint256 internal constant NONZERO_TOKEN_BALANCE = 525;
    uint256 internal constant BALANCE_TOTAL_OVERFLOW = 526;
    uint256 internal constant POOL_NO_TOKENS = 527;
    uint256 internal constant INSUFFICIENT_FLASH_LOAN_BALANCE = 528;

    // Fees
    uint256 internal constant SWAP_FEE_PERCENTAGE_TOO_HIGH = 600;
    uint256 internal constant FLASH_LOAN_FEE_PERCENTAGE_TOO_HIGH = 601;
    uint256 internal constant INSUFFICIENT_FLASH_LOAN_FEE_AMOUNT = 602;
}

File 18 of 18 : LogExpMath.sol
// SPDX-License-Identifier: MIT
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
// documentation files (the “Software”), to deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to the following conditions:

// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
// Software.

// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

pragma solidity ^0.8.13;

import "./BalancerErrors.sol";

/* solhint-disable */

/**
 * @dev Exponentiation and logarithm functions for 18 decimal fixed point numbers (both base and exponent/argument).
 *
 * Exponentiation and logarithm with arbitrary bases (x^y and log_x(y)) are implemented by conversion to natural
 * exponentiation and logarithm (where the base is Euler's number).
 *
 * @author Fernando Martinelli - @fernandomartinelli
 * @author Sergio Yuhjtman - @sergioyuhjtman
 * @author Daniel Fernandez - @dmf7z
 */
library LogExpMath {
    // All fixed point multiplications and divisions are inlined. This means we need to divide by ONE when multiplying
    // two numbers, and multiply by ONE when dividing them.

    // All arguments and return values are 18 decimal fixed point numbers.
    int256 constant ONE_18 = 1e18;

    // Internally, intermediate values are computed with higher precision as 20 decimal fixed point numbers, and in the
    // case of ln36, 36 decimals.
    int256 constant ONE_20 = 1e20;
    int256 constant ONE_36 = 1e36;

    // The domain of natural exponentiation is bound by the word size and number of decimals used.
    //
    // Because internally the result will be stored using 20 decimals, the largest possible result is
    // (2^255 - 1) / 10^20, which makes the largest exponent ln((2^255 - 1) / 10^20) = 130.700829182905140221.
    // The smallest possible result is 10^(-18), which makes largest negative argument
    // ln(10^(-18)) = -41.446531673892822312.
    // We use 130.0 and -41.0 to have some safety margin.
    int256 constant MAX_NATURAL_EXPONENT = 130e18;
    int256 constant MIN_NATURAL_EXPONENT = -41e18;

    // Bounds for ln_36's argument. Both ln(0.9) and ln(1.1) can be represented with 36 decimal places in a fixed point
    // 256 bit integer.
    int256 constant LN_36_LOWER_BOUND = ONE_18 - 1e17;
    int256 constant LN_36_UPPER_BOUND = ONE_18 + 1e17;

    uint256 constant MILD_EXPONENT_BOUND = 2 ** 254 / uint256(ONE_20);

    // 18 decimal constants
    int256 constant x0 = 128_000_000_000_000_000_000; // 2ˆ7
    int256 constant a0 = 38_877_084_059_945_950_922_200_000_000_000_000_000_000_000_000_000_000_000; // eˆ(x0) (no decimals)
    int256 constant x1 = 64_000_000_000_000_000_000; // 2ˆ6
    int256 constant a1 = 6_235_149_080_811_616_882_910_000_000; // eˆ(x1) (no decimals)

    // 20 decimal constants
    int256 constant x2 = 3_200_000_000_000_000_000_000; // 2ˆ5
    int256 constant a2 = 7_896_296_018_268_069_516_100_000_000_000_000; // eˆ(x2)
    int256 constant x3 = 1_600_000_000_000_000_000_000; // 2ˆ4
    int256 constant a3 = 888_611_052_050_787_263_676_000_000; // eˆ(x3)
    int256 constant x4 = 800_000_000_000_000_000_000; // 2ˆ3
    int256 constant a4 = 298_095_798_704_172_827_474_000; // eˆ(x4)
    int256 constant x5 = 400_000_000_000_000_000_000; // 2ˆ2
    int256 constant a5 = 5_459_815_003_314_423_907_810; // eˆ(x5)
    int256 constant x6 = 200_000_000_000_000_000_000; // 2ˆ1
    int256 constant a6 = 738_905_609_893_065_022_723; // eˆ(x6)
    int256 constant x7 = 100_000_000_000_000_000_000; // 2ˆ0
    int256 constant a7 = 271_828_182_845_904_523_536; // eˆ(x7)
    int256 constant x8 = 50_000_000_000_000_000_000; // 2ˆ-1
    int256 constant a8 = 164_872_127_070_012_814_685; // eˆ(x8)
    int256 constant x9 = 25_000_000_000_000_000_000; // 2ˆ-2
    int256 constant a9 = 128_402_541_668_774_148_407; // eˆ(x9)
    int256 constant x10 = 12_500_000_000_000_000_000; // 2ˆ-3
    int256 constant a10 = 113_314_845_306_682_631_683; // eˆ(x10)
    int256 constant x11 = 6_250_000_000_000_000_000; // 2ˆ-4
    int256 constant a11 = 106_449_445_891_785_942_956; // eˆ(x11)

    /**
     * @dev Exponentiation (x^y) with unsigned 18 decimal fixed point base and exponent.
     *
     * Reverts if ln(x) * y is smaller than `MIN_NATURAL_EXPONENT`, or larger than `MAX_NATURAL_EXPONENT`.
     */
    function pow(uint256 x, uint256 y) internal pure returns (uint256) {
        if (y == 0) {
            // We solve the 0^0 indetermination by making it equal one.
            return uint256(ONE_18);
        }

        if (x == 0) {
            return 0;
        }

        // Instead of computing x^y directly, we instead rely on the properties of logarithms and exponentiation to
        // arrive at that result. In particular, exp(ln(x)) = x, and ln(x^y) = y * ln(x). This means
        // x^y = exp(y * ln(x)).

        // The ln function takes a signed value, so we need to make sure x fits in the signed 256 bit range.
        _require(x < 2 ** 255, Errors.X_OUT_OF_BOUNDS);
        int256 x_int256 = int256(x);

        // We will compute y * ln(x) in a single step. Depending on the value of x, we can either use ln or ln_36. In
        // both cases, we leave the division by ONE_18 (due to fixed point multiplication) to the end.

        // This prevents y * ln(x) from overflowing, and at the same time guarantees y fits in the signed 256 bit range.
        _require(y < MILD_EXPONENT_BOUND, Errors.Y_OUT_OF_BOUNDS);
        int256 y_int256 = int256(y);

        int256 logx_times_y;
        if (LN_36_LOWER_BOUND < x_int256 && x_int256 < LN_36_UPPER_BOUND) {
            int256 ln_36_x = _ln_36(x_int256);

            // ln_36_x has 36 decimal places, so multiplying by y_int256 isn't as straightforward, since we can't just
            // bring y_int256 to 36 decimal places, as it might overflow. Instead, we perform two 18 decimal
            // multiplications and add the results: one with the first 18 decimals of ln_36_x, and one with the
            // (downscaled) last 18 decimals.
            logx_times_y = ((ln_36_x / ONE_18) * y_int256 + ((ln_36_x % ONE_18) * y_int256) / ONE_18);
        } else {
            logx_times_y = _ln(x_int256) * y_int256;
        }
        logx_times_y /= ONE_18;

        // Finally, we compute exp(y * ln(x)) to arrive at x^y
        _require(
            MIN_NATURAL_EXPONENT <= logx_times_y && logx_times_y <= MAX_NATURAL_EXPONENT, Errors.PRODUCT_OUT_OF_BOUNDS
        );

        return uint256(exp(logx_times_y));
    }

    /**
     * @dev Natural exponentiation (e^x) with signed 18 decimal fixed point exponent.
     *
     * Reverts if `x` is smaller than MIN_NATURAL_EXPONENT, or larger than `MAX_NATURAL_EXPONENT`.
     */
    function exp(int256 x) internal pure returns (int256) {
        _require(x >= MIN_NATURAL_EXPONENT && x <= MAX_NATURAL_EXPONENT, Errors.INVALID_EXPONENT);

        if (x < 0) {
            // We only handle positive exponents: e^(-x) is computed as 1 / e^x. We can safely make x positive since it
            // fits in the signed 256 bit range (as it is larger than MIN_NATURAL_EXPONENT).
            // Fixed point division requires multiplying by ONE_18.
            return ((ONE_18 * ONE_18) / exp(-x));
        }

        // First, we use the fact that e^(x+y) = e^x * e^y to decompose x into a sum of powers of two, which we call x_n,
        // where x_n == 2^(7 - n), and e^x_n = a_n has been precomputed. We choose the first x_n, x0, to equal 2^7
        // because all larger powers are larger than MAX_NATURAL_EXPONENT, and therefore not present in the
        // decomposition.
        // At the end of this process we will have the product of all e^x_n = a_n that apply, and the remainder of this
        // decomposition, which will be lower than the smallest x_n.
        // exp(x) = k_0 * a_0 * k_1 * a_1 * ... + k_n * a_n * exp(remainder), where each k_n equals either 0 or 1.
        // We mutate x by subtracting x_n, making it the remainder of the decomposition.

        // The first two a_n (e^(2^7) and e^(2^6)) are too large if stored as 18 decimal numbers, and could cause
        // intermediate overflows. Instead we store them as plain integers, with 0 decimals.
        // Additionally, x0 + x1 is larger than MAX_NATURAL_EXPONENT, which means they will not both be present in the
        // decomposition.

        // For each x_n, we test if that term is present in the decomposition (if x is larger than it), and if so deduct
        // it and compute the accumulated product.

        int256 firstAN;
        if (x >= x0) {
            x -= x0;
            firstAN = a0;
        } else if (x >= x1) {
            x -= x1;
            firstAN = a1;
        } else {
            firstAN = 1; // One with no decimal places
        }

        // We now transform x into a 20 decimal fixed point number, to have enhanced precision when computing the
        // smaller terms.
        x *= 100;

        // `product` is the accumulated product of all a_n (except a0 and a1), which starts at 20 decimal fixed point
        // one. Recall that fixed point multiplication requires dividing by ONE_20.
        int256 product = ONE_20;

        if (x >= x2) {
            x -= x2;
            product = (product * a2) / ONE_20;
        }
        if (x >= x3) {
            x -= x3;
            product = (product * a3) / ONE_20;
        }
        if (x >= x4) {
            x -= x4;
            product = (product * a4) / ONE_20;
        }
        if (x >= x5) {
            x -= x5;
            product = (product * a5) / ONE_20;
        }
        if (x >= x6) {
            x -= x6;
            product = (product * a6) / ONE_20;
        }
        if (x >= x7) {
            x -= x7;
            product = (product * a7) / ONE_20;
        }
        if (x >= x8) {
            x -= x8;
            product = (product * a8) / ONE_20;
        }
        if (x >= x9) {
            x -= x9;
            product = (product * a9) / ONE_20;
        }

        // x10 and x11 are unnecessary here since we have high enough precision already.

        // Now we need to compute e^x, where x is small (in particular, it is smaller than x9). We use the Taylor series
        // expansion for e^x: 1 + x + (x^2 / 2!) + (x^3 / 3!) + ... + (x^n / n!).

        int256 seriesSum = ONE_20; // The initial one in the sum, with 20 decimal places.
        int256 term; // Each term in the sum, where the nth term is (x^n / n!).

        // The first term is simply x.
        term = x;
        seriesSum += term;

        // Each term (x^n / n!) equals the previous one times x, divided by n. Since x is a fixed point number,
        // multiplying by it requires dividing by ONE_20, but dividing by the non-fixed point n values does not.

        term = ((term * x) / ONE_20) / 2;
        seriesSum += term;

        term = ((term * x) / ONE_20) / 3;
        seriesSum += term;

        term = ((term * x) / ONE_20) / 4;
        seriesSum += term;

        term = ((term * x) / ONE_20) / 5;
        seriesSum += term;

        term = ((term * x) / ONE_20) / 6;
        seriesSum += term;

        term = ((term * x) / ONE_20) / 7;
        seriesSum += term;

        term = ((term * x) / ONE_20) / 8;
        seriesSum += term;

        term = ((term * x) / ONE_20) / 9;
        seriesSum += term;

        term = ((term * x) / ONE_20) / 10;
        seriesSum += term;

        term = ((term * x) / ONE_20) / 11;
        seriesSum += term;

        term = ((term * x) / ONE_20) / 12;
        seriesSum += term;

        // 12 Taylor terms are sufficient for 18 decimal precision.

        // We now have the first a_n (with no decimals), and the product of all other a_n present, and the Taylor
        // approximation of the exponentiation of the remainder (both with 20 decimals). All that remains is to multiply
        // all three (one 20 decimal fixed point multiplication, dividing by ONE_20, and one integer multiplication),
        // and then drop two digits to return an 18 decimal value.

        return (((product * seriesSum) / ONE_20) * firstAN) / 100;
    }

    /**
     * @dev Internal natural logarithm (ln(a)) with signed 18 decimal fixed point argument.
     */
    function _ln(int256 a) private pure returns (int256) {
        if (a < ONE_18) {
            // Since ln(a^k) = k * ln(a), we can compute ln(a) as ln(a) = ln((1/a)^(-1)) = - ln((1/a)). If a is less
            // than one, 1/a will be greater than one, and this if statement will not be entered in the recursive call.
            // Fixed point division requires multiplying by ONE_18.
            return (-_ln((ONE_18 * ONE_18) / a));
        }

        // First, we use the fact that ln^(a * b) = ln(a) + ln(b) to decompose ln(a) into a sum of powers of two, which
        // we call x_n, where x_n == 2^(7 - n), which are the natural logarithm of precomputed quantities a_n (that is,
        // ln(a_n) = x_n). We choose the first x_n, x0, to equal 2^7 because the exponential of all larger powers cannot
        // be represented as 18 fixed point decimal numbers in 256 bits, and are therefore larger than a.
        // At the end of this process we will have the sum of all x_n = ln(a_n) that apply, and the remainder of this
        // decomposition, which will be lower than the smallest a_n.
        // ln(a) = k_0 * x_0 + k_1 * x_1 + ... + k_n * x_n + ln(remainder), where each k_n equals either 0 or 1.
        // We mutate a by subtracting a_n, making it the remainder of the decomposition.

        // For reasons related to how `exp` works, the first two a_n (e^(2^7) and e^(2^6)) are not stored as fixed point
        // numbers with 18 decimals, but instead as plain integers with 0 decimals, so we need to multiply them by
        // ONE_18 to convert them to fixed point.
        // For each a_n, we test if that term is present in the decomposition (if a is larger than it), and if so divide
        // by it and compute the accumulated sum.

        int256 sum = 0;
        if (a >= a0 * ONE_18) {
            a /= a0; // Integer, not fixed point division
            sum += x0;
        }

        if (a >= a1 * ONE_18) {
            a /= a1; // Integer, not fixed point division
            sum += x1;
        }

        // All other a_n and x_n are stored as 20 digit fixed point numbers, so we convert the sum and a to this format.
        sum *= 100;
        a *= 100;

        // Because further a_n are  20 digit fixed point numbers, we multiply by ONE_20 when dividing by them.

        if (a >= a2) {
            a = (a * ONE_20) / a2;
            sum += x2;
        }

        if (a >= a3) {
            a = (a * ONE_20) / a3;
            sum += x3;
        }

        if (a >= a4) {
            a = (a * ONE_20) / a4;
            sum += x4;
        }

        if (a >= a5) {
            a = (a * ONE_20) / a5;
            sum += x5;
        }

        if (a >= a6) {
            a = (a * ONE_20) / a6;
            sum += x6;
        }

        if (a >= a7) {
            a = (a * ONE_20) / a7;
            sum += x7;
        }

        if (a >= a8) {
            a = (a * ONE_20) / a8;
            sum += x8;
        }

        if (a >= a9) {
            a = (a * ONE_20) / a9;
            sum += x9;
        }

        if (a >= a10) {
            a = (a * ONE_20) / a10;
            sum += x10;
        }

        if (a >= a11) {
            a = (a * ONE_20) / a11;
            sum += x11;
        }

        // a is now a small number (smaller than a_11, which roughly equals 1.06). This means we can use a Taylor series
        // that converges rapidly for values of `a` close to one - the same one used in ln_36.
        // Let z = (a - 1) / (a + 1).
        // ln(a) = 2 * (z + z^3 / 3 + z^5 / 5 + z^7 / 7 + ... + z^(2 * n + 1) / (2 * n + 1))

        // Recall that 20 digit fixed point division requires multiplying by ONE_20, and multiplication requires
        // division by ONE_20.
        int256 z = ((a - ONE_20) * ONE_20) / (a + ONE_20);
        int256 z_squared = (z * z) / ONE_20;

        // num is the numerator of the series: the z^(2 * n + 1) term
        int256 num = z;

        // seriesSum holds the accumulated sum of each term in the series, starting with the initial z
        int256 seriesSum = num;

        // In each step, the numerator is multiplied by z^2
        num = (num * z_squared) / ONE_20;
        seriesSum += num / 3;

        num = (num * z_squared) / ONE_20;
        seriesSum += num / 5;

        num = (num * z_squared) / ONE_20;
        seriesSum += num / 7;

        num = (num * z_squared) / ONE_20;
        seriesSum += num / 9;

        num = (num * z_squared) / ONE_20;
        seriesSum += num / 11;

        // 6 Taylor terms are sufficient for 36 decimal precision.

        // Finally, we multiply by 2 (non fixed point) to compute ln(remainder)
        seriesSum *= 2;

        // We now have the sum of all x_n present, and the Taylor approximation of the logarithm of the remainder (both
        // with 20 decimals). All that remains is to sum these two, and then drop two digits to return a 18 decimal
        // value.

        return (sum + seriesSum) / 100;
    }

    /**
     * @dev Intrnal high precision (36 decimal places) natural logarithm (ln(x)) with signed 18 decimal fixed point argument,
     * for x close to one.
     *
     * Should only be used if x is between LN_36_LOWER_BOUND and LN_36_UPPER_BOUND.
     */
    function _ln_36(int256 x) private pure returns (int256) {
        // Since ln(1) = 0, a value of x close to one will yield a very small result, which makes using 36 digits
        // worthwhile.

        // First, we transform x to a 36 digit fixed point value.
        x *= ONE_18;

        // We will use the following Taylor expansion, which converges very rapidly. Let z = (x - 1) / (x + 1).
        // ln(x) = 2 * (z + z^3 / 3 + z^5 / 5 + z^7 / 7 + ... + z^(2 * n + 1) / (2 * n + 1))

        // Recall that 36 digit fixed point division requires multiplying by ONE_36, and multiplication requires
        // division by ONE_36.
        int256 z = ((x - ONE_36) * ONE_36) / (x + ONE_36);
        int256 z_squared = (z * z) / ONE_36;

        // num is the numerator of the series: the z^(2 * n + 1) term
        int256 num = z;

        // seriesSum holds the accumulated sum of each term in the series, starting with the initial z
        int256 seriesSum = num;

        // In each step, the numerator is multiplied by z^2
        num = (num * z_squared) / ONE_36;
        seriesSum += num / 3;

        num = (num * z_squared) / ONE_36;
        seriesSum += num / 5;

        num = (num * z_squared) / ONE_36;
        seriesSum += num / 7;

        num = (num * z_squared) / ONE_36;
        seriesSum += num / 9;

        num = (num * z_squared) / ONE_36;
        seriesSum += num / 11;

        num = (num * z_squared) / ONE_36;
        seriesSum += num / 13;

        num = (num * z_squared) / ONE_36;
        seriesSum += num / 15;

        // 8 Taylor terms are sufficient for 36 decimal precision.

        // All that remains is multiplying by 2 (non fixed point).
        return seriesSum * 2;
    }
}

Settings
{
  "remappings": [
    "arcadia-lending/=lib/arcadia-lending/",
    "ds-test/=lib/ds-test/src/",
    "forge-std/=lib/forge-std/src/",
    "solmate/=lib/solmate/src/",
    "v2-periphery/=lib/v2-periphery/contracts/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "metadata": {
    "bytecodeHash": "ipfs"
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "evmVersion": "london",
  "libraries": {}
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"contract ERC20","name":"asset_","type":"address"},{"internalType":"address","name":"treasury_","type":"address"},{"internalType":"address","name":"vaultFactory_","type":"address"},{"internalType":"address","name":"liquidator_","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"FunctionIsPaused","type":"error"},{"inputs":[],"name":"FunctionNotImplemented","type":"error"},{"inputs":[],"name":"supplyCapExceeded","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"vault","type":"address"},{"indexed":true,"internalType":"address","name":"by","type":"address"},{"indexed":false,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"fee","type":"uint256"},{"indexed":true,"internalType":"bytes3","name":"referrer","type":"bytes3"}],"name":"Borrow","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint128","name":"borrowCap","type":"uint128"}],"name":"BorrowCapSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"vault","type":"address"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"beneficiary","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"CreditApproval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"assets","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"shares","type":"uint256"}],"name":"Deposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint96","name":"fixedLiquidationCost","type":"uint96"}],"name":"FixedLiquidationCostSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldGuardian","type":"address"},{"indexed":true,"internalType":"address","name":"newGuardian","type":"address"}],"name":"GuardianChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint80","name":"interestRate","type":"uint80"}],"name":"InterestRate","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"index","type":"uint256"},{"indexed":false,"internalType":"uint16","name":"weight","type":"uint16"}],"name":"InterestWeightSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"index","type":"uint256"},{"indexed":false,"internalType":"uint16","name":"weight","type":"uint16"}],"name":"LiquidationWeightSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint80","name":"maxInitiatorFee","type":"uint80"}],"name":"MaxInitiatorFeeSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"originationFee","type":"uint8"}],"name":"OriginationFeeSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"repayPauseUpdate","type":"bool"},{"indexed":false,"internalType":"bool","name":"withdrawPauseUpdate","type":"bool"},{"indexed":false,"internalType":"bool","name":"borrowPauseUpdate","type":"bool"},{"indexed":false,"internalType":"bool","name":"supplyPauseUpdate","type":"bool"},{"indexed":false,"internalType":"bool","name":"liquidationPauseUpdate","type":"bool"}],"name":"PauseUpdate","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"vault","type":"address"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Repay","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint128","name":"supplyCap","type":"uint128"}],"name":"SupplyCapSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"tranche","type":"address"},{"indexed":true,"internalType":"uint8","name":"index","type":"uint8"},{"indexed":false,"internalType":"uint16","name":"interestWeight","type":"uint16"},{"indexed":false,"internalType":"uint16","name":"liquidationWeight","type":"uint16"}],"name":"TrancheAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"tranche","type":"address"}],"name":"TranchePopped","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint16","name":"weight","type":"uint16"}],"name":"TreasuryInterestWeightSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint16","name":"weight","type":"uint16"}],"name":"TreasuryLiquidationWeightSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"vaultVersion","type":"uint256"},{"indexed":false,"internalType":"bool","name":"valid","type":"bool"}],"name":"VaultVersionSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"assets","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"shares","type":"uint256"}],"name":"Withdraw","type":"event"},{"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"YEARLY_SECONDS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"tranche","type":"address"},{"internalType":"uint16","name":"interestWeight_","type":"uint16"},{"internalType":"uint16","name":"liquidationWeight","type":"uint16"}],"name":"addTranche","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"beneficiary","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"vault","type":"address"}],"name":"approveBeneficiary","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"asset","outputs":[{"internalType":"contract ERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"auctionsInProgress","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"vault","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"bytes3","name":"referrer","type":"bytes3"}],"name":"borrow","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"borrowCap","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"borrowPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"calcUnrealisedDebt","outputs":[{"internalType":"uint256","name":"unrealisedDebt","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"guardian_","type":"address"}],"name":"changeGuardian","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"name":"convertToAssets","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"name":"convertToShares","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"creditAllowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"address","name":"","type":"address"}],"name":"deposit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"},{"internalType":"address","name":"from","type":"address"}],"name":"depositInLendingPool","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"depositPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountBorrowed","type":"uint256"},{"internalType":"address","name":"vault","type":"address"},{"internalType":"address","name":"actionHandler","type":"address"},{"internalType":"bytes","name":"actionData","type":"bytes"},{"internalType":"bytes3","name":"referrer","type":"bytes3"}],"name":"doActionWithLeverage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"trancheIndex","type":"uint256"},{"internalType":"uint256","name":"assets","type":"uint256"}],"name":"donateToTranche","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"fixedLiquidationCost","outputs":[{"internalType":"uint96","name":"","type":"uint96"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"vault","type":"address"}],"name":"getOpenPosition","outputs":[{"internalType":"uint256","name":"openPosition","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"guardian","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"interestRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"interestRateConfig","outputs":[{"internalType":"uint72","name":"baseRatePerYear","type":"uint72"},{"internalType":"uint72","name":"lowSlopePerYear","type":"uint72"},{"internalType":"uint72","name":"highSlopePerYear","type":"uint72"},{"internalType":"uint40","name":"utilisationThreshold","type":"uint40"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"interestWeight","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"interestWeightTranches","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"interestWeightTreasury","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"isTranche","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"isValidVersion","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastSyncedTimestamp","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"vault","type":"address"}],"name":"liquidateVault","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"liquidationInitiator","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"liquidationPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"liquidationWeightTranches","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"liquidationWeightTreasury","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"liquidator","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner_","type":"address"}],"name":"liquidityOf","outputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner_","type":"address"}],"name":"liquidityOfAndSync","outputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"maxDeposit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxInitiatorFee","outputs":[{"internalType":"uint80","name":"","type":"uint80"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"maxMint","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"maxRedeem","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"maxWithdraw","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"address","name":"","type":"address"}],"name":"mint","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"nonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"vaultVersion","type":"uint256"}],"name":"openMarginAccount","outputs":[{"internalType":"bool","name":"success","type":"bool"},{"internalType":"address","name":"baseCurrency","type":"address"},{"internalType":"address","name":"liquidator_","type":"address"},{"internalType":"uint256","name":"fixedLiquidationCost_","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"originationFee","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"pauseTimestamp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint8","name":"","type":"uint8"},{"internalType":"bytes32","name":"","type":"bytes32"},{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"permit","outputs":[],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"name":"previewDeposit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"name":"previewMint","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"name":"previewRedeem","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"name":"previewWithdraw","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"realisedDebt","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"realisedLiquidityOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"redeem","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"vault","type":"address"}],"name":"repay","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"repayPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint128","name":"borrowCap_","type":"uint128"}],"name":"setBorrowCap","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint96","name":"fixedLiquidationCost_","type":"uint96"}],"name":"setFixedLiquidationCost","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint72","name":"baseRatePerYear","type":"uint72"},{"internalType":"uint72","name":"lowSlopePerYear","type":"uint72"},{"internalType":"uint72","name":"highSlopePerYear","type":"uint72"},{"internalType":"uint40","name":"utilisationThreshold","type":"uint40"}],"internalType":"struct InterestRateModule.InterestRateConfiguration","name":"newConfig","type":"tuple"}],"name":"setInterestConfig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"},{"internalType":"uint16","name":"weight","type":"uint16"}],"name":"setInterestWeight","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"},{"internalType":"uint16","name":"weight","type":"uint16"}],"name":"setLiquidationWeight","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint80","name":"maxInitiatorFee_","type":"uint80"}],"name":"setMaxInitiatorFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint8","name":"originationFee_","type":"uint8"}],"name":"setOriginationFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint128","name":"supplyCap_","type":"uint128"}],"name":"setSupplyCap","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"treasury_","type":"address"}],"name":"setTreasury","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"interestWeightTreasury_","type":"uint16"}],"name":"setTreasuryInterestWeight","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"liquidationWeightTreasury_","type":"uint16"}],"name":"setTreasuryLiquidationWeight","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"vaultVersion","type":"uint256"},{"internalType":"bool","name":"valid","type":"bool"}],"name":"setVaultVersion","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"vault","type":"address"},{"internalType":"address","name":"originalOwner","type":"address"},{"internalType":"uint256","name":"badDebt","type":"uint256"},{"internalType":"uint256","name":"liquidationInitiatorReward","type":"uint256"},{"internalType":"uint256","name":"liquidationFee","type":"uint256"},{"internalType":"uint256","name":"remainder","type":"uint256"}],"name":"settleLiquidation","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"skim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"supplyCap","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalAssets","outputs":[{"internalType":"uint256","name":"totalDebt","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalInterestWeight","outputs":[{"internalType":"uint24","name":"","type":"uint24"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalLiquidationWeight","outputs":[{"internalType":"uint24","name":"","type":"uint24"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalRealisedLiquidity","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"tranches","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"treasury","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bool","name":"repayPaused_","type":"bool"},{"internalType":"bool","name":"withdrawPaused_","type":"bool"},{"internalType":"bool","name":"borrowPaused_","type":"bool"},{"internalType":"bool","name":"depositPaused_","type":"bool"},{"internalType":"bool","name":"liquidationPaused_","type":"bool"}],"name":"unPause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unPause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"updateInterestRate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"vaultFactory","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"withdraw","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"}],"name":"withdrawFromLendingPool","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"withdrawPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}]

6101406040523480156200001257600080fd5b506040516200675a3803806200675a83398101604081905262000035916200032d565b8380816001600160a01b03166306fdde036040518163ffffffff1660e01b8152600401600060405180830381865afa15801562000076573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052620000a09190810190620003d1565b604051602001620000b2919062000489565b604051602081830303815290604052826001600160a01b03166395d89b416040518163ffffffff1660e01b8152600401600060405180830381865afa15801562000100573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526200012a9190810190620003d1565b6040516020016200013c9190620004ca565b6040516020818303038152906040528181846001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156200018c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001b29190620004f8565b600080546001600160a01b031916339081178255604051909182917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908290a3506004620002018482620005b3565b506005620002108382620005b3565b5060ff81166080524660a0526200022662000278565b60c0525050506001600160a01b0392831660e0525050601080549582166c01000000000000000000000000026001600160601b03909616959095179094555090821661010052166101205250620006fd565b60007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f6004604051620002ac91906200067f565b6040805191829003822060208301939093528101919091527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260c00160405160208183030381529060405280519060200120905090565b6001600160a01b03811681146200032a57600080fd5b50565b600080600080608085870312156200034457600080fd5b8451620003518162000314565b6020860151909450620003648162000314565b6040860151909350620003778162000314565b60608601519092506200038a8162000314565b939692955090935050565b634e487b7160e01b600052604160045260246000fd5b60005b83811015620003c8578181015183820152602001620003ae565b50506000910152565b600060208284031215620003e457600080fd5b81516001600160401b0380821115620003fc57600080fd5b818401915084601f8301126200041157600080fd5b81518181111562000426576200042662000395565b604051601f8201601f19908116603f0116810190838211818310171562000451576200045162000395565b816040528281528760208487010111156200046b57600080fd5b6200047e836020830160208801620003ab565b979650505050505050565b67020b931b0b234b0960c51b815260008251620004ae816008850160208701620003ab565b64081119589d60da1b6008939091019283015250600d01919050565b636461726360e01b815260008251620004eb816004850160208701620003ab565b9190910160040192915050565b6000602082840312156200050b57600080fd5b815160ff811681146200051d57600080fd5b9392505050565b600181811c908216806200053957607f821691505b6020821081036200055a57634e487b7160e01b600052602260045260246000fd5b50919050565b601f821115620005ae57600081815260208120601f850160051c81016020861015620005895750805b601f850160051c820191505b81811015620005aa5782815560010162000595565b5050505b505050565b81516001600160401b03811115620005cf57620005cf62000395565b620005e781620005e0845462000524565b8462000560565b602080601f8311600181146200061f5760008415620006065750858301515b600019600386901b1c1916600185901b178555620005aa565b600085815260208120601f198616915b8281101562000650578886015182559484019460019091019084016200062f565b50858210156200066f5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b60008083546200068f8162000524565b60018281168015620006aa5760018114620006c057620006f1565b60ff1984168752821515830287019450620006f1565b8760005260208060002060005b85811015620006e85781548a820152908401908201620006cd565b50505082870194505b50929695505050505050565b60805160a05160c05160e0516101005161012051615fa4620007b66000396000818161088c015281816110a9015281816114430152612b66015260008181610d82015281816121af0152818161277f0152612c920152600081816108130152818161169a01528181611c8601528181611e8d015281816120c70152818161239f01528181612a5c01528181612b43015261326d01526000611a9e01526000611a6e0152600081816107970152611fe40152615fa46000f3fe608060405234801561001057600080fd5b50600436106105665760003560e01c80638456cb59116102ca578063b78891571161018d578063ce96cb77116100f4578063e11a0b83116100ad578063f0f4426011610087578063f0f4426014610e26578063f2fde38b14610e39578063f7b188a514610e4c578063f89d36a514610e5457600080fd5b8063e11a0b8314610df8578063e2dd93a214610e00578063ef8b30f714610e1357600080fd5b8063ce96cb7714610d43578063d505accf14610d56578063d53dc73914610d69578063d8a06f7314610d7d578063d905777e14610da4578063dd62ed3e14610dcd57600080fd5b8063bfcc565711610146578063bfcc565714610cef578063c11002df14610d02578063c63d75b614610872578063c6e6f59214610d15578063cd387b9814610d28578063ce76756f14610d3b57600080fd5b8063b788915714610c6d578063b8bb5c4214610c82578063ba08765214610c3c578063baf5dc4414610c97578063bc861ab714610cc8578063bcb4bbea14610cdb57600080fd5b806395d89b4111610231578063acb70815116101ea578063acb7081514610be4578063ad84f34114610bf7578063b17935f514610c00578063b3d7f6b914610c29578063b460af9414610c3c578063b73c02ff14610c4a57600080fd5b806395d89b4114610b735780639790576a14610b7b578063980a3f7714610b9e5780639bf4964c14610bb15780639f4020d914610bd1578063a9059cbb146105e757600080fd5b80638da5cb5b116102835780638da5cb5b14610af55780638e33f5ee14610b085780638f69a5c514610b3a5780638f770ad014610b4d5780639086c3a114610b6057806394bf804d146109d857600080fd5b80638456cb5914610a555780638618d38d14610a5d5780638710e70c14610a77578063894bacc914610a8a5780638994685f14610a9d5780638c48052314610ab057600080fd5b806336a36ea41161042d5780634e1255f31161039457806362c9b0f01161034d57806372b5e9231161032757806372b5e92314610a065780637bfbb80214610a195780637c3a00fd14610a2c5780637ecebe0014610a3557600080fd5b806362c9b0f0146109c55780636e553f65146109d857806370a08231146109e657600080fd5b80634e1255f314610937578063542b5fd31461094a5780635b6a14951461095f5780635ef904071461098a57806361d027b3146109a0578063626d6f5e146109ba57600080fd5b80634046ebae116103e65780634046ebae1461088757806340573f6e146108ae57806344d9dca6146108d3578063452a9320146108fe5780634cdad506146109115780634da1f9a81461092457600080fd5b806336a36ea4146107d357806338bfd64d146107f957806338d52e0f1461080e5780633c4750df146108355780633f7ee87314610848578063402d267d1461087257600080fd5b80631bd43293116104d15780632db6c63a1161048a5780632db6c63a146107385780632f3ffb9f146107585780632fcb4f041461076c578063306caf961461077f578063313ce567146107925780633644e515146107cb57600080fd5b80631bd43293146106bd5780631dd19cb4146106d05780631e865815146106d85780631e9dbce6146106eb57806323b872dd146106ff57806326c259621461070d57600080fd5b80630a28a477116105235780630a28a477146105fa578063165bf8c51461060d57806318160ddd14610620578063182bfd20146106295780631919e78b1461063c578063194d7494146106aa57600080fd5b806301e1d1141461056b57806302befd241461058657806302d37a2f146105aa57806306fdde03146105bf57806307a2d13a146105d4578063095ea7b3146105e7575b600080fd5b610573610e5d565b6040519081526020015b60405180910390f35b60015461059a90600160b81b900460ff1681565b604051901515815260200161057d565b6105bd6105b83660046153d1565b610e94565b005b6105c7610f2d565b60405161057d91906153fa565b6105736105e2366004615448565b610fbb565b61059a6105f5366004615476565b610fe8565b610573610608366004615448565b611003565b6105bd61061b3660046154b0565b611023565b61057360065481565b6105bd6106373660046154e0565b6110a7565b600d54610673906001600160481b0380821691600160481b8104821691600160901b82041690600160d81b900464ffffffffff1684565b604080516001600160481b0395861681529385166020850152919093169082015264ffffffffff909116606082015260800161057d565b6105bd6106b8366004615539565b61135a565b6105bd6106cb366004615556565b611596565b6105bd61160e565b6105bd6106e6366004615590565b61179d565b60015461059a90600160a01b900460ff1681565b61059a6105f53660046155ab565b61072061071b366004615448565b611817565b6040516001600160a01b03909116815260200161057d565b610573610746366004615539565b60166020526000908152604090205481565b60015461059a90600160a81b900460ff1681565b6105bd61077a366004615539565b611841565b6105bd61078d3660046155ec565b6118c7565b6107b97f000000000000000000000000000000000000000000000000000000000000000081565b60405160ff909116815260200161057d565b610573611a6a565b6107e66107e1366004615448565b611ac0565b60405161ffff909116815260200161057d565b600e546107e690600160681b900461ffff1681565b6107207f000000000000000000000000000000000000000000000000000000000000000081565b610573610843366004615539565b611af8565b600e5461085e90600160281b900462ffffff1681565b60405162ffffff909116815260200161057d565b610573610880366004615539565b5060001990565b6107207f000000000000000000000000000000000000000000000000000000000000000081565b600e546108be9063ffffffff1681565b60405163ffffffff909116815260200161057d565b600b546108e6906001600160801b031681565b6040516001600160801b03909116815260200161057d565b600154610720906001600160a01b031681565b61057361091f366004615448565b611b8d565b6105bd61093236600461565d565b611b9e565b6105bd610945366004615682565b611d14565b6010546107e690600160501b900461ffff1681565b601054610972906001600160501b031681565b6040516001600160501b03909116815260200161057d565b600e5461085e90600160501b900462ffffff1681565b60105461072090600160601b90046001600160a01b031681565b6105736301e1338081565b6105bd6109d336600461565d565b611d8f565b6105736105f536600461565d565b6105736109f4366004615539565b60076020526000908152604090205481565b6105bd610a143660046156ab565b611ee4565b6105bd610a273660046156e5565b61215a565b610573600c5481565b610573610a43366004615539565b60096020526000908152604090205481565b6105bd612536565b600e546108e690600160781b90046001600160801b031681565b6105bd610a853660046157a8565b612654565b610573610a98366004615539565b612720565b6105bd610aab3660046157c3565b61272a565b610ac3610abe366004615448565b612b1b565b60405161057d949392919093151584526001600160a01b03928316602085015291166040830152606082015260800190565b600054610720906001600160a01b031681565b600f54610b2290600160801b90046001600160601b031681565b6040516001600160601b03909116815260200161057d565b6105bd610b483660046157a8565b612b9e565b600f546108e6906001600160801b031681565b6105bd610b6e366004615814565b612c71565b6105c7612db8565b61059a610b89366004615539565b60146020526000908152604090205460ff1681565b6105bd610bac366004615856565b612dc5565b610573610bbf366004615539565b60156020526000908152604090205481565b6105bd610bdf36600461589b565b613050565b6105bd610bf236600461565d565b61320d565b61057360025481565b610720610c0e366004615539565b6017602052600090815260409020546001600160a01b031681565b610573610c37366004615448565b613303565b6105736105f53660046158c7565b61059a610c58366004615448565b60036020526000908152604090205460ff1681565b600e546107e690600160401b900461ffff1681565b600e546107b990640100000000900460ff1681565b610573610ca53660046158fe565b601860209081526000938452604080852082529284528284209052825290205481565b6105bd610cd636600461592e565b613322565b60015461059a90600160b01b900460ff1681565b6105bd610cfd36600461589b565b613355565b610573610d10366004615539565b6134d1565b610573610d23366004615448565b6134dc565b6107e6610d36366004615448565b6134fc565b6105bd61350c565b610573610d51366004615539565b613534565b6105bd610d64366004615946565b613556565b60015461059a90600160c01b900460ff1681565b6107207f000000000000000000000000000000000000000000000000000000000000000081565b610573610db2366004615539565b6001600160a01b031660009081526007602052604090205490565b610573610ddb3660046159b4565b600860209081526000928352604080842090915290825290205481565b61057361356f565b6105bd610e0e366004615556565b6135d1565b610573610e21366004615448565b613649565b6105bd610e34366004615539565b613654565b6105bd610e47366004615539565b6136a6565b6105bd61371b565b610573600a5481565b600e546000904263ffffffff908116911614610e8d57610e7b61356f565b600a54610e8891906159f8565b905090565b50600a5490565b6000546001600160a01b03163314610ec75760405162461bcd60e51b8152600401610ebe90615a0b565b60405180910390fd5b600f80546bffffffffffffffffffffffff60801b1916600160801b6001600160601b038416908102919091179091556040519081527fce76ed33b01ab134c41431ef53932d4130aaf7a443840d0630b94a7474fe19dc906020015b60405180910390a150565b60048054610f3a90615a31565b80601f0160208091040260200160405190810160405280929190818152602001828054610f6690615a31565b8015610fb35780601f10610f8857610100808354040283529160200191610fb3565b820191906000526020600020905b815481529060010190602001808311610f9657829003601f168201915b505050505081565b6006546000908015610fdf57610fda610fd2610e5d565b849083613832565b610fe1565b825b9392505050565b600060405163ced4f63360e01b815260040160405180910390fd5b6006546000908015610fdf57610fda8161101b610e5d565b859190613858565b6000546001600160a01b0316331461104d5760405162461bcd60e51b8152600401610ebe90615a0b565b6000828152600360205260409020805460ff1916821515179055817f6bd62b850d20e8a0251cb2759fd0ebad03703967c804dabab97f9238a0e40e258260405161109b911515815260200190565b60405180910390a25050565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031633146111155760405162461bcd60e51b815260206004820152601360248201527226281d1027b7363c903634b8bab4b230ba37b960691b6044820152606401610ebe565b61111d613876565b6001600160a01b0380871660009081526017602090815260408083205490931682526016905290812080548592906111569084906159f8565b909155505083156111c857600e54611194908590611185908690600160781b90046001600160801b03166159f8565b61118f9190615a65565b6138bb565b600e600f6101000a8154816001600160801b0302191690836001600160801b031602179055506111c3846138d1565b61126a565b6111d182613a5d565b600e5461120b90829084906111f7908790600160781b90046001600160801b03166159f8565b61120191906159f8565b61118f91906159f8565b600e80546001600160801b0392909216600160781b02600160781b600160f81b0319909216919091179055801561126a576001600160a01b038516600090815260166020526040812080548392906112649084906159f8565b90915550505b6010805461ffff60501b198116600160501b9182900461ffff908116600019018116830291909117928390559104161580156112a7575060135415155b1561133257601380546112bc90600190615a65565b815481106112cc576112cc615a78565b6000918252602082200154604051633dd217f760e21b815260048101929092526001600160a01b03169063f7485fdc90602401600060405180830381600087803b15801561131957600080fd5b505af115801561132d573d6000803e3d6000fd5b505050505b600a54600e546113529190600160781b90046001600160801b0316613b49565b505050505050565b600154600160c01b900460ff16156113855760405163bbc5234f60e01b815260040160405180910390fd5b61138d613876565b600061139882613534565b9050806000036113ea5760405162461bcd60e51b815260206004820152601c60248201527f4c505f4c563a204e6f742061205661756c7420776974682064656274000000006044820152606401610ebe565b6001600160a01b038281166000818152601760205260409081902080546001600160a01b0319163317905560105490516378d6c03f60e01b81526004810192909252602482018490526001600160501b031660448201527f0000000000000000000000000000000000000000000000000000000000000000909116906378d6c03f90606401600060405180830381600087803b15801561148957600080fd5b505af115801561149d573d6000803e3d6000fd5b5050601054600160501b900461ffff166000039150611540905057601380546114c890600190615a65565b815481106114d8576114d8615a78565b600091825260209091200154604051633dd217f760e21b8152600160048201526001600160a01b039091169063f7485fdc90602401600060405180830381600087803b15801561152757600080fd5b505af115801561153b573d6000803e3d6000fd5b505050505b60108054600161ffff600160501b808404821692909201160261ffff60501b19909116179055611571818380613bbb565b5050600a54600e546115939190600160781b90046001600160801b0316613b49565b50565b6000546001600160a01b031633146115c05760405162461bcd60e51b8152600401610ebe90615a0b565b600b80546001600160801b0319166001600160801b0383169081179091556040519081527ff60cdb66d1290884d4b7cdeee8f7b4d52f8b62b9ff1d89ffc4678d00bc1e3a1490602001610f22565b611616613876565b601054600160501b900461ffff161561166a5760405162461bcd60e51b81526020600482015260166024820152754c505f533a2041756374696f6e73204f6e676f696e6760501b6044820152606401610ebe565b600e54600a546040516370a0823160e01b8152306004820152600092600160781b90046001600160801b031691907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa1580156116e9573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061170d9190615a8e565b61171791906159f8565b6117219190615a65565b905061172c816138bb565b600e80546001600160801b03600160781b808304821690940181168402600160781b600160f81b03199092169190911782556010546001600160a01b03600160601b9091041660009081526016602052604090208054909401909355600a54905461179b939192900416613b49565b565b6000546001600160a01b031633146117c75760405162461bcd60e51b8152600401610ebe90615a0b565b600e805464ff00000000191664010000000060ff8416908102919091179091556040519081527f62815047fdec5b7ea69997c870fa83e53a213d8d485f2489b58c049eb76cfd1490602001610f22565b6013818154811061182757600080fd5b6000918252602090912001546001600160a01b0316905081565b6000546001600160a01b0316331461186b5760405162461bcd60e51b8152600401610ebe90615a0b565b6001546040516001600160a01b038084169216907fa14fc14d8620a708a896fd11392a235647d99385500a295f0d7da2a258b2e96790600090a3600180546001600160a01b0319166001600160a01b0392909216919091179055565b6000546001600160a01b031633146118f15760405162461bcd60e51b8152600401610ebe90615a0b565b600154600160a01b900460ff1680156119075750845b60018054911515600160a01b0260ff60a01b199092169190911790819055600160a81b900460ff1680156119385750835b60018054911515600160a81b0260ff60a81b199092169190911790819055600160b01b900460ff1680156119695750825b60018054911515600160b01b0260ff60b01b199092169190911790819055600160b81b900460ff16801561199a5750815b60018054911515600160b81b0260ff60b81b199092169190911790819055600160c01b900460ff1680156119cb5750805b6001805460ff60c01b1916600160c01b921515830217908190556040805160ff600160a01b8404811615158252600160a81b8404811615156020830152600160b01b84048116151592820192909252600160b81b83048216151560608201529290910416151560808201527f8502e0dfa7512c68fe07e3fd09dba9a9545c1e68fb13e18348da704c2fa7275e9060a00160405180910390a15050505050565b60007f00000000000000000000000000000000000000000000000000000000000000004614611a9b57610e88613c7f565b507f000000000000000000000000000000000000000000000000000000000000000090565b60118181548110611ad057600080fd5b9060005260206000209060109182820401919006600202915054906101000a900461ffff1681565b600e546000904263ffffffff908116911614611b6d576001600160a01b038216600090815260156020526040812054600e54611b4a9190600160281b900462ffffff16611b4361356f565b9190613832565b6001600160a01b038416600090815260166020526040902054019150611b889050565b506001600160a01b0381166000908152601660205260409020545b919050565b6000611b9882610fbb565b92915050565b600154600160b81b900460ff1615611bc95760405163bbc5234f60e01b815260040160405180910390fd5b3360009081526014602052604090205460ff16611c1b5760405162461bcd60e51b815260206004820152601060248201526f4c503a204f6e6c79207472616e63686560801b6044820152606401610ebe565b611c23613876565b600f546001600160801b031615611c7957600f54600e546001600160801b0391821691611c5a918591600160781b909104166159f8565b1115611c7957604051638fd0b1ed60e01b815260040160405180910390fd5b611cae6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016823085613d19565b336000908152601660205260409020805483019055611ccc826138bb565b600e80546001600160801b03600160781b808304821690940181168402600160781b600160f81b03199092169190911791829055600a54611d109390920416613b49565b5050565b6000546001600160a01b03163314611d3e5760405162461bcd60e51b8152600401610ebe90615a0b565b6010805469ffffffffffffffffffff19166001600160501b0383169081179091556040519081527fb459d4513fe6c441f14d1f873f0ac9e675919afdb60c6d63f158dd00fc294ecf90602001610f22565b600154600160a81b900460ff1615611dba5760405163bbc5234f60e01b815260040160405180910390fd5b611dc2613876565b33600090815260166020526040902054821115611e215760405162461bcd60e51b815260206004820152601f60248201527f4c505f57464c503a20416d6f756e7420657863656564732062616c616e6365006044820152606401610ebe565b33600090815260166020526040902080548390039055611e40826138bb565b600e8054600f90611e62908490600160781b90046001600160801b0316615aa7565b92506101000a8154816001600160801b0302191690836001600160801b03160217905550611ec481837f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316613da39092919063ffffffff16565b600a54600e54611d109190600160781b90046001600160801b0316613b49565b600154600160b81b900460ff1615611f0f5760405163bbc5234f60e01b815260040160405180910390fd5b611f17613876565b60008111611f5d5760405162461bcd60e51b815260206004820152601360248201527204c505f4454543a20416d6f756e74206973203606c1b6044820152606401610ebe565b600f546001600160801b031615611fb357600f54600e546001600160801b0391821691611f94918491600160781b909104166159f8565b1115611fb357604051638fd0b1ed60e01b815260040160405180910390fd5b600060138381548110611fc857611fc8615a78565b6000918252602090912001546001600160a01b0316905061200a7f0000000000000000000000000000000000000000000000000000000000000000600a615bb2565b816001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612048573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061206c9190615a8e565b10156120ba5760405162461bcd60e51b815260206004820152601b60248201527f4c505f4454543a20496e73756666696369656e742073686172657300000000006044820152606401610ebe565b6120ef6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016333085613d19565b6001600160a01b0381166000908152601660205260409020805483019055612116826138bb565b600e8054600160781b600160f81b03198116600160781b918290046001600160801b0390811694909401841682021791829055600a54611d10945092910416613b49565b600154600160b01b900460ff16156121855760405163bbc5234f60e01b815260040160405180910390fd5b61218d613876565b604051632724fe0960e01b81526001600160a01b0386811660048301526000917f000000000000000000000000000000000000000000000000000000000000000090911690632724fe0990602401602060405180830381865afa1580156121f8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061221c9190615bc1565b90506001600160a01b03811661226b5760405162461bcd60e51b8152602060048201526014602482015273131417d11055d30e88139bdd0818481d985d5b1d60621b6044820152606401610ebe565b600e546000906127109061228a90640100000000900460ff168a615bde565b6122949190615c0b565b61229e90896159f8565b90506001600160a01b0382163314612326576001600160a01b038088166000908152601860209081526040808320938616835292815282822033835290522054600019146123265760405162461bcd60e51b8152602060048201526015602482015274131417d11055d30e8815539055551213d492569151605a1b6044820152606401610ebe565b6123308188613e1b565b5061233c8882036138bb565b600e80546001600160801b03600160781b808304821690940116909202600160781b600160f81b03199092169190911790556010546001600160a01b03600160601b9091048116600090815260166020526040902080548a84030190556123c6907f000000000000000000000000000000000000000000000000000000000000000016878a613da3565b600080886001600160a01b0316634d401a368989896040518463ffffffff1660e01b81526004016123f993929190615c1f565b60408051808303816000875af1158015612417573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061243b9190615c5f565b90925090506001600160a01b03821630148015612466575060008181526003602052604090205460ff165b6124a65760405162461bcd60e51b8152602060048201526011602482015270131417d11055d30e8814995d995c9d1959607a1b6044820152606401610ebe565b6001600160e81b03198516336001600160a01b038b167f921c81c17e72f815c88a3e0fa28e7e709d56f0c5832e17b4bcc606dc9ee1a6118b8e6124e9818a615a65565b604080516001600160a01b03909416845260208401929092529082015260600160405180910390a45050600a54600e546113529350909150600160781b90046001600160801b0316613b49565b6001546001600160a01b031633146125905760405162461bcd60e51b815260206004820152601760248201527f477561726469616e3a204f6e6c7920677561726469616e0000000000000000006044820152606401610ebe565b6002546125a090622a30006159f8565b42116125e25760405162461bcd60e51b8152602060048201526011602482015270475f503a2043616e6e6f7420706175736560781b6044820152606401610ebe565b6001805464ffffffffff60a01b191664010101010160a01b1781554260025560408051828152602081018390529081018290526060810182905260808101919091527f8502e0dfa7512c68fe07e3fd09dba9a9545c1e68fb13e18348da704c2fa7275e9060a0015b60405180910390a1565b6000546001600160a01b0316331461267e5760405162461bcd60e51b8152600401610ebe90615a0b565b600e5461ffff828116916126a691600160681b82041690600160501b900462ffffff16615c8d565b6126b09190615ca9565b600e805464ffffffffff60501b1916600160501b62ffffff939093169290920261ffff60681b191691909117600160681b61ffff8416908102919091179091556040519081527f37ff452135135f1d2c10b27bbd9d50b762f72d6184b09337bc9d38d093169c0390602001610f22565b6000611b6d613876565b600154600160b01b900460ff16156127555760405163bbc5234f60e01b815260040160405180910390fd5b61275d613876565b604051632724fe0960e01b81526001600160a01b0384811660048301526000917f000000000000000000000000000000000000000000000000000000000000000090911690632724fe0990602401602060405180830381865afa1580156127c8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127ec9190615bc1565b90506001600160a01b0381166128385760405162461bcd60e51b8152602060048201526011602482015270131417d08e88139bdd0818481d985d5b1d607a1b6044820152606401610ebe565b600e546000906127109061285790640100000000900460ff1688615bde565b6128619190615c0b565b61286b90876159f8565b90506001600160a01b03821633146128ef576001600160a01b03808616600090815260186020908152604080832093861683529281528282203383529052205460001981146128ed576128be8282615a65565b6001600160a01b0380881660009081526018602090815260408083209388168352928152828220338352905220555b505b6128f98186613e1b565b506129058682036138bb565b600e80546001600160801b03600160781b808304821690940116909202600160781b600160f81b03199092169190911790556010546001600160a01b03600160601b909104811660009081526016602052604081208054898503019055908190819088166317e62b67826129788b613534565b6040516001600160e01b031960e085901b16815260048101929092526024820152604401606060405180830381865afa1580156129b9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129dd9190615cc5565b9250925092508280156129f857506001600160a01b03821630145b8015612a12575060008181526003602052604090205460ff165b612a4f5760405162461bcd60e51b815260206004820152600e60248201526d131417d08e8814995d995c9d195960921b6044820152606401610ebe565b612a836001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016888b613da3565b6001600160e81b03198616336001600160a01b038a167f921c81c17e72f815c88a3e0fa28e7e709d56f0c5832e17b4bcc606dc9ee1a6118a8d612ac6818b615a65565b604080516001600160a01b03909416845260208401929092529082015260600160405180910390a45050600a54600e54612b159450909250600160781b90046001600160801b03169050613b49565b50505050565b60008181526003602052604081205481908190819060ff1615612b97575050600f54600192507f000000000000000000000000000000000000000000000000000000000000000091507f000000000000000000000000000000000000000000000000000000000000000090600160801b90046001600160601b03165b9193509193565b6000546001600160a01b03163314612bc85760405162461bcd60e51b8152600401610ebe90615a0b565b600e5461ffff82811691612bf091600160401b82041690600160281b900462ffffff16615c8d565b612bfa9190615ca9565b600e805469ffffffffff00000000001916600160281b62ffffff939093169290920269ffff0000000000000000191691909117600160401b61ffff8416908102919091179091556040519081527f553cb4d921add3331757ed1c44f851dcfab622fbc4975007ed008dce680ffe4790602001610f22565b604051632724fe0960e01b81526001600160a01b03828116600483015233917f000000000000000000000000000000000000000000000000000000000000000090911690632724fe0990602401602060405180830381865afa158015612cdb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612cff9190615bc1565b6001600160a01b031614612d4b5760405162461bcd60e51b8152602060048201526013602482015272131417d0508e8815539055551213d492569151606a1b6044820152606401610ebe565b6001600160a01b0381811660008181526018602090815260408083203380855290835281842095891680855295835292819020879055518681529192917f9c3c3fddd897f6c3dce14f62fcc742f199fb00b47c0664b980cbdea1be127411910160405180910390a4505050565b60058054610f3a90615a31565b6000546001600160a01b03163314612def5760405162461bcd60e51b8152600401610ebe90615a0b565b6001600160a01b03831660009081526014602052604090205460ff1615612e505760405162461bcd60e51b815260206004820152601560248201527454525f41443a20416c72656164792065786973747360581b6044820152606401610ebe565b8161ffff16600e60058282829054906101000a900462ffffff16612e749190615ca9565b825462ffffff91821661010093840a90810290830219909116179092556011805460018101909155601081047f31ecc21a745e3968a04e9570e4425bc18fa8019c68028196b546d1669c200c6801805461ffff8089166002600f9095169490940290940a838102908502199091161790556001600160a01b038716600090815260156020526040902055600e8054918516935091600a91612f1e918591600160501b900416615ca9565b825461010092830a62ffffff818102199092169290911602179091556012805460018181019092557fbb8a6a4669ba250d26cd7a459eca9d215f8307e33aebe50379bc5a3617ec344460108204018054600f90921660020290930a61ffff8181021990921691861602179091556013805480830182557f66de8ffda797e3de9c05e8fc57b3bf0ec28a930d40b0d285d93c06501cf6a0900180546001600160a01b0319166001600160a01b0388169081179091556000908152601460205260409020805460ff19168317905554612ff59250615a65565b60ff16836001600160a01b03167f5f77a2c0fccc0d2bdab612b4afae9f6108ce73d48f2ea671605aa7191aa60b58848460405161304392919061ffff92831681529116602082015260400190565b60405180910390a3505050565b6000546001600160a01b0316331461307a5760405162461bcd60e51b8152600401610ebe90615a0b565b60135482106130cb5760405162461bcd60e51b815260206004820152601c60248201527f54525f5349573a204e6f6e204578697374696e67205472616e636865000000006044820152606401610ebe565b8061ffff16601183815481106130e3576130e3615a78565b90600052602060002090601091828204019190066002029054906101000a900461ffff1661ffff16600e60059054906101000a900462ffffff166131279190615c8d565b6131319190615ca9565b600e60056101000a81548162ffffff021916908362ffffff160217905550806011838154811061316357613163615a78565b90600052602060002090601091828204019190066002026101000a81548161ffff021916908361ffff1602179055508061ffff1660156000601385815481106131ae576131ae615a78565b6000918252602080832091909101546001600160a01b03168352828101939093526040918201902092909255905161ffff8316815283917f7283d16027b080a3c9be9ae5695b23b19ef3e5066059566674e4680bacf3c8ca910161109b565b600154600160a01b900460ff16156132385760405163bbc5234f60e01b815260040160405180910390fd5b613240613876565b600061324b82613534565b9050600083821161325c578161325e565b835b90506132956001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016333084613d19565b6132a0818485613bbb565b5060405181815233906001600160a01b038516907f05f2eeda0e08e4b437f487c8d7d29b14537d15e3488170dc3de5dbdf8dac46849060200160405180910390a35050600a54600e54611d109190600160781b90046001600160801b0316613b49565b6006546000908015610fdf57610fda61331a610e5d565b849083613858565b6000546001600160a01b0316331461334c5760405162461bcd60e51b8152600401610ebe90615a0b565b61159381613f15565b6000546001600160a01b0316331461337f5760405162461bcd60e51b8152600401610ebe90615a0b565b60135482106133d05760405162461bcd60e51b815260206004820152601c60248201527f54525f534c573a204e6f6e204578697374696e67205472616e636865000000006044820152606401610ebe565b8061ffff16601283815481106133e8576133e8615a78565b90600052602060002090601091828204019190066002029054906101000a900461ffff1661ffff16600e600a9054906101000a900462ffffff1661342c9190615c8d565b6134369190615ca9565b600e600a6101000a81548162ffffff021916908362ffffff160217905550806012838154811061346857613468615a78565b90600052602060002090601091828204019190066002026101000a81548161ffff021916908361ffff160217905550817fa0bb5ed3a1177ecbc7a7ee676d73ea48b239c9261b6e5b6d781c263e71f0b9018260405161109b919061ffff91909116815260200190565b6000611b9882613534565b6006546000908015610fdf57610fda816134f4610e5d565b859190613832565b60128181548110611ad057600080fd5b613514613876565b600a54600e5461179b9190600160781b90046001600160801b0316613b49565b6001600160a01b038116600090815260076020526040812054611b9890610fbb565b60405163ced4f63360e01b815260040160405180910390fd5b600c54600e54600091670de0b6b3a7640000908101916301e1338063ffffffff909116420382020490806135a38484613f27565b03600a5402816135b5576135b5615bf5565b0492506135c1836138bb565b6001600160801b03169250505090565b6000546001600160a01b031633146135fb5760405162461bcd60e51b8152600401610ebe90615a0b565b600f80546001600160801b0319166001600160801b0383169081179091556040519081527fb01769936feb4d3129c98c6f606578713d8b445ff96e0a744154ab58efb15e5090602001610f22565b6000611b98826134dc565b6000546001600160a01b0316331461367e5760405162461bcd60e51b8152600401610ebe90615a0b565b601080546001600160a01b03909216600160601b026001600160601b03909216919091179055565b6000546001600160a01b031633146136d05760405162461bcd60e51b8152600401610ebe90615a0b565b600080546001600160a01b0319166001600160a01b0383169081178255604051909133917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a350565b60025461372b9062278d006159f8565b42116137705760405162461bcd60e51b8152602060048201526014602482015273475f55503a2043616e6e6f7420756e506175736560601b6044820152606401610ebe565b600154600160a01b900460ff16806137915750600154600160a81b900460ff165b806137a55750600154600160b01b900460ff165b806137b95750600154600160b81b900460ff165b806137cd5750600154600160c01b900460ff165b1561179b576001805464ffffffffff60a01b19169055604080516000808252602082018190529181018290526060810182905260808101919091527f8502e0dfa7512c68fe07e3fd09dba9a9545c1e68fb13e18348da704c2fa7275e9060a00161264a565b600082600019048411830215820261384957600080fd5b50910281810615159190040190565b600082600019048411830215820261386f57600080fd5b5091020490565b600e544263ffffffff90811691161461179b57600061389361356f565b600e805463ffffffff19164263ffffffff16179055600a80548201905590506115938161409c565b6000600160801b82106138cd57600080fd5b5090565b60135460009081905b8015612b155780600190039050601381815481106138fa576138fa615a78565b60009182526020808320909101546001600160a01b03168083526016909152604090912054909350915081841015613950576001600160a01b038316600090815260166020526040902080548590039055612b15565b6001600160a01b03831660009081526016602052604081205561397381846141b4565b8184039350826001600160a01b031663f83d08ba6040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156139b357600080fd5b505af11580156139c7573d6000803e3d6000fd5b5050505080600014613a585760136139e0600183615a65565b815481106139f0576139f0615a78565b600091825260209091200154604051633dd217f760e21b8152600160048201526001600160a01b039091169063f7485fdc90602401600060405180830381600087803b158015613a3f57600080fd5b505af1158015613a53573d6000803e3d6000fd5b505050505b6138da565b80600080805b601354811015613b195760128181548110613a8057613a80615a78565b60009182526020909120601082040154600f9091166002026101000a900461ffff1691508115613b1157600e54613ac69086908490600160501b900462ffffff16613858565b9250826016600060138481548110613ae057613ae0615a78565b60009182526020808320909101546001600160a01b0316835282019290925260400190208054909101905592829003925b600101613a63565b50506010546001600160a01b03600160601b90910416600090815260166020526040902080549092019091555050565b60008115613b6c5781613b5f84620186a0615bde565b613b699190615c0b565b90505b7fe4cc9064635aa3e9263498b6ffb48bd2ad68b96a0e14efdbebc7d78590c682e0613b96826143b3565b600c8190556040516001600160501b03909116815260200160405180910390a1505050565b6000613bc684611003565b905080600003613c0c5760405162461bcd60e51b815260206004820152601160248201527044545f573a205a45524f5f53484152455360781b6044820152606401610ebe565b613c168282614435565b83600a6000828254613c289190615a65565b909155505060408051858152602081018390526001600160a01b03808516929086169133917ffbde797d201c681b91056529119e0b02407c7bb96a4a2c75c01fc9667232c8db910160405180910390a49392505050565b60007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f6004604051613cb19190615d08565b6040805191829003822060208301939093528101919091527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260c00160405160208183030381529060405280519060200120905090565b60006040516323b872dd60e01b81528460048201528360248201528260448201526020600060648360008a5af13d15601f3d1160016000511416171691505080613d9c5760405162461bcd60e51b81526020600482015260146024820152731514905394d1915497d19493d357d1905253115160621b6044820152606401610ebe565b5050505050565b600060405163a9059cbb60e01b8152836004820152826024820152602060006044836000895af13d15601f3d1160016000511416171691505080612b155760405162461bcd60e51b815260206004820152600f60248201526e1514905394d1915497d19052531151608a1b6044820152606401610ebe565b6000613e2683613649565b600b549091506001600160801b031615613ea857600b546001600160801b031683613e5084613534565b613e5a91906159f8565b1115613ea85760405162461bcd60e51b815260206004820152601960248201527f44545f443a20424f52524f575f4341505f4558434545444544000000000000006044820152606401610ebe565b613eb282826144b1565b82600a6000828254613ec491906159f8565b909155505060408051848152602081018390526001600160a01b0384169133917fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d7910160405180910390a392915050565b80600d613f228282615dc0565b505050565b600081600003613f405750670de0b6b3a7640000611b98565b82600003613f5057506000611b98565b613f61600160ff1b84106006614515565b82613f85613f7c68056bc75e2d63100000600160fe1b615c0b565b84106007614515565b82600082613fa367016345785d8a0000670de0b6b3a7640000615e82565b128015613fc85750613fc5670de0b6b3a764000067016345785d8a0000615ea2565b83125b15614031576000613fd884614523565b9050670de0b6b3a764000083613fee8284615eca565b613ff89190615ede565b6140029190615f0e565b83614015670de0b6b3a764000084615f0e565b61401f9190615ede565b6140299190615ea2565b915050614048565b8161403b8461475a565b6140459190615ede565b90505b61405a670de0b6b3a764000082615f0e565b905061408981680238fd42c5cf03ffff1913158015614082575068070c1cc73b00c800008213155b6008614515565b61409281614d40565b9695505050505050565b806000805b60135481101561414b576140f9601182815481106140c1576140c1615a78565b60009182526020909120601082040154600e548792600f166002026101000a90910461ffff1690600160281b900462ffffff16613858565b915081601660006013848154811061411357614113615a78565b60009182526020808320909101546001600160a01b0316835282019290925260400190208054909101905591819003916001016140a1565b50614155836138bb565b600e80546001600160801b03600160781b808304821690940116909202600160781b600160f81b0319909216919091179055506010546001600160a01b03600160601b9091041660009081526016602052604090208054909101905550565b601182815481106141c7576141c7615a78565b90600052602060002090601091828204019190066002029054906101000a900461ffff1661ffff16600e60058282829054906101000a900462ffffff1661420e9190615c8d565b92506101000a81548162ffffff021916908362ffffff1602179055506012828154811061423d5761423d615a78565b90600052602060002090601091828204019190066002029054906101000a900461ffff1661ffff16600e600a8282829054906101000a900462ffffff166142849190615c8d565b825462ffffff9182166101009390930a9283029190920219909116179055506001600160a01b0381166000908152601460205260409020805460ff1916905560118054806142d4576142d4615f3c565b600082815260209020601060001990920191820401805461ffff6002600f8516026101000a02191690559055601280548061431157614311615f3c565b600082815260209020601060001990920191820401805461ffff6002600f8516026101000a02191690559055601380548061434e5761434e615f3c565b6000828152602090819020600019908301810180546001600160a01b03191690559091019091556040516001600160a01b03831681527f14254003b9294c30e1b403adc733441503a0aecf4ff410885229833defef329a910160405180910390a15050565b600d54600090600160d81b900464ffffffffff1682106144115750600d54620186a0600160901b82046001600160481b03908116600160d81b840464ffffffffff169485900302600160481b84048216909402939093010491160190565b50600d54620186a06001600160481b03600160481b83048116939093020491160190565b6001600160a01b0382166000908152600760205260408120805483929061445d908490615a65565b90915550506006805482900390556040518181526000906001600160a01b038416907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef906020015b60405180910390a35050565b80600660008282546144c391906159f8565b90915550506001600160a01b0382166000818152600760209081526040808320805486019055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91016144a5565b81611d1057611d1081615377565b6000614537670de0b6b3a764000083615ede565b915060006145536a0c097ce7bc90715b34b9f160241b84615ea2565b6a0c097ce7bc90715b34b9f160241b61456c8186615e82565b6145769190615ede565b6145809190615f0e565b905060006a0c097ce7bc90715b34b9f160241b61459d8380615ede565b6145a79190615f0e565b905081806a0c097ce7bc90715b34b9f160241b6145c48483615ede565b6145ce9190615f0e565b91506145db600383615f0e565b6145e59082615ea2565b90506a0c097ce7bc90715b34b9f160241b6146008484615ede565b61460a9190615f0e565b9150614617600583615f0e565b6146219082615ea2565b90506a0c097ce7bc90715b34b9f160241b61463c8484615ede565b6146469190615f0e565b9150614653600783615f0e565b61465d9082615ea2565b90506a0c097ce7bc90715b34b9f160241b6146788484615ede565b6146829190615f0e565b915061468f600983615f0e565b6146999082615ea2565b90506a0c097ce7bc90715b34b9f160241b6146b48484615ede565b6146be9190615f0e565b91506146cb600b83615f0e565b6146d59082615ea2565b90506a0c097ce7bc90715b34b9f160241b6146f08484615ede565b6146fa9190615f0e565b9150614707600d83615f0e565b6147119082615ea2565b90506a0c097ce7bc90715b34b9f160241b61472c8484615ede565b6147369190615f0e565b9150614743600f83615f0e565b61474d9082615ea2565b9050614092816002615ede565b6000670de0b6b3a764000082121561479a5761479182614782670de0b6b3a764000080615ede565b61478c9190615f0e565b61475a565b611b9890615f52565b60006147c6670de0b6b3a7640000770195e54c5dd42177f53a27172fa9ec630262827000000000615ede565b8312614806576147ee770195e54c5dd42177f53a27172fa9ec63026282700000000084615f0e565b92506148036806f05b59d3b200000082615ea2565b90505b614824670de0b6b3a76400006b1425982cf597cd205cef7380615ede565b8312614858576148406b1425982cf597cd205cef738084615f0e565b92506148556803782dace9d900000082615ea2565b90505b614863606482615ede565b9050614870606484615ede565b92506e01855144814a7ff805980ff008400083126148cd576e01855144814a7ff805980ff00840006148ab68056bc75e2d6310000085615ede565b6148b59190615f0e565b92506148ca68ad78ebc5ac6200000082615ea2565b90505b6b02df0ab5a80a22c61ab5a7008312614922576b02df0ab5a80a22c61ab5a70061490068056bc75e2d6310000085615ede565b61490a9190615f0e565b925061491f6856bc75e2d63100000082615ea2565b90505b693f1fce3da636ea5cf850831261497357693f1fce3da636ea5cf85061495168056bc75e2d6310000085615ede565b61495b9190615f0e565b9250614970682b5e3af16b1880000082615ea2565b90505b690127fa27722cc06cc5e283126149c457690127fa27722cc06cc5e26149a268056bc75e2d6310000085615ede565b6149ac9190615f0e565b92506149c16815af1d78b58c40000082615ea2565b90505b68280e60114edb805d038312614a135768280e60114edb805d036149f168056bc75e2d6310000085615ede565b6149fb9190615f0e565b9250614a10680ad78ebc5ac620000082615ea2565b90505b680ebc5fb417461211108312614a6257680ebc5fb41746121110614a4068056bc75e2d6310000085615ede565b614a4a9190615f0e565b9250614a5f68056bc75e2d6310000082615ea2565b90505b6808f00f760a4b2db55d8312614ab1576808f00f760a4b2db55d614a8f68056bc75e2d6310000085615ede565b614a999190615f0e565b9250614aae6802b5e3af16b188000082615ea2565b90505b6806f5f17757889379378312614b00576806f5f1775788937937614ade68056bc75e2d6310000085615ede565b614ae89190615f0e565b9250614afd68015af1d78b58c4000082615ea2565b90505b6806248f33704b2866038312614b4e576806248f33704b286603614b2d68056bc75e2d6310000085615ede565b614b379190615f0e565b9250614b4b67ad78ebc5ac62000082615ea2565b90505b6805c548670b9510e7ac8312614b9c576805c548670b9510e7ac614b7b68056bc75e2d6310000085615ede565b614b859190615f0e565b9250614b996756bc75e2d631000082615ea2565b90505b6000614bb168056bc75e2d6310000085615ea2565b68056bc75e2d63100000614bc58187615e82565b614bcf9190615ede565b614bd99190615f0e565b9050600068056bc75e2d63100000614bf18380615ede565b614bfb9190615f0e565b9050818068056bc75e2d63100000614c138483615ede565b614c1d9190615f0e565b9150614c2a600383615f0e565b614c349082615ea2565b905068056bc75e2d63100000614c4a8484615ede565b614c549190615f0e565b9150614c61600583615f0e565b614c6b9082615ea2565b905068056bc75e2d63100000614c818484615ede565b614c8b9190615f0e565b9150614c98600783615f0e565b614ca29082615ea2565b905068056bc75e2d63100000614cb88484615ede565b614cc29190615f0e565b9150614ccf600983615f0e565b614cd99082615ea2565b905068056bc75e2d63100000614cef8484615ede565b614cf99190615f0e565b9150614d06600b83615f0e565b614d109082615ea2565b9050614d1d600282615ede565b90506064614d2b8287615ea2565b614d359190615f0e565b979650505050505050565b6000614d6f680238fd42c5cf03ffff198312158015614d68575068070c1cc73b00c800008313155b6009614515565b6000821215614da557614d89614d8483615f52565b614d40565b614d9b670de0b6b3a764000080615ede565b611b989190615f0e565b60006806f05b59d3b20000008312614dec57614dca6806f05b59d3b200000084615e82565b9250770195e54c5dd42177f53a27172fa9ec6302628270000000009050614e29565b6803782dace9d90000008312614e2557614e0f6803782dace9d900000084615e82565b92506b1425982cf597cd205cef73809050614e29565b5060015b614e34606484615ede565b925068056bc75e2d6310000068ad78ebc5ac620000008412614e9557614e6368ad78ebc5ac6200000085615e82565b935068056bc75e2d63100000614e886e01855144814a7ff805980ff008400083615ede565b614e929190615f0e565b90505b6856bc75e2d6310000008412614ee757614eb86856bc75e2d63100000085615e82565b935068056bc75e2d63100000614eda6b02df0ab5a80a22c61ab5a70083615ede565b614ee49190615f0e565b90505b682b5e3af16b188000008412614f3757614f0a682b5e3af16b1880000085615e82565b935068056bc75e2d63100000614f2a693f1fce3da636ea5cf85083615ede565b614f349190615f0e565b90505b6815af1d78b58c4000008412614f8757614f5a6815af1d78b58c40000085615e82565b935068056bc75e2d63100000614f7a690127fa27722cc06cc5e283615ede565b614f849190615f0e565b90505b680ad78ebc5ac62000008412614fd657614faa680ad78ebc5ac620000085615e82565b935068056bc75e2d63100000614fc968280e60114edb805d0383615ede565b614fd39190615f0e565b90505b68056bc75e2d63100000841261502557614ff968056bc75e2d6310000085615e82565b935068056bc75e2d63100000615018680ebc5fb4174612111083615ede565b6150229190615f0e565b90505b6802b5e3af16b18800008412615074576150486802b5e3af16b188000085615e82565b935068056bc75e2d631000006150676808f00f760a4b2db55d83615ede565b6150719190615f0e565b90505b68015af1d78b58c4000084126150c35761509768015af1d78b58c4000085615e82565b935068056bc75e2d631000006150b66806f5f177578893793783615ede565b6150c09190615f0e565b90505b68056bc75e2d63100000846150d88183615ea2565b9150600268056bc75e2d631000006150f08884615ede565b6150fa9190615f0e565b6151049190615f0e565b90506151108183615ea2565b9150600368056bc75e2d631000006151288884615ede565b6151329190615f0e565b61513c9190615f0e565b90506151488183615ea2565b9150600468056bc75e2d631000006151608884615ede565b61516a9190615f0e565b6151749190615f0e565b90506151808183615ea2565b9150600568056bc75e2d631000006151988884615ede565b6151a29190615f0e565b6151ac9190615f0e565b90506151b88183615ea2565b9150600668056bc75e2d631000006151d08884615ede565b6151da9190615f0e565b6151e49190615f0e565b90506151f08183615ea2565b9150600768056bc75e2d631000006152088884615ede565b6152129190615f0e565b61521c9190615f0e565b90506152288183615ea2565b9150600868056bc75e2d631000006152408884615ede565b61524a9190615f0e565b6152549190615f0e565b90506152608183615ea2565b9150600968056bc75e2d631000006152788884615ede565b6152829190615f0e565b61528c9190615f0e565b90506152988183615ea2565b9150600a68056bc75e2d631000006152b08884615ede565b6152ba9190615f0e565b6152c49190615f0e565b90506152d08183615ea2565b9150600b68056bc75e2d631000006152e88884615ede565b6152f29190615f0e565b6152fc9190615f0e565b90506153088183615ea2565b9150600c68056bc75e2d631000006153208884615ede565b61532a9190615f0e565b6153349190615f0e565b90506153408183615ea2565b915060648468056bc75e2d631000006153598587615ede565b6153639190615f0e565b61536d9190615ede565b6140929190615f0e565b6030600a820601600a820491506030600a830601600a830492506030600a8406018060101b8260081b8401016642414c230000000160c81b9250505062461bcd60e51b600052602060045260076024528060445260646000fd5b6000602082840312156153e357600080fd5b81356001600160601b0381168114610fe157600080fd5b600060208083528351808285015260005b818110156154275785810183015185820160400152820161540b565b506000604082860101526040601f19601f8301168501019250505092915050565b60006020828403121561545a57600080fd5b5035919050565b6001600160a01b038116811461159357600080fd5b6000806040838503121561548957600080fd5b823561549481615461565b946020939093013593505050565b801515811461159357600080fd5b600080604083850312156154c357600080fd5b8235915060208301356154d5816154a2565b809150509250929050565b60008060008060008060c087890312156154f957600080fd5b863561550481615461565b9550602087013561551481615461565b95989597505050506040840135936060810135936080820135935060a0909101359150565b60006020828403121561554b57600080fd5b8135610fe181615461565b60006020828403121561556857600080fd5b81356001600160801b0381168114610fe157600080fd5b803560ff81168114611b8857600080fd5b6000602082840312156155a257600080fd5b610fe18261557f565b6000806000606084860312156155c057600080fd5b83356155cb81615461565b925060208401356155db81615461565b929592945050506040919091013590565b600080600080600060a0868803121561560457600080fd5b853561560f816154a2565b9450602086013561561f816154a2565b9350604086013561562f816154a2565b9250606086013561563f816154a2565b9150608086013561564f816154a2565b809150509295509295909350565b6000806040838503121561567057600080fd5b8235915060208301356154d581615461565b60006020828403121561569457600080fd5b81356001600160501b0381168114610fe157600080fd5b600080604083850312156156be57600080fd5b50508035926020909101359150565b80356001600160e81b031981168114611b8857600080fd5b60008060008060008060a087890312156156fe57600080fd5b86359550602087013561571081615461565b9450604087013561572081615461565b9350606087013567ffffffffffffffff8082111561573d57600080fd5b818901915089601f83011261575157600080fd5b81358181111561576057600080fd5b8a602082850101111561577257600080fd5b60208301955080945050505061578a608088016156cd565b90509295509295509295565b803561ffff81168114611b8857600080fd5b6000602082840312156157ba57600080fd5b610fe182615796565b600080600080608085870312156157d957600080fd5b8435935060208501356157eb81615461565b925060408501356157fb81615461565b9150615809606086016156cd565b905092959194509250565b60008060006060848603121561582957600080fd5b833561583481615461565b925060208401359150604084013561584b81615461565b809150509250925092565b60008060006060848603121561586b57600080fd5b833561587681615461565b925061588460208501615796565b915061589260408501615796565b90509250925092565b600080604083850312156158ae57600080fd5b823591506158be60208401615796565b90509250929050565b6000806000606084860312156158dc57600080fd5b8335925060208401356158ee81615461565b9150604084013561584b81615461565b60008060006060848603121561591357600080fd5b833561591e81615461565b925060208401356158ee81615461565b60006080828403121561594057600080fd5b50919050565b600080600080600080600060e0888a03121561596157600080fd5b873561596c81615461565b9650602088013561597c81615461565b955060408801359450606088013593506159986080890161557f565b925060a0880135915060c0880135905092959891949750929550565b600080604083850312156159c757600080fd5b82356159d281615461565b915060208301356154d581615461565b634e487b7160e01b600052601160045260246000fd5b80820180821115611b9857611b986159e2565b6020808252600c908201526b15539055551213d49256915160a21b604082015260600190565b600181811c90821680615a4557607f821691505b60208210810361594057634e487b7160e01b600052602260045260246000fd5b81810381811115611b9857611b986159e2565b634e487b7160e01b600052603260045260246000fd5b600060208284031215615aa057600080fd5b5051919050565b6001600160801b03828116828216039080821115615ac757615ac76159e2565b5092915050565b600181815b80851115615b09578160001904821115615aef57615aef6159e2565b80851615615afc57918102915b93841c9390800290615ad3565b509250929050565b600082615b2057506001611b98565b81615b2d57506000611b98565b8160018114615b435760028114615b4d57615b69565b6001915050611b98565b60ff841115615b5e57615b5e6159e2565b50506001821b611b98565b5060208310610133831016604e8410600b8410161715615b8c575081810a611b98565b615b968383615ace565b8060001904821115615baa57615baa6159e2565b029392505050565b6000610fe160ff841683615b11565b600060208284031215615bd357600080fd5b8151610fe181615461565b8082028115828204841417611b9857611b986159e2565b634e487b7160e01b600052601260045260246000fd5b600082615c1a57615c1a615bf5565b500490565b6001600160a01b03841681526040602082018190528101829052818360608301376000818301606090810191909152601f909201601f1916010192915050565b60008060408385031215615c7257600080fd5b8251615c7d81615461565b6020939093015192949293505050565b62ffffff828116828216039080821115615ac757615ac76159e2565b62ffffff818116838216019080821115615ac757615ac76159e2565b600080600060608486031215615cda57600080fd5b8351615ce5816154a2565b6020850151909350615cf681615461565b80925050604084015190509250925092565b600080835481600182811c915080831680615d2457607f831692505b60208084108203615d4357634e487b7160e01b86526022600452602486fd5b818015615d575760018114615d6c57615d99565b60ff1986168952841515850289019650615d99565b60008a81526020902060005b86811015615d915781548b820152908501908301615d78565b505084890196505b509498975050505050505050565b600081356001600160481b0381168114611b9857600080fd5b6001600160481b03615dd183615da7565b168154816001600160481b0319821617835571ffffffffffffffffff000000000000000000615e0260208601615da7565b60481b16808371ffffffffffffffffffffffffffffffffffff198416171784556001600160481b0360901b615e3960408701615da7565b60901b1664ffffffffff60d81b81858286161784171786556060870135935064ffffffffff84168414615e6b57600080fd5b808460d81b16858417831717865550505050505050565b8181036000831280158383131683831282161715615ac757615ac76159e2565b8082018281126000831280158216821582161715615ec257615ec26159e2565b505092915050565b600082615ed957615ed9615bf5565b500790565b80820260008212600160ff1b84141615615efa57615efa6159e2565b8181058314821517611b9857611b986159e2565b600082615f1d57615f1d615bf5565b600160ff1b821460001984141615615f3757615f376159e2565b500590565b634e487b7160e01b600052603160045260246000fd5b6000600160ff1b8201615f6757615f676159e2565b506000039056fea26469706673582212209780f6277341e8b0493529fdc95bb4bd714f1a96ebea72b6e1cf82e72de3d42c64736f6c63430008110033000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000beb56fbef3387af554a554e7db25830eb7b92e3200000000000000000000000000cb53780ea58503d3059fc02ddd596d0be926cb000000000000000000000000d2a34731586bd10b645f870f4c9dcaf4f9e3823c

Deployed Bytecode

0x608060405234801561001057600080fd5b50600436106105665760003560e01c80638456cb59116102ca578063b78891571161018d578063ce96cb77116100f4578063e11a0b83116100ad578063f0f4426011610087578063f0f4426014610e26578063f2fde38b14610e39578063f7b188a514610e4c578063f89d36a514610e5457600080fd5b8063e11a0b8314610df8578063e2dd93a214610e00578063ef8b30f714610e1357600080fd5b8063ce96cb7714610d43578063d505accf14610d56578063d53dc73914610d69578063d8a06f7314610d7d578063d905777e14610da4578063dd62ed3e14610dcd57600080fd5b8063bfcc565711610146578063bfcc565714610cef578063c11002df14610d02578063c63d75b614610872578063c6e6f59214610d15578063cd387b9814610d28578063ce76756f14610d3b57600080fd5b8063b788915714610c6d578063b8bb5c4214610c82578063ba08765214610c3c578063baf5dc4414610c97578063bc861ab714610cc8578063bcb4bbea14610cdb57600080fd5b806395d89b4111610231578063acb70815116101ea578063acb7081514610be4578063ad84f34114610bf7578063b17935f514610c00578063b3d7f6b914610c29578063b460af9414610c3c578063b73c02ff14610c4a57600080fd5b806395d89b4114610b735780639790576a14610b7b578063980a3f7714610b9e5780639bf4964c14610bb15780639f4020d914610bd1578063a9059cbb146105e757600080fd5b80638da5cb5b116102835780638da5cb5b14610af55780638e33f5ee14610b085780638f69a5c514610b3a5780638f770ad014610b4d5780639086c3a114610b6057806394bf804d146109d857600080fd5b80638456cb5914610a555780638618d38d14610a5d5780638710e70c14610a77578063894bacc914610a8a5780638994685f14610a9d5780638c48052314610ab057600080fd5b806336a36ea41161042d5780634e1255f31161039457806362c9b0f01161034d57806372b5e9231161032757806372b5e92314610a065780637bfbb80214610a195780637c3a00fd14610a2c5780637ecebe0014610a3557600080fd5b806362c9b0f0146109c55780636e553f65146109d857806370a08231146109e657600080fd5b80634e1255f314610937578063542b5fd31461094a5780635b6a14951461095f5780635ef904071461098a57806361d027b3146109a0578063626d6f5e146109ba57600080fd5b80634046ebae116103e65780634046ebae1461088757806340573f6e146108ae57806344d9dca6146108d3578063452a9320146108fe5780634cdad506146109115780634da1f9a81461092457600080fd5b806336a36ea4146107d357806338bfd64d146107f957806338d52e0f1461080e5780633c4750df146108355780633f7ee87314610848578063402d267d1461087257600080fd5b80631bd43293116104d15780632db6c63a1161048a5780632db6c63a146107385780632f3ffb9f146107585780632fcb4f041461076c578063306caf961461077f578063313ce567146107925780633644e515146107cb57600080fd5b80631bd43293146106bd5780631dd19cb4146106d05780631e865815146106d85780631e9dbce6146106eb57806323b872dd146106ff57806326c259621461070d57600080fd5b80630a28a477116105235780630a28a477146105fa578063165bf8c51461060d57806318160ddd14610620578063182bfd20146106295780631919e78b1461063c578063194d7494146106aa57600080fd5b806301e1d1141461056b57806302befd241461058657806302d37a2f146105aa57806306fdde03146105bf57806307a2d13a146105d4578063095ea7b3146105e7575b600080fd5b610573610e5d565b6040519081526020015b60405180910390f35b60015461059a90600160b81b900460ff1681565b604051901515815260200161057d565b6105bd6105b83660046153d1565b610e94565b005b6105c7610f2d565b60405161057d91906153fa565b6105736105e2366004615448565b610fbb565b61059a6105f5366004615476565b610fe8565b610573610608366004615448565b611003565b6105bd61061b3660046154b0565b611023565b61057360065481565b6105bd6106373660046154e0565b6110a7565b600d54610673906001600160481b0380821691600160481b8104821691600160901b82041690600160d81b900464ffffffffff1684565b604080516001600160481b0395861681529385166020850152919093169082015264ffffffffff909116606082015260800161057d565b6105bd6106b8366004615539565b61135a565b6105bd6106cb366004615556565b611596565b6105bd61160e565b6105bd6106e6366004615590565b61179d565b60015461059a90600160a01b900460ff1681565b61059a6105f53660046155ab565b61072061071b366004615448565b611817565b6040516001600160a01b03909116815260200161057d565b610573610746366004615539565b60166020526000908152604090205481565b60015461059a90600160a81b900460ff1681565b6105bd61077a366004615539565b611841565b6105bd61078d3660046155ec565b6118c7565b6107b97f000000000000000000000000000000000000000000000000000000000000000681565b60405160ff909116815260200161057d565b610573611a6a565b6107e66107e1366004615448565b611ac0565b60405161ffff909116815260200161057d565b600e546107e690600160681b900461ffff1681565b6107207f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4881565b610573610843366004615539565b611af8565b600e5461085e90600160281b900462ffffff1681565b60405162ffffff909116815260200161057d565b610573610880366004615539565b5060001990565b6107207f000000000000000000000000d2a34731586bd10b645f870f4c9dcaf4f9e3823c81565b600e546108be9063ffffffff1681565b60405163ffffffff909116815260200161057d565b600b546108e6906001600160801b031681565b6040516001600160801b03909116815260200161057d565b600154610720906001600160a01b031681565b61057361091f366004615448565b611b8d565b6105bd61093236600461565d565b611b9e565b6105bd610945366004615682565b611d14565b6010546107e690600160501b900461ffff1681565b601054610972906001600160501b031681565b6040516001600160501b03909116815260200161057d565b600e5461085e90600160501b900462ffffff1681565b60105461072090600160601b90046001600160a01b031681565b6105736301e1338081565b6105bd6109d336600461565d565b611d8f565b6105736105f536600461565d565b6105736109f4366004615539565b60076020526000908152604090205481565b6105bd610a143660046156ab565b611ee4565b6105bd610a273660046156e5565b61215a565b610573600c5481565b610573610a43366004615539565b60096020526000908152604090205481565b6105bd612536565b600e546108e690600160781b90046001600160801b031681565b6105bd610a853660046157a8565b612654565b610573610a98366004615539565b612720565b6105bd610aab3660046157c3565b61272a565b610ac3610abe366004615448565b612b1b565b60405161057d949392919093151584526001600160a01b03928316602085015291166040830152606082015260800190565b600054610720906001600160a01b031681565b600f54610b2290600160801b90046001600160601b031681565b6040516001600160601b03909116815260200161057d565b6105bd610b483660046157a8565b612b9e565b600f546108e6906001600160801b031681565b6105bd610b6e366004615814565b612c71565b6105c7612db8565b61059a610b89366004615539565b60146020526000908152604090205460ff1681565b6105bd610bac366004615856565b612dc5565b610573610bbf366004615539565b60156020526000908152604090205481565b6105bd610bdf36600461589b565b613050565b6105bd610bf236600461565d565b61320d565b61057360025481565b610720610c0e366004615539565b6017602052600090815260409020546001600160a01b031681565b610573610c37366004615448565b613303565b6105736105f53660046158c7565b61059a610c58366004615448565b60036020526000908152604090205460ff1681565b600e546107e690600160401b900461ffff1681565b600e546107b990640100000000900460ff1681565b610573610ca53660046158fe565b601860209081526000938452604080852082529284528284209052825290205481565b6105bd610cd636600461592e565b613322565b60015461059a90600160b01b900460ff1681565b6105bd610cfd36600461589b565b613355565b610573610d10366004615539565b6134d1565b610573610d23366004615448565b6134dc565b6107e6610d36366004615448565b6134fc565b6105bd61350c565b610573610d51366004615539565b613534565b6105bd610d64366004615946565b613556565b60015461059a90600160c01b900460ff1681565b6107207f00000000000000000000000000cb53780ea58503d3059fc02ddd596d0be926cb81565b610573610db2366004615539565b6001600160a01b031660009081526007602052604090205490565b610573610ddb3660046159b4565b600860209081526000928352604080842090915290825290205481565b61057361356f565b6105bd610e0e366004615556565b6135d1565b610573610e21366004615448565b613649565b6105bd610e34366004615539565b613654565b6105bd610e47366004615539565b6136a6565b6105bd61371b565b610573600a5481565b600e546000904263ffffffff908116911614610e8d57610e7b61356f565b600a54610e8891906159f8565b905090565b50600a5490565b6000546001600160a01b03163314610ec75760405162461bcd60e51b8152600401610ebe90615a0b565b60405180910390fd5b600f80546bffffffffffffffffffffffff60801b1916600160801b6001600160601b038416908102919091179091556040519081527fce76ed33b01ab134c41431ef53932d4130aaf7a443840d0630b94a7474fe19dc906020015b60405180910390a150565b60048054610f3a90615a31565b80601f0160208091040260200160405190810160405280929190818152602001828054610f6690615a31565b8015610fb35780601f10610f8857610100808354040283529160200191610fb3565b820191906000526020600020905b815481529060010190602001808311610f9657829003601f168201915b505050505081565b6006546000908015610fdf57610fda610fd2610e5d565b849083613832565b610fe1565b825b9392505050565b600060405163ced4f63360e01b815260040160405180910390fd5b6006546000908015610fdf57610fda8161101b610e5d565b859190613858565b6000546001600160a01b0316331461104d5760405162461bcd60e51b8152600401610ebe90615a0b565b6000828152600360205260409020805460ff1916821515179055817f6bd62b850d20e8a0251cb2759fd0ebad03703967c804dabab97f9238a0e40e258260405161109b911515815260200190565b60405180910390a25050565b7f000000000000000000000000d2a34731586bd10b645f870f4c9dcaf4f9e3823c6001600160a01b031633146111155760405162461bcd60e51b815260206004820152601360248201527226281d1027b7363c903634b8bab4b230ba37b960691b6044820152606401610ebe565b61111d613876565b6001600160a01b0380871660009081526017602090815260408083205490931682526016905290812080548592906111569084906159f8565b909155505083156111c857600e54611194908590611185908690600160781b90046001600160801b03166159f8565b61118f9190615a65565b6138bb565b600e600f6101000a8154816001600160801b0302191690836001600160801b031602179055506111c3846138d1565b61126a565b6111d182613a5d565b600e5461120b90829084906111f7908790600160781b90046001600160801b03166159f8565b61120191906159f8565b61118f91906159f8565b600e80546001600160801b0392909216600160781b02600160781b600160f81b0319909216919091179055801561126a576001600160a01b038516600090815260166020526040812080548392906112649084906159f8565b90915550505b6010805461ffff60501b198116600160501b9182900461ffff908116600019018116830291909117928390559104161580156112a7575060135415155b1561133257601380546112bc90600190615a65565b815481106112cc576112cc615a78565b6000918252602082200154604051633dd217f760e21b815260048101929092526001600160a01b03169063f7485fdc90602401600060405180830381600087803b15801561131957600080fd5b505af115801561132d573d6000803e3d6000fd5b505050505b600a54600e546113529190600160781b90046001600160801b0316613b49565b505050505050565b600154600160c01b900460ff16156113855760405163bbc5234f60e01b815260040160405180910390fd5b61138d613876565b600061139882613534565b9050806000036113ea5760405162461bcd60e51b815260206004820152601c60248201527f4c505f4c563a204e6f742061205661756c7420776974682064656274000000006044820152606401610ebe565b6001600160a01b038281166000818152601760205260409081902080546001600160a01b0319163317905560105490516378d6c03f60e01b81526004810192909252602482018490526001600160501b031660448201527f000000000000000000000000d2a34731586bd10b645f870f4c9dcaf4f9e3823c909116906378d6c03f90606401600060405180830381600087803b15801561148957600080fd5b505af115801561149d573d6000803e3d6000fd5b5050601054600160501b900461ffff166000039150611540905057601380546114c890600190615a65565b815481106114d8576114d8615a78565b600091825260209091200154604051633dd217f760e21b8152600160048201526001600160a01b039091169063f7485fdc90602401600060405180830381600087803b15801561152757600080fd5b505af115801561153b573d6000803e3d6000fd5b505050505b60108054600161ffff600160501b808404821692909201160261ffff60501b19909116179055611571818380613bbb565b5050600a54600e546115939190600160781b90046001600160801b0316613b49565b50565b6000546001600160a01b031633146115c05760405162461bcd60e51b8152600401610ebe90615a0b565b600b80546001600160801b0319166001600160801b0383169081179091556040519081527ff60cdb66d1290884d4b7cdeee8f7b4d52f8b62b9ff1d89ffc4678d00bc1e3a1490602001610f22565b611616613876565b601054600160501b900461ffff161561166a5760405162461bcd60e51b81526020600482015260166024820152754c505f533a2041756374696f6e73204f6e676f696e6760501b6044820152606401610ebe565b600e54600a546040516370a0823160e01b8152306004820152600092600160781b90046001600160801b031691907f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb486001600160a01b0316906370a0823190602401602060405180830381865afa1580156116e9573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061170d9190615a8e565b61171791906159f8565b6117219190615a65565b905061172c816138bb565b600e80546001600160801b03600160781b808304821690940181168402600160781b600160f81b03199092169190911782556010546001600160a01b03600160601b9091041660009081526016602052604090208054909401909355600a54905461179b939192900416613b49565b565b6000546001600160a01b031633146117c75760405162461bcd60e51b8152600401610ebe90615a0b565b600e805464ff00000000191664010000000060ff8416908102919091179091556040519081527f62815047fdec5b7ea69997c870fa83e53a213d8d485f2489b58c049eb76cfd1490602001610f22565b6013818154811061182757600080fd5b6000918252602090912001546001600160a01b0316905081565b6000546001600160a01b0316331461186b5760405162461bcd60e51b8152600401610ebe90615a0b565b6001546040516001600160a01b038084169216907fa14fc14d8620a708a896fd11392a235647d99385500a295f0d7da2a258b2e96790600090a3600180546001600160a01b0319166001600160a01b0392909216919091179055565b6000546001600160a01b031633146118f15760405162461bcd60e51b8152600401610ebe90615a0b565b600154600160a01b900460ff1680156119075750845b60018054911515600160a01b0260ff60a01b199092169190911790819055600160a81b900460ff1680156119385750835b60018054911515600160a81b0260ff60a81b199092169190911790819055600160b01b900460ff1680156119695750825b60018054911515600160b01b0260ff60b01b199092169190911790819055600160b81b900460ff16801561199a5750815b60018054911515600160b81b0260ff60b81b199092169190911790819055600160c01b900460ff1680156119cb5750805b6001805460ff60c01b1916600160c01b921515830217908190556040805160ff600160a01b8404811615158252600160a81b8404811615156020830152600160b01b84048116151592820192909252600160b81b83048216151560608201529290910416151560808201527f8502e0dfa7512c68fe07e3fd09dba9a9545c1e68fb13e18348da704c2fa7275e9060a00160405180910390a15050505050565b60007f00000000000000000000000000000000000000000000000000000000000000014614611a9b57610e88613c7f565b507fb026f7d2ee25084f34e4d50fad78bcd3d965960a0fe3fe6fb559d060cb136bf390565b60118181548110611ad057600080fd5b9060005260206000209060109182820401919006600202915054906101000a900461ffff1681565b600e546000904263ffffffff908116911614611b6d576001600160a01b038216600090815260156020526040812054600e54611b4a9190600160281b900462ffffff16611b4361356f565b9190613832565b6001600160a01b038416600090815260166020526040902054019150611b889050565b506001600160a01b0381166000908152601660205260409020545b919050565b6000611b9882610fbb565b92915050565b600154600160b81b900460ff1615611bc95760405163bbc5234f60e01b815260040160405180910390fd5b3360009081526014602052604090205460ff16611c1b5760405162461bcd60e51b815260206004820152601060248201526f4c503a204f6e6c79207472616e63686560801b6044820152606401610ebe565b611c23613876565b600f546001600160801b031615611c7957600f54600e546001600160801b0391821691611c5a918591600160781b909104166159f8565b1115611c7957604051638fd0b1ed60e01b815260040160405180910390fd5b611cae6001600160a01b037f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4816823085613d19565b336000908152601660205260409020805483019055611ccc826138bb565b600e80546001600160801b03600160781b808304821690940181168402600160781b600160f81b03199092169190911791829055600a54611d109390920416613b49565b5050565b6000546001600160a01b03163314611d3e5760405162461bcd60e51b8152600401610ebe90615a0b565b6010805469ffffffffffffffffffff19166001600160501b0383169081179091556040519081527fb459d4513fe6c441f14d1f873f0ac9e675919afdb60c6d63f158dd00fc294ecf90602001610f22565b600154600160a81b900460ff1615611dba5760405163bbc5234f60e01b815260040160405180910390fd5b611dc2613876565b33600090815260166020526040902054821115611e215760405162461bcd60e51b815260206004820152601f60248201527f4c505f57464c503a20416d6f756e7420657863656564732062616c616e6365006044820152606401610ebe565b33600090815260166020526040902080548390039055611e40826138bb565b600e8054600f90611e62908490600160781b90046001600160801b0316615aa7565b92506101000a8154816001600160801b0302191690836001600160801b03160217905550611ec481837f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb486001600160a01b0316613da39092919063ffffffff16565b600a54600e54611d109190600160781b90046001600160801b0316613b49565b600154600160b81b900460ff1615611f0f5760405163bbc5234f60e01b815260040160405180910390fd5b611f17613876565b60008111611f5d5760405162461bcd60e51b815260206004820152601360248201527204c505f4454543a20416d6f756e74206973203606c1b6044820152606401610ebe565b600f546001600160801b031615611fb357600f54600e546001600160801b0391821691611f94918491600160781b909104166159f8565b1115611fb357604051638fd0b1ed60e01b815260040160405180910390fd5b600060138381548110611fc857611fc8615a78565b6000918252602090912001546001600160a01b0316905061200a7f0000000000000000000000000000000000000000000000000000000000000006600a615bb2565b816001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612048573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061206c9190615a8e565b10156120ba5760405162461bcd60e51b815260206004820152601b60248201527f4c505f4454543a20496e73756666696369656e742073686172657300000000006044820152606401610ebe565b6120ef6001600160a01b037f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4816333085613d19565b6001600160a01b0381166000908152601660205260409020805483019055612116826138bb565b600e8054600160781b600160f81b03198116600160781b918290046001600160801b0390811694909401841682021791829055600a54611d10945092910416613b49565b600154600160b01b900460ff16156121855760405163bbc5234f60e01b815260040160405180910390fd5b61218d613876565b604051632724fe0960e01b81526001600160a01b0386811660048301526000917f00000000000000000000000000cb53780ea58503d3059fc02ddd596d0be926cb90911690632724fe0990602401602060405180830381865afa1580156121f8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061221c9190615bc1565b90506001600160a01b03811661226b5760405162461bcd60e51b8152602060048201526014602482015273131417d11055d30e88139bdd0818481d985d5b1d60621b6044820152606401610ebe565b600e546000906127109061228a90640100000000900460ff168a615bde565b6122949190615c0b565b61229e90896159f8565b90506001600160a01b0382163314612326576001600160a01b038088166000908152601860209081526040808320938616835292815282822033835290522054600019146123265760405162461bcd60e51b8152602060048201526015602482015274131417d11055d30e8815539055551213d492569151605a1b6044820152606401610ebe565b6123308188613e1b565b5061233c8882036138bb565b600e80546001600160801b03600160781b808304821690940116909202600160781b600160f81b03199092169190911790556010546001600160a01b03600160601b9091048116600090815260166020526040902080548a84030190556123c6907f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4816878a613da3565b600080886001600160a01b0316634d401a368989896040518463ffffffff1660e01b81526004016123f993929190615c1f565b60408051808303816000875af1158015612417573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061243b9190615c5f565b90925090506001600160a01b03821630148015612466575060008181526003602052604090205460ff165b6124a65760405162461bcd60e51b8152602060048201526011602482015270131417d11055d30e8814995d995c9d1959607a1b6044820152606401610ebe565b6001600160e81b03198516336001600160a01b038b167f921c81c17e72f815c88a3e0fa28e7e709d56f0c5832e17b4bcc606dc9ee1a6118b8e6124e9818a615a65565b604080516001600160a01b03909416845260208401929092529082015260600160405180910390a45050600a54600e546113529350909150600160781b90046001600160801b0316613b49565b6001546001600160a01b031633146125905760405162461bcd60e51b815260206004820152601760248201527f477561726469616e3a204f6e6c7920677561726469616e0000000000000000006044820152606401610ebe565b6002546125a090622a30006159f8565b42116125e25760405162461bcd60e51b8152602060048201526011602482015270475f503a2043616e6e6f7420706175736560781b6044820152606401610ebe565b6001805464ffffffffff60a01b191664010101010160a01b1781554260025560408051828152602081018390529081018290526060810182905260808101919091527f8502e0dfa7512c68fe07e3fd09dba9a9545c1e68fb13e18348da704c2fa7275e9060a0015b60405180910390a1565b6000546001600160a01b0316331461267e5760405162461bcd60e51b8152600401610ebe90615a0b565b600e5461ffff828116916126a691600160681b82041690600160501b900462ffffff16615c8d565b6126b09190615ca9565b600e805464ffffffffff60501b1916600160501b62ffffff939093169290920261ffff60681b191691909117600160681b61ffff8416908102919091179091556040519081527f37ff452135135f1d2c10b27bbd9d50b762f72d6184b09337bc9d38d093169c0390602001610f22565b6000611b6d613876565b600154600160b01b900460ff16156127555760405163bbc5234f60e01b815260040160405180910390fd5b61275d613876565b604051632724fe0960e01b81526001600160a01b0384811660048301526000917f00000000000000000000000000cb53780ea58503d3059fc02ddd596d0be926cb90911690632724fe0990602401602060405180830381865afa1580156127c8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127ec9190615bc1565b90506001600160a01b0381166128385760405162461bcd60e51b8152602060048201526011602482015270131417d08e88139bdd0818481d985d5b1d607a1b6044820152606401610ebe565b600e546000906127109061285790640100000000900460ff1688615bde565b6128619190615c0b565b61286b90876159f8565b90506001600160a01b03821633146128ef576001600160a01b03808616600090815260186020908152604080832093861683529281528282203383529052205460001981146128ed576128be8282615a65565b6001600160a01b0380881660009081526018602090815260408083209388168352928152828220338352905220555b505b6128f98186613e1b565b506129058682036138bb565b600e80546001600160801b03600160781b808304821690940116909202600160781b600160f81b03199092169190911790556010546001600160a01b03600160601b909104811660009081526016602052604081208054898503019055908190819088166317e62b67826129788b613534565b6040516001600160e01b031960e085901b16815260048101929092526024820152604401606060405180830381865afa1580156129b9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129dd9190615cc5565b9250925092508280156129f857506001600160a01b03821630145b8015612a12575060008181526003602052604090205460ff165b612a4f5760405162461bcd60e51b815260206004820152600e60248201526d131417d08e8814995d995c9d195960921b6044820152606401610ebe565b612a836001600160a01b037f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4816888b613da3565b6001600160e81b03198616336001600160a01b038a167f921c81c17e72f815c88a3e0fa28e7e709d56f0c5832e17b4bcc606dc9ee1a6118a8d612ac6818b615a65565b604080516001600160a01b03909416845260208401929092529082015260600160405180910390a45050600a54600e54612b159450909250600160781b90046001600160801b03169050613b49565b50505050565b60008181526003602052604081205481908190819060ff1615612b97575050600f54600192507f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4891507f000000000000000000000000d2a34731586bd10b645f870f4c9dcaf4f9e3823c90600160801b90046001600160601b03165b9193509193565b6000546001600160a01b03163314612bc85760405162461bcd60e51b8152600401610ebe90615a0b565b600e5461ffff82811691612bf091600160401b82041690600160281b900462ffffff16615c8d565b612bfa9190615ca9565b600e805469ffffffffff00000000001916600160281b62ffffff939093169290920269ffff0000000000000000191691909117600160401b61ffff8416908102919091179091556040519081527f553cb4d921add3331757ed1c44f851dcfab622fbc4975007ed008dce680ffe4790602001610f22565b604051632724fe0960e01b81526001600160a01b03828116600483015233917f00000000000000000000000000cb53780ea58503d3059fc02ddd596d0be926cb90911690632724fe0990602401602060405180830381865afa158015612cdb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612cff9190615bc1565b6001600160a01b031614612d4b5760405162461bcd60e51b8152602060048201526013602482015272131417d0508e8815539055551213d492569151606a1b6044820152606401610ebe565b6001600160a01b0381811660008181526018602090815260408083203380855290835281842095891680855295835292819020879055518681529192917f9c3c3fddd897f6c3dce14f62fcc742f199fb00b47c0664b980cbdea1be127411910160405180910390a4505050565b60058054610f3a90615a31565b6000546001600160a01b03163314612def5760405162461bcd60e51b8152600401610ebe90615a0b565b6001600160a01b03831660009081526014602052604090205460ff1615612e505760405162461bcd60e51b815260206004820152601560248201527454525f41443a20416c72656164792065786973747360581b6044820152606401610ebe565b8161ffff16600e60058282829054906101000a900462ffffff16612e749190615ca9565b825462ffffff91821661010093840a90810290830219909116179092556011805460018101909155601081047f31ecc21a745e3968a04e9570e4425bc18fa8019c68028196b546d1669c200c6801805461ffff8089166002600f9095169490940290940a838102908502199091161790556001600160a01b038716600090815260156020526040902055600e8054918516935091600a91612f1e918591600160501b900416615ca9565b825461010092830a62ffffff818102199092169290911602179091556012805460018181019092557fbb8a6a4669ba250d26cd7a459eca9d215f8307e33aebe50379bc5a3617ec344460108204018054600f90921660020290930a61ffff8181021990921691861602179091556013805480830182557f66de8ffda797e3de9c05e8fc57b3bf0ec28a930d40b0d285d93c06501cf6a0900180546001600160a01b0319166001600160a01b0388169081179091556000908152601460205260409020805460ff19168317905554612ff59250615a65565b60ff16836001600160a01b03167f5f77a2c0fccc0d2bdab612b4afae9f6108ce73d48f2ea671605aa7191aa60b58848460405161304392919061ffff92831681529116602082015260400190565b60405180910390a3505050565b6000546001600160a01b0316331461307a5760405162461bcd60e51b8152600401610ebe90615a0b565b60135482106130cb5760405162461bcd60e51b815260206004820152601c60248201527f54525f5349573a204e6f6e204578697374696e67205472616e636865000000006044820152606401610ebe565b8061ffff16601183815481106130e3576130e3615a78565b90600052602060002090601091828204019190066002029054906101000a900461ffff1661ffff16600e60059054906101000a900462ffffff166131279190615c8d565b6131319190615ca9565b600e60056101000a81548162ffffff021916908362ffffff160217905550806011838154811061316357613163615a78565b90600052602060002090601091828204019190066002026101000a81548161ffff021916908361ffff1602179055508061ffff1660156000601385815481106131ae576131ae615a78565b6000918252602080832091909101546001600160a01b03168352828101939093526040918201902092909255905161ffff8316815283917f7283d16027b080a3c9be9ae5695b23b19ef3e5066059566674e4680bacf3c8ca910161109b565b600154600160a01b900460ff16156132385760405163bbc5234f60e01b815260040160405180910390fd5b613240613876565b600061324b82613534565b9050600083821161325c578161325e565b835b90506132956001600160a01b037f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4816333084613d19565b6132a0818485613bbb565b5060405181815233906001600160a01b038516907f05f2eeda0e08e4b437f487c8d7d29b14537d15e3488170dc3de5dbdf8dac46849060200160405180910390a35050600a54600e54611d109190600160781b90046001600160801b0316613b49565b6006546000908015610fdf57610fda61331a610e5d565b849083613858565b6000546001600160a01b0316331461334c5760405162461bcd60e51b8152600401610ebe90615a0b565b61159381613f15565b6000546001600160a01b0316331461337f5760405162461bcd60e51b8152600401610ebe90615a0b565b60135482106133d05760405162461bcd60e51b815260206004820152601c60248201527f54525f534c573a204e6f6e204578697374696e67205472616e636865000000006044820152606401610ebe565b8061ffff16601283815481106133e8576133e8615a78565b90600052602060002090601091828204019190066002029054906101000a900461ffff1661ffff16600e600a9054906101000a900462ffffff1661342c9190615c8d565b6134369190615ca9565b600e600a6101000a81548162ffffff021916908362ffffff160217905550806012838154811061346857613468615a78565b90600052602060002090601091828204019190066002026101000a81548161ffff021916908361ffff160217905550817fa0bb5ed3a1177ecbc7a7ee676d73ea48b239c9261b6e5b6d781c263e71f0b9018260405161109b919061ffff91909116815260200190565b6000611b9882613534565b6006546000908015610fdf57610fda816134f4610e5d565b859190613832565b60128181548110611ad057600080fd5b613514613876565b600a54600e5461179b9190600160781b90046001600160801b0316613b49565b6001600160a01b038116600090815260076020526040812054611b9890610fbb565b60405163ced4f63360e01b815260040160405180910390fd5b600c54600e54600091670de0b6b3a7640000908101916301e1338063ffffffff909116420382020490806135a38484613f27565b03600a5402816135b5576135b5615bf5565b0492506135c1836138bb565b6001600160801b03169250505090565b6000546001600160a01b031633146135fb5760405162461bcd60e51b8152600401610ebe90615a0b565b600f80546001600160801b0319166001600160801b0383169081179091556040519081527fb01769936feb4d3129c98c6f606578713d8b445ff96e0a744154ab58efb15e5090602001610f22565b6000611b98826134dc565b6000546001600160a01b0316331461367e5760405162461bcd60e51b8152600401610ebe90615a0b565b601080546001600160a01b03909216600160601b026001600160601b03909216919091179055565b6000546001600160a01b031633146136d05760405162461bcd60e51b8152600401610ebe90615a0b565b600080546001600160a01b0319166001600160a01b0383169081178255604051909133917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a350565b60025461372b9062278d006159f8565b42116137705760405162461bcd60e51b8152602060048201526014602482015273475f55503a2043616e6e6f7420756e506175736560601b6044820152606401610ebe565b600154600160a01b900460ff16806137915750600154600160a81b900460ff165b806137a55750600154600160b01b900460ff165b806137b95750600154600160b81b900460ff165b806137cd5750600154600160c01b900460ff165b1561179b576001805464ffffffffff60a01b19169055604080516000808252602082018190529181018290526060810182905260808101919091527f8502e0dfa7512c68fe07e3fd09dba9a9545c1e68fb13e18348da704c2fa7275e9060a00161264a565b600082600019048411830215820261384957600080fd5b50910281810615159190040190565b600082600019048411830215820261386f57600080fd5b5091020490565b600e544263ffffffff90811691161461179b57600061389361356f565b600e805463ffffffff19164263ffffffff16179055600a80548201905590506115938161409c565b6000600160801b82106138cd57600080fd5b5090565b60135460009081905b8015612b155780600190039050601381815481106138fa576138fa615a78565b60009182526020808320909101546001600160a01b03168083526016909152604090912054909350915081841015613950576001600160a01b038316600090815260166020526040902080548590039055612b15565b6001600160a01b03831660009081526016602052604081205561397381846141b4565b8184039350826001600160a01b031663f83d08ba6040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156139b357600080fd5b505af11580156139c7573d6000803e3d6000fd5b5050505080600014613a585760136139e0600183615a65565b815481106139f0576139f0615a78565b600091825260209091200154604051633dd217f760e21b8152600160048201526001600160a01b039091169063f7485fdc90602401600060405180830381600087803b158015613a3f57600080fd5b505af1158015613a53573d6000803e3d6000fd5b505050505b6138da565b80600080805b601354811015613b195760128181548110613a8057613a80615a78565b60009182526020909120601082040154600f9091166002026101000a900461ffff1691508115613b1157600e54613ac69086908490600160501b900462ffffff16613858565b9250826016600060138481548110613ae057613ae0615a78565b60009182526020808320909101546001600160a01b0316835282019290925260400190208054909101905592829003925b600101613a63565b50506010546001600160a01b03600160601b90910416600090815260166020526040902080549092019091555050565b60008115613b6c5781613b5f84620186a0615bde565b613b699190615c0b565b90505b7fe4cc9064635aa3e9263498b6ffb48bd2ad68b96a0e14efdbebc7d78590c682e0613b96826143b3565b600c8190556040516001600160501b03909116815260200160405180910390a1505050565b6000613bc684611003565b905080600003613c0c5760405162461bcd60e51b815260206004820152601160248201527044545f573a205a45524f5f53484152455360781b6044820152606401610ebe565b613c168282614435565b83600a6000828254613c289190615a65565b909155505060408051858152602081018390526001600160a01b03808516929086169133917ffbde797d201c681b91056529119e0b02407c7bb96a4a2c75c01fc9667232c8db910160405180910390a49392505050565b60007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f6004604051613cb19190615d08565b6040805191829003822060208301939093528101919091527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260c00160405160208183030381529060405280519060200120905090565b60006040516323b872dd60e01b81528460048201528360248201528260448201526020600060648360008a5af13d15601f3d1160016000511416171691505080613d9c5760405162461bcd60e51b81526020600482015260146024820152731514905394d1915497d19493d357d1905253115160621b6044820152606401610ebe565b5050505050565b600060405163a9059cbb60e01b8152836004820152826024820152602060006044836000895af13d15601f3d1160016000511416171691505080612b155760405162461bcd60e51b815260206004820152600f60248201526e1514905394d1915497d19052531151608a1b6044820152606401610ebe565b6000613e2683613649565b600b549091506001600160801b031615613ea857600b546001600160801b031683613e5084613534565b613e5a91906159f8565b1115613ea85760405162461bcd60e51b815260206004820152601960248201527f44545f443a20424f52524f575f4341505f4558434545444544000000000000006044820152606401610ebe565b613eb282826144b1565b82600a6000828254613ec491906159f8565b909155505060408051848152602081018390526001600160a01b0384169133917fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d7910160405180910390a392915050565b80600d613f228282615dc0565b505050565b600081600003613f405750670de0b6b3a7640000611b98565b82600003613f5057506000611b98565b613f61600160ff1b84106006614515565b82613f85613f7c68056bc75e2d63100000600160fe1b615c0b565b84106007614515565b82600082613fa367016345785d8a0000670de0b6b3a7640000615e82565b128015613fc85750613fc5670de0b6b3a764000067016345785d8a0000615ea2565b83125b15614031576000613fd884614523565b9050670de0b6b3a764000083613fee8284615eca565b613ff89190615ede565b6140029190615f0e565b83614015670de0b6b3a764000084615f0e565b61401f9190615ede565b6140299190615ea2565b915050614048565b8161403b8461475a565b6140459190615ede565b90505b61405a670de0b6b3a764000082615f0e565b905061408981680238fd42c5cf03ffff1913158015614082575068070c1cc73b00c800008213155b6008614515565b61409281614d40565b9695505050505050565b806000805b60135481101561414b576140f9601182815481106140c1576140c1615a78565b60009182526020909120601082040154600e548792600f166002026101000a90910461ffff1690600160281b900462ffffff16613858565b915081601660006013848154811061411357614113615a78565b60009182526020808320909101546001600160a01b0316835282019290925260400190208054909101905591819003916001016140a1565b50614155836138bb565b600e80546001600160801b03600160781b808304821690940116909202600160781b600160f81b0319909216919091179055506010546001600160a01b03600160601b9091041660009081526016602052604090208054909101905550565b601182815481106141c7576141c7615a78565b90600052602060002090601091828204019190066002029054906101000a900461ffff1661ffff16600e60058282829054906101000a900462ffffff1661420e9190615c8d565b92506101000a81548162ffffff021916908362ffffff1602179055506012828154811061423d5761423d615a78565b90600052602060002090601091828204019190066002029054906101000a900461ffff1661ffff16600e600a8282829054906101000a900462ffffff166142849190615c8d565b825462ffffff9182166101009390930a9283029190920219909116179055506001600160a01b0381166000908152601460205260409020805460ff1916905560118054806142d4576142d4615f3c565b600082815260209020601060001990920191820401805461ffff6002600f8516026101000a02191690559055601280548061431157614311615f3c565b600082815260209020601060001990920191820401805461ffff6002600f8516026101000a02191690559055601380548061434e5761434e615f3c565b6000828152602090819020600019908301810180546001600160a01b03191690559091019091556040516001600160a01b03831681527f14254003b9294c30e1b403adc733441503a0aecf4ff410885229833defef329a910160405180910390a15050565b600d54600090600160d81b900464ffffffffff1682106144115750600d54620186a0600160901b82046001600160481b03908116600160d81b840464ffffffffff169485900302600160481b84048216909402939093010491160190565b50600d54620186a06001600160481b03600160481b83048116939093020491160190565b6001600160a01b0382166000908152600760205260408120805483929061445d908490615a65565b90915550506006805482900390556040518181526000906001600160a01b038416907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef906020015b60405180910390a35050565b80600660008282546144c391906159f8565b90915550506001600160a01b0382166000818152600760209081526040808320805486019055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91016144a5565b81611d1057611d1081615377565b6000614537670de0b6b3a764000083615ede565b915060006145536a0c097ce7bc90715b34b9f160241b84615ea2565b6a0c097ce7bc90715b34b9f160241b61456c8186615e82565b6145769190615ede565b6145809190615f0e565b905060006a0c097ce7bc90715b34b9f160241b61459d8380615ede565b6145a79190615f0e565b905081806a0c097ce7bc90715b34b9f160241b6145c48483615ede565b6145ce9190615f0e565b91506145db600383615f0e565b6145e59082615ea2565b90506a0c097ce7bc90715b34b9f160241b6146008484615ede565b61460a9190615f0e565b9150614617600583615f0e565b6146219082615ea2565b90506a0c097ce7bc90715b34b9f160241b61463c8484615ede565b6146469190615f0e565b9150614653600783615f0e565b61465d9082615ea2565b90506a0c097ce7bc90715b34b9f160241b6146788484615ede565b6146829190615f0e565b915061468f600983615f0e565b6146999082615ea2565b90506a0c097ce7bc90715b34b9f160241b6146b48484615ede565b6146be9190615f0e565b91506146cb600b83615f0e565b6146d59082615ea2565b90506a0c097ce7bc90715b34b9f160241b6146f08484615ede565b6146fa9190615f0e565b9150614707600d83615f0e565b6147119082615ea2565b90506a0c097ce7bc90715b34b9f160241b61472c8484615ede565b6147369190615f0e565b9150614743600f83615f0e565b61474d9082615ea2565b9050614092816002615ede565b6000670de0b6b3a764000082121561479a5761479182614782670de0b6b3a764000080615ede565b61478c9190615f0e565b61475a565b611b9890615f52565b60006147c6670de0b6b3a7640000770195e54c5dd42177f53a27172fa9ec630262827000000000615ede565b8312614806576147ee770195e54c5dd42177f53a27172fa9ec63026282700000000084615f0e565b92506148036806f05b59d3b200000082615ea2565b90505b614824670de0b6b3a76400006b1425982cf597cd205cef7380615ede565b8312614858576148406b1425982cf597cd205cef738084615f0e565b92506148556803782dace9d900000082615ea2565b90505b614863606482615ede565b9050614870606484615ede565b92506e01855144814a7ff805980ff008400083126148cd576e01855144814a7ff805980ff00840006148ab68056bc75e2d6310000085615ede565b6148b59190615f0e565b92506148ca68ad78ebc5ac6200000082615ea2565b90505b6b02df0ab5a80a22c61ab5a7008312614922576b02df0ab5a80a22c61ab5a70061490068056bc75e2d6310000085615ede565b61490a9190615f0e565b925061491f6856bc75e2d63100000082615ea2565b90505b693f1fce3da636ea5cf850831261497357693f1fce3da636ea5cf85061495168056bc75e2d6310000085615ede565b61495b9190615f0e565b9250614970682b5e3af16b1880000082615ea2565b90505b690127fa27722cc06cc5e283126149c457690127fa27722cc06cc5e26149a268056bc75e2d6310000085615ede565b6149ac9190615f0e565b92506149c16815af1d78b58c40000082615ea2565b90505b68280e60114edb805d038312614a135768280e60114edb805d036149f168056bc75e2d6310000085615ede565b6149fb9190615f0e565b9250614a10680ad78ebc5ac620000082615ea2565b90505b680ebc5fb417461211108312614a6257680ebc5fb41746121110614a4068056bc75e2d6310000085615ede565b614a4a9190615f0e565b9250614a5f68056bc75e2d6310000082615ea2565b90505b6808f00f760a4b2db55d8312614ab1576808f00f760a4b2db55d614a8f68056bc75e2d6310000085615ede565b614a999190615f0e565b9250614aae6802b5e3af16b188000082615ea2565b90505b6806f5f17757889379378312614b00576806f5f1775788937937614ade68056bc75e2d6310000085615ede565b614ae89190615f0e565b9250614afd68015af1d78b58c4000082615ea2565b90505b6806248f33704b2866038312614b4e576806248f33704b286603614b2d68056bc75e2d6310000085615ede565b614b379190615f0e565b9250614b4b67ad78ebc5ac62000082615ea2565b90505b6805c548670b9510e7ac8312614b9c576805c548670b9510e7ac614b7b68056bc75e2d6310000085615ede565b614b859190615f0e565b9250614b996756bc75e2d631000082615ea2565b90505b6000614bb168056bc75e2d6310000085615ea2565b68056bc75e2d63100000614bc58187615e82565b614bcf9190615ede565b614bd99190615f0e565b9050600068056bc75e2d63100000614bf18380615ede565b614bfb9190615f0e565b9050818068056bc75e2d63100000614c138483615ede565b614c1d9190615f0e565b9150614c2a600383615f0e565b614c349082615ea2565b905068056bc75e2d63100000614c4a8484615ede565b614c549190615f0e565b9150614c61600583615f0e565b614c6b9082615ea2565b905068056bc75e2d63100000614c818484615ede565b614c8b9190615f0e565b9150614c98600783615f0e565b614ca29082615ea2565b905068056bc75e2d63100000614cb88484615ede565b614cc29190615f0e565b9150614ccf600983615f0e565b614cd99082615ea2565b905068056bc75e2d63100000614cef8484615ede565b614cf99190615f0e565b9150614d06600b83615f0e565b614d109082615ea2565b9050614d1d600282615ede565b90506064614d2b8287615ea2565b614d359190615f0e565b979650505050505050565b6000614d6f680238fd42c5cf03ffff198312158015614d68575068070c1cc73b00c800008313155b6009614515565b6000821215614da557614d89614d8483615f52565b614d40565b614d9b670de0b6b3a764000080615ede565b611b989190615f0e565b60006806f05b59d3b20000008312614dec57614dca6806f05b59d3b200000084615e82565b9250770195e54c5dd42177f53a27172fa9ec6302628270000000009050614e29565b6803782dace9d90000008312614e2557614e0f6803782dace9d900000084615e82565b92506b1425982cf597cd205cef73809050614e29565b5060015b614e34606484615ede565b925068056bc75e2d6310000068ad78ebc5ac620000008412614e9557614e6368ad78ebc5ac6200000085615e82565b935068056bc75e2d63100000614e886e01855144814a7ff805980ff008400083615ede565b614e929190615f0e565b90505b6856bc75e2d6310000008412614ee757614eb86856bc75e2d63100000085615e82565b935068056bc75e2d63100000614eda6b02df0ab5a80a22c61ab5a70083615ede565b614ee49190615f0e565b90505b682b5e3af16b188000008412614f3757614f0a682b5e3af16b1880000085615e82565b935068056bc75e2d63100000614f2a693f1fce3da636ea5cf85083615ede565b614f349190615f0e565b90505b6815af1d78b58c4000008412614f8757614f5a6815af1d78b58c40000085615e82565b935068056bc75e2d63100000614f7a690127fa27722cc06cc5e283615ede565b614f849190615f0e565b90505b680ad78ebc5ac62000008412614fd657614faa680ad78ebc5ac620000085615e82565b935068056bc75e2d63100000614fc968280e60114edb805d0383615ede565b614fd39190615f0e565b90505b68056bc75e2d63100000841261502557614ff968056bc75e2d6310000085615e82565b935068056bc75e2d63100000615018680ebc5fb4174612111083615ede565b6150229190615f0e565b90505b6802b5e3af16b18800008412615074576150486802b5e3af16b188000085615e82565b935068056bc75e2d631000006150676808f00f760a4b2db55d83615ede565b6150719190615f0e565b90505b68015af1d78b58c4000084126150c35761509768015af1d78b58c4000085615e82565b935068056bc75e2d631000006150b66806f5f177578893793783615ede565b6150c09190615f0e565b90505b68056bc75e2d63100000846150d88183615ea2565b9150600268056bc75e2d631000006150f08884615ede565b6150fa9190615f0e565b6151049190615f0e565b90506151108183615ea2565b9150600368056bc75e2d631000006151288884615ede565b6151329190615f0e565b61513c9190615f0e565b90506151488183615ea2565b9150600468056bc75e2d631000006151608884615ede565b61516a9190615f0e565b6151749190615f0e565b90506151808183615ea2565b9150600568056bc75e2d631000006151988884615ede565b6151a29190615f0e565b6151ac9190615f0e565b90506151b88183615ea2565b9150600668056bc75e2d631000006151d08884615ede565b6151da9190615f0e565b6151e49190615f0e565b90506151f08183615ea2565b9150600768056bc75e2d631000006152088884615ede565b6152129190615f0e565b61521c9190615f0e565b90506152288183615ea2565b9150600868056bc75e2d631000006152408884615ede565b61524a9190615f0e565b6152549190615f0e565b90506152608183615ea2565b9150600968056bc75e2d631000006152788884615ede565b6152829190615f0e565b61528c9190615f0e565b90506152988183615ea2565b9150600a68056bc75e2d631000006152b08884615ede565b6152ba9190615f0e565b6152c49190615f0e565b90506152d08183615ea2565b9150600b68056bc75e2d631000006152e88884615ede565b6152f29190615f0e565b6152fc9190615f0e565b90506153088183615ea2565b9150600c68056bc75e2d631000006153208884615ede565b61532a9190615f0e565b6153349190615f0e565b90506153408183615ea2565b915060648468056bc75e2d631000006153598587615ede565b6153639190615f0e565b61536d9190615ede565b6140929190615f0e565b6030600a820601600a820491506030600a830601600a830492506030600a8406018060101b8260081b8401016642414c230000000160c81b9250505062461bcd60e51b600052602060045260076024528060445260646000fd5b6000602082840312156153e357600080fd5b81356001600160601b0381168114610fe157600080fd5b600060208083528351808285015260005b818110156154275785810183015185820160400152820161540b565b506000604082860101526040601f19601f8301168501019250505092915050565b60006020828403121561545a57600080fd5b5035919050565b6001600160a01b038116811461159357600080fd5b6000806040838503121561548957600080fd5b823561549481615461565b946020939093013593505050565b801515811461159357600080fd5b600080604083850312156154c357600080fd5b8235915060208301356154d5816154a2565b809150509250929050565b60008060008060008060c087890312156154f957600080fd5b863561550481615461565b9550602087013561551481615461565b95989597505050506040840135936060810135936080820135935060a0909101359150565b60006020828403121561554b57600080fd5b8135610fe181615461565b60006020828403121561556857600080fd5b81356001600160801b0381168114610fe157600080fd5b803560ff81168114611b8857600080fd5b6000602082840312156155a257600080fd5b610fe18261557f565b6000806000606084860312156155c057600080fd5b83356155cb81615461565b925060208401356155db81615461565b929592945050506040919091013590565b600080600080600060a0868803121561560457600080fd5b853561560f816154a2565b9450602086013561561f816154a2565b9350604086013561562f816154a2565b9250606086013561563f816154a2565b9150608086013561564f816154a2565b809150509295509295909350565b6000806040838503121561567057600080fd5b8235915060208301356154d581615461565b60006020828403121561569457600080fd5b81356001600160501b0381168114610fe157600080fd5b600080604083850312156156be57600080fd5b50508035926020909101359150565b80356001600160e81b031981168114611b8857600080fd5b60008060008060008060a087890312156156fe57600080fd5b86359550602087013561571081615461565b9450604087013561572081615461565b9350606087013567ffffffffffffffff8082111561573d57600080fd5b818901915089601f83011261575157600080fd5b81358181111561576057600080fd5b8a602082850101111561577257600080fd5b60208301955080945050505061578a608088016156cd565b90509295509295509295565b803561ffff81168114611b8857600080fd5b6000602082840312156157ba57600080fd5b610fe182615796565b600080600080608085870312156157d957600080fd5b8435935060208501356157eb81615461565b925060408501356157fb81615461565b9150615809606086016156cd565b905092959194509250565b60008060006060848603121561582957600080fd5b833561583481615461565b925060208401359150604084013561584b81615461565b809150509250925092565b60008060006060848603121561586b57600080fd5b833561587681615461565b925061588460208501615796565b915061589260408501615796565b90509250925092565b600080604083850312156158ae57600080fd5b823591506158be60208401615796565b90509250929050565b6000806000606084860312156158dc57600080fd5b8335925060208401356158ee81615461565b9150604084013561584b81615461565b60008060006060848603121561591357600080fd5b833561591e81615461565b925060208401356158ee81615461565b60006080828403121561594057600080fd5b50919050565b600080600080600080600060e0888a03121561596157600080fd5b873561596c81615461565b9650602088013561597c81615461565b955060408801359450606088013593506159986080890161557f565b925060a0880135915060c0880135905092959891949750929550565b600080604083850312156159c757600080fd5b82356159d281615461565b915060208301356154d581615461565b634e487b7160e01b600052601160045260246000fd5b80820180821115611b9857611b986159e2565b6020808252600c908201526b15539055551213d49256915160a21b604082015260600190565b600181811c90821680615a4557607f821691505b60208210810361594057634e487b7160e01b600052602260045260246000fd5b81810381811115611b9857611b986159e2565b634e487b7160e01b600052603260045260246000fd5b600060208284031215615aa057600080fd5b5051919050565b6001600160801b03828116828216039080821115615ac757615ac76159e2565b5092915050565b600181815b80851115615b09578160001904821115615aef57615aef6159e2565b80851615615afc57918102915b93841c9390800290615ad3565b509250929050565b600082615b2057506001611b98565b81615b2d57506000611b98565b8160018114615b435760028114615b4d57615b69565b6001915050611b98565b60ff841115615b5e57615b5e6159e2565b50506001821b611b98565b5060208310610133831016604e8410600b8410161715615b8c575081810a611b98565b615b968383615ace565b8060001904821115615baa57615baa6159e2565b029392505050565b6000610fe160ff841683615b11565b600060208284031215615bd357600080fd5b8151610fe181615461565b8082028115828204841417611b9857611b986159e2565b634e487b7160e01b600052601260045260246000fd5b600082615c1a57615c1a615bf5565b500490565b6001600160a01b03841681526040602082018190528101829052818360608301376000818301606090810191909152601f909201601f1916010192915050565b60008060408385031215615c7257600080fd5b8251615c7d81615461565b6020939093015192949293505050565b62ffffff828116828216039080821115615ac757615ac76159e2565b62ffffff818116838216019080821115615ac757615ac76159e2565b600080600060608486031215615cda57600080fd5b8351615ce5816154a2565b6020850151909350615cf681615461565b80925050604084015190509250925092565b600080835481600182811c915080831680615d2457607f831692505b60208084108203615d4357634e487b7160e01b86526022600452602486fd5b818015615d575760018114615d6c57615d99565b60ff1986168952841515850289019650615d99565b60008a81526020902060005b86811015615d915781548b820152908501908301615d78565b505084890196505b509498975050505050505050565b600081356001600160481b0381168114611b9857600080fd5b6001600160481b03615dd183615da7565b168154816001600160481b0319821617835571ffffffffffffffffff000000000000000000615e0260208601615da7565b60481b16808371ffffffffffffffffffffffffffffffffffff198416171784556001600160481b0360901b615e3960408701615da7565b60901b1664ffffffffff60d81b81858286161784171786556060870135935064ffffffffff84168414615e6b57600080fd5b808460d81b16858417831717865550505050505050565b8181036000831280158383131683831282161715615ac757615ac76159e2565b8082018281126000831280158216821582161715615ec257615ec26159e2565b505092915050565b600082615ed957615ed9615bf5565b500790565b80820260008212600160ff1b84141615615efa57615efa6159e2565b8181058314821517611b9857611b986159e2565b600082615f1d57615f1d615bf5565b600160ff1b821460001984141615615f3757615f376159e2565b500590565b634e487b7160e01b600052603160045260246000fd5b6000600160ff1b8201615f6757615f676159e2565b506000039056fea26469706673582212209780f6277341e8b0493529fdc95bb4bd714f1a96ebea72b6e1cf82e72de3d42c64736f6c63430008110033

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

000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000beb56fbef3387af554a554e7db25830eb7b92e3200000000000000000000000000cb53780ea58503d3059fc02ddd596d0be926cb000000000000000000000000d2a34731586bd10b645f870f4c9dcaf4f9e3823c

-----Decoded View---------------
Arg [0] : asset_ (address): 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48
Arg [1] : treasury_ (address): 0xBEB56fbEf3387af554A554E7DB25830eB7b92e32
Arg [2] : vaultFactory_ (address): 0x00CB53780Ea58503D3059FC02dDd596D0Be926cB
Arg [3] : liquidator_ (address): 0xD2A34731586bD10B645f870f4C9DcAF4F9e3823C

-----Encoded View---------------
4 Constructor Arguments found :
Arg [0] : 000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48
Arg [1] : 000000000000000000000000beb56fbef3387af554a554e7db25830eb7b92e32
Arg [2] : 00000000000000000000000000cb53780ea58503d3059fc02ddd596d0be926cb
Arg [3] : 000000000000000000000000d2a34731586bd10b645f870f4c9dcaf4f9e3823c


Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

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

Validator Index Block Amount
View All Withdrawals

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

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.