ETH Price: $2,331.42 (-0.65%)

Token

ERC20 ***
 

Overview

Max Total Supply

0 ERC20 ***

Holders

0

Total Transfers

-

Market

Onchain Market Cap

$0.00

Circulating Supply Market Cap

-

Other Info

Token Contract (WITH 6 Decimals)

Loading...
Loading
Loading...
Loading
Loading...
Loading

Click here to update the token information / general information
# Exchange Pair Price  24H Volume % Volume

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


Loading...
Loading
Loading...
Loading
[ Download: CSV Export  ]

A token is a representation of an on-chain or off-chain asset. The token page shows information such as price, total supply, holders, transfers and social links. Learn more about this page in our Knowledge Base.