ETH Price: $3,786.46 (+5.74%)

Contract

0xB8643Df25B6614eBD9E03144d12F53994e40E770
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Chicken Out169884852023-04-06 8:40:23615 days ago1680770423IN
0xB8643Df2...94e40E770
0 ETH0.0152457725.78500774
Create Bond156738152022-10-04 9:15:11799 days ago1664874911IN
0xB8643Df2...94e40E770
0 ETH0.002849465.84292695
Create Bond156737722022-10-04 9:06:23799 days ago1664874383IN
0xB8643Df2...94e40E770
0 ETH0.002254187.20149193
Create Bond156737692022-10-04 9:05:47799 days ago1664874347IN
0xB8643Df2...94e40E770
0 ETH0.00216866.92808767

View more zero value Internal Transactions in Advanced View mode

Advanced mode:
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
ChickenBondManager

Compiler Version
v0.8.11+commit.d7f03943

Optimization Enabled:
Yes with 500 runs

Other Settings:
default evmVersion, GNU GPLv3 license

Contract Source Code (Solidity)

/**
 *Submitted for verification at Etherscan.io on 2022-10-04
*/

// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.10;

// OpenZeppelin Contracts (last updated v4.5.0) (utils/math/Math.sol)

/**
 * @dev Standard math utilities missing in the Solidity language.
 */
library Math {
    /**
     * @dev Returns the largest of two numbers.
     */
    function max(uint256 a, uint256 b) internal pure returns (uint256) {
        return a >= b ? a : b;
    }

    /**
     * @dev Returns the smallest of two numbers.
     */
    function min(uint256 a, uint256 b) internal pure returns (uint256) {
        return a < b ? a : b;
    }

    /**
     * @dev Returns the average of two numbers. The result is rounded towards
     * zero.
     */
    function average(uint256 a, uint256 b) internal pure returns (uint256) {
        // (a + b) / 2 can overflow.
        return (a & b) + (a ^ b) / 2;
    }

    /**
     * @dev Returns the ceiling of the division of two numbers.
     *
     * This differs from standard division with `/` in that it rounds up instead
     * of rounding down.
     */
    function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
        // (a + b - 1) / b can overflow on addition, so we distribute.
        return a / b + (a % b == 0 ? 0 : 1);
    }
}

// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20 {
    /**
     * @dev Returns the amount of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

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

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

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

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

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

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

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

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

// taken from: https://github.com/liquity/dev/blob/8371355b2f11bee9fa599f9223f4c2f6f429351f/packages/contracts/contracts/Dependencies/LiquityMath.sol
contract ChickenMath is BaseMath {

    /*
     * Multiply two decimal numbers and use normal rounding rules:
     * -round product up if 19'th mantissa digit >= 5
     * -round product down if 19'th mantissa digit < 5
     *
     * Used only inside the exponentiation, decPow().
     */
    function decMul(uint256 x, uint256 y) internal pure returns (uint256) {
        return (x * y + DECIMAL_PRECISION / 2) / DECIMAL_PRECISION;
    }

    /*
     * decPow: Exponentiation function for 18-digit decimal base, and integer exponent n.
     *
     * Uses the efficient "exponentiation by squaring" algorithm. O(log(n)) complexity.
     *
     * Called by ChickenBondManager.calcRedemptionFeePercentage, that represents time in units of minutes:
     *
     * The exponent is capped to avoid reverting due to overflow. The cap 525600000 equals
     * "minutes in 1000 years": 60 * 24 * 365 * 1000
     *
     * If a period of > 1000 years is ever used as an exponent in either of the above functions, the result will be
     * negligibly different from just passing the cap, since:
     * the decayed base rate will be 0 for 1000 years or > 1000 years
     */
    function decPow(uint256 _base, uint256 _exponent) internal pure returns (uint) {

        if (_exponent > 525600000) {_exponent = 525600000;}  // cap to avoid overflow

        if (_exponent == 0) {return DECIMAL_PRECISION;}

        uint256 y = DECIMAL_PRECISION;
        uint256 x = _base;
        uint256 n = _exponent;

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

        return decMul(x, y);
    }
}

// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC721/extensions/IERC721Enumerable.sol)

// OpenZeppelin Contracts v4.4.1 (token/ERC721/IERC721.sol)

// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)

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

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

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

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

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

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

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

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

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

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

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

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

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

/**
 * @title ERC-721 Non-Fungible Token Standard, optional enumeration extension
 * @dev See https://eips.ethereum.org/EIPS/eip-721
 */
interface IERC721Enumerable is IERC721 {
    /**
     * @dev Returns the total amount of tokens stored by the contract.
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns a token ID owned by `owner` at a given `index` of its token list.
     * Use along with {balanceOf} to enumerate all of ``owner``'s tokens.
     */
    function tokenOfOwnerByIndex(address owner, uint256 index) external view returns (uint256);

    /**
     * @dev Returns a token ID at a given `index` of all the tokens stored by the contract.
     * Use along with {totalSupply} to enumerate all tokens.
     */
    function tokenByIndex(uint256 index) external view returns (uint256);
}

interface ILUSDToken is IERC20 { 
    
    // --- Events ---

    event TroveManagerAddressChanged(address _troveManagerAddress);
    event StabilityPoolAddressChanged(address _newStabilityPoolAddress);
    event BorrowerOperationsAddressChanged(address _newBorrowerOperationsAddress);
    event LUSDTokenBalanceUpdated(address _user, uint _amount);

    // --- Functions ---

    function mint(address _account, uint256 _amount) external;

    function burn(address _account, uint256 _amount) external;

    function sendToPool(address _sender,  address poolAddress, uint256 _amount) external;

    function returnFromPool(address poolAddress, address user, uint256 _amount ) external;

    function permit(
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external;
}

interface IBLUSDToken is IERC20 {
    function mint(address _to, uint256 _bLUSDAmount) external;

    function burn(address _from, uint256 _bLUSDAmount) external;
}

interface ICurvePool is IERC20 { 
    function add_liquidity(uint256[2] memory _amounts, uint256 _min_mint_amount) external returns (uint256 mint_amount);

    function remove_liquidity(uint256 burn_amount, uint256[2] memory _min_amounts) external;

    function remove_liquidity_one_coin(uint256 _burn_amount, int128 i, uint256 _min_received) external;

    function exchange(int128 i, int128 j, uint256 dx, uint256 min_dy, address _receiver) external returns (uint256);

    function exchange_underlying(int128 i, int128 j, uint256 dx, uint256 min_dy, address _receiver) external returns (uint256);

    function calc_withdraw_one_coin(uint256 _burn_amount, int128 i) external view returns (uint256);

    function calc_token_amount(uint256[2] memory _amounts, bool _is_deposit) external view returns (uint256);

    function balances(uint256 arg0) external view returns (uint256);

    function token() external view returns (address);

    function totalSupply() external view returns (uint256);

    function get_dy(int128 i,int128 j, uint256 dx) external view returns (uint256);

    function get_dy_underlying(int128 i,int128 j, uint256 dx) external view returns (uint256);

    function get_virtual_price() external view returns (uint256);

    function fee() external view returns (uint256);

    function D() external returns (uint256);

    function future_A_gamma_time() external returns (uint256);
}

interface IYearnVault is IERC20 { 
    function deposit(uint256 _tokenAmount) external returns (uint256);

    function withdraw(uint256 _tokenAmount) external returns (uint256);

    function lastReport() external view returns (uint256);

    function totalDebt() external view returns (uint256);

    function calcTokenToYToken(uint256 _tokenAmount) external pure returns (uint256); 

    function token() external view returns (address);

    function availableDepositLimit() external view returns (uint256);

    function pricePerShare() external view returns (uint256);

    function name() external view returns (string memory);

    function setDepositLimit(uint256 limit) external;

    function withdrawalQueue(uint256) external returns (address);
}

interface IBAMM {
    function deposit(uint256 lusdAmount) external;

    function withdraw(uint256 lusdAmount, address to) external;

    function swap(uint lusdAmount, uint minEthReturn, address payable dest) external returns(uint);

    function getSwapEthAmount(uint lusdQty) external view returns(uint ethAmount, uint feeLusdAmount);

    function getLUSDValue() external view returns (uint256, uint256, uint256);

    function setChicken(address _chicken) external;
}

interface IChickenBondManager {
    // Valid values for `status` returned by `getBondData()`
    enum BondStatus {
        nonExistent,
        active,
        chickenedOut,
        chickenedIn
    }

    function lusdToken() external view returns (ILUSDToken);
    function bLUSDToken() external view returns (IBLUSDToken);
    function curvePool() external view returns (ICurvePool);
    function bammSPVault() external view returns (IBAMM);
    function yearnCurveVault() external view returns (IYearnVault);
    // constants
    function INDEX_OF_LUSD_TOKEN_IN_CURVE_POOL() external pure returns (int128);

    function createBond(uint256 _lusdAmount) external returns (uint256);
    function createBondWithPermit(
        address owner, 
        uint256 amount, 
        uint256 deadline, 
        uint8 v, 
        bytes32 r, 
        bytes32 s
    ) external  returns (uint256);
    function chickenOut(uint256 _bondID, uint256 _minLUSD) external;
    function chickenIn(uint256 _bondID) external;
    function redeem(uint256 _bLUSDToRedeem, uint256 _minLUSDFromBAMMSPVault) external returns (uint256, uint256);

    // getters
    function calcRedemptionFeePercentage(uint256 _fractionOfBLUSDToRedeem) external view returns (uint256);
    function getBondData(uint256 _bondID) external view returns (uint256 lusdAmount, uint64 claimedBLUSD, uint64 startTime, uint64 endTime, uint8 status);
    function getLUSDToAcquire(uint256 _bondID) external view returns (uint256);
    function calcAccruedBLUSD(uint256 _bondID) external view returns (uint256);
    function calcBondBLUSDCap(uint256 _bondID) external view returns (uint256);
    function getLUSDInBAMMSPVault() external view returns (uint256);
    function calcTotalYearnCurveVaultShareValue() external view returns (uint256);
    function calcTotalLUSDValue() external view returns (uint256);
    function getPendingLUSD() external view returns (uint256);
    function getAcquiredLUSDInSP() external view returns (uint256);
    function getAcquiredLUSDInCurve() external view returns (uint256);
    function getTotalAcquiredLUSD() external view returns (uint256);
    function getPermanentLUSD() external view returns (uint256);
    function getOwnedLUSDInSP() external view returns (uint256);
    function getOwnedLUSDInCurve() external view returns (uint256);
    function calcSystemBackingRatio() external view returns (uint256);
    function calcUpdatedAccrualParameter() external view returns (uint256);
    function getBAMMLUSDDebt() external view returns (uint256);
}

interface IBondNFT is IERC721Enumerable {
    struct BondExtraData {
        uint80 initialHalfDna;
        uint80 finalHalfDna;
        uint32 troveSize;         // Debt in LUSD
        uint32 lqtyAmount;        // Holding LQTY, staking or deposited into Pickle
        uint32 curveGaugeSlopes;  // For 3CRV and Frax pools combined
    }

    function mint(address _bonder, uint256 _permanentSeed) external returns (uint256, uint80);
    function setFinalExtraData(address _bonder, uint256 _tokenID, uint256 _permanentSeed) external returns (uint80);
    function chickenBondManager() external view returns (IChickenBondManager);
    function getBondAmount(uint256 _tokenID) external view returns (uint256 amount);
    function getBondStartTime(uint256 _tokenID) external view returns (uint256 startTime);
    function getBondEndTime(uint256 _tokenID) external view returns (uint256 endTime);
    function getBondInitialHalfDna(uint256 _tokenID) external view returns (uint80 initialHalfDna);
    function getBondInitialDna(uint256 _tokenID) external view returns (uint256 initialDna);
    function getBondFinalHalfDna(uint256 _tokenID) external view returns (uint80 finalHalfDna);
    function getBondFinalDna(uint256 _tokenID) external view returns (uint256 finalDna);
    function getBondStatus(uint256 _tokenID) external view returns (uint8 status);
    function getBondExtraData(uint256 _tokenID) external view returns (uint80 initialHalfDna, uint80 finalHalfDna, uint32 troveSize, uint32 lqtyAmount, uint32 curveGaugeSlopes);
}

interface IYearnRegistry {
    function latestVault(address _tokenAddress) external returns (address);
}

interface ICurveLiquidityGaugeV5 is IERC20 {
    // Public state getters

    function reward_data(address _reward_token) external returns (
        address token,
        address distributor,
        uint256 period_finish,
        uint256 rate,
        uint256 last_update,
        uint256 integral
    );

    // User-facing functions

    function deposit(uint256 _value) external;
    function deposit(uint256 _value, address _addr) external;
    function deposit(uint256 _value, address _addr, bool _claim_rewards) external;

    function withdraw(uint256 _value) external;
    function withdraw(uint256 _value, bool _claim_rewards) external;

    function claim_rewards() external;
    function claim_rewards(address _addr) external;
    function claim_rewards(address _addr, address _receiver) external;

    function user_checkpoint(address addr) external returns (bool);
    function set_rewards_receiver(address _receiver) external;
    function kick(address addr) external;

    // Admin functions

    function deposit_reward_token(address _reward_token, uint256 _amount) external;
    function add_reward(address _reward_token, address _distributor) external;
    function set_reward_distributor(address _reward_token, address _distributor) external;
    function set_killed(bool _is_killed) external;

    // View methods

    function claimed_reward(address _addr, address _token) external view returns (uint256);
    function claimable_reward(address _user, address _reward_token) external view returns (uint256);
    function claimable_tokens(address addr) external view returns (uint256);

    function integrate_checkpoint() external view returns (uint256);
    function future_epoch_time() external view returns (uint256);
    function inflation_rate() external view returns (uint256);

    function version() external view returns (string memory);
}

// import "forge-std/console.sol";

contract ChickenBondManager is ChickenMath, IChickenBondManager {

    // ChickenBonds contracts and addresses
    IBondNFT immutable public bondNFT;

    IBLUSDToken immutable public bLUSDToken;
    ILUSDToken immutable public lusdToken;

    // External contracts and addresses
    ICurvePool immutable public curvePool; // LUSD meta-pool (i.e. coin 0 is LUSD, coin 1 is LP token from a base pool)
    ICurvePool immutable public curveBasePool; // base pool of curvePool
    IBAMM immutable public bammSPVault; // B.Protocol Stability Pool vault
    IYearnVault immutable public yearnCurveVault;
    IYearnRegistry immutable public yearnRegistry;
    ICurveLiquidityGaugeV5 immutable public curveLiquidityGauge;

    address immutable public yearnGovernanceAddress;

    uint256 immutable public CHICKEN_IN_AMM_FEE;

    uint256 private pendingLUSD;          // Total pending LUSD. It will always be in SP (B.Protocol)
    uint256 private permanentLUSD;        // Total permanent LUSD
    uint256 private bammLUSDDebt;         // Amount “owed” by B.Protocol to ChickenBonds, equals deposits - withdrawals + rewards
    uint256 public yTokensHeldByCBM;      // Computed balance of Y-tokens of LUSD-3CRV vault owned by this contract
                                          // (to prevent certain attacks where attacker increases the balance and thus the backing ratio)

    // --- Data structures ---

    struct ExternalAdresses {
        address bondNFTAddress;
        address lusdTokenAddress;
        address curvePoolAddress;
        address curveBasePoolAddress;
        address bammSPVaultAddress;
        address yearnCurveVaultAddress;
        address yearnRegistryAddress;
        address yearnGovernanceAddress;
        address bLUSDTokenAddress;
        address curveLiquidityGaugeAddress;
    }

    struct Params {
        uint256 targetAverageAgeSeconds;        // Average outstanding bond age above which the controller will adjust `accrualParameter` in order to speed up accrual
        uint256 initialAccrualParameter;        // Initial value for `accrualParameter`
        uint256 minimumAccrualParameter;        // Stop adjusting `accrualParameter` when this value is reached
        uint256 accrualAdjustmentRate;          // `accrualParameter` is multiplied `1 - accrualAdjustmentRate` every time there's an adjustment
        uint256 accrualAdjustmentPeriodSeconds; // The duration of an adjustment period in seconds
        uint256 chickenInAMMFee;                // Fraction of bonded amount that is sent to Curve Liquidity Gauge to incentivize LUSD-bLUSD liquidity
        uint256 curveDepositDydxThreshold;      // Threshold of SP => Curve shifting
        uint256 curveWithdrawalDxdyThreshold;   // Threshold of Curve => SP shifting
        uint256 bootstrapPeriodChickenIn;       // Min duration of first chicken-in
        uint256 bootstrapPeriodRedeem;          // Redemption lock period after first chicken in
        uint256 bootstrapPeriodShift;           // Period after launch during which shifter functions are disabled
        uint256 shifterDelay;                   // Duration of shifter countdown
        uint256 shifterWindow;                  // Interval in which shifting is possible after countdown finishes
        uint256 minBLUSDSupply;                 // Minimum amount of bLUSD supply that must remain after a redemption
        uint256 minBondAmount;                  // Minimum amount of LUSD that needs to be bonded
        uint256 nftRandomnessDivisor;           // Divisor for permanent LUSD amount in NFT pseudo-randomness computation (see comment below)
        uint256 redemptionFeeBeta;              // Parameter by which to divide the redeemed fraction, in order to calculate the new base rate from a redemption
        uint256 redemptionFeeMinuteDecayFactor; // Factor by which redemption fee decays (exponentially) every minute
    }

    struct BondData {
        uint256 lusdAmount;
        uint64 claimedBLUSD; // In BLUSD units without decimals
        uint64 startTime;
        uint64 endTime; // Timestamp of chicken in/out event
        BondStatus status;
    }

    uint256 public firstChickenInTime; // Timestamp of the first chicken in after bLUSD supply is zero
    uint256 public totalWeightedStartTimes; // Sum of `lusdAmount * startTime` for all outstanding bonds (used to tell weighted average bond age)
    uint256 public lastRedemptionTime; // The timestamp of the latest redemption
    uint256 public baseRedemptionRate; // The latest base redemption rate
    mapping (uint256 => BondData) private idToBondData;

    /* migration: flag which determines whether the system is in migration mode.

    When migration mode has been triggered:

    - No funds are held in the permanent bucket. Liquidity is either pending, or acquired
    - Bond creation and public shifter functions are disabled
    - Users with an existing bond may still chicken in or out
    - Chicken-ins will no longer send the LUSD surplus to the permanent bucket. Instead, they refund the surplus to the bonder
    - bLUSD holders may still redeem
    - Redemption fees are zero
    */
    bool public migration;

    uint256 public countChickenIn;
    uint256 public countChickenOut;

    // --- Constants ---

    uint256 constant MAX_UINT256 = type(uint256).max;
    int128 public constant INDEX_OF_LUSD_TOKEN_IN_CURVE_POOL = 0;
    int128 constant INDEX_OF_3CRV_TOKEN_IN_CURVE_POOL = 1;

    uint256 constant public SECONDS_IN_ONE_MINUTE = 60;

    uint256 public immutable BOOTSTRAP_PERIOD_CHICKEN_IN; // Min duration of first chicken-in
    uint256 public immutable BOOTSTRAP_PERIOD_REDEEM;     // Redemption lock period after first chicken in
    uint256 public immutable BOOTSTRAP_PERIOD_SHIFT;      // Period after launch during which shifter functions are disabled

    uint256 public immutable SHIFTER_DELAY;               // Duration of shifter countdown
    uint256 public immutable SHIFTER_WINDOW;              // Interval in which shifting is possible after countdown finishes

    uint256 public immutable MIN_BLUSD_SUPPLY;            // Minimum amount of bLUSD supply that must remain after a redemption
    uint256 public immutable MIN_BOND_AMOUNT;             // Minimum amount of LUSD that needs to be bonded
    // This is the minimum amount the permanent bucket needs to be increased by an attacker (through previous chicken in or redemption fee),
    // in order to manipulate the obtained NFT. If the attacker finds the desired outcome at attempt N,
    // the permanent increase should be N * NFT_RANDOMNESS_DIVISOR.
    // It also means that as long as Permanent doesn’t change in that order of magnitude, attacker can try to manipulate
    // only changing the event date.
    uint256 public immutable NFT_RANDOMNESS_DIVISOR;

    /*
     * BETA: 18 digit decimal. Parameter by which to divide the redeemed fraction, in order to calc the new base rate from a redemption.
     * Corresponds to (1 / ALPHA) in the Liquity white paper.
     */
    uint256 public immutable BETA;
    uint256 public immutable MINUTE_DECAY_FACTOR;

    uint256 constant CURVE_FEE_DENOMINATOR = 1e10;

    // Thresholds of SP <=> Curve shifting
    uint256 public immutable curveDepositLUSD3CRVExchangeRateThreshold;
    uint256 public immutable curveWithdrawal3CRVLUSDExchangeRateThreshold;

    // Timestamp at which the last shifter countdown started
    uint256 public lastShifterCountdownStartTime;

    // --- Accrual control variables ---

    // `block.timestamp` of the block in which this contract was deployed.
    uint256 public immutable deploymentTimestamp;

    // Average outstanding bond age above which the controller will adjust `accrualParameter` in order to speed up accrual.
    uint256 public immutable targetAverageAgeSeconds;

    // Stop adjusting `accrualParameter` when this value is reached.
    uint256 public immutable minimumAccrualParameter;

    // Number between 0 and 1. `accrualParameter` is multiplied by this every time there's an adjustment.
    uint256 public immutable accrualAdjustmentMultiplier;

    // The duration of an adjustment period in seconds. The controller performs at most one adjustment per every period.
    uint256 public immutable accrualAdjustmentPeriodSeconds;

    // The number of seconds it takes to accrue 50% of the cap, represented as an 18 digit fixed-point number.
    uint256 public accrualParameter;

    // Counts the number of adjustment periods since deployment.
    // Updated by operations that change the average outstanding bond age (createBond, chickenIn, chickenOut).
    // Used by `_calcUpdatedAccrualParameter` to tell whether it's time to perform adjustments, and if so, how many times
    // (in case the time elapsed since the last adjustment is more than one adjustment period).
    uint256 public accrualAdjustmentPeriodCount;

    // --- Events ---

    event BaseRedemptionRateUpdated(uint256 _baseRedemptionRate);
    event LastRedemptionTimeUpdated(uint256 _lastRedemptionFeeOpTime);
    event BondCreated(address indexed bonder, uint256 bondId, uint256 amount, uint80 bondInitialHalfDna);
    event BondClaimed(
        address indexed bonder,
        uint256 bondId,
        uint256 lusdAmount,
        uint256 bLusdAmount,
        uint256 lusdSurplus,
        uint256 chickenInFeeAmount,
        bool migration,
        uint80 bondFinalHalfDna
    );
    event BondCancelled(address indexed bonder, uint256 bondId, uint256 principalLusdAmount, uint256 minLusdAmount, uint256 withdrawnLusdAmount, uint80 bondFinalHalfDna);
    event BLUSDRedeemed(address indexed redeemer, uint256 bLusdAmount, uint256 minLusdAmount, uint256 lusdAmount, uint256 yTokens, uint256 redemptionFee);
    event MigrationTriggered(uint256 previousPermanentLUSD);
    event AccrualParameterUpdated(uint256 accrualParameter);

    // --- Constructor ---

    constructor
    (
        ExternalAdresses memory _externalContractAddresses, // to avoid stack too deep issues
        Params memory _params
    )
    {
        bondNFT = IBondNFT(_externalContractAddresses.bondNFTAddress);
        lusdToken = ILUSDToken(_externalContractAddresses.lusdTokenAddress);
        bLUSDToken = IBLUSDToken(_externalContractAddresses.bLUSDTokenAddress);
        curvePool = ICurvePool(_externalContractAddresses.curvePoolAddress);
        curveBasePool = ICurvePool(_externalContractAddresses.curveBasePoolAddress);
        bammSPVault = IBAMM(_externalContractAddresses.bammSPVaultAddress);
        yearnCurveVault = IYearnVault(_externalContractAddresses.yearnCurveVaultAddress);
        yearnRegistry = IYearnRegistry(_externalContractAddresses.yearnRegistryAddress);
        yearnGovernanceAddress = _externalContractAddresses.yearnGovernanceAddress;

        deploymentTimestamp = block.timestamp;
        targetAverageAgeSeconds = _params.targetAverageAgeSeconds;
        accrualParameter = _params.initialAccrualParameter;
        minimumAccrualParameter = _params.minimumAccrualParameter;
        require(minimumAccrualParameter > 0, "CBM: Min accrual parameter cannot be zero");
        accrualAdjustmentMultiplier = 1e18 - _params.accrualAdjustmentRate;
        accrualAdjustmentPeriodSeconds = _params.accrualAdjustmentPeriodSeconds;

        curveLiquidityGauge = ICurveLiquidityGaugeV5(_externalContractAddresses.curveLiquidityGaugeAddress);
        CHICKEN_IN_AMM_FEE = _params.chickenInAMMFee;

        uint256 fee = curvePool.fee(); // This is practically immutable (can only be set once, in `initialize()`)

        // By exchange rate, we mean the rate at which Curve exchanges LUSD <=> $ value of 3CRV (at the virtual price),
        // which is reduced by the fee.
        // For convenience, we want to parameterize our thresholds in terms of the spot prices -dy/dx & -dx/dy,
        // which are not exposed by Curve directly. Instead, we turn our thresholds into thresholds on the exchange rate
        // by taking into account the fee.
        curveDepositLUSD3CRVExchangeRateThreshold =
            _params.curveDepositDydxThreshold * (CURVE_FEE_DENOMINATOR - fee) / CURVE_FEE_DENOMINATOR;
        curveWithdrawal3CRVLUSDExchangeRateThreshold =
            _params.curveWithdrawalDxdyThreshold * (CURVE_FEE_DENOMINATOR - fee) / CURVE_FEE_DENOMINATOR;

        BOOTSTRAP_PERIOD_CHICKEN_IN = _params.bootstrapPeriodChickenIn;
        BOOTSTRAP_PERIOD_REDEEM = _params.bootstrapPeriodRedeem;
        BOOTSTRAP_PERIOD_SHIFT = _params.bootstrapPeriodShift;
        SHIFTER_DELAY = _params.shifterDelay;
        SHIFTER_WINDOW = _params.shifterWindow;
        MIN_BLUSD_SUPPLY = _params.minBLUSDSupply;
        require(_params.minBondAmount > 0, "CBM: MIN BOND AMOUNT parameter cannot be zero"); // We can still use 1e-18
        MIN_BOND_AMOUNT = _params.minBondAmount;
        NFT_RANDOMNESS_DIVISOR = _params.nftRandomnessDivisor;
        BETA = _params.redemptionFeeBeta;
        MINUTE_DECAY_FACTOR = _params.redemptionFeeMinuteDecayFactor;

        // TODO: Decide between one-time infinite LUSD approval to Yearn and Curve (lower gas cost per user tx, less secure
        // or limited approval at each bonder action (higher gas cost per user tx, more secure)
        lusdToken.approve(address(bammSPVault), MAX_UINT256);
        lusdToken.approve(address(curvePool), MAX_UINT256);
        curvePool.approve(address(yearnCurveVault), MAX_UINT256);
        lusdToken.approve(address(curveLiquidityGauge), MAX_UINT256);

        // Check that the system is hooked up to the correct latest Yearn vault
        assert(address(yearnCurveVault) == yearnRegistry.latestVault(address(curvePool)));
    }

    // --- User-facing functions ---

    function createBond(uint256 _lusdAmount) public returns (uint256) {
        _requireMinBond(_lusdAmount);
        _requireMigrationNotActive();

        _updateAccrualParameter();

        // Mint the bond NFT to the caller and get the bond ID
        (uint256 bondID, uint80 initialHalfDna) = bondNFT.mint(msg.sender, permanentLUSD / NFT_RANDOMNESS_DIVISOR);

        //Record the user’s bond data: bond_amount and start_time
        BondData memory bondData;
        bondData.lusdAmount = _lusdAmount;
        bondData.startTime = uint64(block.timestamp);
        bondData.status = BondStatus.active;
        idToBondData[bondID] = bondData;

        pendingLUSD += _lusdAmount;
        totalWeightedStartTimes += _lusdAmount * block.timestamp;

        lusdToken.transferFrom(msg.sender, address(this), _lusdAmount);

        // Deposit the LUSD to the B.Protocol LUSD vault
        _depositToBAMM(_lusdAmount);

        emit BondCreated(msg.sender, bondID, _lusdAmount, initialHalfDna);

        return bondID;
    }

    function createBondWithPermit(
        address owner, 
        uint256 amount, 
        uint256 deadline, 
        uint8 v, 
        bytes32 r, 
        bytes32 s
    ) external returns (uint256) {
        // LCB-10: don't call permit if the user already has the required amount permitted
        if (lusdToken.allowance(owner, address(this)) < amount) {
            lusdToken.permit(owner, address(this), amount, deadline, v, r, s);
        }
        return createBond(amount);
    }

    function chickenOut(uint256 _bondID, uint256 _minLUSD) external {
        BondData memory bond = idToBondData[_bondID];

        _requireCallerOwnsBond(_bondID);
        _requireActiveStatus(bond.status);

        _updateAccrualParameter();

        idToBondData[_bondID].status = BondStatus.chickenedOut;
        idToBondData[_bondID].endTime = uint64(block.timestamp);
        uint80 newDna = bondNFT.setFinalExtraData(msg.sender, _bondID, permanentLUSD / NFT_RANDOMNESS_DIVISOR);

        countChickenOut += 1;

        pendingLUSD -= bond.lusdAmount;
        totalWeightedStartTimes -= bond.lusdAmount * bond.startTime;

        /* In practice, there could be edge cases where the pendingLUSD is not fully backed:
        * - Heavy liquidations, and before yield has been converted
        * - Heavy loss-making liquidations, i.e. at <100% CR
        * - SP or B.Protocol vault hack that drains LUSD
        *
        * The user can decide how to handle chickenOuts if/when the recorded pendingLUSD is not fully backed by actual
        * LUSD in B.Protocol / the SP, by adjusting _minLUSD */
        uint256 lusdToWithdraw = _requireEnoughLUSDInBAMM(bond.lusdAmount, _minLUSD);

        // Withdraw from B.Protocol LUSD vault
        _withdrawFromBAMM(lusdToWithdraw, msg.sender);

        emit BondCancelled(msg.sender, _bondID, bond.lusdAmount, _minLUSD, lusdToWithdraw, newDna);
    }

    // transfer _lusdToTransfer to the LUSD/bLUSD AMM LP Rewards staking contract
    function _transferToRewardsStakingContract(uint256 _lusdToTransfer) internal {
        uint256 lusdBalanceBefore = lusdToken.balanceOf(address(this));
        curveLiquidityGauge.deposit_reward_token(address(lusdToken), _lusdToTransfer);

        assert(lusdBalanceBefore - lusdToken.balanceOf(address(this)) == _lusdToTransfer);
    }

    function _withdrawFromSPVaultAndTransferToRewardsStakingContract(uint256 _lusdAmount) internal {
        // Pull the LUSD amount from B.Protocol LUSD vault
        _withdrawFromBAMM(_lusdAmount, address(this));

        // Deposit in rewards contract
        _transferToRewardsStakingContract(_lusdAmount);
    }

    /* Divert acquired yield to LUSD/bLUSD AMM LP rewards staking contract
     * It happens on the very first chicken in event of the system, or any time that redemptions deplete bLUSD total supply to zero
     * Assumption: When there have been no chicken ins since the bLUSD supply was set to 0 (either due to system deployment, or full bLUSD redemption),
     * all acquired LUSD must necessarily be pure yield.
     */
    function _firstChickenIn(uint256 _bondStartTime, uint256 _bammLUSDValue, uint256 _lusdInBAMMSPVault) internal returns (uint256) {
        //assert(!migration); // we leave it as a comment so we can uncomment it for automated testing tools

        require(block.timestamp >= _bondStartTime + BOOTSTRAP_PERIOD_CHICKEN_IN, "CBM: First chicken in must wait until bootstrap period is over");
        firstChickenInTime = block.timestamp;

        (
            uint256 acquiredLUSDInSP,
            /* uint256 acquiredLUSDInCurve */,
            /* uint256 ownedLUSDInSP */,
            /* uint256 ownedLUSDInCurve */,
            /* uint256 permanentLUSDCached */
        ) = _getLUSDSplit(_bammLUSDValue);

        // Make sure that LUSD available in B.Protocol is at least as much as acquired
        // If first chicken in happens after an scenario of heavy liquidations and before ETH has been sold by B.Protocol
        // so that there’s not enough LUSD available in B.Protocol to transfer all the acquired bucket to the staking contract,
        // the system would start with a backing ratio greater than 1
        require(_lusdInBAMMSPVault >= acquiredLUSDInSP, "CBM: Not enough LUSD available in B.Protocol");

        // From SP Vault
        if (acquiredLUSDInSP > 0) {
            _withdrawFromSPVaultAndTransferToRewardsStakingContract(acquiredLUSDInSP);
        }

        return _lusdInBAMMSPVault - acquiredLUSDInSP;
    }

    function chickenIn(uint256 _bondID) external {
        BondData memory bond = idToBondData[_bondID];

        _requireCallerOwnsBond(_bondID);
        _requireActiveStatus(bond.status);

        uint256 updatedAccrualParameter = _updateAccrualParameter();
        (uint256 bammLUSDValue, uint256 lusdInBAMMSPVault) = _updateBAMMDebt();

        (uint256 chickenInFeeAmount, uint256 bondAmountMinusChickenInFee) = _getBondWithChickenInFeeApplied(bond.lusdAmount);

        /* Upon the first chicken-in after a) system deployment or b) redemption of the full bLUSD supply, divert
        * any earned yield to the bLUSD-LUSD AMM for fairness.
        *
        * This is not done in migration mode since there is no need to send rewards to the staking contract.
        */
        if (bLUSDToken.totalSupply() == 0 && !migration) {
            lusdInBAMMSPVault = _firstChickenIn(bond.startTime, bammLUSDValue, lusdInBAMMSPVault);
        }

        // Get the LUSD amount to acquire from the bond in proportion to the system's current backing ratio, in order to maintain said ratio.
        uint256 lusdToAcquire = _calcAccruedAmount(bond.startTime, bondAmountMinusChickenInFee, updatedAccrualParameter);
        // Get backing ratio and accrued bLUSD
        uint256 backingRatio = _calcSystemBackingRatioFromBAMMValue(bammLUSDValue);
        uint256 accruedBLUSD = lusdToAcquire * 1e18 / backingRatio;

        idToBondData[_bondID].claimedBLUSD = uint64(Math.min(accruedBLUSD / 1e18, type(uint64).max)); // to units and uint64
        idToBondData[_bondID].status = BondStatus.chickenedIn;
        idToBondData[_bondID].endTime = uint64(block.timestamp);
        uint80 newDna = bondNFT.setFinalExtraData(msg.sender, _bondID, permanentLUSD / NFT_RANDOMNESS_DIVISOR);

        countChickenIn += 1;

        // Subtract the bonded amount from the total pending LUSD (and implicitly increase the total acquired LUSD)
        pendingLUSD -= bond.lusdAmount;
        totalWeightedStartTimes -= bond.lusdAmount * bond.startTime;

        // Get the remaining surplus from the LUSD amount to acquire from the bond
        uint256 lusdSurplus = bondAmountMinusChickenInFee - lusdToAcquire;

        // Handle the surplus LUSD from the chicken-in:
        if (!migration) { // In normal mode, add the surplus to the permanent bucket by increasing the permament tracker. This implicitly decreases the acquired LUSD.
            permanentLUSD += lusdSurplus;
        } else { // In migration mode, withdraw surplus from B.Protocol and refund to bonder
            // TODO: should we allow to pass in a minimum value here too?
            (,lusdInBAMMSPVault,) = bammSPVault.getLUSDValue();
            uint256 lusdToRefund = Math.min(lusdSurplus, lusdInBAMMSPVault);
            if (lusdToRefund > 0) { _withdrawFromBAMM(lusdToRefund, msg.sender); }
        }

        bLUSDToken.mint(msg.sender, accruedBLUSD);

        // Transfer the chicken in fee to the LUSD/bLUSD AMM LP Rewards staking contract during normal mode.
        if (!migration && lusdInBAMMSPVault >= chickenInFeeAmount) {
            _withdrawFromSPVaultAndTransferToRewardsStakingContract(chickenInFeeAmount);
        }

        emit BondClaimed(msg.sender, _bondID, bond.lusdAmount, accruedBLUSD, lusdSurplus, chickenInFeeAmount, migration, newDna);
    }

    function redeem(uint256 _bLUSDToRedeem, uint256 _minLUSDFromBAMMSPVault) external returns (uint256, uint256) {
        _requireNonZeroAmount(_bLUSDToRedeem);
        _requireRedemptionNotDepletingbLUSD(_bLUSDToRedeem);

        require(block.timestamp >= firstChickenInTime + BOOTSTRAP_PERIOD_REDEEM, "CBM: Redemption after first chicken in must wait until bootstrap period is over");

        (
            uint256 acquiredLUSDInSP,
            uint256 acquiredLUSDInCurve,
            /* uint256 ownedLUSDInSP */,
            uint256 ownedLUSDInCurve,
            uint256 permanentLUSDCached
        ) = _getLUSDSplitAfterUpdatingBAMMDebt();

        uint256 fractionOfBLUSDToRedeem = _bLUSDToRedeem * 1e18 / bLUSDToken.totalSupply();
        // Calculate redemption fee. No fee in migration mode.
        uint256 redemptionFeePercentage = migration ? 0 : _updateRedemptionFeePercentage(fractionOfBLUSDToRedeem);
        // Will collect redemption fees from both buckets (in LUSD).
        uint256 redemptionFeeLUSD;

        // TODO: Both _requireEnoughLUSDInBAMM and _updateBAMMDebt call B.Protocol getLUSDValue, so it may be optmized
        // Calculate the LUSD to withdraw from LUSD vault, withdraw and send to redeemer. Move the fee to the permanent bucket.
        uint256 lusdToWithdrawFromSP;
        { // Block scoping to avoid stack too deep issues
            uint256 acquiredLUSDInSPToRedeem = acquiredLUSDInSP * fractionOfBLUSDToRedeem / 1e18;
            uint256 acquiredLUSDInSPToWithdraw = acquiredLUSDInSPToRedeem * (1e18 - redemptionFeePercentage) / 1e18;
            redemptionFeeLUSD += acquiredLUSDInSPToRedeem - acquiredLUSDInSPToWithdraw;
            lusdToWithdrawFromSP = _requireEnoughLUSDInBAMM(acquiredLUSDInSPToWithdraw, _minLUSDFromBAMMSPVault);
            if (lusdToWithdrawFromSP > 0) { _withdrawFromBAMM(lusdToWithdrawFromSP, msg.sender); }
        }

        // Send yTokens to the redeemer according to the proportion of owned LUSD in Curve that's being redeemed
        uint256 yTokensFromCurveVault;
        if (ownedLUSDInCurve > 0) {
            uint256 acquiredLUSDInCurveToRedeem = acquiredLUSDInCurve * fractionOfBLUSDToRedeem / 1e18;
            uint256 lusdToWithdrawFromCurve = acquiredLUSDInCurveToRedeem * (1e18 - redemptionFeePercentage) / 1e18;
            redemptionFeeLUSD += acquiredLUSDInCurveToRedeem - lusdToWithdrawFromCurve;
            yTokensFromCurveVault = yTokensHeldByCBM * lusdToWithdrawFromCurve / ownedLUSDInCurve;
            if (yTokensFromCurveVault > 0) { _transferFromCurve(msg.sender, yTokensFromCurveVault); }
        }

        // Move the fee to permanent. This implicitly removes it from the acquired bucket
        permanentLUSD = permanentLUSDCached + redemptionFeeLUSD;

        _requireNonZeroAmount(lusdToWithdrawFromSP + yTokensFromCurveVault);

        // Burn the redeemed bLUSD
        bLUSDToken.burn(msg.sender, _bLUSDToRedeem);

        emit BLUSDRedeemed(msg.sender, _bLUSDToRedeem, _minLUSDFromBAMMSPVault, lusdToWithdrawFromSP, yTokensFromCurveVault, redemptionFeeLUSD);

        return (lusdToWithdrawFromSP, yTokensFromCurveVault);
    }

    function shiftLUSDFromSPToCurve(uint256 _maxLUSDToShift) external {
        _requireShiftBootstrapPeriodEnded();
        _requireMigrationNotActive();
        _requireNonZeroBLUSDSupply();
        _requireShiftWindowIsOpen();

        (uint256 bammLUSDValue, uint256 lusdInBAMMSPVault) = _updateBAMMDebt();
        uint256 lusdOwnedInBAMMSPVault = bammLUSDValue - pendingLUSD;

        uint256 totalLUSDInCurve = getTotalLUSDInCurve();
        // it can happen due to profits from shifts or rounding errors:
        _requirePermanentGreaterThanCurve(totalLUSDInCurve);

        // Make sure pending bucket is not moved to Curve, so it can be withdrawn on chicken out
        uint256 clampedLUSDToShift = Math.min(_maxLUSDToShift, lusdOwnedInBAMMSPVault);

        // Make sure there’s enough LUSD available in B.Protocol
        clampedLUSDToShift = Math.min(clampedLUSDToShift, lusdInBAMMSPVault);

        // Make sure we don’t make Curve bucket greater than Permanent one with the shift
        // subtraction is safe per _requirePermanentGreaterThanCurve above
        clampedLUSDToShift = Math.min(clampedLUSDToShift, permanentLUSD - totalLUSDInCurve);

        _requireNonZeroAmount(clampedLUSDToShift);

        // Get the 3CRV virtual price only once, and use it for both initial and final check.
        // Adding LUSD liquidity to the meta-pool does not change 3CRV virtual price.
        uint256 _3crvVirtualPrice = curveBasePool.get_virtual_price();
        uint256 initialExchangeRate = _getLUSD3CRVExchangeRate(_3crvVirtualPrice);

        require(
            initialExchangeRate > curveDepositLUSD3CRVExchangeRateThreshold,
            "CBM: LUSD:3CRV exchange rate must be over the deposit threshold before SP->Curve shift"
        );

        // Withdram LUSD from B.Protocol
        _withdrawFromBAMM(clampedLUSDToShift, address(this));

        // Deposit the received LUSD to Curve in return for LUSD3CRV-f tokens
        uint256 lusd3CRVBalanceBefore = curvePool.balanceOf(address(this));
        /* TODO: Determine if we should pass a minimum amount of LP tokens to receive here. Seems infeasible to determinine the mininum on-chain from
        * Curve spot price / quantities, which are manipulable. */
        curvePool.add_liquidity([clampedLUSDToShift, 0], 0);
        uint256 lusd3CRVBalanceDelta = curvePool.balanceOf(address(this)) - lusd3CRVBalanceBefore;

        // Deposit the received LUSD3CRV-f to Yearn Curve vault
        _depositToCurve(lusd3CRVBalanceDelta);

        // Do price check: ensure the SP->Curve shift has decreased the LUSD:3CRV exchange rate, but not into unprofitable territory
        uint256 finalExchangeRate = _getLUSD3CRVExchangeRate(_3crvVirtualPrice);

        require(
            finalExchangeRate < initialExchangeRate &&
            finalExchangeRate >= curveDepositLUSD3CRVExchangeRateThreshold,
            "CBM: SP->Curve shift must decrease LUSD:3CRV exchange rate to a value above the deposit threshold"
        );
    }

    function shiftLUSDFromCurveToSP(uint256 _maxLUSDToShift) external {
        _requireShiftBootstrapPeriodEnded();
        _requireMigrationNotActive();
        _requireNonZeroBLUSDSupply();
        _requireShiftWindowIsOpen();

        // We can’t shift more than what’s in Curve
        uint256 ownedLUSDInCurve = getTotalLUSDInCurve();
        uint256 clampedLUSDToShift = Math.min(_maxLUSDToShift, ownedLUSDInCurve);
        _requireNonZeroAmount(clampedLUSDToShift);

        // Get the 3CRV virtual price only once, and use it for both initial and final check.
        // Removing LUSD liquidity from the meta-pool does not change 3CRV virtual price.
        uint256 _3crvVirtualPrice = curveBasePool.get_virtual_price();
        uint256 initialExchangeRate = _get3CRVLUSDExchangeRate(_3crvVirtualPrice);

        // Here we're using the 3CRV:LUSD exchange rate (with 3CRV being valued at its virtual price),
        // which increases as LUSD price decreases, hence the direction of the inequality.
        require(
            initialExchangeRate > curveWithdrawal3CRVLUSDExchangeRateThreshold,
            "CBM: 3CRV:LUSD exchange rate must be above the withdrawal threshold before Curve->SP shift"
        );

        // Convert yTokens to LUSD3CRV-f
        uint256 lusd3CRVBalanceBefore = curvePool.balanceOf(address(this));

        // ownedLUSDInCurve > 0 implied by _requireNonZeroAmount(clampedLUSDToShift)
        uint256 yTokensToBurnFromCurveVault = yTokensHeldByCBM * clampedLUSDToShift / ownedLUSDInCurve;
        _withdrawFromCurve(yTokensToBurnFromCurveVault);
        uint256 lusd3CRVBalanceDelta = curvePool.balanceOf(address(this)) - lusd3CRVBalanceBefore;

        // Withdraw LUSD from Curve
        uint256 lusdBalanceBefore = lusdToken.balanceOf(address(this));
        /* TODO: Determine if we should pass a minimum amount of LUSD to receive here. Seems infeasible to determinine the mininum on-chain from
        * Curve spot price / quantities, which are manipulable. */
        curvePool.remove_liquidity_one_coin(lusd3CRVBalanceDelta, INDEX_OF_LUSD_TOKEN_IN_CURVE_POOL, 0);
        uint256 lusdBalanceDelta = lusdToken.balanceOf(address(this)) - lusdBalanceBefore;

        // Assertion should hold in principle. In practice, there is usually minor rounding error
        // assert(lusdBalanceDelta == _lusdToShift);

        // Deposit the received LUSD to B.Protocol LUSD vault
        _depositToBAMM(lusdBalanceDelta);

        // Ensure the Curve->SP shift has decreased the 3CRV:LUSD exchange rate, but not into unprofitable territory
        uint256 finalExchangeRate = _get3CRVLUSDExchangeRate(_3crvVirtualPrice);

        require(
            finalExchangeRate < initialExchangeRate &&
            finalExchangeRate >= curveWithdrawal3CRVLUSDExchangeRateThreshold,
            "CBM: Curve->SP shift must increase 3CRV:LUSD exchange rate to a value above the withdrawal threshold"
        );
    }

    // --- B.Protocol debt functions ---

    // If the actual balance of B.Protocol is higher than our internal accounting,
    // it means that B.Protocol has had gains (through sell of ETH or LQTY).
    // We account for those gains
    // If the balance was lower (which would mean losses), we expect them to be eventually recovered
    function _getInternalBAMMLUSDValue() internal view returns (uint256) {
        (, uint256 lusdInBAMMSPVault,) = bammSPVault.getLUSDValue();

        return Math.max(bammLUSDDebt, lusdInBAMMSPVault);
    }

    // TODO: Should we make this one publicly callable, so that external getters can be up to date (by previously calling this)?
    // Returns the value updated
    function _updateBAMMDebt() internal returns (uint256, uint256) {
        (, uint256 lusdInBAMMSPVault,) = bammSPVault.getLUSDValue();
        uint256 bammLUSDDebtCached = bammLUSDDebt;

        // If the actual balance of B.Protocol is higher than our internal accounting,
        // it means that B.Protocol has had gains (through sell of ETH or LQTY).
        // We account for those gains
        // If the balance was lower (which would mean losses), we expect them to be eventually recovered
        if (lusdInBAMMSPVault > bammLUSDDebtCached) {
            bammLUSDDebt = lusdInBAMMSPVault;
            return (lusdInBAMMSPVault, lusdInBAMMSPVault);
        }

        return (bammLUSDDebtCached, lusdInBAMMSPVault);
    }

    function _depositToBAMM(uint256 _lusdAmount) internal {
        bammSPVault.deposit(_lusdAmount);
        bammLUSDDebt += _lusdAmount;
    }

    function _withdrawFromBAMM(uint256 _lusdAmount, address _to) internal {
        bammSPVault.withdraw(_lusdAmount, _to);
        bammLUSDDebt -= _lusdAmount;
    }

    // @dev make sure this wrappers are always used instead of calling yearnCurveVault functions directyl,
    // otherwise the internal accounting would fail
    function _depositToCurve(uint256 _lusd3CRV) internal {
        uint256 yTokensBalanceBefore = yearnCurveVault.balanceOf(address(this));
        yearnCurveVault.deposit(_lusd3CRV);
        uint256 yTokensBalanceDelta = yearnCurveVault.balanceOf(address(this)) - yTokensBalanceBefore;
        yTokensHeldByCBM += yTokensBalanceDelta;
    }

    function _withdrawFromCurve(uint256 _yTokensToSwap) internal {
        yearnCurveVault.withdraw(_yTokensToSwap);
        yTokensHeldByCBM -= _yTokensToSwap;
    }

    function _transferFromCurve(address _to, uint256 _yTokensToTransfer) internal {
        yearnCurveVault.transfer(_to, _yTokensToTransfer);
        yTokensHeldByCBM -= _yTokensToTransfer;
    }

    // --- Migration functionality ---

    /* Migration function callable one-time and only by Yearn governance.
    * Moves all permanent LUSD in Curve to the Curve acquired bucket.
    */
    function activateMigration() external {
        _requireCallerIsYearnGovernance();
        _requireMigrationNotActive();

        migration = true;

        emit MigrationTriggered(permanentLUSD);

        // Zero the permament LUSD tracker. This implicitly makes all permament liquidity acquired (and redeemable)
        permanentLUSD = 0;
    }

    // --- Shifter countdown starter ---

    function startShifterCountdown() public {
        // First check that the previous delay and shifting window have passed
        require(block.timestamp >= lastShifterCountdownStartTime + SHIFTER_DELAY + SHIFTER_WINDOW, "CBM: Previous shift delay and window must have passed");

        // Begin the new countdown from now
        lastShifterCountdownStartTime = block.timestamp;
    }

    // --- Fee share ---

    function sendFeeShare(uint256 _lusdAmount) external {
        _requireCallerIsYearnGovernance();
        require(!migration, "CBM: Receive fee share only in normal mode");

        // Move LUSD from caller to CBM and deposit to B.Protocol LUSD Vault
        lusdToken.transferFrom(yearnGovernanceAddress, address(this), _lusdAmount);
        _depositToBAMM(_lusdAmount);
    }

    // --- Helper functions ---

    function _getLUSD3CRVExchangeRate(uint256 _3crvVirtualPrice) internal view returns (uint256) {
        // Get the amount of 3CRV that would be received by swapping 1 LUSD (after deduction of fees)
        // If p_{LUSD:3CRV} is the price of LUSD quoted in 3CRV, then this returns p_{LUSD:3CRV} * (1 - fee)
        // as long as the pool is large enough so that 1 LUSD doesn't introduce significant slippage.
        uint256 dy = curvePool.get_dy(INDEX_OF_LUSD_TOKEN_IN_CURVE_POOL, INDEX_OF_3CRV_TOKEN_IN_CURVE_POOL, 1e18);

        return dy * _3crvVirtualPrice / 1e18;
    }

    function _get3CRVLUSDExchangeRate(uint256 _3crvVirtualPrice) internal view returns (uint256) {
        // Get the amount of LUSD that would be received by swapping 1 3CRV (after deduction of fees)
        // If p_{3CRV:LUSD} is the price of 3CRV quoted in LUSD, then this returns p_{3CRV:LUSD} * (1 - fee)
        // as long as the pool is large enough so that 1 3CRV doesn't introduce significant slippage.
        uint256 dy = curvePool.get_dy(INDEX_OF_3CRV_TOKEN_IN_CURVE_POOL, INDEX_OF_LUSD_TOKEN_IN_CURVE_POOL, 1e18);

        return dy * 1e18 / _3crvVirtualPrice;
    }

    // Calc decayed redemption rate
    function calcRedemptionFeePercentage(uint256 _fractionOfBLUSDToRedeem) public view returns (uint256) {
        uint256 minutesPassed = _minutesPassedSinceLastRedemption();
        uint256 decayFactor = decPow(MINUTE_DECAY_FACTOR, minutesPassed);

        uint256 decayedBaseRedemptionRate = baseRedemptionRate * decayFactor / DECIMAL_PRECISION;

        // Increase redemption base rate with the new redeemed amount
        uint256 newBaseRedemptionRate = decayedBaseRedemptionRate + _fractionOfBLUSDToRedeem / BETA;
        newBaseRedemptionRate = Math.min(newBaseRedemptionRate, DECIMAL_PRECISION); // cap baseRate at a maximum of 100%
        //assert(newBaseRedemptionRate <= DECIMAL_PRECISION); // This is already enforced in the line above

        return newBaseRedemptionRate;
    }

    // Update the base redemption rate and the last redemption time (only if time passed >= decay interval. This prevents base rate griefing)
    function _updateRedemptionFeePercentage(uint256 _fractionOfBLUSDToRedeem) internal returns (uint256) {
        uint256 newBaseRedemptionRate = calcRedemptionFeePercentage(_fractionOfBLUSDToRedeem);
        baseRedemptionRate = newBaseRedemptionRate;
        emit BaseRedemptionRateUpdated(newBaseRedemptionRate);

        uint256 timePassed = block.timestamp - lastRedemptionTime;

        if (timePassed >= SECONDS_IN_ONE_MINUTE) {
            lastRedemptionTime = block.timestamp;
            emit LastRedemptionTimeUpdated(block.timestamp);
        }

        return newBaseRedemptionRate;
    }

    function _minutesPassedSinceLastRedemption() internal view returns (uint256) {
        return (block.timestamp - lastRedemptionTime) / SECONDS_IN_ONE_MINUTE;
    }

    function _getBondWithChickenInFeeApplied(uint256 _bondLUSDAmount) internal view returns (uint256, uint256) {
        // Apply zero fee in migration mode
        if (migration) {return (0, _bondLUSDAmount);}

        // Otherwise, apply the constant fee rate
        uint256 chickenInFeeAmount = _bondLUSDAmount * CHICKEN_IN_AMM_FEE / 1e18;
        uint256 bondAmountMinusChickenInFee = _bondLUSDAmount - chickenInFeeAmount;

        return (chickenInFeeAmount, bondAmountMinusChickenInFee);
    }

    function _getBondAmountMinusChickenInFee(uint256 _bondLUSDAmount) internal view returns (uint256) {
        (, uint256 bondAmountMinusChickenInFee) = _getBondWithChickenInFeeApplied(_bondLUSDAmount);
        return bondAmountMinusChickenInFee;
    }

    /* _calcAccruedAmount: internal getter for calculating accrued token amount for a given bond.
    *
    * This function is unit-agnostic. It can be used to calculate a bonder's accrrued bLUSD, or the LUSD that that the
    * CB system would acquire (i.e. receive to the acquired bucket) if the bond were Chickened In now.
    *
    * For the bonder, _capAmount is their bLUSD cap.
    * For the CB system, _capAmount is the LUSD bond amount (less the Chicken In fee).
    */
    function _calcAccruedAmount(uint256 _startTime, uint256 _capAmount, uint256 _accrualParameter) internal view returns (uint256) {
        // All bonds have a non-zero creation timestamp, so return accrued sLQTY 0 if the startTime is 0
        if (_startTime == 0) {return 0;}

        // Scale `bondDuration` up to an 18 digit fixed-point number.
        // This lets us add it to `accrualParameter`, which is also an 18-digit FP.
        uint256 bondDuration = 1e18 * (block.timestamp - _startTime);

        uint256 accruedAmount = _capAmount * bondDuration / (bondDuration + _accrualParameter);
        //assert(accruedAmount < _capAmount); // we leave it as a comment so we can uncomment it for automated testing tools

        return accruedAmount;
    }

    // Gauge the average (size-weighted) outstanding bond age and adjust accrual parameter if it's higher than our target.
    // If there's been more than one adjustment period since the last adjustment, perform multiple adjustments retroactively.
    function _calcUpdatedAccrualParameter(
        uint256 _storedAccrualParameter,
        uint256 _storedAccrualAdjustmentCount
    )
        internal
        view
        returns (
            uint256 updatedAccrualParameter,
            uint256 updatedAccrualAdjustmentPeriodCount
        )
    {
        updatedAccrualAdjustmentPeriodCount = (block.timestamp - deploymentTimestamp) / accrualAdjustmentPeriodSeconds;

        if (
            // There hasn't been enough time since the last update to warrant another update
            updatedAccrualAdjustmentPeriodCount == _storedAccrualAdjustmentCount ||
            // or `accrualParameter` is already bottomed-out
            _storedAccrualParameter == minimumAccrualParameter ||
            // or there are no outstanding bonds (avoid division by zero)
            pendingLUSD == 0
        ) {
            return (_storedAccrualParameter, updatedAccrualAdjustmentPeriodCount);
        }

        uint256 averageStartTime = totalWeightedStartTimes / pendingLUSD;

        // We want to calculate the period when the average age will have reached or exceeded the
        // target average age, to be used later in a check against the actual current period.
        //
        // At any given timestamp `t`, the average age can be calculated as:
        //   averageAge(t) = t - averageStartTime
        //
        // For any period `n`, the average age is evaluated at the following timestamp:
        //   tSample(n) = deploymentTimestamp + n * accrualAdjustmentPeriodSeconds
        //
        // Hence we're looking for the smallest integer `n` such that:
        //   averageAge(tSample(n)) >= targetAverageAgeSeconds
        //
        // If `n` is the smallest integer for which the above inequality stands, then:
        //   averageAge(tSample(n - 1)) < targetAverageAgeSeconds
        //
        // Combining the two inequalities:
        //   averageAge(tSample(n - 1)) < targetAverageAgeSeconds <= averageAge(tSample(n))
        //
        // Substituting and rearranging:
        //   1.    deploymentTimestamp + (n - 1) * accrualAdjustmentPeriodSeconds - averageStartTime
        //       < targetAverageAgeSeconds
        //      <= deploymentTimestamp + n * accrualAdjustmentPeriodSeconds - averageStartTime
        //
        //   2.    (n - 1) * accrualAdjustmentPeriodSeconds
        //       < averageStartTime + targetAverageAgeSeconds - deploymentTimestamp
        //      <= n * accrualAdjustmentPeriodSeconds
        //
        //   3. n - 1 < (averageStartTime + targetAverageAgeSeconds - deploymentTimestamp) / accrualAdjustmentPeriodSeconds <= n
        //
        // Using equivalence `n = ceil(x) <=> n - 1 < x <= n` we arrive at:
        //   n = ceil((averageStartTime + targetAverageAgeSeconds - deploymentTimestamp) / accrualAdjustmentPeriodSeconds)
        //
        // We can calculate `ceil(a / b)` using `Math.ceilDiv(a, b)`.
        uint256 adjustmentPeriodCountWhenTargetIsExceeded = Math.ceilDiv(
            averageStartTime + targetAverageAgeSeconds - deploymentTimestamp,
            accrualAdjustmentPeriodSeconds
        );

        if (updatedAccrualAdjustmentPeriodCount < adjustmentPeriodCountWhenTargetIsExceeded) {
            // No adjustment needed; target average age hasn't been exceeded yet
            return (_storedAccrualParameter, updatedAccrualAdjustmentPeriodCount);
        }

        uint256 numberOfAdjustments = updatedAccrualAdjustmentPeriodCount - Math.max(
            _storedAccrualAdjustmentCount,
            adjustmentPeriodCountWhenTargetIsExceeded - 1
        );

        updatedAccrualParameter = Math.max(
            _storedAccrualParameter * decPow(accrualAdjustmentMultiplier, numberOfAdjustments) / 1e18,
            minimumAccrualParameter
        );
    }

    function _updateAccrualParameter() internal returns (uint256) {
        uint256 storedAccrualParameter = accrualParameter;
        uint256 storedAccrualAdjustmentPeriodCount = accrualAdjustmentPeriodCount;

        (uint256 updatedAccrualParameter, uint256 updatedAccrualAdjustmentPeriodCount) =
            _calcUpdatedAccrualParameter(storedAccrualParameter, storedAccrualAdjustmentPeriodCount);

        if (updatedAccrualAdjustmentPeriodCount != storedAccrualAdjustmentPeriodCount) {
            accrualAdjustmentPeriodCount = updatedAccrualAdjustmentPeriodCount;

            if (updatedAccrualParameter != storedAccrualParameter) {
                accrualParameter = updatedAccrualParameter;
                emit AccrualParameterUpdated(updatedAccrualParameter);
            }
        }

        return updatedAccrualParameter;
    }

    // Internal getter for calculating the bond bLUSD cap based on bonded amount and backing ratio
    function _calcBondBLUSDCap(uint256 _bondedAmount, uint256 _backingRatio) internal pure returns (uint256) {
        // TODO: potentially refactor this -  i.e. have a (1 / backingRatio) function for more precision
        return _bondedAmount * 1e18 / _backingRatio;
    }

    // --- 'require' functions

    function _requireCallerOwnsBond(uint256 _bondID) internal view {
        require(msg.sender == bondNFT.ownerOf(_bondID), "CBM: Caller must own the bond");
    }

    function _requireActiveStatus(BondStatus status) internal pure {
        require(status == BondStatus.active, "CBM: Bond must be active");
    }

    function _requireNonZeroAmount(uint256 _amount) internal pure {
        require(_amount > 0, "CBM: Amount must be > 0");
    }

    function _requireNonZeroBLUSDSupply() internal view {
        require(bLUSDToken.totalSupply() > 0, "CBM: bLUSD Supply must be > 0 upon shifting");
    }

    function _requireMinBond(uint256 _lusdAmount) internal view {
        require(_lusdAmount >= MIN_BOND_AMOUNT, "CBM: Bond minimum amount not reached");
    }

    function _requireRedemptionNotDepletingbLUSD(uint256 _bLUSDToRedeem) internal view {
        if (!migration) {
            //require(_bLUSDToRedeem < bLUSDTotalSupply, "CBM: Cannot redeem total supply");
            require(_bLUSDToRedeem + MIN_BLUSD_SUPPLY <= bLUSDToken.totalSupply(), "CBM: Cannot redeem below min supply");
        }
    }

    function _requireMigrationNotActive() internal view {
        require(!migration, "CBM: Migration must be not be active");
    }

    function _requireCallerIsYearnGovernance() internal view {
        require(msg.sender == yearnGovernanceAddress, "CBM: Only Yearn Governance can call");
    }

    function _requireEnoughLUSDInBAMM(uint256 _requestedLUSD, uint256 _minLUSD) internal view returns (uint256) {
        require(_requestedLUSD >= _minLUSD, "CBM: Min value cannot be greater than nominal amount");

        (, uint256 lusdInBAMMSPVault,) = bammSPVault.getLUSDValue();
        require(lusdInBAMMSPVault >= _minLUSD, "CBM: Not enough LUSD available in B.Protocol");

        uint256 lusdToWithdraw = Math.min(_requestedLUSD, lusdInBAMMSPVault);

        return lusdToWithdraw;
    }

    function _requireShiftBootstrapPeriodEnded() internal view {
        require(block.timestamp - deploymentTimestamp >= BOOTSTRAP_PERIOD_SHIFT, "CBM: Shifter only callable after shift bootstrap period ends");
    }

    function _requireShiftWindowIsOpen() internal view {
        uint256 shiftWindowStartTime = lastShifterCountdownStartTime + SHIFTER_DELAY;
        uint256 shiftWindowFinishTime = shiftWindowStartTime + SHIFTER_WINDOW;

        require(block.timestamp >= shiftWindowStartTime && block.timestamp < shiftWindowFinishTime, "CBM: Shift only possible inside shifting window");
    }

    function _requirePermanentGreaterThanCurve(uint256 _totalLUSDInCurve) internal view {
        require(permanentLUSD >= _totalLUSDInCurve, "CBM: The amount in Curve cannot be greater than the Permanent bucket");
    }

    // --- Getter convenience functions ---

    // Bond getters

    function getBondData(uint256 _bondID)
        external
        view
        returns (
            uint256 lusdAmount,
            uint64 claimedBLUSD,
            uint64 startTime,
            uint64 endTime,
            uint8 status
        )
    {
        BondData memory bond = idToBondData[_bondID];
        return (bond.lusdAmount, bond.claimedBLUSD, bond.startTime, bond.endTime, uint8(bond.status));
    }

    function getLUSDToAcquire(uint256 _bondID) external view returns (uint256) {
        BondData memory bond = idToBondData[_bondID];

        (uint256 updatedAccrualParameter, ) = _calcUpdatedAccrualParameter(accrualParameter, accrualAdjustmentPeriodCount);

        return _calcAccruedAmount(bond.startTime, _getBondAmountMinusChickenInFee(bond.lusdAmount), updatedAccrualParameter);
    }

    function calcAccruedBLUSD(uint256 _bondID) external view returns (uint256) {
        BondData memory bond = idToBondData[_bondID];

        if (bond.status != BondStatus.active) {
            return 0;
        }

        uint256 bondBLUSDCap = _calcBondBLUSDCap(_getBondAmountMinusChickenInFee(bond.lusdAmount), calcSystemBackingRatio());

        (uint256 updatedAccrualParameter, ) = _calcUpdatedAccrualParameter(accrualParameter, accrualAdjustmentPeriodCount);

        return _calcAccruedAmount(bond.startTime, bondBLUSDCap, updatedAccrualParameter);
    }

    function calcBondBLUSDCap(uint256 _bondID) external view returns (uint256) {
        uint256 backingRatio = calcSystemBackingRatio();

        BondData memory bond = idToBondData[_bondID];

        return _calcBondBLUSDCap(_getBondAmountMinusChickenInFee(bond.lusdAmount), backingRatio);
    }

    function getLUSDInBAMMSPVault() external view returns (uint256) {
        (, uint256 lusdInBAMMSPVault,) = bammSPVault.getLUSDValue();

        return lusdInBAMMSPVault;
    }

    // Native vault token value getters

    // Calculates the LUSD3CRV value of LUSD Curve Vault yTokens held by the ChickenBondManager
    function calcTotalYearnCurveVaultShareValue() public view returns (uint256) {
        return yTokensHeldByCBM * yearnCurveVault.pricePerShare() / 1e18;
    }

    // Calculates the LUSD value of this contract, including B.Protocol LUSD Vault and Curve Vault
    function calcTotalLUSDValue() external view returns (uint256) {
        uint256 totalLUSDInCurve = getTotalLUSDInCurve();
        uint256 bammLUSDValue = _getInternalBAMMLUSDValue();

        return bammLUSDValue + totalLUSDInCurve;
    }

    function getTotalLUSDInCurve() public view returns (uint256) {
        uint256 LUSD3CRVInCurve = calcTotalYearnCurveVaultShareValue();
        uint256 totalLUSDInCurve;
        if (LUSD3CRVInCurve > 0) {
            uint256 LUSD3CRVVirtualPrice = curvePool.get_virtual_price();
            totalLUSDInCurve = LUSD3CRVInCurve * LUSD3CRVVirtualPrice / 1e18;
        }

        return totalLUSDInCurve;
    }

    // Pending getter

    function getPendingLUSD() external view returns (uint256) {
        return pendingLUSD;
    }

    // Acquired getters

    function _getLUSDSplit(uint256 _bammLUSDValue)
        internal
        view
        returns (
            uint256 acquiredLUSDInSP,
            uint256 acquiredLUSDInCurve,
            uint256 ownedLUSDInSP,
            uint256 ownedLUSDInCurve,
            uint256 permanentLUSDCached
        )
    {
        // _bammLUSDValue is guaranteed to be at least pendingLUSD due to the way we track BAMM debt
        ownedLUSDInSP = _bammLUSDValue - pendingLUSD;
        ownedLUSDInCurve = getTotalLUSDInCurve(); // All LUSD in Curve is owned
        permanentLUSDCached = permanentLUSD;

        uint256 ownedLUSD = ownedLUSDInSP + ownedLUSDInCurve;

        if (ownedLUSD > permanentLUSDCached) {
            // ownedLUSD > 0 implied
            uint256 acquiredLUSD = ownedLUSD - permanentLUSDCached;
            acquiredLUSDInSP = acquiredLUSD * ownedLUSDInSP / ownedLUSD;
            acquiredLUSDInCurve = acquiredLUSD - acquiredLUSDInSP;
        }
    }

    // Helper to avoid stack too deep in redeem() (we save one local variable)
    function _getLUSDSplitAfterUpdatingBAMMDebt()
        internal
        returns (
            uint256 acquiredLUSDInSP,
            uint256 acquiredLUSDInCurve,
            uint256 ownedLUSDInSP,
            uint256 ownedLUSDInCurve,
            uint256 permanentLUSDCached
        )
    {
        (uint256 bammLUSDValue,) = _updateBAMMDebt();
        return _getLUSDSplit(bammLUSDValue);
    }

    function getTotalAcquiredLUSD() public view returns (uint256) {
        uint256 bammLUSDValue = _getInternalBAMMLUSDValue();
        (uint256 acquiredLUSDInSP, uint256 acquiredLUSDInCurve,,,) = _getLUSDSplit(bammLUSDValue);
        return acquiredLUSDInSP + acquiredLUSDInCurve;
    }

    function getAcquiredLUSDInSP() external view returns (uint256) {
        uint256 bammLUSDValue = _getInternalBAMMLUSDValue();
        (uint256 acquiredLUSDInSP,,,,) = _getLUSDSplit(bammLUSDValue);
        return acquiredLUSDInSP;
    }

    function getAcquiredLUSDInCurve() external view returns (uint256) {
        uint256 bammLUSDValue = _getInternalBAMMLUSDValue();
        (, uint256 acquiredLUSDInCurve,,,) = _getLUSDSplit(bammLUSDValue);
        return acquiredLUSDInCurve;
    }

    // Permanent getter

    function getPermanentLUSD() external view returns (uint256) {
        return permanentLUSD;
    }

    // Owned getters

    function getOwnedLUSDInSP() external view returns (uint256) {
        uint256 bammLUSDValue = _getInternalBAMMLUSDValue();
        (,, uint256 ownedLUSDInSP,,) = _getLUSDSplit(bammLUSDValue);
        return ownedLUSDInSP;
    }

    function getOwnedLUSDInCurve() external view returns (uint256) {
        uint256 bammLUSDValue = _getInternalBAMMLUSDValue();
        (,,, uint256 ownedLUSDInCurve,) = _getLUSDSplit(bammLUSDValue);
        return ownedLUSDInCurve;
    }

    // Other getters

    function calcSystemBackingRatio() public view returns (uint256) {
        uint256 bammLUSDValue = _getInternalBAMMLUSDValue();
        return _calcSystemBackingRatioFromBAMMValue(bammLUSDValue);
    }

    function _calcSystemBackingRatioFromBAMMValue(uint256 _bammLUSDValue) public view returns (uint256) {
        uint256 totalBLUSDSupply = bLUSDToken.totalSupply();
        (uint256 acquiredLUSDInSP, uint256 acquiredLUSDInCurve,,,) = _getLUSDSplit(_bammLUSDValue);

        /* TODO: Determine how to define the backing ratio when there is 0 bLUSD and 0 totalAcquiredLUSD,
         * i.e. before the first chickenIn. For now, return a backing ratio of 1. Note: Both quantities would be 0
         * also when the bLUSD supply is fully redeemed.
         */
        //if (totalBLUSDSupply == 0  && totalAcquiredLUSD == 0) {return 1e18;}
        //if (totalBLUSDSupply == 0) {return MAX_UINT256;}
        if (totalBLUSDSupply == 0) {return 1e18;}

        return  (acquiredLUSDInSP + acquiredLUSDInCurve) * 1e18 / totalBLUSDSupply;
    }

    function calcUpdatedAccrualParameter() external view returns (uint256) {
        (uint256 updatedAccrualParameter, ) = _calcUpdatedAccrualParameter(accrualParameter, accrualAdjustmentPeriodCount);
        return updatedAccrualParameter;
    }

    function getBAMMLUSDDebt() external view returns (uint256) {
        return bammLUSDDebt;
    }

    function getTreasury()
        external
        view
        returns (
            // We don't normally use leading underscores for return values,
            // but we do so here in order to avoid shadowing state variables
            uint256 _pendingLUSD,
            uint256 _totalAcquiredLUSD,
            uint256 _permanentLUSD
        )
    {
        _pendingLUSD = pendingLUSD;
        _totalAcquiredLUSD = getTotalAcquiredLUSD();
        _permanentLUSD = permanentLUSD;
    }

    function getOpenBondCount() external view returns (uint256 openBondCount) {
        return bondNFT.totalSupply() - countChickenIn - countChickenOut;
    }
}

Contract Security Audit

Contract ABI

[{"inputs":[{"components":[{"internalType":"address","name":"bondNFTAddress","type":"address"},{"internalType":"address","name":"lusdTokenAddress","type":"address"},{"internalType":"address","name":"curvePoolAddress","type":"address"},{"internalType":"address","name":"curveBasePoolAddress","type":"address"},{"internalType":"address","name":"bammSPVaultAddress","type":"address"},{"internalType":"address","name":"yearnCurveVaultAddress","type":"address"},{"internalType":"address","name":"yearnRegistryAddress","type":"address"},{"internalType":"address","name":"yearnGovernanceAddress","type":"address"},{"internalType":"address","name":"bLUSDTokenAddress","type":"address"},{"internalType":"address","name":"curveLiquidityGaugeAddress","type":"address"}],"internalType":"struct ChickenBondManager.ExternalAdresses","name":"_externalContractAddresses","type":"tuple"},{"components":[{"internalType":"uint256","name":"targetAverageAgeSeconds","type":"uint256"},{"internalType":"uint256","name":"initialAccrualParameter","type":"uint256"},{"internalType":"uint256","name":"minimumAccrualParameter","type":"uint256"},{"internalType":"uint256","name":"accrualAdjustmentRate","type":"uint256"},{"internalType":"uint256","name":"accrualAdjustmentPeriodSeconds","type":"uint256"},{"internalType":"uint256","name":"chickenInAMMFee","type":"uint256"},{"internalType":"uint256","name":"curveDepositDydxThreshold","type":"uint256"},{"internalType":"uint256","name":"curveWithdrawalDxdyThreshold","type":"uint256"},{"internalType":"uint256","name":"bootstrapPeriodChickenIn","type":"uint256"},{"internalType":"uint256","name":"bootstrapPeriodRedeem","type":"uint256"},{"internalType":"uint256","name":"bootstrapPeriodShift","type":"uint256"},{"internalType":"uint256","name":"shifterDelay","type":"uint256"},{"internalType":"uint256","name":"shifterWindow","type":"uint256"},{"internalType":"uint256","name":"minBLUSDSupply","type":"uint256"},{"internalType":"uint256","name":"minBondAmount","type":"uint256"},{"internalType":"uint256","name":"nftRandomnessDivisor","type":"uint256"},{"internalType":"uint256","name":"redemptionFeeBeta","type":"uint256"},{"internalType":"uint256","name":"redemptionFeeMinuteDecayFactor","type":"uint256"}],"internalType":"struct ChickenBondManager.Params","name":"_params","type":"tuple"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"accrualParameter","type":"uint256"}],"name":"AccrualParameterUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"redeemer","type":"address"},{"indexed":false,"internalType":"uint256","name":"bLusdAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"minLusdAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"lusdAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"yTokens","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"redemptionFee","type":"uint256"}],"name":"BLUSDRedeemed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_baseRedemptionRate","type":"uint256"}],"name":"BaseRedemptionRateUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"bonder","type":"address"},{"indexed":false,"internalType":"uint256","name":"bondId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"principalLusdAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"minLusdAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"withdrawnLusdAmount","type":"uint256"},{"indexed":false,"internalType":"uint80","name":"bondFinalHalfDna","type":"uint80"}],"name":"BondCancelled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"bonder","type":"address"},{"indexed":false,"internalType":"uint256","name":"bondId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"lusdAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"bLusdAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"lusdSurplus","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"chickenInFeeAmount","type":"uint256"},{"indexed":false,"internalType":"bool","name":"migration","type":"bool"},{"indexed":false,"internalType":"uint80","name":"bondFinalHalfDna","type":"uint80"}],"name":"BondClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"bonder","type":"address"},{"indexed":false,"internalType":"uint256","name":"bondId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint80","name":"bondInitialHalfDna","type":"uint80"}],"name":"BondCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_lastRedemptionFeeOpTime","type":"uint256"}],"name":"LastRedemptionTimeUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"previousPermanentLUSD","type":"uint256"}],"name":"MigrationTriggered","type":"event"},{"inputs":[],"name":"BETA","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"BOOTSTRAP_PERIOD_CHICKEN_IN","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"BOOTSTRAP_PERIOD_REDEEM","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"BOOTSTRAP_PERIOD_SHIFT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"CHICKEN_IN_AMM_FEE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DECIMAL_PRECISION","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"INDEX_OF_LUSD_TOKEN_IN_CURVE_POOL","outputs":[{"internalType":"int128","name":"","type":"int128"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MINUTE_DECAY_FACTOR","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_BLUSD_SUPPLY","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_BOND_AMOUNT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"NFT_RANDOMNESS_DIVISOR","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SECONDS_IN_ONE_MINUTE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SHIFTER_DELAY","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SHIFTER_WINDOW","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_bammLUSDValue","type":"uint256"}],"name":"_calcSystemBackingRatioFromBAMMValue","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"accrualAdjustmentMultiplier","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"accrualAdjustmentPeriodCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"accrualAdjustmentPeriodSeconds","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"accrualParameter","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"activateMigration","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"bLUSDToken","outputs":[{"internalType":"contract IBLUSDToken","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"bammSPVault","outputs":[{"internalType":"contract IBAMM","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"baseRedemptionRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"bondNFT","outputs":[{"internalType":"contract IBondNFT","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_bondID","type":"uint256"}],"name":"calcAccruedBLUSD","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_bondID","type":"uint256"}],"name":"calcBondBLUSDCap","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_fractionOfBLUSDToRedeem","type":"uint256"}],"name":"calcRedemptionFeePercentage","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"calcSystemBackingRatio","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"calcTotalLUSDValue","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"calcTotalYearnCurveVaultShareValue","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"calcUpdatedAccrualParameter","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_bondID","type":"uint256"}],"name":"chickenIn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_bondID","type":"uint256"},{"internalType":"uint256","name":"_minLUSD","type":"uint256"}],"name":"chickenOut","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"countChickenIn","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"countChickenOut","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_lusdAmount","type":"uint256"}],"name":"createBond","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"createBondWithPermit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"curveBasePool","outputs":[{"internalType":"contract ICurvePool","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"curveDepositLUSD3CRVExchangeRateThreshold","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"curveLiquidityGauge","outputs":[{"internalType":"contract ICurveLiquidityGaugeV5","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"curvePool","outputs":[{"internalType":"contract ICurvePool","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"curveWithdrawal3CRVLUSDExchangeRateThreshold","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"deploymentTimestamp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"firstChickenInTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getAcquiredLUSDInCurve","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getAcquiredLUSDInSP","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getBAMMLUSDDebt","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_bondID","type":"uint256"}],"name":"getBondData","outputs":[{"internalType":"uint256","name":"lusdAmount","type":"uint256"},{"internalType":"uint64","name":"claimedBLUSD","type":"uint64"},{"internalType":"uint64","name":"startTime","type":"uint64"},{"internalType":"uint64","name":"endTime","type":"uint64"},{"internalType":"uint8","name":"status","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLUSDInBAMMSPVault","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_bondID","type":"uint256"}],"name":"getLUSDToAcquire","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getOpenBondCount","outputs":[{"internalType":"uint256","name":"openBondCount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getOwnedLUSDInCurve","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getOwnedLUSDInSP","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getPendingLUSD","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getPermanentLUSD","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTotalAcquiredLUSD","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTotalLUSDInCurve","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTreasury","outputs":[{"internalType":"uint256","name":"_pendingLUSD","type":"uint256"},{"internalType":"uint256","name":"_totalAcquiredLUSD","type":"uint256"},{"internalType":"uint256","name":"_permanentLUSD","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastRedemptionTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastShifterCountdownStartTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lusdToken","outputs":[{"internalType":"contract ILUSDToken","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"migration","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minimumAccrualParameter","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_bLUSDToRedeem","type":"uint256"},{"internalType":"uint256","name":"_minLUSDFromBAMMSPVault","type":"uint256"}],"name":"redeem","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_lusdAmount","type":"uint256"}],"name":"sendFeeShare","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_maxLUSDToShift","type":"uint256"}],"name":"shiftLUSDFromCurveToSP","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_maxLUSDToShift","type":"uint256"}],"name":"shiftLUSDFromSPToCurve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"startShifterCountdown","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"targetAverageAgeSeconds","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalWeightedStartTimes","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"yTokensHeldByCBM","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"yearnCurveVault","outputs":[{"internalType":"contract IYearnVault","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"yearnGovernanceAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"yearnRegistry","outputs":[{"internalType":"contract IYearnRegistry","name":"","type":"address"}],"stateMutability":"view","type":"function"}]

6104006040523480156200001257600080fd5b50604051620058bb380380620058bb83398101604081905262000035916200070c565b81516001600160a01b039081166080908152602080850151831660c090815261010080870151851660a0908152604080890151871660e090815260608a0151881690935294880151861661012052870151851661014052908601518416610160528501519092166101a052426103605282516103805290820151600d558101516103a08190526200011f5760405162461bcd60e51b815260206004820152602960248201527f43424d3a204d696e206163637275616c20706172616d657465722063616e6e6f60448201526874206265207a65726f60b81b60648201526084015b60405180910390fd5b60608101516200013890670de0b6b3a76400006200082c565b6103c05260808101516103e0526101208201516001600160a01b039081166101805260a08201516101c05260e0516040805163ddca3f4360e01b81529051600093929092169163ddca3f43916004808201926020929091908290030181865afa158015620001aa573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001d0919062000846565b90506402540be400620001e482826200082c565b8360c00151620001f5919062000860565b62000201919062000882565b610320526402540be4006200021782826200082c565b8360e0015162000228919062000860565b62000234919062000882565b610340526101008201516101e052610120820151610200526101408201516102205261016082015161024052610180820151610260526101a0820151610280526101c0820151620002de5760405162461bcd60e51b815260206004820152602d60248201527f43424d3a204d494e20424f4e4420414d4f554e5420706172616d65746572206360448201526c616e6e6f74206265207a65726f60981b606482015260840162000116565b6101c08201516102a0526101e08201516102c0526102008201516102e0526102208201516103005260c0516101205160405163095ea7b360e01b81526001600160a01b039182166004820152600019602482015291169063095ea7b3906044016020604051808303816000875af11580156200035e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620003849190620008a5565b5060c05160e05160405163095ea7b360e01b81526001600160a01b039182166004820152600019602482015291169063095ea7b3906044016020604051808303816000875af1158015620003dc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620004029190620008a5565b5060e0516101405160405163095ea7b360e01b81526001600160a01b039182166004820152600019602482015291169063095ea7b3906044016020604051808303816000875af11580156200045b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620004819190620008a5565b5060c0516101805160405163095ea7b360e01b81526001600160a01b039182166004820152600019602482015291169063095ea7b3906044016020604051808303816000875af1158015620004da573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620005009190620008a5565b506101605160e051604051630e177dc760e41b81526001600160a01b03918216600482015291169063e177dc70906024016020604051808303816000875af115801562000551573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620005779190620008d0565b6001600160a01b0316610140516001600160a01b0316146200059d576200059d620008ee565b50505062000904565b60405161024081016001600160401b0381118282101715620005d857634e487b7160e01b600052604160045260246000fd5b60405290565b60405161014081016001600160401b0381118282101715620005d857634e487b7160e01b600052604160045260246000fd5b80516001600160a01b03811681146200062857600080fd5b919050565b600061024082840312156200064157600080fd5b6200064b620005a6565b825181526020808401519082015260408084015190820152606080840151908201526080808401519082015260a0808401519082015260c0808401519082015260e08084015190820152610100808401519082015261012080840151908201526101408084015190820152610160808401519082015261018080840151908201526101a080840151908201526101c080840151908201526101e080840151908201526102008084015190820152610220928301519281019290925250919050565b6000808284036103808112156200072257600080fd5b610140808212156200073357600080fd5b6200073d620005de565b91506200074a8562000610565b82526200075a6020860162000610565b60208301526200076d6040860162000610565b6040830152620007806060860162000610565b6060830152620007936080860162000610565b6080830152620007a660a0860162000610565b60a0830152620007b960c0860162000610565b60c0830152620007cc60e0860162000610565b60e0830152610100620007e181870162000610565b90830152610120620007f586820162000610565b81840152508193506200080b868287016200062d565b925050509250929050565b634e487b7160e01b600052601160045260246000fd5b60008282101562000841576200084162000816565b500390565b6000602082840312156200085957600080fd5b5051919050565b60008160001904831182151516156200087d576200087d62000816565b500290565b600082620008a057634e487b7160e01b600052601260045260246000fd5b500490565b600060208284031215620008b857600080fd5b81518015158114620008c957600080fd5b9392505050565b600060208284031215620008e357600080fd5b620008c98262000610565b634e487b7160e01b600052600160045260246000fd5b60805160a05160c05160e05161010051610120516101405161016051610180516101a0516101c0516101e05161020051610220516102405161026051610280516102a0516102c0516102e05161030051610320516103405161036051610380516103a0516103c0516103e051614c6162000c5a600039600081816104480152818161330f0152613418015260008181610b2e0152613483015260008181610a250152818161336f01526134be01526000818161052c01526133e70152600081816109d001528181613333015281816133c30152613bb7015260008181610953015281816127a40152612b7b0152600081816108f201528181611c5f0152611f13015260008181610a670152610ba90152600081816104820152610bfc015260008181610712015281816110a5015281816114fe0152612d8e0152600081816108710152613a220152600081816106c401526142080152600081816107d6015281816124780152613d6e015260008181610794015281816124990152613d390152600081816105940152613b930152600081816106eb0152611ffc015260008181610675015261384501526000818161060501526137f501526000818161075d015281816125f901526145790152600081816104a90152614888015260006109a9015260008181610a97015281816123df01528181613fc00152818161404c015281816140e4015281816144ee01526146c001526000818161055c015281816111dd015281816118b801528181613152015281816137260152818161399701528181613b1301526143d30152600081816108c301528181611bce01526127130152600081816105050152818161180a01528181611d3f01528181611de001528181611e7a015281816128750152818161293201528181612a5c01528181613f28015261462a015260008181610982015281816116f80152818161196a01528181611a250152818161262e015281816129ca01528181612ae2015281816147cc0152818161485601526148fc0152600081816105d601528181610eda0152818161129e015281816120de015281816122fb01528181612f2a01528181613c54015261418301526000818161092c0152818161106c015281816114ce01528181611aa001528181612d5d015261357e0152614c616000f3fe608060405234801561001057600080fd5b506004361061043e5760003560e01c80637cbc237311610236578063b83f91a21161013b578063cc0c986e116100c3578063e9dc9e6d11610087578063e9dc9e6d14610b18578063edb134f314610b20578063f1b0cff514610b29578063f3c4023d14610b50578063f58369b914610b5857600080fd5b8063cc0c986e14610a89578063cfc31f6f14610a92578063d2e892dd14610ab9578063da10594314610ac2578063e324634914610b0f57600080fd5b8063c3c297451161010a578063c3c2974514610a0d578063c484cc5f14610a20578063c6c50ce814610a47578063c6d2d26114610a4f578063c7b5548114610a6257600080fd5b8063b83f91a21461097d578063bb870317146109a4578063bfc12c05146109cb578063c0639bbd146109f257600080fd5b8063a21ec280116101be578063acf955c71161018d578063acf955c7146108ed578063aefcc4fd14610914578063b0f3af4714610927578063b23ad3ee1461094e578063b7a65dce1461097557600080fd5b8063a21ec280146108a2578063a79e5683146108b5578063a891c684146108be578063ac8af3a9146108e557600080fd5b806390d532901161020557806390d532901461085357806391dc186f1461085c5780639c283187146108645780639fbc4a5f1461086c578063a20baee61461089357600080fd5b80637cbc23731461081357806384c2dea51461083b5780638ac6e2f4146108435780638caffae11461084b57600080fd5b80634237e191116103475780636350e4b2116102cf578063695e89da11610293578063695e89da146107b65780636a57b253146107be5780636b4fbbed146107d15780636bdac50b146107f85780637b3c7df61461080057600080fd5b80636350e4b2146107455780636381211414610758578063653a81981461077f57806366462ab11461078757806367e48a7e1461078f57600080fd5b80635041382b116103165780635041382b146106bf57806351a643ae146106e6578063570dd5241461070d57806359372e2e1461073457806361ec893d1461073d57600080fd5b80634237e1911461065d5780634903970a146106705780634b10543b146106975780634bb41097146106ac57600080fd5b806335f1d0e0116103ca5780633792dcb9116103995780633792dcb9146105d157806339f01388146105f85780633a517326146106005780633b19e84a146106275780633cbe79261461064a57600080fd5b806335f1d0e014610587578063361628831461058f57806336e2819e146105b657806337303e58146105c957600080fd5b8063218751b211610411578063218751b214610500578063233b0ee71461052757806327fafcd31461054e57806333624a861461055757806335567cda1461057e57600080fd5b80630277407314610443578063071a75411461047d5780630f34d74d146104a45780631705a3bd146104e3575b600080fd5b61046a7f000000000000000000000000000000000000000000000000000000000000000081565b6040519081526020015b60405180910390f35b61046a7f000000000000000000000000000000000000000000000000000000000000000081565b6104cb7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b039091168152602001610474565b6009546104f09060ff1681565b6040519015158152602001610474565b6104cb7f000000000000000000000000000000000000000000000000000000000000000081565b61046a7f000000000000000000000000000000000000000000000000000000000000000081565b61046a600a5481565b6104cb7f000000000000000000000000000000000000000000000000000000000000000081565b61046a60035481565b61046a610b61565b61046a7f000000000000000000000000000000000000000000000000000000000000000081565b61046a6105c4366004614987565b610b95565b61046a610c49565b6104cb7f000000000000000000000000000000000000000000000000000000000000000081565b60015461046a565b61046a7f000000000000000000000000000000000000000000000000000000000000000081565b61062f610c6d565b60408051938452602084019290925290820152606001610474565b61046a610658366004614987565b610c87565b61046a61066b366004614987565b610d55565b61046a7f000000000000000000000000000000000000000000000000000000000000000081565b6106aa6106a5366004614987565b610e08565b005b61046a6106ba366004614987565b6113a4565b61046a7f000000000000000000000000000000000000000000000000000000000000000081565b61046a7f000000000000000000000000000000000000000000000000000000000000000081565b61046a7f000000000000000000000000000000000000000000000000000000000000000081565b61046a60055481565b61046a603c81565b61046a610753366004614987565b6114ad565b6104cb7f000000000000000000000000000000000000000000000000000000000000000081565b61046a6117ce565b61046a6117f1565b61046a7f000000000000000000000000000000000000000000000000000000000000000081565b61046a6118b3565b61046a6107cc3660046149b5565b611940565b61046a7f000000000000000000000000000000000000000000000000000000000000000081565b61046a611a96565b6106aa61080e366004614987565b611b39565b610826610821366004614a17565b611fe5565b60408051928352602083019190915201610474565b61046a6123d2565b6106aa612476565b60005461046a565b61046a60045481565b61046a61254a565b60025461046a565b61046a7f000000000000000000000000000000000000000000000000000000000000000081565b61046a670de0b6b3a764000081565b6106aa6108b0366004614987565b612574565b61046a60075481565b6104cb7f000000000000000000000000000000000000000000000000000000000000000081565b61046a6126a8565b61046a7f000000000000000000000000000000000000000000000000000000000000000081565b6106aa610922366004614987565b6126cc565b6104cb7f000000000000000000000000000000000000000000000000000000000000000081565b61046a7f000000000000000000000000000000000000000000000000000000000000000081565b61046a612c44565b6104cb7f000000000000000000000000000000000000000000000000000000000000000081565b6104cb7f000000000000000000000000000000000000000000000000000000000000000081565b61046a7f000000000000000000000000000000000000000000000000000000000000000081565b6109fa600081565b604051600f9190910b8152602001610474565b6106aa610a1b366004614a17565b612c68565b61046a7f000000000000000000000000000000000000000000000000000000000000000081565b61046a612f0d565b61046a610a5d366004614987565b612f25565b61046a7f000000000000000000000000000000000000000000000000000000000000000081565b61046a600d5481565b6104cb7f000000000000000000000000000000000000000000000000000000000000000081565b61046a600c5481565b610ad5610ad0366004614987565b613001565b6040805195865267ffffffffffffffff948516602087015292841692850192909252909116606083015260ff16608082015260a001610474565b61046a60065481565b6106aa6130d6565b61046a600b5481565b61046a7f000000000000000000000000000000000000000000000000000000000000000081565b61046a613131565b61046a600e5481565b600080610b6c61314d565b9050600080610b7a836131e2565b505050915091508082610b8d9190614a4f565b935050505090565b600080610ba061325c565b90506000610bce7f00000000000000000000000000000000000000000000000000000000000000008361326e565b90506000670de0b6b3a764000082600754610be99190614a67565b610bf39190614a9c565b90506000610c217f000000000000000000000000000000000000000000000000000000000000000087614a9c565b610c2b9083614a4f565b9050610c3f81670de0b6b3a76400006132f2565b9695505050505050565b600080610c5461314d565b90506000610c61826131e2565b50909695505050505050565b600080549080610c7b610b61565b91506001549050909192565b6000818152600860209081526040808320815160a08101835281548152600182015467ffffffffffffffff80821695830195909552600160401b8104851693820193909352600160801b830490931660608401528392916080830190600160c01b900460ff166003811115610cfe57610cfe614ab0565b6003811115610d0f57610d0f614ab0565b8152505090506000610d25600d54600e5461330a565b509050610d4d826040015167ffffffffffffffff16610d4784600001516134ee565b836134fa565b949350505050565b600080610d60613131565b6000848152600860209081526040808320815160a08101835281548152600182015467ffffffffffffffff80821695830195909552600160401b8104851693820193909352600160801b83049093166060840152939450919290916080830190600160c01b900460ff166003811115610ddb57610ddb614ab0565b6003811115610dec57610dec614ab0565b815250509050610d4d610e0282600001516134ee565b83613549565b6000818152600860209081526040808320815160a08101835281548152600182015467ffffffffffffffff80821695830195909552600160401b8104851693820193909352600160801b83049093166060840152906080830190600160c01b900460ff166003811115610e7d57610e7d614ab0565b6003811115610e8e57610e8e614ab0565b9052509050610e9c82613568565b610ea98160800151613651565b6000610eb36136b2565b9050600080610ec061371f565b91509150600080610ed486600001516137cd565b915091507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610f36573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f5a9190614ac6565b158015610f6a575060095460ff16155b15610f8b57610f88866040015167ffffffffffffffff16858561383e565b92505b6000610fa6876040015167ffffffffffffffff1683886134fa565b90506000610fb386612f25565b9050600081610fca84670de0b6b3a7640000614a67565b610fd49190614a9c565b9050610ff9610feb670de0b6b3a764000083614a9c565b67ffffffffffffffff6132f2565b60008b81526008602052604081206001908101805467ffffffffffffffff9485167fffffffffffffff00ffffffffffffffffffffffffffffffff000000000000000090911617600360c01b1767ffffffffffffffff60801b1916600160801b4295909516949094029390931790925590547f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690639841a0189033908e906110ca907f000000000000000000000000000000000000000000000000000000000000000090614a9c565b6040516001600160e01b031960e086901b1681526001600160a01b039093166004840152602483019190915260448201526064016020604051808303816000875af115801561111d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111419190614afe565b90506001600a60008282546111569190614a4f565b9091555050895160008054819061116e908490614b19565b909155505060408a01518a5161118e9167ffffffffffffffff1690614a67565b6005600082825461119f9190614b19565b90915550600090506111b18587614b19565b60095490915060ff166111db5780600160008282546111d09190614a4f565b909155506112829050565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663bfca6c116040518163ffffffff1660e01b8152600401606060405180830381865afa158015611239573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061125d9190614b30565b5098506000905061126e828a6132f2565b90508015611280576112808133613972565b505b6040516340c10f1960e01b8152336004820152602481018490527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906340c10f1990604401600060405180830381600087803b1580156112ea57600080fd5b505af11580156112fe573d6000803e3d6000fd5b505060095460ff161591505080156113165750868810155b156113245761132487613a0d565b8a51600954604080518f815260208101939093528201859052606082018390526080820189905260ff16151560a082015269ffffffffffffffffffff831660c082015233907fe0ae890eaa03f699e40e47e1644539436b9871b84f64d484b069ac9e0e9189149060e00160405180910390a2505050505050505050505050565b6000818152600860209081526040808320815160a08101835281548152600182015467ffffffffffffffff80821695830195909552600160401b8104851693820193909352600160801b830490931660608401528392916080830190600160c01b900460ff16600381111561141b5761141b614ab0565b600381111561142c5761142c614ab0565b905250905060018160800151600381111561144957611449614ab0565b146114575750600092915050565b600061147661146983600001516134ee565b611471613131565b613549565b90506000611488600d54600e5461330a565b5090506114a4836040015167ffffffffffffffff1683836134fa565b95945050505050565b60006114b882613a20565b6114c0613a9c565b6114c86136b2565b506000807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166340c10f19337f000000000000000000000000000000000000000000000000000000000000000060015461152a9190614a9c565b6040516001600160e01b031960e085901b1681526001600160a01b039092166004830152602482015260440160408051808303816000875af1158015611574573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115989190614b5e565b915091506115cb6040805160a0810182526000808252602082018190529181018290526060810182905290608082015290565b8481524267ffffffffffffffff16604082015260016080820181905250600083815260086020908152604091829020835181559083015160018201805493850151606086015167ffffffffffffffff908116600160801b0267ffffffffffffffff60801b19928216600160401b026fffffffffffffffffffffffffffffffff199097169190941617949094179384168217815560808501518594909260ff60c01b191668ffffffffffffffffff60801b1990911617600160c01b83600381111561169757611697614ab0565b0217905550905050846000808282546116b09190614a4f565b909155506116c090504286614a67565b600560008282546116d19190614a4f565b90915550506040516323b872dd60e01b8152336004820152306024820152604481018690527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906323b872dd906064016020604051808303816000875af1158015611749573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061176d9190614b8a565b5061177785613afd565b604080518481526020810187905269ffffffffffffffffffff841681830152905133917ff3305d3ff042bc9868a6e25d2980cb0790e1edd5d6f0a32bb73650bce4926dd2919081900360600190a250909392505050565b6000806117d961314d565b905060006117e6826131e2565b509695505050505050565b6000806117fc6123d2565b9050600081156118ad5760007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663bb7b8b806040518163ffffffff1660e01b8152600401602060405180830381865afa158015611866573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061188a9190614ac6565b9050670de0b6b3a764000061189f8285614a67565b6118a99190614a9c565b9150505b92915050565b6000807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663bfca6c116040518163ffffffff1660e01b8152600401606060405180830381865afa158015611914573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119389190614b30565b509392505050565b604051636eb1769f60e11b81526001600160a01b03878116600483015230602483015260009187917f0000000000000000000000000000000000000000000000000000000000000000169063dd62ed3e90604401602060405180830381865afa1580156119b1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119d59190614ac6565b1015611a825760405163d505accf60e01b81526001600160a01b038881166004830152306024830152604482018890526064820187905260ff8616608483015260a4820185905260c482018490527f0000000000000000000000000000000000000000000000000000000000000000169063d505accf9060e401600060405180830381600087803b158015611a6957600080fd5b505af1158015611a7d573d6000803e3d6000fd5b505050505b611a8b866114ad565b979650505050505050565b6000600b54600a547f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611afc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b209190614ac6565b611b2a9190614b19565b611b349190614b19565b905090565b611b41613b91565b611b49613a9c565b611b51613c50565b611b59613d35565b600080611b6461371f565b915091506000805483611b779190614b19565b90506000611b836117f1565b9050611b8e81613e1a565b6000611b9a86846132f2565b9050611ba681856132f2565b9050611bbf8183600154611bba9190614b19565b6132f2565b9050611bca81613ea0565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663bb7b8b806040518163ffffffff1660e01b8152600401602060405180830381865afa158015611c2a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c4e9190614ac6565b90506000611c5b82613ef0565b90507f00000000000000000000000000000000000000000000000000000000000000008111611d1d5760405162461bcd60e51b815260206004820152605660248201527f43424d3a204c5553443a334352562065786368616e67652072617465206d757360448201527f74206265206f76657220746865206465706f736974207468726573686f6c642060648201527f6265666f72652053502d3e437572766520736869667400000000000000000000608482015260a4015b60405180910390fd5b611d278330613972565b6040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa158015611d8e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611db29190614ac6565b6040805180820182528681526000602082018190529151630b4c7e4d60e01b81529293506001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001692630b4c7e4d92611e149291600401614bac565b6020604051808303816000875af1158015611e33573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e579190614ac6565b506040516370a0823160e01b815230600482015260009082906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906370a0823190602401602060405180830381865afa158015611ec1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ee59190614ac6565b611eef9190614b19565b9050611efa81613fa8565b6000611f0585613ef0565b90508381108015611f3657507f00000000000000000000000000000000000000000000000000000000000000008110155b611fd85760405162461bcd60e51b815260206004820152606160248201527f43424d3a2053502d3e4375727665207368696674206d7573742064656372656160448201527f7365204c5553443a334352562065786368616e6765207261746520746f20612060648201527f76616c75652061626f766520746865206465706f736974207468726573686f6c6084820152601960fa1b60a482015260c401611d14565b5050505050505050505050565b600080611ff184613ea0565b611ffa84614177565b7f00000000000000000000000000000000000000000000000000000000000000006004546120289190614a4f565b4210156120c35760405162461bcd60e51b815260206004820152604f60248201527f43424d3a20526564656d7074696f6e206166746572206669727374206368696360448201527f6b656e20696e206d757374207761697420756e74696c20626f6f74737472617060648201527f20706572696f64206973206f7665720000000000000000000000000000000000608482015260a401611d14565b6000806000806120d1614287565b94509450509350935060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561213a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061215e9190614ac6565b6121708a670de0b6b3a7640000614a67565b61217a9190614a9c565b60095490915060009060ff1661219857612193826142b6565b61219b565b60005b905060008080670de0b6b3a76400006121b4868b614a67565b6121be9190614a9c565b90506000670de0b6b3a76400006121d58682614b19565b6121df9084614a67565b6121e99190614a9c565b90506121f58183614b19565b6121ff9085614a4f565b935061220b818e614357565b9250821561221d5761221d8333613972565b506000905086156122b8576000670de0b6b3a764000061223d878b614a67565b6122479190614a9c565b90506000670de0b6b3a764000061225e8782614b19565b6122689084614a67565b6122729190614a9c565b905061227e8183614b19565b6122889086614a4f565b945088816003546122999190614a67565b6122a39190614a9c565b925082156122b5576122b533846144c8565b50505b6122c28387614a4f565b6001556122d76122d28284614a4f565b613ea0565b604051632770a7eb60e21b8152336004820152602481018e90526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690639dc29fac90604401600060405180830381600087803b15801561233f57600080fd5b505af1158015612353573d6000803e3d6000fd5b50505050336001600160a01b03167fc0ac8b09f0bc9dd02f48d9145336ab9df1dc378b6115bc78e0f6c3d72bc37b178e8e8585886040516123b6959493929190948552602085019390935260408401919091526060830152608082015260a00190565b60405180910390a29099509750505050505050505b9250929050565b6000670de0b6b3a76400007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166399530b066040518163ffffffff1660e01b8152600401602060405180830381865afa15801561243b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061245f9190614ac6565b60035461246c9190614a67565b611b349190614a9c565b7f00000000000000000000000000000000000000000000000000000000000000007f0000000000000000000000000000000000000000000000000000000000000000600c546124c59190614a4f565b6124cf9190614a4f565b4210156125445760405162461bcd60e51b815260206004820152603560248201527f43424d3a2050726576696f75732073686966742064656c617920616e6420776960448201527f6e646f77206d75737420686176652070617373656400000000000000000000006064820152608401611d14565b42600c55565b6000806125556117f1565b9050600061256161314d565b905061256d8282614a4f565b9250505090565b61257c61456e565b60095460ff16156125e25760405162461bcd60e51b815260206004820152602a60248201527f43424d3a205265636569766520666565207368617265206f6e6c7920696e206e6044820152696f726d616c206d6f646560b01b6064820152608401611d14565b6040516323b872dd60e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166004830152306024830152604482018390527f000000000000000000000000000000000000000000000000000000000000000016906323b872dd906064016020604051808303816000875af1158015612677573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061269b9190614b8a565b506126a581613afd565b50565b6000806126b361314d565b905060006126c0826131e2565b50929695505050505050565b6126d4613b91565b6126dc613a9c565b6126e4613c50565b6126ec613d35565b60006126f66117f1565b9050600061270483836132f2565b905061270f81613ea0565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663bb7b8b806040518163ffffffff1660e01b8152600401602060405180830381865afa15801561276f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127939190614ac6565b905060006127a0826145f2565b90507f0000000000000000000000000000000000000000000000000000000000000000811161285d5760405162461bcd60e51b815260206004820152605a60248201527f43424d3a20334352563a4c5553442065786368616e67652072617465206d757360448201527f742062652061626f766520746865207769746864726177616c2074687265736860648201527f6f6c64206265666f72652043757276652d3e5350207368696674000000000000608482015260a401611d14565b6040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa1580156128c4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128e89190614ac6565b9050600085856003546128fb9190614a67565b6129059190614a9c565b9050612910816146aa565b6040516370a0823160e01b815230600482015260009083906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906370a0823190602401602060405180830381865afa158015612979573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061299d9190614ac6565b6129a79190614b19565b6040516370a0823160e01b81523060048201529091506000906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906370a0823190602401602060405180830381865afa158015612a11573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a359190614ac6565b604051630d2680e960e11b81526004810184905260006024820181905260448201529091507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690631a4d01d290606401600060405180830381600087803b158015612aa857600080fd5b505af1158015612abc573d6000803e3d6000fd5b50506040516370a0823160e01b8152306004820152600092508391506001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906370a0823190602401602060405180830381865afa158015612b29573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b4d9190614ac6565b612b579190614b19565b9050612b6281613afd565b6000612b6d886145f2565b90508681108015612b9e57507f00000000000000000000000000000000000000000000000000000000000000008110155b611fd85760405162461bcd60e51b8152602060048201526064602482018190527f43424d3a2043757276652d3e5350207368696674206d75737420696e6372656160448301527f736520334352563a4c5553442065786368616e6765207261746520746f206120908201527f76616c75652061626f766520746865207769746864726177616c2074687265736084820152631a1bdb1960e21b60a482015260c401611d14565b600080612c4f61314d565b90506000612c5c826131e2565b50919695505050505050565b6000828152600860209081526040808320815160a08101835281548152600182015467ffffffffffffffff80821695830195909552600160401b8104851693820193909352600160801b83049093166060840152906080830190600160c01b900460ff166003811115612cdd57612cdd614ab0565b6003811115612cee57612cee614ab0565b9052509050612cfc83613568565b612d098160800151613651565b612d116136b2565b5060008381526008602052604081206001908101805467ffffffffffffffff4216600160801b0268ffffffffffffffffff60801b1990911617600160c11b179055546001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690639841a0189033908790612db3907f000000000000000000000000000000000000000000000000000000000000000090614a9c565b6040516001600160e01b031960e086901b1681526001600160a01b039093166004840152602483019190915260448201526064016020604051808303816000875af1158015612e06573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e2a9190614afe565b90506001600b6000828254612e3f9190614a4f565b90915550508151600080548190612e57908490614b19565b909155505060408201518251612e779167ffffffffffffffff1690614a67565b60056000828254612e889190614b19565b90915550508151600090612e9c9085614357565b9050612ea88133613972565b825160408051878152602081019290925281018590526060810182905269ffffffffffffffffffff8316608082015233907f3bd7a45d09d2d31d78737a80c00ac48ba89dd3cce7537ad56bf1bee66c9dc39e9060a00160405180910390a25050505050565b600080612f1e600d54600e5461330a565b5092915050565b6000807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612f86573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612faa9190614ac6565b9050600080612fb8856131e2565b505050915091508260001415612fda5750670de0b6b3a7640000949350505050565b82612fe58284614a4f565b612ff790670de0b6b3a7640000614a67565b6114a49190614a9c565b6000818152600860209081526040808320815160a08101835281548152600182015467ffffffffffffffff80821695830195909552600160401b8104851693820193909352600160801b83049093166060840152839283928392839283929091906080830190600160c01b900460ff16600381111561308257613082614ab0565b600381111561309357613093614ab0565b8152505090508060000151816020015182604001518360600151846080015160038111156130c3576130c3614ab0565b939b929a50909850965090945092505050565b6130de61456e565b6130e6613a9c565b6009805460ff19166001908117909155546040519081527f6330fd496eb4822cdd507776770666698db359e48ce5a7797a0aaba0c879adca9060200160405180910390a16000600155565b60008061313c61314d565b905061314781612f25565b91505090565b6000807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663bfca6c116040518163ffffffff1660e01b8152600401606060405180830381865afa1580156131ae573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131d29190614b30565b5091505061314760025482614748565b60008060008060008054866131f79190614b19565b92506132016117f1565b600154909250905060006132158385614a4f565b90508181111561325257600061322b8383614b19565b9050816132388683614a67565b6132429190614a9c565b965061324e8782614b19565b9550505b5091939590929450565b6000603c6006544261246c9190614b19565b6000631f54050082111561328457631f54050091505b816132985750670de0b6b3a76400006118ad565b670de0b6b3a764000083835b60018111156132e8576132b8600282614be4565b156132ca576132c78284614758565b92505b6132d48283614758565b91506132e1600282614a9c565b90506132a4565b610c3f8284614758565b60008183106133015781613303565b825b9392505050565b6000807f00000000000000000000000000000000000000000000000000000000000000006133587f000000000000000000000000000000000000000000000000000000000000000042614b19565b6133629190614a9c565b90508281148061339157507f000000000000000000000000000000000000000000000000000000000000000084145b8061339c5750600054155b156133a9578391506123cb565b600080546005546133ba9190614a9c565b9050600061343c7f000000000000000000000000000000000000000000000000000000000000000061340c7f000000000000000000000000000000000000000000000000000000000000000085614a4f565b6134169190614b19565b7f0000000000000000000000000000000000000000000000000000000000000000614782565b9050808310156134505785935050506123cb565b600061346686613461600185614b19565b614748565b6134709085614b19565b90506134e2670de0b6b3a76400006134a87f00000000000000000000000000000000000000000000000000000000000000008461326e565b6134b2908a614a67565b6134bc9190614a9c565b7f0000000000000000000000000000000000000000000000000000000000000000614748565b94505050509250929050565b600080610d4d836137cd565b60008361350957506000613303565b60006135158542614b19565b61352790670de0b6b3a7640000614a67565b905060006135358483614a4f565b61353f8387614a67565b610c3f9190614a9c565b60008161355e84670de0b6b3a7640000614a67565b6133039190614a9c565b6040516331a9108f60e11b8152600481018290527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690636352211e90602401602060405180830381865afa1580156135cd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135f19190614bf8565b6001600160a01b0316336001600160a01b0316146126a55760405162461bcd60e51b815260206004820152601d60248201527f43424d3a2043616c6c6572206d757374206f776e2074686520626f6e640000006044820152606401611d14565b600181600381111561366557613665614ab0565b146126a55760405162461bcd60e51b815260206004820152601860248201527f43424d3a20426f6e64206d7573742062652061637469766500000000000000006044820152606401611d14565b600d54600e546000919082806136c8848461330a565b9150915082811461193857600e81905581841461193857600d8290556040518281527fdf0b753b5dc9a250a9e6268e9c010c895cd12d6e66f6cfb57531a3a49315d09a9060200160405180910390a1509392505050565b60008060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663bfca6c116040518163ffffffff1660e01b8152600401606060405180830381865afa158015613782573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137a69190614b30565b506002549092509050808211156137c557506002819055928392509050565b939092509050565b600954600090819060ff16156137e557506000929050565b6000670de0b6b3a764000061381a7f000000000000000000000000000000000000000000000000000000000000000086614a67565b6138249190614a9c565b905060006138328286614b19565b91959194509092505050565b600061386a7f000000000000000000000000000000000000000000000000000000000000000085614a4f565b4210156138df5760405162461bcd60e51b815260206004820152603e60248201527f43424d3a20466972737420636869636b656e20696e206d75737420776169742060448201527f756e74696c20626f6f74737472617020706572696f64206973206f76657200006064820152608401611d14565b4260045560006138ee846131e2565b505050509050808310156139595760405162461bcd60e51b815260206004820152602c60248201527f43424d3a204e6f7420656e6f756768204c55534420617661696c61626c65206960448201526b1b88108b941c9bdd1bd8dbdb60a21b6064820152608401611d14565b80156139685761396881613a0d565b6114a48184614b19565b604051627b8a6760e11b8152600481018390526001600160a01b0382811660248301527f0000000000000000000000000000000000000000000000000000000000000000169062f714ce90604401600060405180830381600087803b1580156139da57600080fd5b505af11580156139ee573d6000803e3d6000fd5b505050508160026000828254613a049190614b19565b90915550505050565b613a178130613972565b6126a5816147b4565b7f00000000000000000000000000000000000000000000000000000000000000008110156126a55760405162461bcd60e51b8152602060048201526024808201527f43424d3a20426f6e64206d696e696d756d20616d6f756e74206e6f742072656160448201526318da195960e21b6064820152608401611d14565b60095460ff1615613afb5760405162461bcd60e51b8152602060048201526024808201527f43424d3a204d6967726174696f6e206d757374206265206e6f742062652061636044820152637469766560e01b6064820152608401611d14565b565b60405163b6b55f2560e01b8152600481018290527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063b6b55f2590602401600060405180830381600087803b158015613b5f57600080fd5b505af1158015613b73573d6000803e3d6000fd5b505050508060026000828254613b899190614a4f565b909155505050565b7f0000000000000000000000000000000000000000000000000000000000000000613bdc7f000000000000000000000000000000000000000000000000000000000000000042614b19565b1015613afb5760405162461bcd60e51b815260206004820152603c60248201527f43424d3a2053686966746572206f6e6c792063616c6c61626c6520616674657260448201527f20736869667420626f6f74737472617020706572696f6420656e6473000000006064820152608401611d14565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613cb0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613cd49190614ac6565b11613afb5760405162461bcd60e51b815260206004820152602b60248201527f43424d3a20624c55534420537570706c79206d757374206265203e203020757060448201526a6f6e207368696674696e6760a81b6064820152608401611d14565b60007f0000000000000000000000000000000000000000000000000000000000000000600c54613d659190614a4f565b90506000613d937f000000000000000000000000000000000000000000000000000000000000000083614a4f565b9050814210158015613da457508042105b613e165760405162461bcd60e51b815260206004820152602f60248201527f43424d3a205368696674206f6e6c7920706f737369626c6520696e736964652060448201527f7368696674696e672077696e646f7700000000000000000000000000000000006064820152608401611d14565b5050565b8060015410156126a55760405162461bcd60e51b8152602060048201526044602482018190527f43424d3a2054686520616d6f756e7420696e2043757276652063616e6e6f7420908201527f62652067726561746572207468616e20746865205065726d616e656e7420627560648201526318dad95d60e21b608482015260a401611d14565b600081116126a55760405162461bcd60e51b815260206004820152601760248201527f43424d3a20416d6f756e74206d757374206265203e20300000000000000000006044820152606401611d14565b604051635e0d443f60e01b815260006004820181905260016024830152670de0b6b3a764000060448301529081906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690635e0d443f90606401602060405180830381865afa158015613f6f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613f939190614ac6565b9050670de0b6b3a764000061355e8483614a67565b6040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa15801561400f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906140339190614ac6565b60405163b6b55f2560e01b8152600481018490529091507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063b6b55f25906024016020604051808303816000875af115801561409d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906140c19190614ac6565b506040516370a0823160e01b815230600482015260009082906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906370a0823190602401602060405180830381865afa15801561412b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061414f9190614ac6565b6141599190614b19565b9050806003600082825461416d9190614a4f565b9091555050505050565b60095460ff166126a5577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156141df573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906142039190614ac6565b61422d7f000000000000000000000000000000000000000000000000000000000000000083614a4f565b11156126a55760405162461bcd60e51b815260206004820152602360248201527f43424d3a2043616e6e6f742072656465656d2062656c6f77206d696e20737570604482015262706c7960e81b6064820152608401611d14565b60008060008060008061429861371f565b5090506142a4816131e2565b95509550955095509550509091929394565b6000806142c283610b95565b60078190556040518181529091507fe31dea26c34fb8440bf2eec033dfd26bd39e88e026348d996e275a396417109b9060200160405180910390a160006006544261430d9190614b19565b9050603c8110612f1e574260068190556040519081527fbab964312bdd13595266f3e549bca3102965a6d718c6c1f8cd7eaac076b9c6c29060200160405180910390a15092915050565b6000818310156143cf5760405162461bcd60e51b815260206004820152603460248201527f43424d3a204d696e2076616c75652063616e6e6f74206265206772656174657260448201527f207468616e206e6f6d696e616c20616d6f756e740000000000000000000000006064820152608401611d14565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663bfca6c116040518163ffffffff1660e01b8152600401606060405180830381865afa15801561442f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906144539190614b30565b50915050828110156144bc5760405162461bcd60e51b815260206004820152602c60248201527f43424d3a204e6f7420656e6f756768204c55534420617661696c61626c65206960448201526b1b88108b941c9bdd1bd8dbdb60a21b6064820152608401611d14565b60006114a485836132f2565b60405163a9059cbb60e01b81526001600160a01b038381166004830152602482018390527f0000000000000000000000000000000000000000000000000000000000000000169063a9059cbb906044016020604051808303816000875af1158015614537573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061455b9190614b8a565b508060036000828254613a049190614b19565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614613afb5760405162461bcd60e51b815260206004820152602360248201527f43424d3a204f6e6c7920596561726e20476f7665726e616e63652063616e2063604482015262185b1b60ea1b6064820152608401611d14565b604051635e0d443f60e01b815260016004820152600060248201819052670de0b6b3a764000060448301529081906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690635e0d443f90606401602060405180830381865afa158015614671573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906146959190614ac6565b90508261355e82670de0b6b3a7640000614a67565b604051632e1a7d4d60e01b8152600481018290527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690632e1a7d4d906024016020604051808303816000875af1158015614711573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906147359190614ac6565b508060036000828254613b899190614b19565b6000818310156133015781613303565b6000670de0b6b3a764000061476e600282614a9c565b6147788486614a67565b61355e9190614a4f565b600061478e8284614be4565b1561479a57600161479d565b60005b60ff166147aa8385614a9c565b6133039190614a4f565b6040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa15801561481b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061483f9190614ac6565b6040516393f7aa6760e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166004830152602482018590529192507f0000000000000000000000000000000000000000000000000000000000000000909116906393f7aa6790604401600060405180830381600087803b1580156148ce57600080fd5b505af11580156148e2573d6000803e3d6000fd5b50506040516370a0823160e01b81523060048201528492507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031691506370a0823190602401602060405180830381865afa15801561494c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906149709190614ac6565b61497a9083614b19565b14613e1657613e16614c15565b60006020828403121561499957600080fd5b5035919050565b6001600160a01b03811681146126a557600080fd5b60008060008060008060c087890312156149ce57600080fd5b86356149d9816149a0565b95506020870135945060408701359350606087013560ff811681146149fd57600080fd5b9598949750929560808101359460a0909101359350915050565b60008060408385031215614a2a57600080fd5b50508035926020909101359150565b634e487b7160e01b600052601160045260246000fd5b60008219821115614a6257614a62614a39565b500190565b6000816000190483118215151615614a8157614a81614a39565b500290565b634e487b7160e01b600052601260045260246000fd5b600082614aab57614aab614a86565b500490565b634e487b7160e01b600052602160045260246000fd5b600060208284031215614ad857600080fd5b5051919050565b805169ffffffffffffffffffff81168114614af957600080fd5b919050565b600060208284031215614b1057600080fd5b61330382614adf565b600082821015614b2b57614b2b614a39565b500390565b600080600060608486031215614b4557600080fd5b8351925060208401519150604084015190509250925092565b60008060408385031215614b7157600080fd5b82519150614b8160208401614adf565b90509250929050565b600060208284031215614b9c57600080fd5b8151801515811461330357600080fd5b60608101818460005b6002811015614bd4578151835260209283019290910190600101614bb5565b5050508260408301529392505050565b600082614bf357614bf3614a86565b500690565b600060208284031215614c0a57600080fd5b8151613303816149a0565b634e487b7160e01b600052600160045260246000fdfea2646970667358221220d50cb42b3fa172de0f06883778cf4e6e0328c7e338330d8671e5c083cbaed28a64736f6c634300080b0033000000000000000000000000c96265c8748c8361d77fe99d42ae78aae63995a60000000000000000000000005f98805a4e8be255a32880fdec7f6728c6568ba0000000000000000000000000ed279fdd11ca84beef15af5d39bb4d4bee23f0ca000000000000000000000000bebc44782c7db0a1a60cb6fe97d0b483032ff1c70000000000000000000000009062d1477c3cd000301a471be03c9db85c3fc27a0000000000000000000000005fa5b62c8af877cb37031e0a3b2f34a78e3c56a600000000000000000000000050c1a2ea0a861a967d9d0ffe2ae4012c2e053804000000000000000000000000feb4acf3df3cdea7399794d0869ef76a6efaff5200000000000000000000000020658291677a29efddfd0e303f8b23113d837cc7000000000000000000000000009644832140fed8b3b2b40405612f0c06ab3917000000000000000000000000000000000000000000000000000000000013c68000000000000000000000000000000000000000000000437af901e1dfac4c000000000000000000000000000000000000000000000000001146649c213f678000000000000000000000000000000000000000000000000000002386f26fc100000000000000000000000000000000000000000000000000000000000000015180000000000000000000000000000000000000000000000000006a94d74f4300000000000000000000000000000000000000000000000000000de2227fe94d00000000000000000000000000000000000000000000000000000de2227fe94d0000000000000000000000000000000000000000000000000000000000000013c680000000000000000000000000000000000000000000000000000000000013c68000000000000000000000000000000000000000000000000000000000003b53800000000000000000000000000000000000000000000000000000000000000e1000000000000000000000000000000000000000000000000000000000000002580000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000000000056bc75e2d6310000000000000000000000000000000000000000000000000003635c9adc5dea00000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000

Deployed Bytecode

0x608060405234801561001057600080fd5b506004361061043e5760003560e01c80637cbc237311610236578063b83f91a21161013b578063cc0c986e116100c3578063e9dc9e6d11610087578063e9dc9e6d14610b18578063edb134f314610b20578063f1b0cff514610b29578063f3c4023d14610b50578063f58369b914610b5857600080fd5b8063cc0c986e14610a89578063cfc31f6f14610a92578063d2e892dd14610ab9578063da10594314610ac2578063e324634914610b0f57600080fd5b8063c3c297451161010a578063c3c2974514610a0d578063c484cc5f14610a20578063c6c50ce814610a47578063c6d2d26114610a4f578063c7b5548114610a6257600080fd5b8063b83f91a21461097d578063bb870317146109a4578063bfc12c05146109cb578063c0639bbd146109f257600080fd5b8063a21ec280116101be578063acf955c71161018d578063acf955c7146108ed578063aefcc4fd14610914578063b0f3af4714610927578063b23ad3ee1461094e578063b7a65dce1461097557600080fd5b8063a21ec280146108a2578063a79e5683146108b5578063a891c684146108be578063ac8af3a9146108e557600080fd5b806390d532901161020557806390d532901461085357806391dc186f1461085c5780639c283187146108645780639fbc4a5f1461086c578063a20baee61461089357600080fd5b80637cbc23731461081357806384c2dea51461083b5780638ac6e2f4146108435780638caffae11461084b57600080fd5b80634237e191116103475780636350e4b2116102cf578063695e89da11610293578063695e89da146107b65780636a57b253146107be5780636b4fbbed146107d15780636bdac50b146107f85780637b3c7df61461080057600080fd5b80636350e4b2146107455780636381211414610758578063653a81981461077f57806366462ab11461078757806367e48a7e1461078f57600080fd5b80635041382b116103165780635041382b146106bf57806351a643ae146106e6578063570dd5241461070d57806359372e2e1461073457806361ec893d1461073d57600080fd5b80634237e1911461065d5780634903970a146106705780634b10543b146106975780634bb41097146106ac57600080fd5b806335f1d0e0116103ca5780633792dcb9116103995780633792dcb9146105d157806339f01388146105f85780633a517326146106005780633b19e84a146106275780633cbe79261461064a57600080fd5b806335f1d0e014610587578063361628831461058f57806336e2819e146105b657806337303e58146105c957600080fd5b8063218751b211610411578063218751b214610500578063233b0ee71461052757806327fafcd31461054e57806333624a861461055757806335567cda1461057e57600080fd5b80630277407314610443578063071a75411461047d5780630f34d74d146104a45780631705a3bd146104e3575b600080fd5b61046a7f000000000000000000000000000000000000000000000000000000000001518081565b6040519081526020015b60405180910390f35b61046a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81565b6104cb7f000000000000000000000000009644832140fed8b3b2b40405612f0c06ab391781565b6040516001600160a01b039091168152602001610474565b6009546104f09060ff1681565b6040519015158152602001610474565b6104cb7f000000000000000000000000ed279fdd11ca84beef15af5d39bb4d4bee23f0ca81565b61046a7f000000000000000000000000000000000000000000000000000000000013c68081565b61046a600a5481565b6104cb7f0000000000000000000000009062d1477c3cd000301a471be03c9db85c3fc27a81565b61046a60035481565b61046a610b61565b61046a7f00000000000000000000000000000000000000000000000000000000003b538081565b61046a6105c4366004614987565b610b95565b61046a610c49565b6104cb7f00000000000000000000000020658291677a29efddfd0e303f8b23113d837cc781565b60015461046a565b61046a7f000000000000000000000000000000000000000000000000006a94d74f43000081565b61062f610c6d565b60408051938452602084019290925290820152606001610474565b61046a610658366004614987565b610c87565b61046a61066b366004614987565b610d55565b61046a7f000000000000000000000000000000000000000000000000000000000013c68081565b6106aa6106a5366004614987565b610e08565b005b61046a6106ba366004614987565b6113a4565b61046a7f0000000000000000000000000000000000000000000000000de0b6b3a764000081565b61046a7f000000000000000000000000000000000000000000000000000000000013c68081565b61046a7f00000000000000000000000000000000000000000000003635c9adc5dea0000081565b61046a60055481565b61046a603c81565b61046a610753366004614987565b6114ad565b6104cb7f000000000000000000000000feb4acf3df3cdea7399794d0869ef76a6efaff5281565b61046a6117ce565b61046a6117f1565b61046a7f0000000000000000000000000000000000000000000000000000000000000e1081565b61046a6118b3565b61046a6107cc3660046149b5565b611940565b61046a7f000000000000000000000000000000000000000000000000000000000000025881565b61046a611a96565b6106aa61080e366004614987565b611b39565b610826610821366004614a17565b611fe5565b60408051928352602083019190915201610474565b61046a6123d2565b6106aa612476565b60005461046a565b61046a60045481565b61046a61254a565b60025461046a565b61046a7f0000000000000000000000000000000000000000000000056bc75e2d6310000081565b61046a670de0b6b3a764000081565b6106aa6108b0366004614987565b612574565b61046a60075481565b6104cb7f000000000000000000000000bebc44782c7db0a1a60cb6fe97d0b483032ff1c781565b61046a6126a8565b61046a7f0000000000000000000000000000000000000000000000000de0b68e66a5c00081565b6106aa610922366004614987565b6126cc565b6104cb7f000000000000000000000000c96265c8748c8361d77fe99d42ae78aae63995a681565b61046a7f0000000000000000000000000000000000000000000000000de0b68e66a5c00081565b61046a612c44565b6104cb7f0000000000000000000000005f98805a4e8be255a32880fdec7f6728c6568ba081565b6104cb7f00000000000000000000000050c1a2ea0a861a967d9d0ffe2ae4012c2e05380481565b61046a7f00000000000000000000000000000000000000000000000000000000633bee1781565b6109fa600081565b604051600f9190910b8152602001610474565b6106aa610a1b366004614a17565b612c68565b61046a7f00000000000000000000000000000000000000000000001146649c213f67800081565b61046a612f0d565b61046a610a5d366004614987565b612f25565b61046a7f000000000000000000000000000000000000000000000000000000000000000081565b61046a600d5481565b6104cb7f0000000000000000000000005fa5b62c8af877cb37031e0a3b2f34a78e3c56a681565b61046a600c5481565b610ad5610ad0366004614987565b613001565b6040805195865267ffffffffffffffff948516602087015292841692850192909252909116606083015260ff16608082015260a001610474565b61046a60065481565b6106aa6130d6565b61046a600b5481565b61046a7f0000000000000000000000000000000000000000000000000dbd2fc137a3000081565b61046a613131565b61046a600e5481565b600080610b6c61314d565b9050600080610b7a836131e2565b505050915091508082610b8d9190614a4f565b935050505090565b600080610ba061325c565b90506000610bce7f00000000000000000000000000000000000000000000000000000000000000008361326e565b90506000670de0b6b3a764000082600754610be99190614a67565b610bf39190614a9c565b90506000610c217fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff87614a9c565b610c2b9083614a4f565b9050610c3f81670de0b6b3a76400006132f2565b9695505050505050565b600080610c5461314d565b90506000610c61826131e2565b50909695505050505050565b600080549080610c7b610b61565b91506001549050909192565b6000818152600860209081526040808320815160a08101835281548152600182015467ffffffffffffffff80821695830195909552600160401b8104851693820193909352600160801b830490931660608401528392916080830190600160c01b900460ff166003811115610cfe57610cfe614ab0565b6003811115610d0f57610d0f614ab0565b8152505090506000610d25600d54600e5461330a565b509050610d4d826040015167ffffffffffffffff16610d4784600001516134ee565b836134fa565b949350505050565b600080610d60613131565b6000848152600860209081526040808320815160a08101835281548152600182015467ffffffffffffffff80821695830195909552600160401b8104851693820193909352600160801b83049093166060840152939450919290916080830190600160c01b900460ff166003811115610ddb57610ddb614ab0565b6003811115610dec57610dec614ab0565b815250509050610d4d610e0282600001516134ee565b83613549565b6000818152600860209081526040808320815160a08101835281548152600182015467ffffffffffffffff80821695830195909552600160401b8104851693820193909352600160801b83049093166060840152906080830190600160c01b900460ff166003811115610e7d57610e7d614ab0565b6003811115610e8e57610e8e614ab0565b9052509050610e9c82613568565b610ea98160800151613651565b6000610eb36136b2565b9050600080610ec061371f565b91509150600080610ed486600001516137cd565b915091507f00000000000000000000000020658291677a29efddfd0e303f8b23113d837cc76001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610f36573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f5a9190614ac6565b158015610f6a575060095460ff16155b15610f8b57610f88866040015167ffffffffffffffff16858561383e565b92505b6000610fa6876040015167ffffffffffffffff1683886134fa565b90506000610fb386612f25565b9050600081610fca84670de0b6b3a7640000614a67565b610fd49190614a9c565b9050610ff9610feb670de0b6b3a764000083614a9c565b67ffffffffffffffff6132f2565b60008b81526008602052604081206001908101805467ffffffffffffffff9485167fffffffffffffff00ffffffffffffffffffffffffffffffff000000000000000090911617600360c01b1767ffffffffffffffff60801b1916600160801b4295909516949094029390931790925590547f000000000000000000000000c96265c8748c8361d77fe99d42ae78aae63995a66001600160a01b031690639841a0189033908e906110ca907f00000000000000000000000000000000000000000000003635c9adc5dea0000090614a9c565b6040516001600160e01b031960e086901b1681526001600160a01b039093166004840152602483019190915260448201526064016020604051808303816000875af115801561111d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111419190614afe565b90506001600a60008282546111569190614a4f565b9091555050895160008054819061116e908490614b19565b909155505060408a01518a5161118e9167ffffffffffffffff1690614a67565b6005600082825461119f9190614b19565b90915550600090506111b18587614b19565b60095490915060ff166111db5780600160008282546111d09190614a4f565b909155506112829050565b7f0000000000000000000000009062d1477c3cd000301a471be03c9db85c3fc27a6001600160a01b031663bfca6c116040518163ffffffff1660e01b8152600401606060405180830381865afa158015611239573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061125d9190614b30565b5098506000905061126e828a6132f2565b90508015611280576112808133613972565b505b6040516340c10f1960e01b8152336004820152602481018490527f00000000000000000000000020658291677a29efddfd0e303f8b23113d837cc76001600160a01b0316906340c10f1990604401600060405180830381600087803b1580156112ea57600080fd5b505af11580156112fe573d6000803e3d6000fd5b505060095460ff161591505080156113165750868810155b156113245761132487613a0d565b8a51600954604080518f815260208101939093528201859052606082018390526080820189905260ff16151560a082015269ffffffffffffffffffff831660c082015233907fe0ae890eaa03f699e40e47e1644539436b9871b84f64d484b069ac9e0e9189149060e00160405180910390a2505050505050505050505050565b6000818152600860209081526040808320815160a08101835281548152600182015467ffffffffffffffff80821695830195909552600160401b8104851693820193909352600160801b830490931660608401528392916080830190600160c01b900460ff16600381111561141b5761141b614ab0565b600381111561142c5761142c614ab0565b905250905060018160800151600381111561144957611449614ab0565b146114575750600092915050565b600061147661146983600001516134ee565b611471613131565b613549565b90506000611488600d54600e5461330a565b5090506114a4836040015167ffffffffffffffff1683836134fa565b95945050505050565b60006114b882613a20565b6114c0613a9c565b6114c86136b2565b506000807f000000000000000000000000c96265c8748c8361d77fe99d42ae78aae63995a66001600160a01b03166340c10f19337f00000000000000000000000000000000000000000000003635c9adc5dea0000060015461152a9190614a9c565b6040516001600160e01b031960e085901b1681526001600160a01b039092166004830152602482015260440160408051808303816000875af1158015611574573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115989190614b5e565b915091506115cb6040805160a0810182526000808252602082018190529181018290526060810182905290608082015290565b8481524267ffffffffffffffff16604082015260016080820181905250600083815260086020908152604091829020835181559083015160018201805493850151606086015167ffffffffffffffff908116600160801b0267ffffffffffffffff60801b19928216600160401b026fffffffffffffffffffffffffffffffff199097169190941617949094179384168217815560808501518594909260ff60c01b191668ffffffffffffffffff60801b1990911617600160c01b83600381111561169757611697614ab0565b0217905550905050846000808282546116b09190614a4f565b909155506116c090504286614a67565b600560008282546116d19190614a4f565b90915550506040516323b872dd60e01b8152336004820152306024820152604481018690527f0000000000000000000000005f98805a4e8be255a32880fdec7f6728c6568ba06001600160a01b0316906323b872dd906064016020604051808303816000875af1158015611749573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061176d9190614b8a565b5061177785613afd565b604080518481526020810187905269ffffffffffffffffffff841681830152905133917ff3305d3ff042bc9868a6e25d2980cb0790e1edd5d6f0a32bb73650bce4926dd2919081900360600190a250909392505050565b6000806117d961314d565b905060006117e6826131e2565b509695505050505050565b6000806117fc6123d2565b9050600081156118ad5760007f000000000000000000000000ed279fdd11ca84beef15af5d39bb4d4bee23f0ca6001600160a01b031663bb7b8b806040518163ffffffff1660e01b8152600401602060405180830381865afa158015611866573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061188a9190614ac6565b9050670de0b6b3a764000061189f8285614a67565b6118a99190614a9c565b9150505b92915050565b6000807f0000000000000000000000009062d1477c3cd000301a471be03c9db85c3fc27a6001600160a01b031663bfca6c116040518163ffffffff1660e01b8152600401606060405180830381865afa158015611914573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119389190614b30565b509392505050565b604051636eb1769f60e11b81526001600160a01b03878116600483015230602483015260009187917f0000000000000000000000005f98805a4e8be255a32880fdec7f6728c6568ba0169063dd62ed3e90604401602060405180830381865afa1580156119b1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119d59190614ac6565b1015611a825760405163d505accf60e01b81526001600160a01b038881166004830152306024830152604482018890526064820187905260ff8616608483015260a4820185905260c482018490527f0000000000000000000000005f98805a4e8be255a32880fdec7f6728c6568ba0169063d505accf9060e401600060405180830381600087803b158015611a6957600080fd5b505af1158015611a7d573d6000803e3d6000fd5b505050505b611a8b866114ad565b979650505050505050565b6000600b54600a547f000000000000000000000000c96265c8748c8361d77fe99d42ae78aae63995a66001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611afc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b209190614ac6565b611b2a9190614b19565b611b349190614b19565b905090565b611b41613b91565b611b49613a9c565b611b51613c50565b611b59613d35565b600080611b6461371f565b915091506000805483611b779190614b19565b90506000611b836117f1565b9050611b8e81613e1a565b6000611b9a86846132f2565b9050611ba681856132f2565b9050611bbf8183600154611bba9190614b19565b6132f2565b9050611bca81613ea0565b60007f000000000000000000000000bebc44782c7db0a1a60cb6fe97d0b483032ff1c76001600160a01b031663bb7b8b806040518163ffffffff1660e01b8152600401602060405180830381865afa158015611c2a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c4e9190614ac6565b90506000611c5b82613ef0565b90507f0000000000000000000000000000000000000000000000000de0b68e66a5c0008111611d1d5760405162461bcd60e51b815260206004820152605660248201527f43424d3a204c5553443a334352562065786368616e67652072617465206d757360448201527f74206265206f76657220746865206465706f736974207468726573686f6c642060648201527f6265666f72652053502d3e437572766520736869667400000000000000000000608482015260a4015b60405180910390fd5b611d278330613972565b6040516370a0823160e01b81523060048201526000907f000000000000000000000000ed279fdd11ca84beef15af5d39bb4d4bee23f0ca6001600160a01b0316906370a0823190602401602060405180830381865afa158015611d8e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611db29190614ac6565b6040805180820182528681526000602082018190529151630b4c7e4d60e01b81529293506001600160a01b037f000000000000000000000000ed279fdd11ca84beef15af5d39bb4d4bee23f0ca1692630b4c7e4d92611e149291600401614bac565b6020604051808303816000875af1158015611e33573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e579190614ac6565b506040516370a0823160e01b815230600482015260009082906001600160a01b037f000000000000000000000000ed279fdd11ca84beef15af5d39bb4d4bee23f0ca16906370a0823190602401602060405180830381865afa158015611ec1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ee59190614ac6565b611eef9190614b19565b9050611efa81613fa8565b6000611f0585613ef0565b90508381108015611f3657507f0000000000000000000000000000000000000000000000000de0b68e66a5c0008110155b611fd85760405162461bcd60e51b815260206004820152606160248201527f43424d3a2053502d3e4375727665207368696674206d7573742064656372656160448201527f7365204c5553443a334352562065786368616e6765207261746520746f20612060648201527f76616c75652061626f766520746865206465706f736974207468726573686f6c6084820152601960fa1b60a482015260c401611d14565b5050505050505050505050565b600080611ff184613ea0565b611ffa84614177565b7f000000000000000000000000000000000000000000000000000000000013c6806004546120289190614a4f565b4210156120c35760405162461bcd60e51b815260206004820152604f60248201527f43424d3a20526564656d7074696f6e206166746572206669727374206368696360448201527f6b656e20696e206d757374207761697420756e74696c20626f6f74737472617060648201527f20706572696f64206973206f7665720000000000000000000000000000000000608482015260a401611d14565b6000806000806120d1614287565b94509450509350935060007f00000000000000000000000020658291677a29efddfd0e303f8b23113d837cc76001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561213a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061215e9190614ac6565b6121708a670de0b6b3a7640000614a67565b61217a9190614a9c565b60095490915060009060ff1661219857612193826142b6565b61219b565b60005b905060008080670de0b6b3a76400006121b4868b614a67565b6121be9190614a9c565b90506000670de0b6b3a76400006121d58682614b19565b6121df9084614a67565b6121e99190614a9c565b90506121f58183614b19565b6121ff9085614a4f565b935061220b818e614357565b9250821561221d5761221d8333613972565b506000905086156122b8576000670de0b6b3a764000061223d878b614a67565b6122479190614a9c565b90506000670de0b6b3a764000061225e8782614b19565b6122689084614a67565b6122729190614a9c565b905061227e8183614b19565b6122889086614a4f565b945088816003546122999190614a67565b6122a39190614a9c565b925082156122b5576122b533846144c8565b50505b6122c28387614a4f565b6001556122d76122d28284614a4f565b613ea0565b604051632770a7eb60e21b8152336004820152602481018e90526001600160a01b037f00000000000000000000000020658291677a29efddfd0e303f8b23113d837cc71690639dc29fac90604401600060405180830381600087803b15801561233f57600080fd5b505af1158015612353573d6000803e3d6000fd5b50505050336001600160a01b03167fc0ac8b09f0bc9dd02f48d9145336ab9df1dc378b6115bc78e0f6c3d72bc37b178e8e8585886040516123b6959493929190948552602085019390935260408401919091526060830152608082015260a00190565b60405180910390a29099509750505050505050505b9250929050565b6000670de0b6b3a76400007f0000000000000000000000005fa5b62c8af877cb37031e0a3b2f34a78e3c56a66001600160a01b03166399530b066040518163ffffffff1660e01b8152600401602060405180830381865afa15801561243b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061245f9190614ac6565b60035461246c9190614a67565b611b349190614a9c565b7f00000000000000000000000000000000000000000000000000000000000002587f0000000000000000000000000000000000000000000000000000000000000e10600c546124c59190614a4f565b6124cf9190614a4f565b4210156125445760405162461bcd60e51b815260206004820152603560248201527f43424d3a2050726576696f75732073686966742064656c617920616e6420776960448201527f6e646f77206d75737420686176652070617373656400000000000000000000006064820152608401611d14565b42600c55565b6000806125556117f1565b9050600061256161314d565b905061256d8282614a4f565b9250505090565b61257c61456e565b60095460ff16156125e25760405162461bcd60e51b815260206004820152602a60248201527f43424d3a205265636569766520666565207368617265206f6e6c7920696e206e6044820152696f726d616c206d6f646560b01b6064820152608401611d14565b6040516323b872dd60e01b81526001600160a01b037f000000000000000000000000feb4acf3df3cdea7399794d0869ef76a6efaff5281166004830152306024830152604482018390527f0000000000000000000000005f98805a4e8be255a32880fdec7f6728c6568ba016906323b872dd906064016020604051808303816000875af1158015612677573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061269b9190614b8a565b506126a581613afd565b50565b6000806126b361314d565b905060006126c0826131e2565b50929695505050505050565b6126d4613b91565b6126dc613a9c565b6126e4613c50565b6126ec613d35565b60006126f66117f1565b9050600061270483836132f2565b905061270f81613ea0565b60007f000000000000000000000000bebc44782c7db0a1a60cb6fe97d0b483032ff1c76001600160a01b031663bb7b8b806040518163ffffffff1660e01b8152600401602060405180830381865afa15801561276f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127939190614ac6565b905060006127a0826145f2565b90507f0000000000000000000000000000000000000000000000000de0b68e66a5c000811161285d5760405162461bcd60e51b815260206004820152605a60248201527f43424d3a20334352563a4c5553442065786368616e67652072617465206d757360448201527f742062652061626f766520746865207769746864726177616c2074687265736860648201527f6f6c64206265666f72652043757276652d3e5350207368696674000000000000608482015260a401611d14565b6040516370a0823160e01b81523060048201526000907f000000000000000000000000ed279fdd11ca84beef15af5d39bb4d4bee23f0ca6001600160a01b0316906370a0823190602401602060405180830381865afa1580156128c4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128e89190614ac6565b9050600085856003546128fb9190614a67565b6129059190614a9c565b9050612910816146aa565b6040516370a0823160e01b815230600482015260009083906001600160a01b037f000000000000000000000000ed279fdd11ca84beef15af5d39bb4d4bee23f0ca16906370a0823190602401602060405180830381865afa158015612979573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061299d9190614ac6565b6129a79190614b19565b6040516370a0823160e01b81523060048201529091506000906001600160a01b037f0000000000000000000000005f98805a4e8be255a32880fdec7f6728c6568ba016906370a0823190602401602060405180830381865afa158015612a11573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a359190614ac6565b604051630d2680e960e11b81526004810184905260006024820181905260448201529091507f000000000000000000000000ed279fdd11ca84beef15af5d39bb4d4bee23f0ca6001600160a01b031690631a4d01d290606401600060405180830381600087803b158015612aa857600080fd5b505af1158015612abc573d6000803e3d6000fd5b50506040516370a0823160e01b8152306004820152600092508391506001600160a01b037f0000000000000000000000005f98805a4e8be255a32880fdec7f6728c6568ba016906370a0823190602401602060405180830381865afa158015612b29573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b4d9190614ac6565b612b579190614b19565b9050612b6281613afd565b6000612b6d886145f2565b90508681108015612b9e57507f0000000000000000000000000000000000000000000000000de0b68e66a5c0008110155b611fd85760405162461bcd60e51b8152602060048201526064602482018190527f43424d3a2043757276652d3e5350207368696674206d75737420696e6372656160448301527f736520334352563a4c5553442065786368616e6765207261746520746f206120908201527f76616c75652061626f766520746865207769746864726177616c2074687265736084820152631a1bdb1960e21b60a482015260c401611d14565b600080612c4f61314d565b90506000612c5c826131e2565b50919695505050505050565b6000828152600860209081526040808320815160a08101835281548152600182015467ffffffffffffffff80821695830195909552600160401b8104851693820193909352600160801b83049093166060840152906080830190600160c01b900460ff166003811115612cdd57612cdd614ab0565b6003811115612cee57612cee614ab0565b9052509050612cfc83613568565b612d098160800151613651565b612d116136b2565b5060008381526008602052604081206001908101805467ffffffffffffffff4216600160801b0268ffffffffffffffffff60801b1990911617600160c11b179055546001600160a01b037f000000000000000000000000c96265c8748c8361d77fe99d42ae78aae63995a61690639841a0189033908790612db3907f00000000000000000000000000000000000000000000003635c9adc5dea0000090614a9c565b6040516001600160e01b031960e086901b1681526001600160a01b039093166004840152602483019190915260448201526064016020604051808303816000875af1158015612e06573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e2a9190614afe565b90506001600b6000828254612e3f9190614a4f565b90915550508151600080548190612e57908490614b19565b909155505060408201518251612e779167ffffffffffffffff1690614a67565b60056000828254612e889190614b19565b90915550508151600090612e9c9085614357565b9050612ea88133613972565b825160408051878152602081019290925281018590526060810182905269ffffffffffffffffffff8316608082015233907f3bd7a45d09d2d31d78737a80c00ac48ba89dd3cce7537ad56bf1bee66c9dc39e9060a00160405180910390a25050505050565b600080612f1e600d54600e5461330a565b5092915050565b6000807f00000000000000000000000020658291677a29efddfd0e303f8b23113d837cc76001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612f86573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612faa9190614ac6565b9050600080612fb8856131e2565b505050915091508260001415612fda5750670de0b6b3a7640000949350505050565b82612fe58284614a4f565b612ff790670de0b6b3a7640000614a67565b6114a49190614a9c565b6000818152600860209081526040808320815160a08101835281548152600182015467ffffffffffffffff80821695830195909552600160401b8104851693820193909352600160801b83049093166060840152839283928392839283929091906080830190600160c01b900460ff16600381111561308257613082614ab0565b600381111561309357613093614ab0565b8152505090508060000151816020015182604001518360600151846080015160038111156130c3576130c3614ab0565b939b929a50909850965090945092505050565b6130de61456e565b6130e6613a9c565b6009805460ff19166001908117909155546040519081527f6330fd496eb4822cdd507776770666698db359e48ce5a7797a0aaba0c879adca9060200160405180910390a16000600155565b60008061313c61314d565b905061314781612f25565b91505090565b6000807f0000000000000000000000009062d1477c3cd000301a471be03c9db85c3fc27a6001600160a01b031663bfca6c116040518163ffffffff1660e01b8152600401606060405180830381865afa1580156131ae573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131d29190614b30565b5091505061314760025482614748565b60008060008060008054866131f79190614b19565b92506132016117f1565b600154909250905060006132158385614a4f565b90508181111561325257600061322b8383614b19565b9050816132388683614a67565b6132429190614a9c565b965061324e8782614b19565b9550505b5091939590929450565b6000603c6006544261246c9190614b19565b6000631f54050082111561328457631f54050091505b816132985750670de0b6b3a76400006118ad565b670de0b6b3a764000083835b60018111156132e8576132b8600282614be4565b156132ca576132c78284614758565b92505b6132d48283614758565b91506132e1600282614a9c565b90506132a4565b610c3f8284614758565b60008183106133015781613303565b825b9392505050565b6000807f00000000000000000000000000000000000000000000000000000000000151806133587f00000000000000000000000000000000000000000000000000000000633bee1742614b19565b6133629190614a9c565b90508281148061339157507f00000000000000000000000000000000000000000000001146649c213f67800084145b8061339c5750600054155b156133a9578391506123cb565b600080546005546133ba9190614a9c565b9050600061343c7f00000000000000000000000000000000000000000000000000000000633bee1761340c7f000000000000000000000000000000000000000000000000000000000013c68085614a4f565b6134169190614b19565b7f0000000000000000000000000000000000000000000000000000000000015180614782565b9050808310156134505785935050506123cb565b600061346686613461600185614b19565b614748565b6134709085614b19565b90506134e2670de0b6b3a76400006134a87f0000000000000000000000000000000000000000000000000dbd2fc137a300008461326e565b6134b2908a614a67565b6134bc9190614a9c565b7f00000000000000000000000000000000000000000000001146649c213f678000614748565b94505050509250929050565b600080610d4d836137cd565b60008361350957506000613303565b60006135158542614b19565b61352790670de0b6b3a7640000614a67565b905060006135358483614a4f565b61353f8387614a67565b610c3f9190614a9c565b60008161355e84670de0b6b3a7640000614a67565b6133039190614a9c565b6040516331a9108f60e11b8152600481018290527f000000000000000000000000c96265c8748c8361d77fe99d42ae78aae63995a66001600160a01b031690636352211e90602401602060405180830381865afa1580156135cd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135f19190614bf8565b6001600160a01b0316336001600160a01b0316146126a55760405162461bcd60e51b815260206004820152601d60248201527f43424d3a2043616c6c6572206d757374206f776e2074686520626f6e640000006044820152606401611d14565b600181600381111561366557613665614ab0565b146126a55760405162461bcd60e51b815260206004820152601860248201527f43424d3a20426f6e64206d7573742062652061637469766500000000000000006044820152606401611d14565b600d54600e546000919082806136c8848461330a565b9150915082811461193857600e81905581841461193857600d8290556040518281527fdf0b753b5dc9a250a9e6268e9c010c895cd12d6e66f6cfb57531a3a49315d09a9060200160405180910390a1509392505050565b60008060007f0000000000000000000000009062d1477c3cd000301a471be03c9db85c3fc27a6001600160a01b031663bfca6c116040518163ffffffff1660e01b8152600401606060405180830381865afa158015613782573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137a69190614b30565b506002549092509050808211156137c557506002819055928392509050565b939092509050565b600954600090819060ff16156137e557506000929050565b6000670de0b6b3a764000061381a7f000000000000000000000000000000000000000000000000006a94d74f43000086614a67565b6138249190614a9c565b905060006138328286614b19565b91959194509092505050565b600061386a7f000000000000000000000000000000000000000000000000000000000013c68085614a4f565b4210156138df5760405162461bcd60e51b815260206004820152603e60248201527f43424d3a20466972737420636869636b656e20696e206d75737420776169742060448201527f756e74696c20626f6f74737472617020706572696f64206973206f76657200006064820152608401611d14565b4260045560006138ee846131e2565b505050509050808310156139595760405162461bcd60e51b815260206004820152602c60248201527f43424d3a204e6f7420656e6f756768204c55534420617661696c61626c65206960448201526b1b88108b941c9bdd1bd8dbdb60a21b6064820152608401611d14565b80156139685761396881613a0d565b6114a48184614b19565b604051627b8a6760e11b8152600481018390526001600160a01b0382811660248301527f0000000000000000000000009062d1477c3cd000301a471be03c9db85c3fc27a169062f714ce90604401600060405180830381600087803b1580156139da57600080fd5b505af11580156139ee573d6000803e3d6000fd5b505050508160026000828254613a049190614b19565b90915550505050565b613a178130613972565b6126a5816147b4565b7f0000000000000000000000000000000000000000000000056bc75e2d631000008110156126a55760405162461bcd60e51b8152602060048201526024808201527f43424d3a20426f6e64206d696e696d756d20616d6f756e74206e6f742072656160448201526318da195960e21b6064820152608401611d14565b60095460ff1615613afb5760405162461bcd60e51b8152602060048201526024808201527f43424d3a204d6967726174696f6e206d757374206265206e6f742062652061636044820152637469766560e01b6064820152608401611d14565b565b60405163b6b55f2560e01b8152600481018290527f0000000000000000000000009062d1477c3cd000301a471be03c9db85c3fc27a6001600160a01b03169063b6b55f2590602401600060405180830381600087803b158015613b5f57600080fd5b505af1158015613b73573d6000803e3d6000fd5b505050508060026000828254613b899190614a4f565b909155505050565b7f00000000000000000000000000000000000000000000000000000000003b5380613bdc7f00000000000000000000000000000000000000000000000000000000633bee1742614b19565b1015613afb5760405162461bcd60e51b815260206004820152603c60248201527f43424d3a2053686966746572206f6e6c792063616c6c61626c6520616674657260448201527f20736869667420626f6f74737472617020706572696f6420656e6473000000006064820152608401611d14565b60007f00000000000000000000000020658291677a29efddfd0e303f8b23113d837cc76001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613cb0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613cd49190614ac6565b11613afb5760405162461bcd60e51b815260206004820152602b60248201527f43424d3a20624c55534420537570706c79206d757374206265203e203020757060448201526a6f6e207368696674696e6760a81b6064820152608401611d14565b60007f0000000000000000000000000000000000000000000000000000000000000e10600c54613d659190614a4f565b90506000613d937f000000000000000000000000000000000000000000000000000000000000025883614a4f565b9050814210158015613da457508042105b613e165760405162461bcd60e51b815260206004820152602f60248201527f43424d3a205368696674206f6e6c7920706f737369626c6520696e736964652060448201527f7368696674696e672077696e646f7700000000000000000000000000000000006064820152608401611d14565b5050565b8060015410156126a55760405162461bcd60e51b8152602060048201526044602482018190527f43424d3a2054686520616d6f756e7420696e2043757276652063616e6e6f7420908201527f62652067726561746572207468616e20746865205065726d616e656e7420627560648201526318dad95d60e21b608482015260a401611d14565b600081116126a55760405162461bcd60e51b815260206004820152601760248201527f43424d3a20416d6f756e74206d757374206265203e20300000000000000000006044820152606401611d14565b604051635e0d443f60e01b815260006004820181905260016024830152670de0b6b3a764000060448301529081906001600160a01b037f000000000000000000000000ed279fdd11ca84beef15af5d39bb4d4bee23f0ca1690635e0d443f90606401602060405180830381865afa158015613f6f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613f939190614ac6565b9050670de0b6b3a764000061355e8483614a67565b6040516370a0823160e01b81523060048201526000907f0000000000000000000000005fa5b62c8af877cb37031e0a3b2f34a78e3c56a66001600160a01b0316906370a0823190602401602060405180830381865afa15801561400f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906140339190614ac6565b60405163b6b55f2560e01b8152600481018490529091507f0000000000000000000000005fa5b62c8af877cb37031e0a3b2f34a78e3c56a66001600160a01b03169063b6b55f25906024016020604051808303816000875af115801561409d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906140c19190614ac6565b506040516370a0823160e01b815230600482015260009082906001600160a01b037f0000000000000000000000005fa5b62c8af877cb37031e0a3b2f34a78e3c56a616906370a0823190602401602060405180830381865afa15801561412b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061414f9190614ac6565b6141599190614b19565b9050806003600082825461416d9190614a4f565b9091555050505050565b60095460ff166126a5577f00000000000000000000000020658291677a29efddfd0e303f8b23113d837cc76001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156141df573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906142039190614ac6565b61422d7f0000000000000000000000000000000000000000000000000de0b6b3a764000083614a4f565b11156126a55760405162461bcd60e51b815260206004820152602360248201527f43424d3a2043616e6e6f742072656465656d2062656c6f77206d696e20737570604482015262706c7960e81b6064820152608401611d14565b60008060008060008061429861371f565b5090506142a4816131e2565b95509550955095509550509091929394565b6000806142c283610b95565b60078190556040518181529091507fe31dea26c34fb8440bf2eec033dfd26bd39e88e026348d996e275a396417109b9060200160405180910390a160006006544261430d9190614b19565b9050603c8110612f1e574260068190556040519081527fbab964312bdd13595266f3e549bca3102965a6d718c6c1f8cd7eaac076b9c6c29060200160405180910390a15092915050565b6000818310156143cf5760405162461bcd60e51b815260206004820152603460248201527f43424d3a204d696e2076616c75652063616e6e6f74206265206772656174657260448201527f207468616e206e6f6d696e616c20616d6f756e740000000000000000000000006064820152608401611d14565b60007f0000000000000000000000009062d1477c3cd000301a471be03c9db85c3fc27a6001600160a01b031663bfca6c116040518163ffffffff1660e01b8152600401606060405180830381865afa15801561442f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906144539190614b30565b50915050828110156144bc5760405162461bcd60e51b815260206004820152602c60248201527f43424d3a204e6f7420656e6f756768204c55534420617661696c61626c65206960448201526b1b88108b941c9bdd1bd8dbdb60a21b6064820152608401611d14565b60006114a485836132f2565b60405163a9059cbb60e01b81526001600160a01b038381166004830152602482018390527f0000000000000000000000005fa5b62c8af877cb37031e0a3b2f34a78e3c56a6169063a9059cbb906044016020604051808303816000875af1158015614537573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061455b9190614b8a565b508060036000828254613a049190614b19565b336001600160a01b037f000000000000000000000000feb4acf3df3cdea7399794d0869ef76a6efaff521614613afb5760405162461bcd60e51b815260206004820152602360248201527f43424d3a204f6e6c7920596561726e20476f7665726e616e63652063616e2063604482015262185b1b60ea1b6064820152608401611d14565b604051635e0d443f60e01b815260016004820152600060248201819052670de0b6b3a764000060448301529081906001600160a01b037f000000000000000000000000ed279fdd11ca84beef15af5d39bb4d4bee23f0ca1690635e0d443f90606401602060405180830381865afa158015614671573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906146959190614ac6565b90508261355e82670de0b6b3a7640000614a67565b604051632e1a7d4d60e01b8152600481018290527f0000000000000000000000005fa5b62c8af877cb37031e0a3b2f34a78e3c56a66001600160a01b031690632e1a7d4d906024016020604051808303816000875af1158015614711573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906147359190614ac6565b508060036000828254613b899190614b19565b6000818310156133015781613303565b6000670de0b6b3a764000061476e600282614a9c565b6147788486614a67565b61355e9190614a4f565b600061478e8284614be4565b1561479a57600161479d565b60005b60ff166147aa8385614a9c565b6133039190614a4f565b6040516370a0823160e01b81523060048201526000907f0000000000000000000000005f98805a4e8be255a32880fdec7f6728c6568ba06001600160a01b0316906370a0823190602401602060405180830381865afa15801561481b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061483f9190614ac6565b6040516393f7aa6760e01b81526001600160a01b037f0000000000000000000000005f98805a4e8be255a32880fdec7f6728c6568ba081166004830152602482018590529192507f000000000000000000000000009644832140fed8b3b2b40405612f0c06ab3917909116906393f7aa6790604401600060405180830381600087803b1580156148ce57600080fd5b505af11580156148e2573d6000803e3d6000fd5b50506040516370a0823160e01b81523060048201528492507f0000000000000000000000005f98805a4e8be255a32880fdec7f6728c6568ba06001600160a01b031691506370a0823190602401602060405180830381865afa15801561494c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906149709190614ac6565b61497a9083614b19565b14613e1657613e16614c15565b60006020828403121561499957600080fd5b5035919050565b6001600160a01b03811681146126a557600080fd5b60008060008060008060c087890312156149ce57600080fd5b86356149d9816149a0565b95506020870135945060408701359350606087013560ff811681146149fd57600080fd5b9598949750929560808101359460a0909101359350915050565b60008060408385031215614a2a57600080fd5b50508035926020909101359150565b634e487b7160e01b600052601160045260246000fd5b60008219821115614a6257614a62614a39565b500190565b6000816000190483118215151615614a8157614a81614a39565b500290565b634e487b7160e01b600052601260045260246000fd5b600082614aab57614aab614a86565b500490565b634e487b7160e01b600052602160045260246000fd5b600060208284031215614ad857600080fd5b5051919050565b805169ffffffffffffffffffff81168114614af957600080fd5b919050565b600060208284031215614b1057600080fd5b61330382614adf565b600082821015614b2b57614b2b614a39565b500390565b600080600060608486031215614b4557600080fd5b8351925060208401519150604084015190509250925092565b60008060408385031215614b7157600080fd5b82519150614b8160208401614adf565b90509250929050565b600060208284031215614b9c57600080fd5b8151801515811461330357600080fd5b60608101818460005b6002811015614bd4578151835260209283019290910190600101614bb5565b5050508260408301529392505050565b600082614bf357614bf3614a86565b500690565b600060208284031215614c0a57600080fd5b8151613303816149a0565b634e487b7160e01b600052600160045260246000fdfea2646970667358221220d50cb42b3fa172de0f06883778cf4e6e0328c7e338330d8671e5c083cbaed28a64736f6c634300080b0033

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

000000000000000000000000c96265c8748c8361d77fe99d42ae78aae63995a60000000000000000000000005f98805a4e8be255a32880fdec7f6728c6568ba0000000000000000000000000ed279fdd11ca84beef15af5d39bb4d4bee23f0ca000000000000000000000000bebc44782c7db0a1a60cb6fe97d0b483032ff1c70000000000000000000000009062d1477c3cd000301a471be03c9db85c3fc27a0000000000000000000000005fa5b62c8af877cb37031e0a3b2f34a78e3c56a600000000000000000000000050c1a2ea0a861a967d9d0ffe2ae4012c2e053804000000000000000000000000feb4acf3df3cdea7399794d0869ef76a6efaff5200000000000000000000000020658291677a29efddfd0e303f8b23113d837cc7000000000000000000000000009644832140fed8b3b2b40405612f0c06ab3917000000000000000000000000000000000000000000000000000000000013c68000000000000000000000000000000000000000000000437af901e1dfac4c000000000000000000000000000000000000000000000000001146649c213f678000000000000000000000000000000000000000000000000000002386f26fc100000000000000000000000000000000000000000000000000000000000000015180000000000000000000000000000000000000000000000000006a94d74f4300000000000000000000000000000000000000000000000000000de2227fe94d00000000000000000000000000000000000000000000000000000de2227fe94d0000000000000000000000000000000000000000000000000000000000000013c680000000000000000000000000000000000000000000000000000000000013c68000000000000000000000000000000000000000000000000000000000003b53800000000000000000000000000000000000000000000000000000000000000e1000000000000000000000000000000000000000000000000000000000000002580000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000000000056bc75e2d6310000000000000000000000000000000000000000000000000003635c9adc5dea00000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000

-----Decoded View---------------
Arg [0] : _externalContractAddresses (tuple): System.Collections.Generic.List`1[Nethereum.ABI.FunctionEncoding.ParameterOutput]
Arg [1] : _params (tuple): System.Collections.Generic.List`1[Nethereum.ABI.FunctionEncoding.ParameterOutput]

-----Encoded View---------------
28 Constructor Arguments found :
Arg [0] : 000000000000000000000000c96265c8748c8361d77fe99d42ae78aae63995a6
Arg [1] : 0000000000000000000000005f98805a4e8be255a32880fdec7f6728c6568ba0
Arg [2] : 000000000000000000000000ed279fdd11ca84beef15af5d39bb4d4bee23f0ca
Arg [3] : 000000000000000000000000bebc44782c7db0a1a60cb6fe97d0b483032ff1c7
Arg [4] : 0000000000000000000000009062d1477c3cd000301a471be03c9db85c3fc27a
Arg [5] : 0000000000000000000000005fa5b62c8af877cb37031e0a3b2f34a78e3c56a6
Arg [6] : 00000000000000000000000050c1a2ea0a861a967d9d0ffe2ae4012c2e053804
Arg [7] : 000000000000000000000000feb4acf3df3cdea7399794d0869ef76a6efaff52
Arg [8] : 00000000000000000000000020658291677a29efddfd0e303f8b23113d837cc7
Arg [9] : 000000000000000000000000009644832140fed8b3b2b40405612f0c06ab3917
Arg [10] : 000000000000000000000000000000000000000000000000000000000013c680
Arg [11] : 00000000000000000000000000000000000000000000437af901e1dfac4c0000
Arg [12] : 00000000000000000000000000000000000000000000001146649c213f678000
Arg [13] : 000000000000000000000000000000000000000000000000002386f26fc10000
Arg [14] : 0000000000000000000000000000000000000000000000000000000000015180
Arg [15] : 000000000000000000000000000000000000000000000000006a94d74f430000
Arg [16] : 0000000000000000000000000000000000000000000000000de2227fe94d0000
Arg [17] : 0000000000000000000000000000000000000000000000000de2227fe94d0000
Arg [18] : 000000000000000000000000000000000000000000000000000000000013c680
Arg [19] : 000000000000000000000000000000000000000000000000000000000013c680
Arg [20] : 00000000000000000000000000000000000000000000000000000000003b5380
Arg [21] : 0000000000000000000000000000000000000000000000000000000000000e10
Arg [22] : 0000000000000000000000000000000000000000000000000000000000000258
Arg [23] : 0000000000000000000000000000000000000000000000000de0b6b3a7640000
Arg [24] : 0000000000000000000000000000000000000000000000056bc75e2d63100000
Arg [25] : 00000000000000000000000000000000000000000000003635c9adc5dea00000
Arg [26] : ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
Arg [27] : 0000000000000000000000000000000000000000000000000000000000000000


Deployed Bytecode Sourcemap

22654:57812:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;31030:55;;;;;;;;160:25:1;;;148:2;133:18;31030:55:0;;;;;;;;29805:29;;;;;23321:59;;;;;;;;-1:-1:-1;;;;;391:55:1;;;373:74;;361:2;346:18;23321:59:0;196:257:1;27888:21:0;;;;;;;;;;;;623:14:1;;616:22;598:41;;586:2;571:18;27888:21:0;458:187:1;22947:37:0;;;;;30556:48;;;;;27918:29;;;;;;23142:34;;;;;23802:31;;;;;;76911:288;;;:::i;28467:47::-;;;;;60230:802;;;;;;:::i;:::-;;:::i;77869:231::-;;;:::i;22814:39::-;;;;;77738:99;77816:13;;77738:99;;23445:43;;;;;79802:497;;;:::i;:::-;;;;1780:25:1;;;1836:2;1821:18;;1814:34;;;;1864:18;;;1857:34;1768:2;1753:18;79802:497:0;1578:319:1;72721:394:0;;;;;;:::i;:::-;;:::i;73703:299::-;;;;;;:::i;:::-;;:::i;28264:52::-;;;;;42233:3375;;;;;;:::i;:::-;;:::i;:::-;;73123:572;;;;;;:::i;:::-;;:::i;28815:41::-;;;;;28359:48;;;;;29531:47;;;;;26971:38;;;;;;28205:50;;28253:2;28205:50;;36583:1049;;;;;;:::i;:::-;;:::i;23389:47::-;;;;;78108:240;;;:::i;74855:414::-;;;:::i;28595:38::-;;;;;74010:179;;;:::i;37640:497::-;;;;;;:::i;:::-;;:::i;28687:39::-;;;;;80307:156;;;:::i;48811:3052::-;;;;;;:::i;:::-;;:::i;45616:3187::-;;;;;;:::i;:::-;;:::i;:::-;;;;3411:25:1;;;3467:2;3452:18;;3445:34;;;;3384:18;45616:3187:0;3237:248:1;74337:159:0;;;:::i;58160:391::-;;;:::i;75302:95::-;75351:7;75378:11;75302:95;;26867:33;;;;;;74604:243;;;:::i;79697:97::-;79774:12;;79697:97;;28944:40;;;;;4093:45;;4134:4;4093:45;;58587:383;;;;;;:::i;:::-;;:::i;27200:33::-;;;;;;23068:41;;;;;77207:239;;;:::i;29992:66::-;;;;;51871:2993;;;;;;:::i;:::-;;:::i;22772:33::-;;;;;30065:69;;;;;77454:249;;;:::i;22860:37::-;;;;;23269:45;;;;;30378:44;;;;;28076:60;;28135:1;28076:60;;;;;4414:2:1;4403:22;;;;4385:41;;4373:2;4358:18;28076:60:0;4241:191:1;38145:1422:0;;;;;;:::i;:::-;;:::i;30683:48::-;;;;;79444:245;;;:::i;78591:845::-;;;;;;:::i;:::-;;:::i;29841:44::-;;;;;31206:31;;;;;;23218:44;;;;;30205;;;;;;72288:425;;;;;;:::i;:::-;;:::i;:::-;;;;4936:25:1;;;4980:18;5034:15;;;5029:2;5014:18;;5007:43;5086:15;;;5066:18;;;5059:43;;;;5138:15;;;5133:2;5118:18;;5111:43;5203:4;5191:17;5185:3;5170:19;;5163:46;4923:3;4908:19;72288:425:0;4687:528:1;27118:33:0;;;;;;57752:356;;;:::i;27954:30::-;;;;;;30847:52;;;;;78380:203;;;:::i;31644:43::-;;;;;;76911:288;76964:7;76984:21;77008:27;:25;:27::i;:::-;76984:51;;77047:24;77073:27;77107:28;77121:13;77107;:28::i;:::-;77046:89;;;;;;;77172:19;77153:16;:38;;;;:::i;:::-;77146:45;;;;;76911:288;:::o;60230:802::-;60322:7;60342:21;60366:35;:33;:35::i;:::-;60342:59;;60412:19;60434:42;60441:19;60462:13;60434:6;:42::i;:::-;60412:64;;60489:33;4134:4;60546:11;60525:18;;:32;;;;:::i;:::-;:52;;;;:::i;:::-;60489:88;-1:-1:-1;60661:29:0;60721:31;60748:4;60721:24;:31;:::i;:::-;60693:59;;:25;:59;:::i;:::-;60661:91;;60787:50;60796:21;4134:4;60787:8;:50::i;:::-;60763:74;60230:802;-1:-1:-1;;;;;;60230:802:0:o;77869:231::-;77920:7;77940:21;77964:27;:25;:27::i;:::-;77940:51;;78006:21;78033:28;78047:13;78033;:28::i;:::-;-1:-1:-1;78002:59:0;;77869:231;-1:-1:-1;;;;;;77869:231:0:o;79802:497::-;80044:20;80185:11;;;80044:20;80228:22;:20;:22::i;:::-;80207:43;;80278:13;;80261:30;;79802:497;;;:::o;72721:394::-;72787:7;72830:21;;;:12;:21;;;;;;;;72807:44;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;72807:44:0;;;;;;;;;;;-1:-1:-1;;;72807:44:0;;;;;;;;;72787:7;;72807:44;;;;;-1:-1:-1;;;72807:44:0;;;;;;;;;;;;:::i;:::-;;;;;;;;;:::i;:::-;;;;;;;72865:31;72902:76;72931:16;;72949:28;;72902;:76::i;:::-;72864:114;;;72998:109;73017:4;:14;;;72998:109;;73033:48;73065:4;:15;;;73033:31;:48::i;:::-;73083:23;72998:18;:109::i;:::-;72991:116;72721:394;-1:-1:-1;;;;72721:394:0:o;73703:299::-;73769:7;73789:20;73812:24;:22;:24::i;:::-;73849:20;73872:21;;;:12;:21;;;;;;;;73849:44;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;73849:44:0;;;;;;;;;;;-1:-1:-1;;;73849:44:0;;;;;;;;;73789:47;;-1:-1:-1;73849:20:0;;:44;;;;;;-1:-1:-1;;;73849:44:0;;;;;;;;;;;;:::i;:::-;;;;;;;;;:::i;:::-;;;;;;;73913:81;73931:48;73963:4;:15;;;73931:31;:48::i;:::-;73981:12;73913:17;:81::i;42233:3375::-;42289:20;42312:21;;;:12;:21;;;;;;;;42289:44;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;42289:44:0;;;;;;;;;;;-1:-1:-1;;;42289:44:0;;;;;;;;;42312:21;42289:44;;;;-1:-1:-1;;;42289:44:0;;;;;;;;;;;;:::i;:::-;;;;;;;;;:::i;:::-;;;-1:-1:-1;42289:44:0;-1:-1:-1;42346:31:0;42369:7;42346:22;:31::i;:::-;42388:33;42409:4;:11;;;42388:20;:33::i;:::-;42434:31;42468:25;:23;:25::i;:::-;42434:59;;42505:21;42528:25;42557:17;:15;:17::i;:::-;42504:70;;;;42588:26;42616:35;42655:48;42687:4;:15;;;42655:31;:48::i;:::-;42587:116;;;;43032:10;-1:-1:-1;;;;;43032:22:0;;:24;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:29;:43;;;;-1:-1:-1;43066:9:0;;;;43065:10;43032:43;43028:161;;;43112:65;43128:4;:14;;;43112:65;;43144:13;43159:17;43112:15;:65::i;:::-;43092:85;;43028:161;43344:21;43368:88;43387:4;:14;;;43368:88;;43403:27;43432:23;43368:18;:88::i;:::-;43344:112;;43515:20;43538:51;43575:13;43538:36;:51::i;:::-;43515:74;-1:-1:-1;43600:20:0;43515:74;43623:20;:13;43639:4;43623:20;:::i;:::-;:35;;;;:::i;:::-;43600:58;-1:-1:-1;43715:47:0;43724:19;43739:4;43600:58;43724:19;:::i;:::-;43745:16;43715:8;:47::i;:::-;43671:21;;;;:12;:21;;;;;:34;;;;:92;;;;;;43797:53;;;;;-1:-1:-1;;;43797:53:0;-1:-1:-1;;;;43861:55:0;-1:-1:-1;;;43900:15:0;43861:55;;;;;;;;;;;;;;;43990:13;;43943:7;-1:-1:-1;;;;;43943:25:0;;;;43969:10;;43671:21;;43990:38;;44006:22;;43990:38;:::i;:::-;43943:86;;-1:-1:-1;;;;;;43943:86:0;;;;;;;-1:-1:-1;;;;;6456:55:1;;;43943:86:0;;;6438:74:1;6528:18;;;6521:34;;;;6571:18;;;6564:34;6411:18;;43943:86:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;43927:102;;44060:1;44042:14;;:19;;;;;;;:::i;:::-;;;;-1:-1:-1;;44206:15:0;;;44191:30;;44206:15;;44191:30;;44206:15;;44191:30;:::i;:::-;;;;-1:-1:-1;;44277:14:0;;;;44259:15;;:32;;;;;;:::i;:::-;44232:23;;:59;;;;;;;:::i;:::-;;;;-1:-1:-1;44388:19:0;;-1:-1:-1;44410:43:0;44440:13;44410:27;:43;:::i;:::-;44528:9;;44388:65;;-1:-1:-1;44528:9:0;;44523:608;;44712:11;44695:13;;:28;;;;;;;:::i;:::-;;;;-1:-1:-1;44523:608:0;;-1:-1:-1;44523:608:0;;44931:11;-1:-1:-1;;;;;44931:24:0;;:26;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;44907:50:0;-1:-1:-1;44972:20:0;;-1:-1:-1;44995:40:0;45004:11;44907:50;44995:8;:40::i;:::-;44972:63;-1:-1:-1;45054:16:0;;45050:70;;45074:43;45092:12;45106:10;45074:17;:43::i;:::-;44741:390;44523:608;45143:41;;-1:-1:-1;;;45143:41:0;;45159:10;45143:41;;;7619:74:1;7709:18;;;7702:34;;;45143:10:0;-1:-1:-1;;;;;45143:15:0;;;;7592:18:1;;45143:41:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;45312:9:0;;;;45311:10;;-1:-1:-1;;45311:53:0;;;;;45346:18;45325:17;:39;;45311:53;45307:161;;;45381:75;45437:18;45381:55;:75::i;:::-;45518:15;;45582:9;;45485:115;;;8054:25:1;;;8110:2;8095:18;;8088:34;;;;8138:18;;8131:34;;;8196:2;8181:18;;8174:34;;;8239:3;8224:19;;8217:35;;;45582:9:0;;8296:14:1;8289:22;8283:3;8268:19;;8261:51;8361:22;8349:35;;8343:3;8328:19;;8321:64;45497:10:0;;45485:115;;8041:3:1;8026:19;45485:115:0;;;;;;;42278:3330;;;;;;;;;;;42233:3375;:::o;73123:572::-;73189:7;73232:21;;;:12;:21;;;;;;;;73209:44;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;73209:44:0;;;;;;;;;;;-1:-1:-1;;;73209:44:0;;;;;;;;;73189:7;;73209:44;;;;;-1:-1:-1;;;73209:44:0;;;;;;;;;;;;:::i;:::-;;;;;;;;;:::i;:::-;;;-1:-1:-1;73209:44:0;-1:-1:-1;73285:17:0;73270:4;:11;;;:32;;;;;;;;:::i;:::-;;73266:73;;-1:-1:-1;73326:1:0;;73123:572;-1:-1:-1;;73123:572:0:o;73266:73::-;73351:20;73374:93;73392:48;73424:4;:15;;;73392:31;:48::i;:::-;73442:24;:22;:24::i;:::-;73374:17;:93::i;:::-;73351:116;;73481:31;73518:76;73547:16;;73565:28;;73518;:76::i;:::-;73480:114;;;73614:73;73633:4;:14;;;73614:73;;73649:12;73663:23;73614:18;:73::i;:::-;73607:80;73123:572;-1:-1:-1;;;;;73123:572:0:o;36583:1049::-;36640:7;36660:28;36676:11;36660:15;:28::i;:::-;36699;:26;:28::i;:::-;36740:25;:23;:25::i;:::-;;36843:14;36859:21;36884:7;-1:-1:-1;;;;;36884:12:0;;36897:10;36925:22;36909:13;;:38;;;;:::i;:::-;36884:64;;-1:-1:-1;;;;;;36884:64:0;;;;;;;-1:-1:-1;;;;;7637:55:1;;;36884:64:0;;;7619:74:1;7709:18;;;7702:34;7592:18;;36884:64:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;36842:106;;;;37030:24;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;37030:24:0;37065:33;;;37137:15;37109:44;;:18;;;:44;37182:17;37164:15;;;37182:17;37164:35;;-1:-1:-1;37210:20:0;;;;:12;:20;;;;;;;;;:31;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;37210:31:0;-1:-1:-1;;;;37210:31:0;;;-1:-1:-1;;;37210:31:0;-1:-1:-1;;37210:31:0;;;;;;;;;;;;;;;;;;;;;;;37233:8;;37210:31;;-1:-1:-1;;;;37210:31:0;-1:-1:-1;;;;37210:31:0;;;;-1:-1:-1;;;37210:31:0;;;;;;;;;:::i;:::-;;;;;;;;;37269:11;37254;;:26;;;;;;;:::i;:::-;;;;-1:-1:-1;37318:29:0;;-1:-1:-1;37332:15:0;37318:11;:29;:::i;:::-;37291:23;;:56;;;;;;;:::i;:::-;;;;-1:-1:-1;;37360:62:0;;-1:-1:-1;;;37360:62:0;;37383:10;37360:62;;;8931:34:1;37403:4:0;8981:18:1;;;8974:43;9033:18;;;9026:34;;;37360:9:0;-1:-1:-1;;;;;37360:22:0;;;;8843:18:1;;37360:62:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;37493:27;37508:11;37493:14;:27::i;:::-;37538:60;;;9553:25:1;;;9609:2;9594:18;;9587:34;;;9669:22;9657:35;;9637:18;;;9630:63;37538:60:0;;37550:10;;37538:60;;;;;;9541:2:1;37538:60:0;;;-1:-1:-1;37618:6:0;;36583:1049;-1:-1:-1;;;36583:1049:0:o;78108:240::-;78162:7;78182:21;78206:27;:25;:27::i;:::-;78182:51;;78249:24;78278:28;78292:13;78278;:28::i;:::-;-1:-1:-1;78244:62:0;78108:240;-1:-1:-1;;;;;;78108:240:0:o;74855:414::-;74907:7;74927:23;74953:36;:34;:36::i;:::-;74927:62;-1:-1:-1;75000:24:0;75039:19;;75035:191;;75075:28;75106:9;-1:-1:-1;;;;;75106:27:0;;:29;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;75075:60;-1:-1:-1;75210:4:0;75169:38;75075:60;75169:15;:38;:::i;:::-;:45;;;;:::i;:::-;75150:64;;75060:166;75035:191;75245:16;74855:414;-1:-1:-1;;74855:414:0:o;74010:179::-;74065:7;74088:25;74118:11;-1:-1:-1;;;;;74118:24:0;;:26;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;74085:59:0;74010:179;-1:-1:-1;;;74010:179:0:o;37640:497::-;37950:41;;-1:-1:-1;;;37950:41:0;;-1:-1:-1;;;;;9957:15:1;;;37950:41:0;;;9939:34:1;37985:4:0;9989:18:1;;;9982:43;37834:7:0;;37994:6;;37950:9;:19;;;;9851:18:1;;37950:41:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:50;37946:148;;;38017:65;;-1:-1:-1;;;38017:65:0;;-1:-1:-1;;;;;10426:15:1;;;38017:65:0;;;10408:34:1;38049:4:0;10458:18:1;;;10451:43;10510:18;;;10503:34;;;10553:18;;;10546:34;;;10629:4;10617:17;;10596:19;;;10589:46;10651:19;;;10644:35;;;10695:19;;;10688:35;;;38017:9:0;:16;;;;10319:19:1;;38017:65:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;37946:148;38111:18;38122:6;38111:10;:18::i;:::-;38104:25;37640:497;-1:-1:-1;;;;;;;37640:497:0:o;80307:156::-;80358:21;80440:15;;80423:14;;80399:7;-1:-1:-1;;;;;80399:19:0;;:21;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:38;;;;:::i;:::-;:56;;;;:::i;:::-;80392:63;;80307:156;:::o;48811:3052::-;48888:35;:33;:35::i;:::-;48934:28;:26;:28::i;:::-;48973;:26;:28::i;:::-;49012:27;:25;:27::i;:::-;49053:21;49076:25;49105:17;:15;:17::i;:::-;49052:70;;;;49133:30;49182:11;;49166:13;:27;;;;:::i;:::-;49133:60;;49206:24;49233:21;:19;:21::i;:::-;49206:48;;49338:51;49372:16;49338:33;:51::i;:::-;49500:26;49529:49;49538:15;49555:22;49529:8;:49::i;:::-;49500:78;;49680:47;49689:18;49709:17;49680:8;:47::i;:::-;49659:68;;49930:62;49939:18;49975:16;49959:13;;:32;;;;:::i;:::-;49930:8;:62::i;:::-;49909:83;;50005:41;50027:18;50005:21;:41::i;:::-;50241:25;50269:13;-1:-1:-1;;;;;50269:31:0;;:33;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;50241:61;;50313:27;50343:43;50368:17;50343:24;:43::i;:::-;50313:73;;50443:41;50421:19;:63;50399:199;;;;-1:-1:-1;;;50399:199:0;;10936:2:1;50399:199:0;;;10918:21:1;10975:2;10955:18;;;10948:30;11014:34;10994:18;;;10987:62;11085:34;11065:18;;;11058:62;11157:24;11136:19;;;11129:53;11199:19;;50399:199:0;;;;;;;;;50653:52;50671:18;50699:4;50653:17;:52::i;:::-;50829:34;;-1:-1:-1;;;50829:34:0;;50857:4;50829:34;;;373:74:1;50797:29:0;;50829:9;-1:-1:-1;;;;;50829:19:0;;;;346:18:1;;50829:34:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;51093:51;;;;;;;;;;;-1:-1:-1;51093:51:0;;;;;;;;-1:-1:-1;;;51093:51:0;;50797:66;;-1:-1:-1;;;;;;51093:9:0;:23;;;;:51;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;51186:34:0;;-1:-1:-1;;;51186:34:0;;51214:4;51186:34;;;373:74:1;51155:28:0;;51223:21;;-1:-1:-1;;;;;51186:9:0;:19;;;;346:18:1;;51186:34:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:58;;;;:::i;:::-;51155:89;;51322:37;51338:20;51322:15;:37::i;:::-;51506:25;51534:43;51559:17;51534:24;:43::i;:::-;51506:71;;51632:19;51612:17;:39;:118;;;;;51689:41;51668:17;:62;;51612:118;51590:265;;;;-1:-1:-1;;;51590:265:0;;12009:2:1;51590:265:0;;;11991:21:1;12048:2;12028:18;;;12021:30;12087:34;12067:18;;;12060:62;12158:34;12138:18;;;12131:62;12230:34;12209:19;;;12202:63;-1:-1:-1;;;12281:19:1;;;12274:32;12323:19;;51590:265:0;11807:541:1;51590:265:0;48877:2986;;;;;;;;;;48811:3052;:::o;45616:3187::-;45707:7;45716;45736:37;45758:14;45736:21;:37::i;:::-;45784:51;45820:14;45784:35;:51::i;:::-;45896:23;45875:18;;:44;;;;:::i;:::-;45856:15;:63;;45848:155;;;;-1:-1:-1;;;45848:155:0;;12555:2:1;45848:155:0;;;12537:21:1;12594:2;12574:18;;;12567:30;12633:34;12613:18;;;12606:62;12704:34;12684:18;;;12677:62;12776:17;12755:19;;;12748:46;12811:19;;45848:155:0;12353:483:1;45848:155:0;46031:24;46070:27;46154:24;46193:27;46234:36;:34;:36::i;:::-;46016:254;;;;;;;;;46283:31;46341:10;-1:-1:-1;;;;;46341:22:0;;:24;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;46317:21;:14;46334:4;46317:21;:::i;:::-;:48;;;;:::i;:::-;46474:9;;46283:82;;-1:-1:-1;46440:31:0;;46474:9;;:71;;46490:55;46521:23;46490:30;:55::i;:::-;46474:71;;;46486:1;46474:71;46440:105;-1:-1:-1;46626:25:0;;;47095:4;47050:42;47069:23;47050:16;:42;:::i;:::-;:49;;;;:::i;:::-;47015:84;-1:-1:-1;47114:34:0;47213:4;47179:30;47186:23;47213:4;47179:30;:::i;:::-;47151:59;;:24;:59;:::i;:::-;:66;;;;:::i;:::-;47114:103;-1:-1:-1;47253:53:0;47114:103;47253:24;:53;:::i;:::-;47232:74;;;;:::i;:::-;;;47344:77;47369:26;47397:23;47344:24;:77::i;:::-;47321:100;-1:-1:-1;47440:24:0;;47436:86;;47468:51;47486:20;47508:10;47468:17;:51::i;:::-;-1:-1:-1;47659:29:0;;-1:-1:-1;47703:20:0;;47699:553;;47740:35;47826:4;47778:45;47800:23;47778:19;:45;:::i;:::-;:52;;;;:::i;:::-;47740:90;-1:-1:-1;47845:31:0;47944:4;47910:30;47917:23;47944:4;47910:30;:::i;:::-;47879:62;;:27;:62;:::i;:::-;:69;;;;:::i;:::-;47845:103;-1:-1:-1;47984:53:0;47845:103;47984:27;:53;:::i;:::-;47963:74;;;;:::i;:::-;;;48121:16;48095:23;48076:16;;:42;;;;:::i;:::-;:61;;;;:::i;:::-;48052:85;-1:-1:-1;48156:25:0;;48152:89;;48185:53;48204:10;48216:21;48185:18;:53::i;:::-;47725:527;;47699:553;48371:39;48393:17;48371:19;:39;:::i;:::-;48355:13;:55;48423:67;48445:44;48468:21;48445:20;:44;:::i;:::-;48423:21;:67::i;:::-;48539:43;;-1:-1:-1;;;48539:43:0;;48555:10;48539:43;;;7619:74:1;7709:18;;;7702:34;;;-1:-1:-1;;;;;48539:10:0;:15;;;;7592:18:1;;48539:43:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;48614:10;-1:-1:-1;;;;;48600:130:0;;48626:14;48642:23;48667:20;48689:21;48712:17;48600:130;;;;;;;;;13100:25:1;;;13156:2;13141:18;;13134:34;;;;13199:2;13184:18;;13177:34;;;;13242:2;13227:18;;13220:34;13285:3;13270:19;;13263:35;13087:3;13072:19;;12841:463;48600:130:0;;;;;;;;48751:20;;-1:-1:-1;48773:21:0;-1:-1:-1;;;;;;;;45616:3187:0;;;;;;:::o;74337:159::-;74404:7;74484:4;74450:15;-1:-1:-1;;;;;74450:29:0;;:31;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;74431:16;;:50;;;;:::i;:::-;:57;;;;:::i;58160:391::-;58366:14;58350:13;58318:29;;:45;;;;:::i;:::-;:62;;;;:::i;:::-;58299:15;:81;;58291:147;;;;-1:-1:-1;;;58291:147:0;;13511:2:1;58291:147:0;;;13493:21:1;13550:2;13530:18;;;13523:30;13589:34;13569:18;;;13562:62;13660:23;13640:18;;;13633:51;13701:19;;58291:147:0;13309:417:1;58291:147:0;58528:15;58496:29;:47;58160:391::o;74604:243::-;74657:7;74677:24;74704:21;:19;:21::i;:::-;74677:48;;74736:21;74760:27;:25;:27::i;:::-;74736:51;-1:-1:-1;74807:32:0;74823:16;74736:51;74807:32;:::i;:::-;74800:39;;;;74604:243;:::o;58587:383::-;58650:33;:31;:33::i;:::-;58703:9;;;;58702:10;58694:65;;;;-1:-1:-1;;;58694:65:0;;13933:2:1;58694:65:0;;;13915:21:1;13972:2;13952:18;;;13945:30;14011:34;13991:18;;;13984:62;-1:-1:-1;;;14062:18:1;;;14055:40;14112:19;;58694:65:0;13731:406:1;58694:65:0;58850:74;;-1:-1:-1;;;58850:74:0;;-1:-1:-1;;;;;58873:22:0;8949:15:1;;58850:74:0;;;8931:34:1;58905:4:0;8981:18:1;;;8974:43;9033:18;;;9026:34;;;58850:9:0;:22;;;;8843:18:1;;58850:74:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;58935:27;58950:11;58935:14;:27::i;:::-;58587:383;:::o;77207:239::-;77261:7;77281:21;77305:27;:25;:27::i;:::-;77281:51;;77344:24;77376:28;77390:13;77376;:28::i;:::-;-1:-1:-1;77343:61:0;;77207:239;-1:-1:-1;;;;;;77207:239:0:o;51871:2993::-;51948:35;:33;:35::i;:::-;51994:28;:26;:28::i;:::-;52033;:26;:28::i;:::-;52072:27;:25;:27::i;:::-;52169:24;52196:21;:19;:21::i;:::-;52169:48;;52228:26;52257:43;52266:15;52283:16;52257:8;:43::i;:::-;52228:72;;52311:41;52333:18;52311:21;:41::i;:::-;52551:25;52579:13;-1:-1:-1;;;;;52579:31:0;;:33;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;52551:61;;52623:27;52653:43;52678:17;52653:24;:43::i;:::-;52623:73;;52949:44;52927:19;:66;52905:206;;;;-1:-1:-1;;;52905:206:0;;14344:2:1;52905:206:0;;;14326:21:1;14383:2;14363:18;;;14356:30;14422:34;14402:18;;;14395:62;14493:34;14473:18;;;14466:62;14565:28;14544:19;;;14537:57;14611:19;;52905:206:0;14142:494:1;52905:206:0;53198:34;;-1:-1:-1;;;53198:34:0;;53226:4;53198:34;;;373:74:1;53166:29:0;;53198:9;-1:-1:-1;;;;;53198:19:0;;;;346:18:1;;53198:34:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;53166:66;;53331:35;53409:16;53388:18;53369:16;;:37;;;;:::i;:::-;:56;;;;:::i;:::-;53331:94;;53436:47;53455:27;53436:18;:47::i;:::-;53525:34;;-1:-1:-1;;;53525:34:0;;53553:4;53525:34;;;373:74:1;53494:28:0;;53562:21;;-1:-1:-1;;;;;53525:9:0;:19;;;;346:18:1;;53525:34:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:58;;;;:::i;:::-;53661:34;;-1:-1:-1;;;53661:34:0;;53689:4;53661:34;;;373:74:1;53494:89:0;;-1:-1:-1;53633:25:0;;-1:-1:-1;;;;;53661:9:0;:19;;;;346:18:1;;53661:34:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;53920:95;;-1:-1:-1;;;53920:95:0;;;;;14849:25:1;;;28135:1:0;14890:18:1;;;14883:50;;;14949:18;;;14942:34;53633:62:0;;-1:-1:-1;53920:9:0;-1:-1:-1;;;;;53920:35:0;;;;14822:18:1;;53920:95:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;54053:34:0;;-1:-1:-1;;;54053:34:0;;54081:4;54053:34;;;373:74:1;54026:24:0;;-1:-1:-1;54090:17:0;;-1:-1:-1;;;;;;54053:9:0;:19;;;;346:18:1;;54053:34:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:54;;;;:::i;:::-;54026:81;;54338:32;54353:16;54338:14;:32::i;:::-;54501:25;54529:43;54554:17;54529:24;:43::i;:::-;54501:71;;54627:19;54607:17;:39;:121;;;;;54684:44;54663:17;:65;;54607:121;54585:271;;;;-1:-1:-1;;;54585:271:0;;15189:2:1;54585:271:0;;;15171:21:1;15228:3;15208:18;;;15201:31;;;15268:34;15248:18;;;15241:62;15339:34;15319:18;;;15312:62;15411:34;15390:19;;;15383:63;-1:-1:-1;;;15462:19:1;;;15455:35;15507:19;;54585:271:0;14987:545:1;77454:249:0;77511:7;77531:21;77555:27;:25;:27::i;:::-;77531:51;;77596:27;77630:28;77644:13;77630;:28::i;:::-;-1:-1:-1;77593:65:0;;77454:249;-1:-1:-1;;;;;;77454:249:0:o;38145:1422::-;38220:20;38243:21;;;:12;:21;;;;;;;;38220:44;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;38220:44:0;;;;;;;;;;;-1:-1:-1;;;38220:44:0;;;;;;;;;38243:21;38220:44;;;;-1:-1:-1;;;38220:44:0;;;;;;;;;;;;:::i;:::-;;;;;;;;;:::i;:::-;;;-1:-1:-1;38220:44:0;-1:-1:-1;38277:31:0;38300:7;38277:22;:31::i;:::-;38319:33;38340:4;:11;;;38319:20;:33::i;:::-;38365:25;:23;:25::i;:::-;-1:-1:-1;38403:21:0;;;;:12;:21;;;;;:28;;;;:54;;38468:55;38507:15;38468:55;-1:-1:-1;;;38468:55:0;-1:-1:-1;;;;38468:55:0;;;;-1:-1:-1;;;38468:55:0;;;38597:13;-1:-1:-1;;;;;38550:7:0;:25;;;;38576:10;;38403:21;;38597:38;;38613:22;;38597:38;:::i;:::-;38550:86;;-1:-1:-1;;;;;;38550:86:0;;;;;;;-1:-1:-1;;;;;6456:55:1;;;38550:86:0;;;6438:74:1;6528:18;;;6521:34;;;;6571:18;;;6564:34;6411:18;;38550:86:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;38534:102;;38668:1;38649:15;;:20;;;;;;;:::i;:::-;;;;-1:-1:-1;;38697:15:0;;;38682:30;;38697:15;;38682:30;;38697:15;;38682:30;:::i;:::-;;;;-1:-1:-1;;38768:14:0;;;;38750:15;;:32;;;;;;:::i;:::-;38723:23;;:59;;;;;;;:::i;:::-;;;;-1:-1:-1;;39324:15:0;;39274:22;;39299:51;;39341:8;39299:24;:51::i;:::-;39274:76;;39411:45;39429:14;39445:10;39411:17;:45::i;:::-;39509:15;;39474:85;;;15794:25:1;;;15850:2;15835:18;;15828:34;;;;15878:18;;15871:34;;;15936:2;15921:18;;15914:34;;;15997:22;15985:35;;15979:3;15964:19;;15957:64;39488:10:0;;39474:85;;15781:3:1;15766:19;39474:85:0;;;;;;;38209:1358;;;38145:1422;;:::o;79444:245::-;79506:7;79527:31;79564:76;79593:16;;79611:28;;79564;:76::i;:::-;-1:-1:-1;79526:114:0;79444:245;-1:-1:-1;;79444:245:0:o;78591:845::-;78682:7;78702:24;78729:10;-1:-1:-1;;;;;78729:22:0;;:24;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;78702:51;;78765:24;78791:27;78825:29;78839:14;78825:13;:29::i;:::-;78764:90;;;;;;;79305:16;79325:1;79305:21;79301:41;;;-1:-1:-1;79336:4:0;;78591:845;-1:-1:-1;;;;78591:845:0:o;79301:41::-;79412:16;79363:38;79382:19;79363:16;:38;:::i;:::-;79362:47;;79405:4;79362:47;:::i;:::-;:66;;;;:::i;72288:425::-;72390:18;72580:21;;;:12;:21;;;;;;;;72557:44;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;72557:44:0;;;;;;;;;;;-1:-1:-1;;;72557:44:0;;;;;;;;;72390:18;;;;;;;;;;72557:44;;72580:21;72557:44;;;;-1:-1:-1;;;72557:44:0;;;;;;;;;;;;:::i;:::-;;;;;;;;;:::i;:::-;;;;;;;72620:4;:15;;;72637:4;:17;;;72656:4;:14;;;72672:4;:12;;;72692:4;:11;;;72686:18;;;;;;;;:::i;:::-;72612:93;;;;-1:-1:-1;72612:93:0;;-1:-1:-1;72612:93:0;-1:-1:-1;72612:93:0;;-1:-1:-1;72288:425:0;-1:-1:-1;;;72288:425:0:o;57752:356::-;57801:33;:31;:33::i;:::-;57845:28;:26;:28::i;:::-;57886:9;:16;;-1:-1:-1;;57886:16:0;57898:4;57886:16;;;;;;57939:13;57920:33;;160:25:1;;;57920:33:0;;148:2:1;133:18;57920:33:0;;;;;;;58099:1;58083:13;:17;57752:356::o;78380:203::-;78435:7;78455:21;78479:27;:25;:27::i;:::-;78455:51;;78524;78561:13;78524:36;:51::i;:::-;78517:58;;;78380:203;:::o;55215:208::-;55275:7;55298:25;55328:11;-1:-1:-1;;;;;55328:24:0;;:26;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;55295:59;;;;55374:41;55383:12;;55397:17;55374:8;:41::i;75432:978::-;75543:24;75582:27;75624:21;75660:24;75699:27;75889:11;;75872:14;:28;;;;:::i;:::-;75856:44;;75930:21;:19;:21::i;:::-;76014:13;;75911:40;;-1:-1:-1;76014:13:0;-1:-1:-1;76040:17:0;76060:32;75911:40;76060:13;:32;:::i;:::-;76040:52;;76121:19;76109:9;:31;76105:298;;;76195:20;76218:31;76230:19;76218:9;:31;:::i;:::-;76195:54;-1:-1:-1;76314:9:0;76283:28;76298:13;76195:54;76283:28;:::i;:::-;:40;;;;:::i;:::-;76264:59;-1:-1:-1;76360:31:0;76264:59;76360:12;:31;:::i;:::-;76338:53;;76142:261;76105:298;75743:667;75432:978;;;;;;;:::o;61802:165::-;61870:7;28253:2;61916:18;;61898:15;:36;;;;:::i;5487:582::-;5560:4;5595:9;5583;:21;5579:51;;;5619:9;5607:21;;5579:51;5672:14;5668:47;;-1:-1:-1;4134:4:0;5689:24;;5668:47;4134:4;5779:5;5807:9;5868:162;5879:1;5875;:5;5868:162;;;5901:5;5905:1;5901;:5;:::i;:::-;:10;5897:67;;5936:12;5943:1;5946;5936:6;:12::i;:::-;5932:16;;5897:67;5982:12;5989:1;5992;5982:6;:12::i;:::-;5978:16;-1:-1:-1;6013:5:0;6017:1;6013;:5;:::i;:::-;6009:9;;5868:162;;;6049:12;6056:1;6059;6049:6;:12::i;485:106::-;543:7;574:1;570;:5;:13;;582:1;570:13;;;578:1;570:13;563:20;485:106;-1:-1:-1;;;485:106:0:o;64264:3870::-;64463:31;;64660:30;64619:37;64637:19;64619:15;:37;:::i;:::-;64618:72;;;;:::i;:::-;64580:110;;64854:29;64815:35;:68;:197;;;;64989:23;64962;:50;64815:197;:305;;;-1:-1:-1;65104:11:0;;:16;64815:305;64703:525;;;65155:23;65147:69;;;;64703:525;65240:24;65293:11;;65267:23;;:37;;;;:::i;:::-;65240:64;-1:-1:-1;67248:49:0;67300:147;67372:19;67327:42;67346:23;65240:64;67327:42;:::i;:::-;:64;;;;:::i;:::-;67406:30;67300:12;:147::i;:::-;67248:199;;67502:41;67464:35;:79;67460:263;;;67650:23;67642:69;;;;;;67460:263;67735:27;67803:123;67826:29;67870:45;67914:1;67870:41;:45;:::i;:::-;67803:8;:123::i;:::-;67765:161;;:35;:161;:::i;:::-;67735:191;;67965:161;68073:4;68014:56;68021:27;68050:19;68014:6;:56::i;:::-;67988:82;;:23;:82;:::i;:::-;:89;;;;:::i;:::-;68092:23;67965:8;:161::i;:::-;67939:187;;64569:3565;;;64264:3870;;;;;:::o;62488:252::-;62577:7;62600:35;62639:48;62671:15;62639:31;:48::i;63235:770::-;63353:7;63483:15;63479:32;;-1:-1:-1;63508:1:0;63501:8;;63479:32;63679:20;63710:28;63728:10;63710:15;:28;:::i;:::-;63702:37;;:4;:37;:::i;:::-;63679:60;-1:-1:-1;63752:21:0;63805:32;63820:17;63679:60;63805:32;:::i;:::-;63776:25;63789:12;63776:10;:25;:::i;:::-;:62;;;;:::i;69106:273::-;69202:7;69358:13;69335:20;:13;69351:4;69335:20;:::i;:::-;:36;;;;:::i;69421:162::-;69517:24;;-1:-1:-1;;;69517:24:0;;;;;160:25:1;;;69517:7:0;-1:-1:-1;;;;;69517:15:0;;;;133:18:1;;69517:24:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;69503:38:0;:10;-1:-1:-1;;;;;69503:38:0;;69495:80;;;;-1:-1:-1;;;69495:80:0;;16607:2:1;69495:80:0;;;16589:21:1;16646:2;16626:18;;;16619:30;16685:31;16665:18;;;16658:59;16734:18;;69495:80:0;16405:353:1;69591:146:0;69683:17;69673:6;:27;;;;;;;;:::i;:::-;;69665:64;;;;-1:-1:-1;;;69665:64:0;;16965:2:1;69665:64:0;;;16947:21:1;17004:2;16984:18;;;16977:30;17043:26;17023:18;;;17016:54;17087:18;;69665:64:0;16763:348:1;68142:856:0;68248:16;;68320:28;;68195:7;;68248:16;68195:7;;68455:88;68248:16;68320:28;68455;:88::i;:::-;68361:182;;;;68599:34;68560:35;:73;68556:392;;68650:28;:66;;;68737:49;;;68733:204;;68807:16;:42;;;68873:48;;160:25:1;;;68873:48:0;;148:2:1;133:18;68873:48:0;;;;;;;-1:-1:-1;68967:23:0;68142:856;-1:-1:-1;;;68142:856:0:o;55595:742::-;55640:7;55649;55672:25;55702:11;-1:-1:-1;;;;;55702:24:0;;:26;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;55768:12:0;;55669:59;;-1:-1:-1;55768:12:0;-1:-1:-1;56112:38:0;;;56108:163;;;-1:-1:-1;56167:12:0;:32;;;56182:17;;;-1:-1:-1;55595:742:0;-1:-1:-1;55595:742:0:o;56108:163::-;56291:18;56311:17;;-1:-1:-1;55595:742:0;-1:-1:-1;55595:742:0:o;61975:505::-;62142:9;;62064:7;;;;62142:9;;62138:45;;;-1:-1:-1;62162:1:0;;61975:505;-1:-1:-1;61975:505:0:o;62138:45::-;62246:26;62314:4;62275:36;62293:18;62275:15;:36;:::i;:::-;:43;;;;:::i;:::-;62246:72;-1:-1:-1;62329:35:0;62367:36;62246:72;62367:15;:36;:::i;:::-;62424:18;;62329:74;;-1:-1:-1;61975:505:0;;-1:-1:-1;;;61975:505:0:o;40761:1464::-;40880:7;41039:44;41056:27;41039:14;:44;:::i;:::-;41020:15;:63;;41012:138;;;;-1:-1:-1;;;41012:138:0;;17318:2:1;41012:138:0;;;17300:21:1;17357:2;17337:18;;;17330:30;17396:34;17376:18;;;17369:62;17467:32;17447:18;;;17440:60;17517:19;;41012:138:0;17116:426:1;41012:138:0;41182:15;41161:18;:36;41225:24;41446:29;41460:14;41446:13;:29::i;:::-;41210:265;;;;;;41931:16;41909:18;:38;;41901:95;;;;-1:-1:-1;;;41901:95:0;;17749:2:1;41901:95:0;;;17731:21:1;17788:2;17768:18;;;17761:30;17827:34;17807:18;;;17800:62;-1:-1:-1;;;17878:18:1;;;17871:42;17930:19;;41901:95:0;17547:408:1;41901:95:0;42039:20;;42035:126;;42076:73;42132:16;42076:55;:73::i;:::-;42180:37;42201:16;42180:18;:37;:::i;56496:165::-;56577:38;;-1:-1:-1;;;56577:38:0;;;;;18134:25:1;;;-1:-1:-1;;;;;18195:55:1;;;18175:18;;;18168:83;56577:11:0;:20;;;;18107:18:1;;56577:38:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;56642:11;56626:12;;:27;;;;;;;:::i;:::-;;;;-1:-1:-1;;;;56496:165:0:o;40006:318::-;40172:45;40190:11;40211:4;40172:17;:45::i;:::-;40270:46;40304:11;40270:33;:46::i;70044:158::-;70138:15;70123:11;:30;;70115:79;;;;-1:-1:-1;;;70115:79:0;;18464:2:1;70115:79:0;;;18446:21:1;18503:2;18483:18;;;18476:30;18542:34;18522:18;;;18515:62;-1:-1:-1;;;18593:18:1;;;18586:34;18637:19;;70115:79:0;18262:400:1;70565:130:0;70637:9;;;;70636:10;70628:59;;;;-1:-1:-1;;;70628:59:0;;18869:2:1;70628:59:0;;;18851:21:1;18908:2;18888:18;;;18881:30;18947:34;18927:18;;;18920:62;-1:-1:-1;;;18998:18:1;;;18991:34;19042:19;;70628:59:0;18667:400:1;70628:59:0;70565:130::o;56345:143::-;56410:32;;-1:-1:-1;;;56410:32:0;;;;;160:25:1;;;56410:11:0;-1:-1:-1;;;;;56410:19:0;;;;133:18:1;;56410:32:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;56469:11;56453:12;;:27;;;;;;;:::i;:::-;;;;-1:-1:-1;;;56345:143:0:o;71381:214::-;71500:22;71459:37;71477:19;71459:15;:37;:::i;:::-;:63;;71451:136;;;;-1:-1:-1;;;71451:136:0;;19274:2:1;71451:136:0;;;19256:21:1;19313:2;19293:18;;;19286:30;19352:34;19332:18;;;19325:62;19423:30;19403:18;;;19396:58;19471:19;;71451:136:0;19072:424:1;69881:155:0;69979:1;69952:10;-1:-1:-1;;;;;69952:22:0;;:24;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:28;69944:84;;;;-1:-1:-1;;;69944:84:0;;19703:2:1;69944:84:0;;;19685:21:1;19742:2;19722:18;;;19715:30;19781:34;19761:18;;;19754:62;-1:-1:-1;;;19832:18:1;;;19825:41;19883:19;;69944:84:0;19501:407:1;71603:381:0;71665:28;71728:13;71696:29;;:45;;;;:::i;:::-;71665:76;-1:-1:-1;71752:29:0;71784:37;71807:14;71665:76;71784:37;:::i;:::-;71752:69;;71861:20;71842:15;:39;;:82;;;;;71903:21;71885:15;:39;71842:82;71834:142;;;;-1:-1:-1;;;71834:142:0;;20115:2:1;71834:142:0;;;20097:21:1;20154:2;20134:18;;;20127:30;20193:34;20173:18;;;20166:62;20264:17;20244:18;;;20237:45;20299:19;;71834:142:0;19913:411:1;71834:142:0;71654:330;;71603:381::o;71992:218::-;72112:17;72095:13;;:34;;72087:115;;;;-1:-1:-1;;;72087:115:0;;20531:2:1;72087:115:0;;;20513:21:1;20570:2;20550:18;;;20543:30;;;20609:34;20589:18;;;20582:62;20680:34;20660:18;;;20653:62;-1:-1:-1;;;20731:19:1;;;20724:35;20776:19;;72087:115:0;20329:472:1;69745:128:0;69836:1;69826:7;:11;69818:47;;;;-1:-1:-1;;;69818:47:0;;21008:2:1;69818:47:0;;;20990:21:1;21047:2;21027:18;;;21020:30;21086:25;21066:18;;;21059:53;21129:18;;69818:47:0;20806:347:1;59013:582:0;59446:92;;-1:-1:-1;;;59446:92:0;;59097:7;59446:92;;;21382:41:1;;;28195:1:0;21439:18:1;;;21432:50;59533:4:0;21498:18:1;;;21491:34;59097:7:0;;;-1:-1:-1;;;;;59446:9:0;:16;;;;21355:18:1;;59446:92:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;59433:105;-1:-1:-1;59583:4:0;59558:22;59563:17;59433:105;59558:22;:::i;56830:342::-;56925:40;;-1:-1:-1;;;56925:40:0;;56959:4;56925:40;;;373:74:1;56894:28:0;;56925:15;-1:-1:-1;;;;;56925:25:0;;;;346:18:1;;56925:40:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;56976:34;;-1:-1:-1;;;56976:34:0;;;;;160:25:1;;;56894:71:0;;-1:-1:-1;56976:15:0;-1:-1:-1;;;;;56976:23:0;;;;133:18:1;;56976:34:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;57051:40:0;;-1:-1:-1;;;57051:40:0;;57085:4;57051:40;;;373:74:1;57021:27:0;;57094:20;;-1:-1:-1;;;;;57051:15:0;:25;;;;346:18:1;;57051:40:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:63;;;;:::i;:::-;57021:93;;57145:19;57125:16;;:39;;;;;;;:::i;:::-;;;;-1:-1:-1;;;;;56830:342:0:o;70210:347::-;70309:9;;;;70304:246;;70474:10;-1:-1:-1;;;;;70474:22:0;;:24;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;70437:33;70454:16;70437:14;:33;:::i;:::-;:61;;70429:109;;;;-1:-1:-1;;;70429:109:0;;21738:2:1;70429:109:0;;;21720:21:1;21777:2;21757:18;;;21750:30;21816:34;21796:18;;;21789:62;-1:-1:-1;;;21867:18:1;;;21860:33;21910:19;;70429:109:0;21536:399:1;76498:405:0;76594:24;76633:27;76675:21;76711:24;76750:27;76806:21;76832:17;:15;:17::i;:::-;76805:44;;;76867:28;76881:13;76867;:28::i;:::-;76860:35;;;;;;;;;;;76498:405;;;;;:::o;61183:611::-;61275:7;61295:29;61327:53;61355:24;61327:27;:53::i;:::-;61391:18;:42;;;61449:48;;160:25:1;;;61295:85:0;;-1:-1:-1;61449:48:0;;148:2:1;133:18;61449:48:0;;;;;;;61510:18;61549;;61531:15;:36;;;;:::i;:::-;61510:57;;28253:2;61584:10;:35;61580:166;;61657:15;61636:18;:36;;;61692:42;;160:25:1;;;61692:42:0;;148:2:1;133:18;61692:42:0;;;;;;;-1:-1:-1;61765:21:0;61183:611;-1:-1:-1;;61183:611:0:o;70871:502::-;70970:7;71016:8;70998:14;:26;;70990:91;;;;-1:-1:-1;;;70990:91:0;;22142:2:1;70990:91:0;;;22124:21:1;22181:2;22161:18;;;22154:30;22220:34;22200:18;;;22193:62;22291:22;22271:18;;;22264:50;22331:19;;70990:91:0;21940:416:1;70990:91:0;71097:25;71127:11;-1:-1:-1;;;;;71127:24:0;;:26;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;71094:59;;;;71193:8;71172:17;:29;;71164:86;;;;-1:-1:-1;;;71164:86:0;;17749:2:1;71164:86:0;;;17731:21:1;17788:2;17768:18;;;17761:30;17827:34;17807:18;;;17800:62;-1:-1:-1;;;17878:18:1;;;17871:42;17930:19;;71164:86:0;17547:408:1;71164:86:0;71263:22;71288:43;71297:14;71313:17;71288:8;:43::i;57353:195::-;57442:49;;-1:-1:-1;;;57442:49:0;;-1:-1:-1;;;;;7637:55:1;;;57442:49:0;;;7619:74:1;7709:18;;;7702:34;;;57442:15:0;:24;;;;7592:18:1;;57442:49:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;57522:18;57502:16;;:38;;;;;;;:::i;70703:160::-;70779:10;-1:-1:-1;;;;;70793:22:0;70779:36;;70771:84;;;;-1:-1:-1;;;70771:84:0;;22563:2:1;70771:84:0;;;22545:21:1;22602:2;22582:18;;;22575:30;22641:34;22621:18;;;22614:62;-1:-1:-1;;;22692:18:1;;;22685:33;22735:19;;70771:84:0;22361:399:1;59603:582:0;60036:92;;-1:-1:-1;;;60036:92:0;;28195:1;60036:92;;;21382:41:1;59687:7:0;21439:18:1;;;21432:50;;;60123:4:0;21498:18:1;;;21491:34;59687:7:0;;;-1:-1:-1;;;;;60036:9:0;:16;;;;21355:18:1;;60036:92:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;60023:105;-1:-1:-1;60160:17:0;60148:9;60023:105;60153:4;60148:9;:::i;57180:165::-;57252:40;;-1:-1:-1;;;57252:40:0;;;;;160:25:1;;;57252:15:0;-1:-1:-1;;;;;57252:24:0;;;;133:18:1;;57252:40:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;57323:14;57303:16;;:34;;;;;;;:::i;302:107::-;360:7;392:1;387;:6;;:14;;400:1;387:14;;4598:147;4659:7;4134:4;4695:21;4715:1;4134:4;4695:21;:::i;:::-;4687:5;4691:1;4687;:5;:::i;:::-;:29;;;;:::i;1073:197::-;1135:7;1243:5;1247:1;1243;:5;:::i;:::-;:10;:18;;1260:1;1243:18;;;1256:1;1243:18;1234:28;;:5;1238:1;1234;:5;:::i;:::-;:28;;;;:::i;39658:340::-;39774:34;;-1:-1:-1;;;39774:34:0;;39802:4;39774:34;;;373:74:1;39746:25:0;;39774:9;-1:-1:-1;;;;;39774:19:0;;;;346:18:1;;39774:34:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;39819:77;;-1:-1:-1;;;39819:77:0;;-1:-1:-1;;;;;39868:9:0;7637:55:1;;39819:77:0;;;7619:74:1;7709:18;;;7702:34;;;39746:62:0;;-1:-1:-1;39819:19:0;:40;;;;;;7592:18:1;;39819:77:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;39936:34:0;;-1:-1:-1;;;39936:34:0;;39964:4;39936:34;;;373:74:1;39974:15:0;;-1:-1:-1;39936:9:0;-1:-1:-1;;;;;39936:19:0;;-1:-1:-1;39936:19:0;;346:18:1;;39936:34:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;39916:54;;:17;:54;:::i;:::-;:73;39909:81;;;;:::i;1143:180:1:-;1202:6;1255:2;1243:9;1234:7;1230:23;1226:32;1223:52;;;1271:1;1268;1261:12;1223:52;-1:-1:-1;1294:23:1;;1143:180;-1:-1:-1;1143:180:1:o;2133:154::-;-1:-1:-1;;;;;2212:5:1;2208:54;2201:5;2198:65;2188:93;;2277:1;2274;2267:12;2292:687;2394:6;2402;2410;2418;2426;2434;2487:3;2475:9;2466:7;2462:23;2458:33;2455:53;;;2504:1;2501;2494:12;2455:53;2543:9;2530:23;2562:31;2587:5;2562:31;:::i;:::-;2612:5;-1:-1:-1;2664:2:1;2649:18;;2636:32;;-1:-1:-1;2715:2:1;2700:18;;2687:32;;-1:-1:-1;2771:2:1;2756:18;;2743:32;2819:4;2806:18;;2794:31;;2784:59;;2839:1;2836;2829:12;2784:59;2292:687;;;;-1:-1:-1;2292:687:1;;2916:3;2901:19;;2888:33;;2968:3;2953:19;;;2940:33;;-1:-1:-1;2292:687:1;-1:-1:-1;;2292:687:1:o;2984:248::-;3052:6;3060;3113:2;3101:9;3092:7;3088:23;3084:32;3081:52;;;3129:1;3126;3119:12;3081:52;-1:-1:-1;;3152:23:1;;;3222:2;3207:18;;;3194:32;;-1:-1:-1;2984:248:1:o;5220:127::-;5281:10;5276:3;5272:20;5269:1;5262:31;5312:4;5309:1;5302:15;5336:4;5333:1;5326:15;5352:128;5392:3;5423:1;5419:6;5416:1;5413:13;5410:39;;;5429:18;;:::i;:::-;-1:-1:-1;5465:9:1;;5352:128::o;5485:168::-;5525:7;5591:1;5587;5583:6;5579:14;5576:1;5573:21;5568:1;5561:9;5554:17;5550:45;5547:71;;;5598:18;;:::i;:::-;-1:-1:-1;5638:9:1;;5485:168::o;5658:127::-;5719:10;5714:3;5710:20;5707:1;5700:31;5750:4;5747:1;5740:15;5774:4;5771:1;5764:15;5790:120;5830:1;5856;5846:35;;5861:18;;:::i;:::-;-1:-1:-1;5895:9:1;;5790:120::o;5915:127::-;5976:10;5971:3;5967:20;5964:1;5957:31;6007:4;6004:1;5997:15;6031:4;6028:1;6021:15;6047:184;6117:6;6170:2;6158:9;6149:7;6145:23;6141:32;6138:52;;;6186:1;6183;6176:12;6138:52;-1:-1:-1;6209:16:1;;6047:184;-1:-1:-1;6047:184:1:o;6609:179::-;6687:13;;6740:22;6729:34;;6719:45;;6709:73;;6778:1;6775;6768:12;6709:73;6609:179;;;:::o;6793:206::-;6862:6;6915:2;6903:9;6894:7;6890:23;6886:32;6883:52;;;6931:1;6928;6921:12;6883:52;6954:39;6983:9;6954:39;:::i;7004:125::-;7044:4;7072:1;7069;7066:8;7063:34;;;7077:18;;:::i;:::-;-1:-1:-1;7114:9:1;;7004:125::o;7134:306::-;7222:6;7230;7238;7291:2;7279:9;7270:7;7266:23;7262:32;7259:52;;;7307:1;7304;7297:12;7259:52;7336:9;7330:16;7320:26;;7386:2;7375:9;7371:18;7365:25;7355:35;;7430:2;7419:9;7415:18;7409:25;7399:35;;7134:306;;;;;:::o;8396:267::-;8474:6;8482;8535:2;8523:9;8514:7;8510:23;8506:32;8503:52;;;8551:1;8548;8541:12;8503:52;8580:9;8574:16;8564:26;;8609:48;8653:2;8642:9;8638:18;8609:48;:::i;:::-;8599:58;;8396:267;;;;;:::o;9071:277::-;9138:6;9191:2;9179:9;9170:7;9166:23;9162:32;9159:52;;;9207:1;9204;9197:12;9159:52;9239:9;9233:16;9292:5;9285:13;9278:21;9271:5;9268:32;9258:60;;9314:1;9311;9304:12;11229:573;11445:2;11430:18;;11434:9;11525:6;11403:4;11559:194;11573:4;11570:1;11567:11;11559:194;;;11632:13;;11620:26;;11669:4;11693:12;;;;11728:15;;;;11593:1;11586:9;11559:194;;;11563:3;;;11789:6;11784:2;11773:9;11769:18;11762:34;11229:573;;;;;:::o;16032:112::-;16064:1;16090;16080:35;;16095:18;;:::i;:::-;-1:-1:-1;16129:9:1;;16032:112::o;16149:251::-;16219:6;16272:2;16260:9;16251:7;16247:23;16243:32;16240:52;;;16288:1;16285;16278:12;16240:52;16320:9;16314:16;16339:31;16364:5;16339:31;:::i;22765:127::-;22826:10;22821:3;22817:20;22814:1;22807:31;22857:4;22854:1;22847:15;22881:4;22878:1;22871:15

Swarm Source

ipfs://d50cb42b3fa172de0f06883778cf4e6e0328c7e338330d8671e5c083cbaed28a

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

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

Validator Index Block Amount
View All Withdrawals

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

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