Source Code
More Info
Private Name Tags
ContractCreator
TokenTracker
Latest 25 from a total of 250 transactions
| Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
| Redeem | 60565867 | 10 hrs ago | IN | 0 MON | 0.12852703 | ||||
| Deposit As Colla... | 60559207 | 11 hrs ago | IN | 0 MON | 0.03513583 | ||||
| Redeem | 60558897 | 11 hrs ago | IN | 0 MON | 0.11665691 | ||||
| Redeem | 60558300 | 11 hrs ago | IN | 0 MON | 0.12588993 | ||||
| Redeem | 60549359 | 12 hrs ago | IN | 0 MON | 0.12366834 | ||||
| Deposit As Colla... | 60540813 | 13 hrs ago | IN | 0 MON | 0.03350341 | ||||
| Deposit As Colla... | 60539975 | 13 hrs ago | IN | 0 MON | 0.02797377 | ||||
| Deposit As Colla... | 60539409 | 13 hrs ago | IN | 0 MON | 0.03324432 | ||||
| Deposit As Colla... | 60538874 | 13 hrs ago | IN | 0 MON | 0.03380171 | ||||
| Deposit As Colla... | 60477991 | 20 hrs ago | IN | 0 MON | 0.04271342 | ||||
| Deposit As Colla... | 60411116 | 28 hrs ago | IN | 0 MON | 0.04234825 | ||||
| Redeem | 60410682 | 28 hrs ago | IN | 0 MON | 0.11635501 | ||||
| Redeem | 60410044 | 28 hrs ago | IN | 0 MON | 0.12589258 | ||||
| Deposit As Colla... | 60383310 | 31 hrs ago | IN | 0 MON | 0.02576493 | ||||
| Deposit As Colla... | 60382878 | 31 hrs ago | IN | 0 MON | 0.02576628 | ||||
| Deposit As Colla... | 60382625 | 31 hrs ago | IN | 0 MON | 0.02576628 | ||||
| Deposit As Colla... | 60382404 | 31 hrs ago | IN | 0 MON | 0.02576628 | ||||
| Deposit As Colla... | 60381813 | 31 hrs ago | IN | 0 MON | 0.02576628 | ||||
| Deposit As Colla... | 60381660 | 31 hrs ago | IN | 0 MON | 0.02576628 | ||||
| Deposit As Colla... | 60381474 | 31 hrs ago | IN | 0 MON | 0.02576628 | ||||
| Deposit As Colla... | 60381298 | 31 hrs ago | IN | 0 MON | 0.03105404 | ||||
| Deposit As Colla... | 60380813 | 31 hrs ago | IN | 0 MON | 0.02576628 | ||||
| Deposit As Colla... | 60380505 | 31 hrs ago | IN | 0 MON | 0.02576628 | ||||
| Deposit As Colla... | 60380090 | 31 hrs ago | IN | 0 MON | 0.02576628 | ||||
| Deposit As Colla... | 60379935 | 31 hrs ago | IN | 0 MON | 0.03105404 |
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
BorrowableCToken
Compiler Version
v0.8.28+commit.7893614a
Contract Source Code (Solidity)
/**
*Submitted for verification at monadscan.com on 2026-01-15
*/
// SPDX-License-Identifier: BUSL-1.1
pragma solidity =0.8.28;
// contracts/interfaces/ICentralRegistry.sol
/// TYPES ///
/// @notice Configuration data for a separately supported blockchain.
/// @param isSupported Whether the chain is supported or not.
/// @param messagingChainId Messaging Chain ID where this address authorized.
/// @param domain Domain for the chain.
/// @param messagingHub Messaging Hub address on the chain.
/// @param votingHub Voting Hub address on the chain.
/// @param cveAddress CVE address on the chain.
/// @param feeTokenAddress Fee token address on the chain.
/// @param crosschainRelayer Crosschain relayer address on the chain.
struct ChainConfig {
bool isSupported;
uint16 messagingChainId;
uint32 domain;
address messagingHub;
address votingHub;
address cveAddress;
address feeTokenAddress;
address crosschainRelayer;
}
interface ICentralRegistry {
/// @notice The length of one protocol epoch, in seconds.
function EPOCH_DURATION() external view returns (uint256);
/// @notice Sequencer uptime oracle on this chain (for L2s).
function SEQUENCER_ORACLE() external view returns (address);
/// @notice Returns Genesis Epoch Timestamp of Curvance.
function genesisEpoch() external view returns (uint256);
/// @notice Returns Protocol DAO address.
function daoAddress() external view returns (address);
/// @notice Returns Protocol Emergency Council address.
function emergencyCouncil() external view returns (address);
/// @notice Indicates if address has DAO permissions or not.
function hasDaoPermissions(
address addressToCheck
) external view returns (bool);
/// @notice Indicates if address has elevated DAO permissions or not.
function hasElevatedPermissions(
address addressToCheck
) external view returns (bool);
/// @notice Indicates if address has lock creation permissions or not.
function hasLockingPermissions(
address addressToCheck
) external view returns (bool);
/// @notice Indicates if address has auction permissions or not.
function hasAuctionPermissions(
address addressToCheck
) external view returns (bool);
/// @notice Indicates if address has market permissions or not.
function hasMarketPermissions(
address addressToCheck
) external view returns (bool);
/// @notice Indicates if address has harvest permissions or not.
function hasHarvestPermissions(
address addressToCheck
) external view returns (bool);
/// @notice Returns Reward Manager address.
function rewardManager() external view returns (address);
/// @notice Returns Gauge Manager address.
function gaugeManager() external view returns (address);
/// @notice Returns CVE address.
function cve() external view returns (address);
/// @notice Returns veCVE address.
function veCVE() external view returns (address);
/// @notice Returns Voting Hub address.
function votingHub() external view returns (address);
/// @notice Returns Messaging Hub address.
function messagingHub() external view returns (address);
/// @notice Returns Oracle Manager address.
function oracleManager() external view returns (address);
/// @notice Returns Fee Manager address.
function feeManager() external view returns (address);
/// @notice Returns Fee Token address.
function feeToken() external view returns (address);
/// @notice Returns Crosschain Core contract address.
function crosschainCore() external view returns (address);
/// @notice Returns Crosschain Relayer contract address.
function crosschainRelayer() external view returns (address);
/// @notice Returns Token Messenger contract address.
function tokenMessager() external view returns (address);
/// @notice Returns Messenger Transmitter contract address.
function messageTransmitter() external view returns (address);
/// @notice Returns domain value.
function domain() external view returns (uint32);
/// @notice Returns protocol gas fee on harvest, in `BPS`.
function protocolCompoundFee() external view returns (uint256);
/// @notice Returns protocol yield fee on strategy harvest, in `BPS`.
function protocolYieldFee() external view returns (uint256);
/// @notice Returns protocol yield + gas fee on strategy harvest,
/// in `BPS`.
function protocolHarvestFee() external view returns (uint256);
/// @notice Returns protocol fee on leverage actions, in `BPS`.
function protocolLeverageFee() external view returns (uint256);
/// @notice Returns default fee on interest generated from active loans,
/// in `BPS`.
function defaultProtocolInterestFee() external view returns (uint256);
/// @notice Returns earlyUnlockPenaltyMultiplier value, in `BPS`.
function earlyUnlockPenaltyMultiplier() external view returns (uint256);
/// @notice Returns voteBoostMultiplier value, in `BPS`.
function voteBoostMultiplier() external view returns (uint256);
/// @notice Returns lockBoostMultiplier value, in `BPS`.
function lockBoostMultiplier() external view returns (uint256);
/// @notice Returns swap slippage limit, in `BPS`.
function slippageLimit() external view returns (uint256);
/// @notice Returns an array of Chain IDs recorded in the Crosschain
/// Protocol's Chain ID format.
function foreignChainIds() external view returns (uint256[] memory);
/// @notice Returns an array of Curvance markets on this chain.
function marketManagers() external view returns (address[] memory);
/// @notice Increments a caller's approval index.
/// @dev By incrementing their approval index, a user's delegates will all
/// have their delegation authority revoked across all Curvance
/// contracts.
/// Emits an {ApprovalIndexIncremented} event.
function incrementApprovalIndex() external;
/// @notice Returns `user`'s approval index.
/// @param user The user to check approval index for.
function userApprovalIndex(address user) external view returns (uint256);
/// @notice Returns whether a user has delegation disabled.
/// @param user The user to check delegation status for.
function checkNewDelegationDisabled(
address user
) external view returns (bool);
/// @notice Returns whether a particular GETH chainId is supported.
/// ChainId => messagingHub address, 2 = supported; 1 = unsupported.
function chainConfig(
uint256 chainId
) external view returns (ChainConfig memory);
/// @notice Returns the GETH chainId corresponding chainId corresponding
/// to Crosschain Messaging Protocol's `chainId`.
/// @param chainId The Crosschain Messaging Protocol's chainId.
/// @return The GETH chainId corresponding chainId corresponding to
/// Crosschain Messaging Protocol's `chainId`.
function messagingToGETHChainId(
uint16 chainId
) external view returns (uint256);
/// @notice Returns the Crosschain Messaging Protocol's ChainId
/// corresponding to the GETH `chainId`.
/// @param chainId The GETH chainId.
/// @return The Crosschain Messaging Protocol's ChainId
/// corresponding to the GETH `chainId`.
function GETHToMessagingChainId(
uint256 chainId
) external view returns (uint256);
/// @notice Indicates if an address is a market manager or not.
function isMarketManager(
address addressToCheck
) external view returns (bool);
/// @notice Maps an intent target address to the contract that will
/// inspect provided external calldata.
function externalCalldataChecker(
address addressToCheck
) external view returns (address);
/// @notice Maps a Multicall target address to the contract that will
/// inspect provided multicall calldata.
function multicallChecker(
address addressToCheck
) external view returns (address);
/// @notice Indicates the amount of token rewards allocated on this chain,
/// for an epoch.
function emissionsAllocatedByEpoch(
uint256 epoch
) external view returns (uint256);
/// @notice Indicates the amount of token rewards allocated across all
/// chains, for an era. An era is a particular period in time in
/// which rewards are constant, before a halvening event moves the
/// protocol to a new era.
function targetEmissionAllocationByEra(
uint256 era
) external view returns (uint256);
/// @notice Unlocks a market to process auction-based liquidations.
/// @param marketToUnlock The address of the market manager to unlock
/// auction-based liquidations with a specific
/// liquidation bonus.
function unlockAuctionForMarket(address marketToUnlock) external;
/// @notice Checks if a market is unlocked for auction operations.
/// @return Whether the caller is an unlocked market, approved for
/// auction-based liquidations.
function isMarketUnlocked() external view returns (bool);
/// @notice Sets the amount of token rewards allocated on this chain,
/// for an epoch.
/// @dev Only callable by the Voting Hub.
/// @param epoch The epoch having its token emission values set.
/// @param emissionsAllocated The amount of token rewards allocated on
/// this chain, for an epoch.
function setEmissionsAllocatedByEpoch(
uint256 epoch,
uint256 emissionsAllocated
) external;
/// @notice Checks whether `user` has transferability enabled or disabled
/// for their tokens.
/// @dev This is inherited from ActionRegistry portion of centralRegistry.
/// @param user The address to check whether transferability is enabled or
/// disabled for.
/// @return result Indicates whether `user` has transferability disabled
/// or not, true = disabled, false = not disabled.
function checkTransfersDisabled(
address user
) external view returns (bool result);
}
// contracts/interfaces/IDynamicIRM.sol
interface IDynamicIRM {
/// @notice Returns the interval at which interest rates are adjusted.
/// @notice The interval at which interest rates are adjusted,
/// in seconds.
function ADJUSTMENT_RATE() external view returns (uint256);
/// @notice The borrowable token linked to this interest rate model
/// contract.
function linkedToken() external view returns (address);
/// @notice Calculates the current borrow rate, per second.
/// @dev This function's intention is for frontend data querying and
/// should not be used for onchain execution.
/// @param assetsHeld The amount of underlying assets held in the pool.
/// @param debt The amount of outstanding debt in the pool.
/// @return result The borrow interest rate percentage, per second,
/// in `WAD`.
function borrowRate(
uint256 assetsHeld,
uint256 debt
) external view returns (uint256 result);
/// @notice Calculates the current borrow rate per second,
/// with updated vertex multiplier applied.
/// @param assetsHeld The amount of underlying assets held in the pool.
/// @param debt The amount of outstanding debt in the pool.
/// @return result The borrow rate percentage per second, in `WAD`.
function predictedBorrowRate(
uint256 assetsHeld,
uint256 debt
) external view returns (uint256 result);
/// @notice Calculates the current supply rate, per second.
/// @dev This function's intention is for frontend data querying and
/// should not be used for onchain execution.
/// @param assetsHeld The amount of underlying assets held in the pool.
/// @param debt The amount of outstanding debt in the pool.
/// @param interestFee The current interest rate protocol fee
/// for the market token.
/// @return result The supply interest rate percentage, per second,
/// in `WAD`.
function supplyRate(
uint256 assetsHeld,
uint256 debt,
uint256 interestFee
) external view returns (uint256 result);
/// @notice Calculates the interest rate paid per second by borrowers,
/// in percentage paid, per second, in `WAD`, and updates
/// `vertexMultiplier` if necessary.
/// @param assetsHeld The amount of underlying assets held in the pool.
/// @param debt The amount of outstanding debt in the pool.
/// @return ratePerSecond The interest rate paid per second by borrowers,
/// in percentage paid, per second, in `WAD`.
/// @return adjustmentRate The period of time at which interest rates are
/// adjusted, in seconds.
function adjustedBorrowRate(
uint256 assetsHeld,
uint256 debt
) external returns (uint256 ratePerSecond, uint256 adjustmentRate);
/// @notice Calculates the borrow utilization rate of the market.
/// @param assetsHeld The amount of underlying assets held in the pool.
/// @param outstandingDebt The amount of outstanding debt in the pool.
/// @return The utilization rate between [0, WAD].
function utilizationRate(
uint256 assetsHeld,
uint256 outstandingDebt
) external view returns (uint256);
}
// contracts/interfaces/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);
}
// contracts/interfaces/IERC20.sol
// @dev Interface of the ERC20 standard
interface IERC20 {
// @dev Returns the name of the token.
function name() external view returns (string memory);
// @dev Returns the symbol of the token.
function symbol() external view returns (string memory);
// @dev Returns the decimals of the token.
function decimals() external view returns (uint8);
// @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
);
// @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 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 Returns the remaining number of tokens that `spender` will be
// allowed to spend on behalf of `owner` through {transferFrom}. This
// is zero by default.
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);
}
// contracts/interfaces/IFlashLoan.sol
interface IFlashLoan {
/// @notice The fee to be charged for a given flashloan.
/// @param assets The amount of `asset()` lent during the flashloan.
/// return The assets of `asset()` to be charged for the flashloan.
function flashFee(uint256 assets) external view returns (uint256);
/// @notice Required callback for using a flashloan on Curvance.
/// @param assets The amount of the token loaned during the flashloan.
/// @param assetsReturned The amount of token required to be returned
/// for the flashloan.
/// @param data Arbitrary calldata passed to flashloan callback to execute
/// desired action during the flashloan.
function onFlashLoan(
uint256 assets,
uint256 assetsReturned,
bytes calldata data
) external returns (bytes32);
}
// contracts/interfaces/IMarketManager.sol
interface IMarketManager {
/// TYPES ///
/// @notice Data structure passed communicating the intended liquidation
/// scenario to review based on current liquidity levels.
/// @param collateralToken The token which was used as collateral
/// by `account` and may be seized.
/// @param debtToken The token to potentially repay which has
/// outstanding debt by `account`.
/// @param numAccounts The number of accounts to be, potentially,
/// liquidated.
/// @param liquidateExact Whether the liquidator desires a specific
/// liquidation amount.
/// @param liquidatedShares Empty variable slot to store how much
/// `collateralToken` will be seized as
/// part of a particular liquidation.
/// @param debtRepaid Empty variable slot to store how much
/// `debtToken` will be repaid as part of a
/// particular liquidation.
/// @param badDebt Empty variable slot to store how much bad debt will
/// be realized by lenders as part of a particular
/// liquidation.
struct LiqAction {
address collateralToken;
address debtToken;
uint256 numAccounts;
bool liquidateExact;
uint256 liquidatedShares;
uint256 debtRepaid;
uint256 badDebt;
}
/// @notice Data structure returned communicating outcome of a liquidity
/// scenario review based on current liquidity levels.
/// @param liquidatedShares An array containing the collateral amounts to
/// liquidate from accounts, in shares.
/// @param debtRepaid The total amount of debt to repay from accounts,
/// in assets.
/// @param badDebtRealized The total amount of debt to realize as losses
/// for lenders, in assets.
struct LiqResult {
uint256[] liquidatedShares;
uint256 debtRepaid;
uint256 badDebtRealized;
}
/// @notice Returns whether minting, collateralization, borrowing of
/// `cToken` is paused.
/// @param cToken The address of the Curvance token to return
/// action statuses of.
/// @return bool Whether minting `cToken` is paused or not.
/// @return bool Whether collateralization `cToken` is paused or not.
/// @return bool Whether borrowing `cToken` is paused or not.
function actionsPaused(
address cToken
) external view returns (bool, bool, bool);
/// @notice Returns the current collateralization configuration
/// of `cToken`.
/// @param cToken The address of the Curvance token to return
/// collateralization configuration of.
/// @return The ratio at which this token can be borrowed against
/// when collateralized.
/// @return The collateral requirement where dipping below this
/// will cause a soft liquidation.
/// @return The collateral requirement where dipping below
/// this will cause a hard liquidation.
function collConfig(address cToken) external view returns (
uint256, uint256, uint256
);
/// @notice Returns the current liquidation configuration
/// of `cToken`.
/// @param cToken The address of the Curvance token to return
/// liquidation configuration of.
/// @return The base ratio at which this token will be
/// compensated on soft liquidation.
/// @return The liquidation incentive curve length between soft
/// liquidation to hard liquidation, in `WAD`. e.g. 5% base
/// incentive with 8% curve length results in 13% liquidation
/// incentive on hard liquidation.
/// @return The minimum possible liquidation incentive for during an
/// auction, in `WAD`.
/// @return The maximum possible liquidation incentive for during an
/// auction, in `WAD`.
/// @return Maximum % that a liquidator can repay when soft
/// liquidating an account, in `WAD`.
/// @return Curve length between soft liquidation and hard liquidation,
/// should be equal to 100% - `closeFactorBase`, in `WAD`.
/// @return The minimum possible close factor for during an auction,
/// in `WAD`.
/// @return The maximum possible close factor for during an auction,
/// in `WAD`.
function liquidationConfig(address cToken) external view returns (
uint256, uint256, uint256, uint256, uint256, uint256, uint256, uint256
);
/// @notice Enables an auction-based liquidation, potentially with a dynamic
/// close factor and liquidation penalty values in transient storage.
/// @dev Transient storage enforces any liquidator outside auction-based
/// liquidations uses the default risk parameters.
/// @param cToken The Curvance token to configure liquidations for during
/// an auction-based liquidation.
/// @param incentive The auction liquidation incentive value, in `BPS`.
/// @param closeFactor The auction close factor value, in `BPS`.
function setTransientLiquidationConfig(
address cToken,
uint256 incentive,
uint256 closeFactor
) external;
/// @notice Called from the AuctionManager as a post hook after liquidations
/// are tried to enable all collateral to be liquidated outside
/// an Auction tx.
/// @notice Resets the liquidation risk parameters in transient storage to
/// zero.
/// @dev This is redundant since the transient values will be reset after
/// the liquidation transaction, but can be useful during meta calls
/// with multiple liquidations during a single transaction.
function resetTransientLiquidationConfig() external;
/// @notice Checks if the account should be allowed to mint tokens
/// in the given market.
/// @param cToken The token to verify mints against.
function canMint(address cToken) external;
/// @notice Checks if the account should be allowed to collateralize
/// their shares of the given market.
/// Prunes unused positions in `account` data.
/// @dev May emit a {PositionUpdated} event.
/// @param cToken The token to verify collateralization of.
/// @param account The account which would collateralize the asset.
/// @param newNetCollateral The amount of shares that would be
/// collateralized in total if allowed.
function canCollateralize(
address cToken,
address account,
uint256 newNetCollateral
) external;
/// @notice Checks if the account should be allowed to redeem tokens
/// in the given market, and then redeems.
/// @dev This can only be called by the cToken itself.
/// @param cToken The token to verify the redemption against.
/// @param shares The number of cToken shares to redeem for the
/// underlying asset in the market.
/// @param account The account which would redeem `shares`.
/// @param balanceOf The current cToken share balance of `account`.
/// @param collateralPosted The current cToken shares posted as
/// collateral by `account`.
/// @param forceRedeemCollateral Whether the collateral should be always
/// reduced.
function canRedeemWithCollateralRemoval(
address cToken,
uint256 shares,
address account,
uint256 balanceOf,
uint256 collateralPosted,
bool forceRedeemCollateral
) external returns (uint256);
/// @notice Checks if the account should be allowed to borrow
/// the underlying asset of the given market.
/// Prunes unused positions in `account` data.
/// @dev May emit a {PositionUpdated} event.
/// @param cToken The token to verify borrowability of.
/// @param assets The amount of underlying assets `account` would borrow.
/// @param account The account which would borrow the asset.
/// @param newNetDebt The amount of assets that would be
/// outstanding debt in total if allowed.
function canBorrow(
address cToken,
uint256 assets,
address account,
uint256 newNetDebt
) external;
/// @notice Checks if the account should be allowed to borrow
/// the underlying asset of the given market,
/// and notifies the market of the borrow.
/// @dev This can only be called by the market itself.
/// @param cToken The market to verify the borrow against.
/// @param assets The amount of underlying assets `account` would borrow.
/// @param account The account which would borrow the asset.
/// @param newNetDebt The amount of assets that would be
/// outstanding debt in total if allowed.
function canBorrowWithNotify(
address cToken,
uint256 assets,
address account,
uint256 newNetDebt
) external;
/// @notice Checks if the account should be allowed to repay a borrow
/// in the given market, may clean up positions.
/// @param cToken The Curvance token to verify the repayment of.
/// @param newNetDebt The new debt amount owed by `account` after
/// repayment.
/// @param debtAsset The debt asset being repaid to `cToken`.
/// @param decimals The decimals that `debtToken` is measured in.
/// @param account The account who will have their loan repaid.
function canRepayWithReview(
address cToken,
uint256 newNetDebt,
address debtAsset,
uint256 decimals,
address account
) external view;
/// @notice Checks if the liquidation should be allowed to occur,
/// and returns how many collateralized shares should be seized
/// on liquidation.
/// @param debtAmounts The amounts of outstanding debt the liquidator
/// wishes to repay, in underlying assets, empty if
/// intention is to liquidate maximum amount possible
/// for each account.
/// @param liquidator The address of the account trying to liquidate
/// `accounts`.
/// @param accounts The addresses of the accounts to be liquidated.
/// @param action A LiqAction struct containing:
/// collateralToken The token which is used as collateral
/// by `account` and may be seized.
/// debtToken The token to potentially repay which has
/// outstanding debt by `account`.
/// numAccounts The number of accounts to be, potentially,
/// liquidated.
/// liquidateExact Whether the liquidator desires a
/// specific liquidation amount.
/// collateralLiquidated Empty variable slot to store how
/// much `collateralToken` will be
/// seized as part of a particular
/// liquidation.
/// debtRepaid Empty variable slot to store how much
/// `debtToken` will be repaid as part of a
/// particular liquidation.
/// badDebt Empty variable slot to store how much bad debt
/// will be realized as part of a particular
/// liquidation.
/// @return result A LiqResult struct containing:
/// liquidatedShares An array containing the collateral
/// amounts to liquidate from
/// `accounts`.
/// debtRepaid The total amount of debt to repay from
/// `accounts`.
/// badDebtRealized The total amount of debt to realize as
/// losses for lenders inside this market.
/// @return An array containing the debt amounts to repay from
/// `accounts`, in assets.
function canLiquidate(
uint256[] memory debtAmounts,
address liquidator,
address[] calldata accounts,
IMarketManager.LiqAction memory action
) external returns (LiqResult memory, uint256[] memory);
/// @notice Checks if the seizing of `collateralToken` by repayment of
/// `debtToken` should be allowed.
/// @param collateralToken The Curvance token which was used as collateral
/// and will be seized.
/// @param debtToken The Curvance token which has outstanding debt to and
/// would be repaid during `collateralToken` seizure.
function canSeize(address collateralToken, address debtToken) external;
/// @notice Checks if the account should be allowed to transfer collateral
/// tokens in the given market.
/// @param cToken The Curvance token to verify the transfer of.
/// @param shares The amount of `cToken` to transfer.
/// @param account The account which will transfer `shares`.
/// @param balanceOf The current balance that `account` has of `cToken`
/// shares.
/// @param collateralPosted The amount of `cToken` shares posted as
/// collateral by `account`.
/// @param isCollateral Boolean indicating whether the token is currently
/// being used as collateral.
function canTransfer(
address cToken,
uint256 shares,
address account,
uint256 balanceOf,
uint256 collateralPosted,
bool isCollateral
) external returns (uint256);
/// @notice Updates `account` cooldownTimestamp to the current block
/// timestamp.
/// @dev The caller must be a listed cToken in the `markets` mapping.
/// @param cToken The address of the token that the account is borrowing.
/// @param account The address of the account that has just borrowed.
function notifyBorrow(address cToken, address account) external;
/// @notice A list of all tokens inside this market for
/// offchain querying.
function queryTokensListed() external view returns (address[] memory);
/// @notice Returns whether `cToken` is listed in the lending market.
/// @param cToken market token address.
function isListed(address cToken) external view returns (bool);
/// @notice The total amount of `cToken` that can be posted as collateral,
/// in shares.
function collateralCaps(address cToken) external view returns (uint256);
/// @notice The total amount of `cToken` underlying that can be borrowed,
/// in assets.
function debtCaps(address cToken) external view returns (uint256);
/// @notice Returns whether `addressToCheck` is an approved position
/// manager or not.
/// @param addressToCheck Address to check for position management
/// authority.
function isPositionManager(
address addressToCheck
) external view returns (bool);
/// @notice Returns the assets an account has entered.
/// @param account The address of the account to pull assets for.
/// @return A dynamic list with the assets `account` has entered.
function assetsOf(
address account
) external view returns (address[] memory);
/// @notice Determine `account`'s current status between collateral,
/// debt, and additional liquidity.
/// @param account The account to determine liquidity for.
/// @return The current total collateral amount of `account`.
/// @return The maximum debt amount of `account` can take out with
/// their current collateral.
/// @return The current total borrow amount of `account`.
function statusOf(
address account
) external returns (uint256, uint256, uint256);
}
// contracts/interfaces/IMulticallChecker.sol
interface IMulticallChecker {
function checkCalldata(
address caller,
address target,
bytes memory data
) external;
}
// contracts/interfaces/IPluginDelegable.sol
interface IPluginDelegable {
/// @notice Returns whether a user or contract has the ability to act
/// on behalf of an account.
/// @param user The address to check whether `delegate` has delegation
/// permissions.
/// @param delegate The address that will be approved or restricted
/// from delegated actions on behalf of the caller.
/// @return result Indicates whether `delegate` is an approved delegate or
/// not of `user`, true = disabled, false = not disabled.
function isDelegate(
address user,
address delegate
) external view returns (bool result);
/// @notice Approves or restricts `delegate`'s authority to operate
/// on the caller's behalf.
/// @dev NOTE: Be careful who you approve here!
/// They can delay actions such as asset redemption through repeated
/// denial of service.
/// Emits a {DelegateApproval} event.
/// @param delegate The address that will be approved or restricted
/// from delegated actions on behalf of the caller.
/// @param isApproved Whether `delegate` is being approved or restricted
/// of authority to operate on behalf of caller.
function setDelegateApproval(address delegate, bool isApproved) external;
}
// contracts/libraries/ConstantsLib.sol
/// @dev Scalar for math. `WAD` * `WAD`.
uint256 constant WAD_SQUARED = 1e36;
/// @dev Scalar for math. `WAD` * `WAD` / `BPS`.
/// 1e18 * 1e18 / 1e4
uint256 constant WAD_SQUARED_BPS_OFFSET = 1e32;
/// @dev Scalar for math. Increased precision when WAD is insufficient
/// but WAD_SQUARED runs the risk of overflow.
uint256 constant RAY = 1e27;
/// @dev Scalar for math. `WAD` * `BPS`.
uint256 constant WAD_BPS = 1e22;
/// @dev Scalar for math. Base precision matching ether.
uint256 constant WAD = 1e18;
/// @dev Scalar for math. Represents basis points typically used in TradFi.
uint256 constant BPS = 1e4;
/// @dev Return value indicating no price returned at all.
uint256 constant BAD_SOURCE = 2;
/// @dev Return value indicating price divergence or a missing price feed.
uint256 constant CAUTION = 1;
/// @dev Return value indicating no price error.
uint256 constant NO_ERROR = 0;
/// @dev Extra time added to top end Oracle feed heartbeat incase of
/// transaction congestion delaying an update.
uint256 constant HEARTBEAT_GRACE_PERIOD = 120;
/// @dev Unix time has 31,536,000 seconds per year.
/// All my homies hate leap seconds and leap years.
uint256 constant SECONDS_PER_YEAR = 31_536_000;
// contracts/libraries/LowLevelCallsHelper.sol
library LowLevelCallsHelper {
/// ERRORS ///
error LowLevelCallsHelper__InsufficientBalance();
error LowLevelCallsHelper__CallFailed();
/// INTERNAL FUNCTIONS ///
/// @notice Executes a low level .call() and validates that execution
/// was safely performed.
/// @dev Bubbles up errors and reverts if anything along the execution
/// path failed or was a red flag.
/// @param target The target contract address to execute .call() at.
/// @param data The bytecode data to attach to the .call() execution
/// including the function signature hash and function call
/// parameters.
function _call(
address target,
bytes memory data
) internal returns (bytes memory) {
(bool success, bytes memory returnData) = target.call{value: 0}(data);
return _verifyResult(target, success, returnData);
}
/// @notice Executes a low level .call(), with attached native token
/// and validates that execution was safely performed.
/// @dev Bubbles up errors and reverts if anything along the execution
/// path failed or was a red flag.
/// @param target The target contract address to execute .call() at.
/// @param data The bytecode data to attach to the .call() execution
/// including the function signature hash and function call
/// parameters.
/// @param value The amount of native token to attach to the low level
/// call.
function _callWithNative(
address target,
bytes memory data,
uint256 value
) internal returns (bytes memory) {
if (address(this).balance < value) {
revert LowLevelCallsHelper__InsufficientBalance();
}
(bool success, bytes memory returnData) = target.call{
value: value
}(data);
return _verifyResult(target, success, returnData);
}
/// @notice Executes a low level .delegatecall() and validates that
/// execution was safely performed.
/// @dev Bubbles up errors and reverts if anything along the execution
/// path failed or was a red flag.
/// @param target The target contract address to execute .delegatecall()
/// at.
/// @param data The bytecode data to attach to the .call() execution
/// including the function signature hash and function call
/// parameters.
function _delegateCall(
address target,
bytes memory data
) internal returns (bytes memory) {
(bool success, bytes memory returnData) = target.delegatecall(data);
return _verifyResult(target, success, returnData);
}
/// @dev Validates whether the low level call or delegate call was
/// successful and reverts in cases of bubbled up revert messages
/// or if `target` was not actually a contract.
function _verifyResult(
address target,
bool success,
bytes memory returnData
) internal view returns (bytes memory) {
_propagateError(success, returnData);
// If the call was successful but there was no return data we need
// to make sure a contract was actually called as expected.
if (returnData.length == 0 && target.code.length == 0) {
revert LowLevelCallsHelper__CallFailed();
}
return returnData;
}
/// @dev Propagates an error message, if necessary.
/// @param success If transaction was successful.
/// @param resultData The transaction result data.
function _propagateError(
bool success,
bytes memory resultData
) internal pure {
if (!success) {
if (resultData.length == 0) {
revert LowLevelCallsHelper__CallFailed();
}
// Bubble up error if there was one given.
assembly {
revert(add(32, resultData), mload(resultData))
}
}
}
}
// contracts/libraries/ReentrancyGuardTransient.sol
/// @notice Reentrancy guard mixin.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/ReentrancyGuardTransient.sol)
/// @dev Mai: Edited to always use transient storage.
abstract contract ReentrancyGuard {
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* CUSTOM ERRORS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Unauthorized reentrant call.
error Reentrancy();
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* STORAGE */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Equivalent to: `uint32(bytes4(keccak256("Reentrancy()"))) | 1 << 71`.
/// 9 bytes is large enough to avoid collisions in practice,
/// but not too large to result in excessive bytecode bloat.
uint256 private constant _REENTRANCY_GUARD_SLOT = 0x8000000000ab143c06;
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* REENTRANCY GUARD */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Guards a function from reentrancy.
modifier nonReentrant() virtual {
/// @solidity memory-safe-assembly
assembly {
if tload(_REENTRANCY_GUARD_SLOT) {
mstore(0x00, 0xab143c06) // `Reentrancy()`.
revert(0x1c, 0x04)
}
tstore(_REENTRANCY_GUARD_SLOT, address())
}
_;
/// @solidity memory-safe-assembly
assembly {
tstore(_REENTRANCY_GUARD_SLOT, 0)
}
}
/// @dev Guards a view function from read-only reentrancy.
modifier nonReadReentrant() virtual {
/// @solidity memory-safe-assembly
assembly {
if tload(_REENTRANCY_GUARD_SLOT) {
mstore(0x00, 0xab143c06) // `Reentrancy()`.
revert(0x1c, 0x04)
}
}
_;
}
}
// contracts/libraries/external/ERC20.sol
/// @notice Simple ERC20 + EIP-2612 implementation.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/tokens/ERC20.sol)
/// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC20.sol)
/// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/ERC20.sol)
///
/// @dev Note:
/// - The ERC20 standard allows minting and transferring to and from the zero address,
/// minting and transferring zero tokens, as well as self-approvals.
/// For performance, this implementation WILL NOT revert for such actions.
/// Please add any checks with overrides if desired.
/// - The `permit` function uses the ecrecover precompile (0x1).
///
/// If you are overriding:
/// - NEVER violate the ERC20 invariant:
/// the total sum of all balances must be equal to `totalSupply()`.
/// - Check that the overridden function is actually used in the function you want to
/// change the behavior of. Much of the code has been manually inlined for performance.
abstract contract ERC20 {
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* CUSTOM ERRORS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev The total supply has overflowed.
error TotalSupplyOverflow();
/// @dev The allowance has overflowed.
error AllowanceOverflow();
/// @dev The allowance has underflowed.
error AllowanceUnderflow();
/// @dev Insufficient balance.
error InsufficientBalance();
/// @dev Insufficient allowance.
error InsufficientAllowance();
/// @dev The permit is invalid.
error InvalidPermit();
/// @dev The permit has expired.
error PermitExpired();
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* EVENTS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Emitted when `amount` tokens is transferred from `from` to `to`.
event Transfer(address indexed from, address indexed to, uint256 amount);
/// @dev Emitted when `amount` tokens is approved by `owner` to be used by `spender`.
event Approval(address indexed owner, address indexed spender, uint256 amount);
/// @dev `keccak256(bytes("Transfer(address,address,uint256)"))`.
uint256 private constant _TRANSFER_EVENT_SIGNATURE =
0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef;
/// @dev `keccak256(bytes("Approval(address,address,uint256)"))`.
uint256 private constant _APPROVAL_EVENT_SIGNATURE =
0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925;
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* STORAGE */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev The storage slot for the total supply.
uint256 private constant _TOTAL_SUPPLY_SLOT = 0x05345cdf77eb68f44c;
/// @dev The balance slot of `owner` is given by:
/// ```
/// mstore(0x0c, _BALANCE_SLOT_SEED)
/// mstore(0x00, owner)
/// let balanceSlot := keccak256(0x0c, 0x20)
/// ```
uint256 private constant _BALANCE_SLOT_SEED = 0x87a211a2;
/// @dev The allowance slot of (`owner`, `spender`) is given by:
/// ```
/// mstore(0x20, spender)
/// mstore(0x0c, _ALLOWANCE_SLOT_SEED)
/// mstore(0x00, owner)
/// let allowanceSlot := keccak256(0x0c, 0x34)
/// ```
uint256 private constant _ALLOWANCE_SLOT_SEED = 0x7f5e9f20;
/// @dev The nonce slot of `owner` is given by:
/// ```
/// mstore(0x0c, _NONCES_SLOT_SEED)
/// mstore(0x00, owner)
/// let nonceSlot := keccak256(0x0c, 0x20)
/// ```
uint256 private constant _NONCES_SLOT_SEED = 0x38377508;
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* CONSTANTS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev `(_NONCES_SLOT_SEED << 16) | 0x1901`.
uint256 private constant _NONCES_SLOT_SEED_WITH_SIGNATURE_PREFIX = 0x383775081901;
/// @dev `keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)")`.
bytes32 private constant _DOMAIN_TYPEHASH =
0x8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f;
/// @dev `keccak256("1")`.
bytes32 private constant _VERSION_HASH =
0xc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc6;
/// @dev `keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)")`.
bytes32 private constant _PERMIT_TYPEHASH =
0x6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9;
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* ERC20 METADATA */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Returns the name of the token.
function name() public view virtual returns (string memory);
/// @dev Returns the symbol of the token.
function symbol() public view virtual returns (string memory);
/// @dev Returns the decimals places of the token.
function decimals() public view virtual returns (uint8) {
return 18;
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* ERC20 */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Returns the amount of tokens in existence.
function totalSupply() public view virtual returns (uint256 result) {
/// @solidity memory-safe-assembly
assembly {
result := sload(_TOTAL_SUPPLY_SLOT)
}
}
/// @dev Returns the amount of tokens owned by `owner`.
function balanceOf(address owner) public view virtual returns (uint256 result) {
/// @solidity memory-safe-assembly
assembly {
mstore(0x0c, _BALANCE_SLOT_SEED)
mstore(0x00, owner)
result := sload(keccak256(0x0c, 0x20))
}
}
/// @dev Returns the amount of tokens that `spender` can spend on behalf of `owner`.
function allowance(address owner, address spender)
public
view
virtual
returns (uint256 result)
{
/// @solidity memory-safe-assembly
assembly {
mstore(0x20, spender)
mstore(0x0c, _ALLOWANCE_SLOT_SEED)
mstore(0x00, owner)
result := sload(keccak256(0x0c, 0x34))
}
}
/// @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
///
/// Emits a {Approval} event.
function approve(address spender, uint256 amount) public virtual returns (bool) {
/// @solidity memory-safe-assembly
assembly {
// Compute the allowance slot and store the amount.
mstore(0x20, spender)
mstore(0x0c, _ALLOWANCE_SLOT_SEED)
mstore(0x00, caller())
sstore(keccak256(0x0c, 0x34), amount)
// Emit the {Approval} event.
mstore(0x00, amount)
log3(0x00, 0x20, _APPROVAL_EVENT_SIGNATURE, caller(), shr(96, mload(0x2c)))
}
return true;
}
/// @dev Transfer `amount` tokens from the caller to `to`.
///
/// Requirements:
/// - `from` must at least have `amount`.
///
/// Emits a {Transfer} event.
function transfer(address to, uint256 amount) public virtual returns (bool) {
_beforeTokenTransfer(msg.sender, to, amount);
/// @solidity memory-safe-assembly
assembly {
// Compute the balance slot and load its value.
mstore(0x0c, _BALANCE_SLOT_SEED)
mstore(0x00, caller())
let fromBalanceSlot := keccak256(0x0c, 0x20)
let fromBalance := sload(fromBalanceSlot)
// Revert if insufficient balance.
if gt(amount, fromBalance) {
mstore(0x00, 0xf4d678b8) // `InsufficientBalance()`.
revert(0x1c, 0x04)
}
// Subtract and store the updated balance.
sstore(fromBalanceSlot, sub(fromBalance, amount))
// Compute the balance slot of `to`.
mstore(0x00, to)
let toBalanceSlot := keccak256(0x0c, 0x20)
// Add and store the updated balance of `to`.
// Will not overflow because the sum of all user balances
// cannot exceed the maximum uint256 value.
sstore(toBalanceSlot, add(sload(toBalanceSlot), amount))
// Emit the {Transfer} event.
mstore(0x20, amount)
log3(0x20, 0x20, _TRANSFER_EVENT_SIGNATURE, caller(), shr(96, mload(0x0c)))
}
_afterTokenTransfer(msg.sender, to, amount);
return true;
}
/// @dev Transfers `amount` tokens from `from` to `to`.
///
/// Note: Does not update the allowance if it is the maximum uint256 value.
///
/// Requirements:
/// - `from` must at least have `amount`.
/// - The caller must have at least `amount` of allowance to transfer the tokens of `from`.
///
/// Emits a {Transfer} event.
function transferFrom(address from, address to, uint256 amount) public virtual returns (bool) {
_beforeTokenTransfer(from, to, amount);
/// @solidity memory-safe-assembly
assembly {
let from_ := shl(96, from)
// Compute the allowance slot and load its value.
mstore(0x20, caller())
mstore(0x0c, or(from_, _ALLOWANCE_SLOT_SEED))
let allowanceSlot := keccak256(0x0c, 0x34)
let allowance_ := sload(allowanceSlot)
// If the allowance is not the maximum uint256 value.
if add(allowance_, 1) {
// Revert if the amount to be transferred exceeds the allowance.
if gt(amount, allowance_) {
mstore(0x00, 0x13be252b) // `InsufficientAllowance()`.
revert(0x1c, 0x04)
}
// Subtract and store the updated allowance.
sstore(allowanceSlot, sub(allowance_, amount))
}
// Compute the balance slot and load its value.
mstore(0x0c, or(from_, _BALANCE_SLOT_SEED))
let fromBalanceSlot := keccak256(0x0c, 0x20)
let fromBalance := sload(fromBalanceSlot)
// Revert if insufficient balance.
if gt(amount, fromBalance) {
mstore(0x00, 0xf4d678b8) // `InsufficientBalance()`.
revert(0x1c, 0x04)
}
// Subtract and store the updated balance.
sstore(fromBalanceSlot, sub(fromBalance, amount))
// Compute the balance slot of `to`.
mstore(0x00, to)
let toBalanceSlot := keccak256(0x0c, 0x20)
// Add and store the updated balance of `to`.
// Will not overflow because the sum of all user balances
// cannot exceed the maximum uint256 value.
sstore(toBalanceSlot, add(sload(toBalanceSlot), amount))
// Emit the {Transfer} event.
mstore(0x20, amount)
log3(0x20, 0x20, _TRANSFER_EVENT_SIGNATURE, shr(96, from_), shr(96, mload(0x0c)))
}
_afterTokenTransfer(from, to, amount);
return true;
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* EIP-2612 */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev For more performance, override to return the constant value
/// of `keccak256(bytes(name()))` if `name()` will never change.
function _constantNameHash() internal view virtual returns (bytes32 result) {}
/// @dev Returns the current nonce for `owner`.
/// This value is used to compute the signature for EIP-2612 permit.
function nonces(address owner) public view virtual returns (uint256 result) {
/// @solidity memory-safe-assembly
assembly {
// Compute the nonce slot and load its value.
mstore(0x0c, _NONCES_SLOT_SEED)
mstore(0x00, owner)
result := sload(keccak256(0x0c, 0x20))
}
}
/// @dev Sets `value` as the allowance of `spender` over the tokens of `owner`,
/// authorized by a signed approval by `owner`.
///
/// Emits a {Approval} event.
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) public virtual {
bytes32 nameHash = _constantNameHash();
// We simply calculate it on-the-fly to allow for cases where the `name` may change.
if (nameHash == bytes32(0)) nameHash = keccak256(bytes(name()));
/// @solidity memory-safe-assembly
assembly {
// Revert if the block timestamp is greater than `deadline`.
if gt(timestamp(), deadline) {
mstore(0x00, 0x1a15a3cc) // `PermitExpired()`.
revert(0x1c, 0x04)
}
let m := mload(0x40) // Grab the free memory pointer.
// Clean the upper 96 bits.
owner := shr(96, shl(96, owner))
spender := shr(96, shl(96, spender))
// Compute the nonce slot and load its value.
mstore(0x0e, _NONCES_SLOT_SEED_WITH_SIGNATURE_PREFIX)
mstore(0x00, owner)
let nonceSlot := keccak256(0x0c, 0x20)
let nonceValue := sload(nonceSlot)
// Prepare the domain separator.
mstore(m, _DOMAIN_TYPEHASH)
mstore(add(m, 0x20), nameHash)
mstore(add(m, 0x40), _VERSION_HASH)
mstore(add(m, 0x60), chainid())
mstore(add(m, 0x80), address())
mstore(0x2e, keccak256(m, 0xa0))
// Prepare the struct hash.
mstore(m, _PERMIT_TYPEHASH)
mstore(add(m, 0x20), owner)
mstore(add(m, 0x40), spender)
mstore(add(m, 0x60), value)
mstore(add(m, 0x80), nonceValue)
mstore(add(m, 0xa0), deadline)
mstore(0x4e, keccak256(m, 0xc0))
// Prepare the ecrecover calldata.
mstore(0x00, keccak256(0x2c, 0x42))
mstore(0x20, and(0xff, v))
mstore(0x40, r)
mstore(0x60, s)
let t := staticcall(gas(), 1, 0, 0x80, 0x20, 0x20)
// If the ecrecover fails, the returndatasize will be 0x00,
// `owner` will be checked if it equals the hash at 0x00,
// which evaluates to false (i.e. 0), and we will revert.
// If the ecrecover succeeds, the returndatasize will be 0x20,
// `owner` will be compared against the returned address at 0x20.
if iszero(eq(mload(returndatasize()), owner)) {
mstore(0x00, 0xddafbaef) // `InvalidPermit()`.
revert(0x1c, 0x04)
}
// Increment and store the updated nonce.
sstore(nonceSlot, add(nonceValue, t)) // `t` is 1 if ecrecover succeeds.
// Compute the allowance slot and store the value.
// The `owner` is already at slot 0x20.
mstore(0x40, or(shl(160, _ALLOWANCE_SLOT_SEED), spender))
sstore(keccak256(0x2c, 0x34), value)
// Emit the {Approval} event.
log3(add(m, 0x60), 0x20, _APPROVAL_EVENT_SIGNATURE, owner, spender)
mstore(0x40, m) // Restore the free memory pointer.
mstore(0x60, 0) // Restore the zero pointer.
}
}
/// @dev Returns the EIP-712 domain separator for the EIP-2612 permit.
function DOMAIN_SEPARATOR() public view virtual returns (bytes32 result) {
bytes32 nameHash = _constantNameHash();
// We simply calculate it on-the-fly to allow for cases where the `name` may change.
if (nameHash == bytes32(0)) nameHash = keccak256(bytes(name()));
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40) // Grab the free memory pointer.
mstore(m, _DOMAIN_TYPEHASH)
mstore(add(m, 0x20), nameHash)
mstore(add(m, 0x40), _VERSION_HASH)
mstore(add(m, 0x60), chainid())
mstore(add(m, 0x80), address())
result := keccak256(m, 0xa0)
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* INTERNAL MINT FUNCTIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Mints `amount` tokens to `to`, increasing the total supply.
///
/// Emits a {Transfer} event.
function _mint(address to, uint256 amount) internal virtual {
_beforeTokenTransfer(address(0), to, amount);
/// @solidity memory-safe-assembly
assembly {
let totalSupplyBefore := sload(_TOTAL_SUPPLY_SLOT)
let totalSupplyAfter := add(totalSupplyBefore, amount)
// Revert if the total supply overflows.
if lt(totalSupplyAfter, totalSupplyBefore) {
mstore(0x00, 0xe5cfe957) // `TotalSupplyOverflow()`.
revert(0x1c, 0x04)
}
// Store the updated total supply.
sstore(_TOTAL_SUPPLY_SLOT, totalSupplyAfter)
// Compute the balance slot and load its value.
mstore(0x0c, _BALANCE_SLOT_SEED)
mstore(0x00, to)
let toBalanceSlot := keccak256(0x0c, 0x20)
// Add and store the updated balance.
sstore(toBalanceSlot, add(sload(toBalanceSlot), amount))
// Emit the {Transfer} event.
mstore(0x20, amount)
log3(0x20, 0x20, _TRANSFER_EVENT_SIGNATURE, 0, shr(96, mload(0x0c)))
}
_afterTokenTransfer(address(0), to, amount);
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* INTERNAL BURN FUNCTIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Burns `amount` tokens from `from`, reducing the total supply.
///
/// Emits a {Transfer} event.
function _burn(address from, uint256 amount) internal virtual {
_beforeTokenTransfer(from, address(0), amount);
/// @solidity memory-safe-assembly
assembly {
// Compute the balance slot and load its value.
mstore(0x0c, _BALANCE_SLOT_SEED)
mstore(0x00, from)
let fromBalanceSlot := keccak256(0x0c, 0x20)
let fromBalance := sload(fromBalanceSlot)
// Revert if insufficient balance.
if gt(amount, fromBalance) {
mstore(0x00, 0xf4d678b8) // `InsufficientBalance()`.
revert(0x1c, 0x04)
}
// Subtract and store the updated balance.
sstore(fromBalanceSlot, sub(fromBalance, amount))
// Subtract and store the updated total supply.
sstore(_TOTAL_SUPPLY_SLOT, sub(sload(_TOTAL_SUPPLY_SLOT), amount))
// Emit the {Transfer} event.
mstore(0x00, amount)
log3(0x00, 0x20, _TRANSFER_EVENT_SIGNATURE, shr(96, shl(96, from)), 0)
}
_afterTokenTransfer(from, address(0), amount);
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* INTERNAL TRANSFER FUNCTIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Moves `amount` of tokens from `from` to `to`.
function _transfer(address from, address to, uint256 amount) internal virtual {
_beforeTokenTransfer(from, to, amount);
/// @solidity memory-safe-assembly
assembly {
let from_ := shl(96, from)
// Compute the balance slot and load its value.
mstore(0x0c, or(from_, _BALANCE_SLOT_SEED))
let fromBalanceSlot := keccak256(0x0c, 0x20)
let fromBalance := sload(fromBalanceSlot)
// Revert if insufficient balance.
if gt(amount, fromBalance) {
mstore(0x00, 0xf4d678b8) // `InsufficientBalance()`.
revert(0x1c, 0x04)
}
// Subtract and store the updated balance.
sstore(fromBalanceSlot, sub(fromBalance, amount))
// Compute the balance slot of `to`.
mstore(0x00, to)
let toBalanceSlot := keccak256(0x0c, 0x20)
// Add and store the updated balance of `to`.
// Will not overflow because the sum of all user balances
// cannot exceed the maximum uint256 value.
sstore(toBalanceSlot, add(sload(toBalanceSlot), amount))
// Emit the {Transfer} event.
mstore(0x20, amount)
log3(0x20, 0x20, _TRANSFER_EVENT_SIGNATURE, shr(96, from_), shr(96, mload(0x0c)))
}
_afterTokenTransfer(from, to, amount);
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* INTERNAL ALLOWANCE FUNCTIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Updates the allowance of `owner` for `spender` based on spent `amount`.
function _spendAllowance(address owner, address spender, uint256 amount) internal virtual {
/// @solidity memory-safe-assembly
assembly {
// Compute the allowance slot and load its value.
mstore(0x20, spender)
mstore(0x0c, _ALLOWANCE_SLOT_SEED)
mstore(0x00, owner)
let allowanceSlot := keccak256(0x0c, 0x34)
let allowance_ := sload(allowanceSlot)
// If the allowance is not the maximum uint256 value.
if add(allowance_, 1) {
// Revert if the amount to be transferred exceeds the allowance.
if gt(amount, allowance_) {
mstore(0x00, 0x13be252b) // `InsufficientAllowance()`.
revert(0x1c, 0x04)
}
// Subtract and store the updated allowance.
sstore(allowanceSlot, sub(allowance_, amount))
}
}
}
/// @dev Sets `amount` as the allowance of `spender` over the tokens of `owner`.
///
/// Emits a {Approval} event.
function _approve(address owner, address spender, uint256 amount) internal virtual {
/// @solidity memory-safe-assembly
assembly {
let owner_ := shl(96, owner)
// Compute the allowance slot and store the amount.
mstore(0x20, spender)
mstore(0x0c, or(owner_, _ALLOWANCE_SLOT_SEED))
sstore(keccak256(0x0c, 0x34), amount)
// Emit the {Approval} event.
mstore(0x00, amount)
log3(0x00, 0x20, _APPROVAL_EVENT_SIGNATURE, shr(96, owner_), shr(96, mload(0x2c)))
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* HOOKS TO OVERRIDE */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Hook that is called before any transfer of tokens.
/// This includes minting and burning.
function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual {}
/// @dev Hook that is called after any transfer of tokens.
/// This includes minting and burning.
function _afterTokenTransfer(address from, address to, uint256 amount) internal virtual {}
}
// contracts/libraries/external/FixedPointMathLib.sol
/// @notice Arithmetic library with operations for fixed-point numbers.
/// @dev Reduced function scope from full FixedPointMathLib library to only what is needed for Curvance.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/FixedPointMathLib.sol)
/// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/FixedPointMathLib.sol)
library FixedPointMathLib {
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* CUSTOM ERRORS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev The operation failed, either due to a multiplication overflow, or a division by a zero.
error MulDivFailed();
/// @dev The full precision multiply-divide operation failed, either due
/// to the result being larger than 256 bits, or a division by a zero.
error FullMulDivFailed();
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* GENERAL NUMBER UTILITIES */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Calculates `floor(x * y / d)` with full precision.
/// Throws if result overflows a uint256 or when `d` is zero.
/// Credit to Remco Bloemen under MIT license: https://2π.com/21/muldiv
function fullMulDiv(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 result) {
/// @solidity memory-safe-assembly
assembly {
for {} 1 {} {
// 512-bit multiply `[p1 p0] = x * y`.
// Compute the product mod `2**256` and mod `2**256 - 1`
// then use the Chinese Remainder Theorem to reconstruct
// the 512 bit result. The result is stored in two 256
// variables such that `product = p1 * 2**256 + p0`.
// Least significant 256 bits of the product.
result := mul(x, y) // Temporarily use `result` as `p0` to save gas.
let mm := mulmod(x, y, not(0))
// Most significant 256 bits of the product.
let p1 := sub(mm, add(result, lt(mm, result)))
// Handle non-overflow cases, 256 by 256 division.
if iszero(p1) {
if iszero(d) {
mstore(0x00, 0xae47f702) // `FullMulDivFailed()`.
revert(0x1c, 0x04)
}
result := div(result, d)
break
}
// Make sure the result is less than `2**256`. Also prevents `d == 0`.
if iszero(gt(d, p1)) {
mstore(0x00, 0xae47f702) // `FullMulDivFailed()`.
revert(0x1c, 0x04)
}
/*------------------- 512 by 256 division --------------------*/
// Make division exact by subtracting the remainder from `[p1 p0]`.
// Compute remainder using mulmod.
let r := mulmod(x, y, d)
// `t` is the least significant bit of `d`.
// Always greater or equal to 1.
let t := and(d, sub(0, d))
// Divide `d` by `t`, which is a power of two.
d := div(d, t)
// Invert `d mod 2**256`
// Now that `d` is an odd number, it has an inverse
// modulo `2**256` such that `d * inv = 1 mod 2**256`.
// Compute the inverse by starting with a seed that is correct
// correct for four bits. That is, `d * inv = 1 mod 2**4`.
let inv := xor(2, mul(3, d))
// Now use Newton-Raphson iteration to improve the precision.
// Thanks to Hensel's lifting lemma, this also works in modular
// arithmetic, doubling the correct bits in each step.
inv := mul(inv, sub(2, mul(d, inv))) // inverse mod 2**8
inv := mul(inv, sub(2, mul(d, inv))) // inverse mod 2**16
inv := mul(inv, sub(2, mul(d, inv))) // inverse mod 2**32
inv := mul(inv, sub(2, mul(d, inv))) // inverse mod 2**64
inv := mul(inv, sub(2, mul(d, inv))) // inverse mod 2**128
result :=
mul(
// Divide [p1 p0] by the factors of two.
// Shift in bits from `p1` into `p0`. For this we need
// to flip `t` such that it is `2**256 / t`.
or(
mul(sub(p1, gt(r, result)), add(div(sub(0, t), t), 1)),
div(sub(result, r), t)
),
// inverse mod 2**256
mul(inv, sub(2, mul(d, inv)))
)
break
}
}
}
/// @dev Calculates `floor(x * y / d)` with full precision, rounded up.
/// Throws if result overflows a uint256 or when `d` is zero.
/// Credit to Uniswap-v3-core under MIT license:
/// https://github.com/Uniswap/v3-core/blob/contracts/libraries/FullMath.sol
function fullMulDivUp(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 result) {
result = fullMulDiv(x, y, d);
/// @solidity memory-safe-assembly
assembly {
if mulmod(x, y, d) {
result := add(result, 1)
if iszero(result) {
mstore(0x00, 0xae47f702) // `FullMulDivFailed()`.
revert(0x1c, 0x04)
}
}
}
}
/// @dev Returns `floor(x * y / d)`.
/// Reverts if `x * y` overflows, or `d` is zero.
function mulDiv(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
// Equivalent to require(d != 0 && (y == 0 || x <= type(uint256).max / y))
if iszero(mul(d, iszero(mul(y, gt(x, div(not(0), y)))))) {
mstore(0x00, 0xad251c27) // `MulDivFailed()`.
revert(0x1c, 0x04)
}
z := div(mul(x, y), d)
}
}
/// @dev Returns `ceil(x * y / d)`.
/// Reverts if `x * y` overflows, or `d` is zero.
function mulDivUp(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
// Equivalent to require(d != 0 && (y == 0 || x <= type(uint256).max / y))
if iszero(mul(d, iszero(mul(y, gt(x, div(not(0), y)))))) {
mstore(0x00, 0xad251c27) // `MulDivFailed()`.
revert(0x1c, 0x04)
}
z := add(iszero(iszero(mod(mul(x, y), d))), div(mul(x, y), d))
}
}
/// @dev Returns the square root of `x`.
function sqrt(uint256 x) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
// `floor(sqrt(2**15)) = 181`. `sqrt(2**15) - 181 = 2.84`.
z := 181 // The "correct" value is 1, but this saves a multiplication later.
// This segment is to get a reasonable initial estimate for the Babylonian method. With a bad
// start, the correct # of bits increases ~linearly each iteration instead of ~quadratically.
// Let `y = x / 2**r`. We check `y >= 2**(k + 8)`
// but shift right by `k` bits to ensure that if `x >= 256`, then `y >= 256`.
let r := shl(7, lt(0xffffffffffffffffffffffffffffffffff, x))
r := or(r, shl(6, lt(0xffffffffffffffffff, shr(r, x))))
r := or(r, shl(5, lt(0xffffffffff, shr(r, x))))
r := or(r, shl(4, lt(0xffffff, shr(r, x))))
z := shl(shr(1, r), z)
// Goal was to get `z*z*y` within a small factor of `x`. More iterations could
// get y in a tighter range. Currently, we will have y in `[256, 256*(2**16))`.
// We ensured `y >= 256` so that the relative difference between `y` and `y+1` is small.
// That's not possible if `x < 256` but we can just verify those cases exhaustively.
// Now, `z*z*y <= x < z*z*(y+1)`, and `y <= 2**(16+8)`, and either `y >= 256`, or `x < 256`.
// Correctness can be checked exhaustively for `x < 256`, so we assume `y >= 256`.
// Then `z*sqrt(y)` is within `sqrt(257)/sqrt(256)` of `sqrt(x)`, or about 20bps.
// For `s` in the range `[1/256, 256]`, the estimate `f(s) = (181/1024) * (s+1)`
// is in the range `(1/2.84 * sqrt(s), 2.84 * sqrt(s))`,
// with largest error when `s = 1` and when `s = 256` or `1/256`.
// Since `y` is in `[256, 256*(2**16))`, let `a = y/65536`, so that `a` is in `[1/256, 256)`.
// Then we can estimate `sqrt(y)` using
// `sqrt(65536) * 181/1024 * (a + 1) = 181/4 * (y + 65536)/65536 = 181 * (y + 65536)/2**18`.
// There is no overflow risk here since `y < 2**136` after the first branch above.
z := shr(18, mul(z, add(shr(r, x), 65536))) // A `mul()` is saved from starting `z` at 181.
// Given the worst case multiplicative error of 2.84 above, 7 iterations should be enough.
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
// If `x+1` is a perfect square, the Babylonian method cycles between
// `floor(sqrt(x))` and `ceil(sqrt(x))`. This statement ensures we return floor.
// See: https://en.wikipedia.org/wiki/Integer_square_root#Using_only_integer_division
z := sub(z, lt(div(x, z), z))
}
}
}
// contracts/libraries/external/SafeTransferLib.sol
/// @notice Safe ETH and ERC20 transfer library that gracefully handles missing return values.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/SafeTransferLib.sol)
/// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/SafeTransferLib.sol)
///
/// @dev Note:
/// - For ETH transfers, please use `forceSafeTransferETH` for DoS protection.
/// - For ERC20s, this implementation won't check that a token has code,
/// responsibility is delegated to the caller.
library SafeTransferLib {
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* CUSTOM ERRORS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev The ETH transfer has failed.
error ETHTransferFailed();
/// @dev The ERC20 `transferFrom` has failed.
error TransferFromFailed();
/// @dev The ERC20 `transfer` has failed.
error TransferFailed();
/// @dev The ERC20 `approve` has failed.
error ApproveFailed();
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* CONSTANTS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Suggested gas stipend for contract receiving ETH that disallows any storage writes.
uint256 internal constant GAS_STIPEND_NO_STORAGE_WRITES = 2300;
/// @dev Suggested gas stipend for contract receiving ETH to perform a few
/// storage reads and writes, but low enough to prevent griefing.
uint256 internal constant GAS_STIPEND_NO_GRIEF = 100000;
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* ETH OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
// If the ETH transfer MUST succeed with a reasonable gas budget, use the force variants.
//
// The regular variants:
// - Forwards all remaining gas to the target.
// - Reverts if the target reverts.
// - Reverts if the current contract has insufficient balance.
//
// The force variants:
// - Forwards with an optional gas stipend
// (defaults to `GAS_STIPEND_NO_GRIEF`, which is sufficient for most cases).
// - If the target reverts, or if the gas stipend is exhausted,
// creates a temporary contract to force send the ETH via `SELFDESTRUCT`.
// Future compatible with `SENDALL`: https://eips.ethereum.org/EIPS/eip-4758.
// - Reverts if the current contract has insufficient balance.
//
// The try variants:
// - Forwards with a mandatory gas stipend.
// - Instead of reverting, returns whether the transfer succeeded.
/// @dev Sends `amount` (in wei) ETH to `to`.
function safeTransferETH(address to, uint256 amount) internal {
/// @solidity memory-safe-assembly
assembly {
if iszero(call(gas(), to, amount, codesize(), 0x00, codesize(), 0x00)) {
mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`.
revert(0x1c, 0x04)
}
}
}
/// @dev Sends all the ETH in the current contract to `to`.
function safeTransferAllETH(address to) internal {
/// @solidity memory-safe-assembly
assembly {
// Transfer all the ETH and check if it succeeded or not.
if iszero(call(gas(), to, selfbalance(), codesize(), 0x00, codesize(), 0x00)) {
mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`.
revert(0x1c, 0x04)
}
}
}
/// @dev Force sends `amount` (in wei) ETH to `to`, with a `gasStipend`.
function forceSafeTransferETH(address to, uint256 amount, uint256 gasStipend) internal {
/// @solidity memory-safe-assembly
assembly {
if lt(selfbalance(), amount) {
mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`.
revert(0x1c, 0x04)
}
if iszero(call(gasStipend, to, amount, codesize(), 0x00, codesize(), 0x00)) {
mstore(0x00, to) // Store the address in scratch space.
mstore8(0x0b, 0x73) // Opcode `PUSH20`.
mstore8(0x20, 0xff) // Opcode `SELFDESTRUCT`.
if iszero(create(amount, 0x0b, 0x16)) { revert(codesize(), codesize()) } // For gas estimation.
}
}
}
/// @dev Force sends all the ETH in the current contract to `to`, with a `gasStipend`.
function forceSafeTransferAllETH(address to, uint256 gasStipend) internal {
/// @solidity memory-safe-assembly
assembly {
if iszero(call(gasStipend, to, selfbalance(), codesize(), 0x00, codesize(), 0x00)) {
mstore(0x00, to) // Store the address in scratch space.
mstore8(0x0b, 0x73) // Opcode `PUSH20`.
mstore8(0x20, 0xff) // Opcode `SELFDESTRUCT`.
if iszero(create(selfbalance(), 0x0b, 0x16)) { revert(codesize(), codesize()) } // For gas estimation.
}
}
}
/// @dev Force sends `amount` (in wei) ETH to `to`, with `GAS_STIPEND_NO_GRIEF`.
function forceSafeTransferETH(address to, uint256 amount) internal {
/// @solidity memory-safe-assembly
assembly {
if lt(selfbalance(), amount) {
mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`.
revert(0x1c, 0x04)
}
if iszero(call(GAS_STIPEND_NO_GRIEF, to, amount, codesize(), 0x00, codesize(), 0x00)) {
mstore(0x00, to) // Store the address in scratch space.
mstore8(0x0b, 0x73) // Opcode `PUSH20`.
mstore8(0x20, 0xff) // Opcode `SELFDESTRUCT`.
if iszero(create(amount, 0x0b, 0x16)) { revert(codesize(), codesize()) } // For gas estimation.
}
}
}
/// @dev Force sends all the ETH in the current contract to `to`, with `GAS_STIPEND_NO_GRIEF`.
function forceSafeTransferAllETH(address to) internal {
/// @solidity memory-safe-assembly
assembly {
// forgefmt: disable-next-item
if iszero(call(GAS_STIPEND_NO_GRIEF, to, selfbalance(), codesize(), 0x00, codesize(), 0x00)) {
mstore(0x00, to) // Store the address in scratch space.
mstore8(0x0b, 0x73) // Opcode `PUSH20`.
mstore8(0x20, 0xff) // Opcode `SELFDESTRUCT`.
if iszero(create(selfbalance(), 0x0b, 0x16)) { revert(codesize(), codesize()) } // For gas estimation.
}
}
}
/// @dev Sends `amount` (in wei) ETH to `to`, with a `gasStipend`.
function trySafeTransferETH(address to, uint256 amount, uint256 gasStipend)
internal
returns (bool success)
{
/// @solidity memory-safe-assembly
assembly {
success := call(gasStipend, to, amount, codesize(), 0x00, codesize(), 0x00)
}
}
/// @dev Sends all the ETH in the current contract to `to`, with a `gasStipend`.
function trySafeTransferAllETH(address to, uint256 gasStipend)
internal
returns (bool success)
{
/// @solidity memory-safe-assembly
assembly {
success := call(gasStipend, to, selfbalance(), codesize(), 0x00, codesize(), 0x00)
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* ERC20 OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Sends `amount` of ERC20 `token` from `from` to `to`.
/// Reverts upon failure.
///
/// The `from` account must have at least `amount` approved for
/// the current contract to manage.
function safeTransferFrom(address token, address from, address to, uint256 amount) internal {
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40) // Cache the free memory pointer.
mstore(0x60, amount) // Store the `amount` argument.
mstore(0x40, to) // Store the `to` argument.
mstore(0x2c, shl(96, from)) // Store the `from` argument.
mstore(0x0c, 0x23b872dd000000000000000000000000) // `transferFrom(address,address,uint256)`.
// Perform the transfer, reverting upon failure.
if iszero(
and( // The arguments of `and` are evaluated from right to left.
or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.
call(gas(), token, 0, 0x1c, 0x64, 0x00, 0x20)
)
) {
mstore(0x00, 0x7939f424) // `TransferFromFailed()`.
revert(0x1c, 0x04)
}
mstore(0x60, 0) // Restore the zero slot to zero.
mstore(0x40, m) // Restore the free memory pointer.
}
}
/// @dev Sends all of ERC20 `token` from `from` to `to`.
/// Reverts upon failure.
///
/// The `from` account must have their entire balance approved for
/// the current contract to manage.
function safeTransferAllFrom(address token, address from, address to)
internal
returns (uint256 amount)
{
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40) // Cache the free memory pointer.
mstore(0x40, to) // Store the `to` argument.
mstore(0x2c, shl(96, from)) // Store the `from` argument.
mstore(0x0c, 0x70a08231000000000000000000000000) // `balanceOf(address)`.
// Read the balance, reverting upon failure.
if iszero(
and( // The arguments of `and` are evaluated from right to left.
gt(returndatasize(), 0x1f), // At least 32 bytes returned.
staticcall(gas(), token, 0x1c, 0x24, 0x60, 0x20)
)
) {
mstore(0x00, 0x7939f424) // `TransferFromFailed()`.
revert(0x1c, 0x04)
}
mstore(0x00, 0x23b872dd) // `transferFrom(address,address,uint256)`.
amount := mload(0x60) // The `amount` is already at 0x60. We'll need to return it.
// Perform the transfer, reverting upon failure.
if iszero(
and( // The arguments of `and` are evaluated from right to left.
or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.
call(gas(), token, 0, 0x1c, 0x64, 0x00, 0x20)
)
) {
mstore(0x00, 0x7939f424) // `TransferFromFailed()`.
revert(0x1c, 0x04)
}
mstore(0x60, 0) // Restore the zero slot to zero.
mstore(0x40, m) // Restore the free memory pointer.
}
}
/// @dev Sends `amount` of ERC20 `token` from the current contract to `to`.
/// Reverts upon failure.
function safeTransfer(address token, address to, uint256 amount) internal {
/// @solidity memory-safe-assembly
assembly {
mstore(0x14, to) // Store the `to` argument.
mstore(0x34, amount) // Store the `amount` argument.
mstore(0x00, 0xa9059cbb000000000000000000000000) // `transfer(address,uint256)`.
// Perform the transfer, reverting upon failure.
if iszero(
and( // The arguments of `and` are evaluated from right to left.
or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.
call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
)
) {
mstore(0x00, 0x90b8ec18) // `TransferFailed()`.
revert(0x1c, 0x04)
}
mstore(0x34, 0) // Restore the part of the free memory pointer that was overwritten.
}
}
/// @dev Sends all of ERC20 `token` from the current contract to `to`.
/// Reverts upon failure.
function safeTransferAll(address token, address to) internal returns (uint256 amount) {
/// @solidity memory-safe-assembly
assembly {
mstore(0x00, 0x70a08231) // Store the function selector of `balanceOf(address)`.
mstore(0x20, address()) // Store the address of the current contract.
// Read the balance, reverting upon failure.
if iszero(
and( // The arguments of `and` are evaluated from right to left.
gt(returndatasize(), 0x1f), // At least 32 bytes returned.
staticcall(gas(), token, 0x1c, 0x24, 0x34, 0x20)
)
) {
mstore(0x00, 0x90b8ec18) // `TransferFailed()`.
revert(0x1c, 0x04)
}
mstore(0x14, to) // Store the `to` argument.
amount := mload(0x34) // The `amount` is already at 0x34. We'll need to return it.
mstore(0x00, 0xa9059cbb000000000000000000000000) // `transfer(address,uint256)`.
// Perform the transfer, reverting upon failure.
if iszero(
and( // The arguments of `and` are evaluated from right to left.
or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.
call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
)
) {
mstore(0x00, 0x90b8ec18) // `TransferFailed()`.
revert(0x1c, 0x04)
}
mstore(0x34, 0) // Restore the part of the free memory pointer that was overwritten.
}
}
/// @dev Sets `amount` of ERC20 `token` for `to` to manage on behalf of the current contract.
/// Reverts upon failure.
function safeApprove(address token, address to, uint256 amount) internal {
/// @solidity memory-safe-assembly
assembly {
mstore(0x14, to) // Store the `to` argument.
mstore(0x34, amount) // Store the `amount` argument.
mstore(0x00, 0x095ea7b3000000000000000000000000) // `approve(address,uint256)`.
// Perform the approval, reverting upon failure.
if iszero(
and( // The arguments of `and` are evaluated from right to left.
or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.
call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
)
) {
mstore(0x00, 0x3e3f8f73) // `ApproveFailed()`.
revert(0x1c, 0x04)
}
mstore(0x34, 0) // Restore the part of the free memory pointer that was overwritten.
}
}
/// @dev Sets `amount` of ERC20 `token` for `to` to manage on behalf of the current contract.
/// If the initial attempt to approve fails, attempts to reset the approved amount to zero,
/// then retries the approval again (some tokens, e.g. USDT, requires this).
/// Reverts upon failure.
function safeApproveWithRetry(address token, address to, uint256 amount) internal {
/// @solidity memory-safe-assembly
assembly {
mstore(0x14, to) // Store the `to` argument.
mstore(0x34, amount) // Store the `amount` argument.
mstore(0x00, 0x095ea7b3000000000000000000000000) // `approve(address,uint256)`.
// Perform the approval, retrying upon failure.
if iszero(
and( // The arguments of `and` are evaluated from right to left.
or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.
call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
)
) {
mstore(0x34, 0) // Store 0 for the `amount`.
mstore(0x00, 0x095ea7b3000000000000000000000000) // `approve(address,uint256)`.
pop(call(gas(), token, 0, 0x10, 0x44, codesize(), 0x00)) // Reset the approval.
mstore(0x34, amount) // Store back the original `amount`.
// Retry the approval, reverting upon failure.
if iszero(
and(
or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.
call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
)
) {
mstore(0x00, 0x3e3f8f73) // `ApproveFailed()`.
revert(0x1c, 0x04)
}
}
mstore(0x34, 0) // Restore the part of the free memory pointer that was overwritten.
}
}
/// @dev Returns the amount of ERC20 `token` owned by `account`.
/// Returns zero if the `token` does not exist.
function balanceOf(address token, address account) internal view returns (uint256 amount) {
/// @solidity memory-safe-assembly
assembly {
mstore(0x14, account) // Store the `account` argument.
mstore(0x00, 0x70a08231000000000000000000000000) // `balanceOf(address)`.
amount :=
mul(
mload(0x20),
and( // The arguments of `and` are evaluated from right to left.
gt(returndatasize(), 0x1f), // At least 32 bytes returned.
staticcall(gas(), token, 0x10, 0x24, 0x20, 0x20)
)
)
}
}
}
// contracts/libraries/external/ERC165.sol
/**
* @dev Implementation of the {IERC165} interface.
*
* Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
* for the additional interface id that will be supported. For example:
*
* ```solidity
* function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
* return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
* }
* ```
*
* Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.
*/
abstract contract ERC165 is IERC165 {
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(
bytes4 interfaceId
) public view virtual override returns (bool) {
return interfaceId == type(IERC165).interfaceId;
}
}
// contracts/libraries/external/ERC165Checker.sol
// @author Modified from OpenZeppelin Contracts (utils/introspection/ERC165Checker.sol)
/**
* @dev Library used to query support of an interface declared via {IERC165}.
*
* Note that these functions return the actual result of the query: they do not
* `revert` if an interface is not supported. It is up to the caller to decide
* what to do in these cases.
*/
library ERC165Checker {
// As per the EIP-165 spec, no interface should ever match 0xffffffff
bytes4 private constant _INTERFACE_ID_INVALID = 0xffffffff;
/**
* @dev Returns true if `account` supports the {IERC165} interface.
*/
function supportsERC165(address account) internal view returns (bool) {
// Any contract that implements ERC165 must explicitly indicate support of
// InterfaceId_ERC165 and explicitly indicate non-support of InterfaceId_Invalid
return
supportsERC165InterfaceUnchecked(
account,
type(IERC165).interfaceId
) &&
!supportsERC165InterfaceUnchecked(account, _INTERFACE_ID_INVALID);
}
/**
* @dev Returns true if `account` supports the interface defined by
* `interfaceId`. Support for {IERC165} itself is queried automatically.
*
* See {IERC165-supportsInterface}.
*/
function supportsInterface(
address account,
bytes4 interfaceId
) internal view returns (bool) {
// query support of both ERC165 as per the spec and support of _interfaceId
return
supportsERC165(account) &&
supportsERC165InterfaceUnchecked(account, interfaceId);
}
/**
* @notice Query if a contract implements an interface, does not check ERC165 support
* @param account The address of the contract to query for support of an interface
* @param interfaceId The interface identifier, as specified in ERC-165
* @return true if the contract at account indicates support of the interface with
* identifier interfaceId, false otherwise
* @dev Assumes that account contains a contract that supports ERC165, otherwise
* the behavior of this method is undefined. This precondition can be checked
* with {supportsERC165}.
*
* Some precompiled contracts will falsely indicate support for a given interface, so caution
* should be exercised when using this function.
*
* Interface identification is specified in ERC-165.
*/
function supportsERC165InterfaceUnchecked(
address account,
bytes4 interfaceId
) internal view returns (bool) {
// prepare call
bytes memory encodedParams = abi.encodeCall(
IERC165.supportsInterface,
(interfaceId)
);
// perform static call
bool success;
uint256 returnSize;
uint256 returnValue;
assembly {
success := staticcall(
30000,
account,
add(encodedParams, 0x20),
mload(encodedParams),
0x00,
0x20
)
returnSize := returndatasize()
returnValue := mload(0x00)
}
return success && returnSize >= 0x20 && returnValue > 0;
}
}
// contracts/libraries/CentralRegistryLib.sol
/// @title Curvance Central Registry Validation Library
/// @notice For validating that Central Registry is configured properly
/// on launch.
library CentralRegistryLib {
/// ERRORS ///
error CentralRegistryLib__InvalidCentralRegistry();
/// INTERNAL FUNCTIONS ///
/// @notice Validates that `cr` is the Protocol Central Registry.
/// @param cr The proposed Protocol Central Registry.
function _isCentralRegistry(ICentralRegistry cr) internal view {
if (
!ERC165Checker.supportsInterface(
address(cr),
type(ICentralRegistry).interfaceId
)
) {
revert CentralRegistryLib__InvalidCentralRegistry();
}
}
}
// contracts/libraries/Multicall.sol
/// @title Curvance Multicall helper.
/// @notice Multicall implementation to support pull based oracles and
/// other chained actions within Curvance.
abstract contract Multicall {
/// TYPES ///
/// @notice Struct containing information on the desired
/// multicall action to execute.
/// @param target The address of the target contract to execute the call at.
/// @param isPriceUpdate Boolean indicating if the call is a price update.
/// @param data The data to attach to the call.
struct MulticallAction {
address target;
bool isPriceUpdate;
bytes data;
}
/// ERRORS ///
error Multicall__InvalidTarget();
error Multicall__UnknownCalldata();
/// EXTERNAL FUNCTIONS ///
/// @notice Executes multiple calls in a single transaction.
/// This can be used to update oracle prices before
/// a liquidity dependent action.
function multicall(
MulticallAction[] calldata calls
) external returns (bytes[] memory results) {
ICentralRegistry cr = _getCentralRegistry();
uint256 numCalls = calls.length;
results = new bytes[](numCalls);
MulticallAction memory cachedCall;
for (uint256 i; i < numCalls; ++i) {
cachedCall = calls[i];
if (cachedCall.isPriceUpdate) {
// CASE: We need to update a pull based price oracle and we
// need a direct call to the target address.
address checker = cr.multicallChecker(cachedCall.target);
// Validate we know how to verify this calldata.
if (checker == address(0)) {
revert Multicall__UnknownCalldata();
}
IMulticallChecker(checker).checkCalldata(
msg.sender,
cachedCall.target,
cachedCall.data
);
results[i] = LowLevelCallsHelper.
_call(cachedCall.target, cachedCall.data);
continue;
}
// CASE: Not a price update and we need delegate the call to the
// current address.
if (address(this) != cachedCall.target) {
revert Multicall__InvalidTarget();
}
results[i] = LowLevelCallsHelper.
_delegateCall(address(this), cachedCall.data);
}
}
/// @notice Returns the Protocol Central Registry contract in interface
/// form.
/// @dev MUST be overridden in every multicallable contract's
/// implementation.
function _getCentralRegistry()
internal
view
virtual
returns (ICentralRegistry);
}
// contracts/libraries/external/ERC4626.sol
/// @notice Simple ERC4626 tokenized Vault implementation.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/tokens/ERC4626.sol)
/// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/mixins/ERC4626.sol)
/// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/extensions/ERC4626.sol)
abstract contract ERC4626 is ERC20 {
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* CONSTANTS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev The default underlying decimals.
uint8 internal constant _DEFAULT_UNDERLYING_DECIMALS = 18;
/// @dev The default decimals offset.
uint8 internal constant _DEFAULT_DECIMALS_OFFSET = 0;
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* CUSTOM ERRORS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Cannot deposit more than the max limit.
error DepositMoreThanMax();
/// @dev Cannot mint more than the max limit.
error MintMoreThanMax();
/// @dev Cannot withdraw more than the max limit.
error WithdrawMoreThanMax();
/// @dev Cannot redeem more than the max limit.
error RedeemMoreThanMax();
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* EVENTS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Emitted during a mint call or deposit call.
event Deposit(address indexed by, address indexed owner, uint256 assets, uint256 shares);
/// @dev Emitted during a withdraw call or redeem call.
event Withdraw(
address indexed by,
address indexed to,
address indexed owner,
uint256 assets,
uint256 shares
);
/// @dev `keccak256(bytes("Deposit(address,address,uint256,uint256)"))`.
uint256 private constant _DEPOSIT_EVENT_SIGNATURE =
0xdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d7;
/// @dev `keccak256(bytes("Withdraw(address,address,address,uint256,uint256)"))`.
uint256 private constant _WITHDRAW_EVENT_SIGNATURE =
0xfbde797d201c681b91056529119e0b02407c7bb96a4a2c75c01fc9667232c8db;
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* ERC4626 CONSTANTS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev To be overridden to return the address of the underlying asset.
///
/// - MUST be an ERC20 token contract.
/// - MUST NOT revert.
function asset() public view virtual returns (address);
/// @dev To be overridden to return the number of decimals of the underlying asset.
/// Default: 18.
///
/// - MUST NOT revert.
function _underlyingDecimals() internal view virtual returns (uint8) {
return _DEFAULT_UNDERLYING_DECIMALS;
}
/// @dev Override to return a non-zero value to make the inflation attack even more unfeasible.
/// Only used when {_useVirtualShares} returns true.
/// Default: 0.
///
/// - MUST NOT revert.
function _decimalsOffset() internal view virtual returns (uint8) {
return _DEFAULT_DECIMALS_OFFSET;
}
/// @dev Returns whether virtual shares will be used to mitigate the inflation attack.
/// See: https://github.com/OpenZeppelin/openzeppelin-contracts/issues/3706
/// Override to return true or false.
/// Default: true.
///
/// - MUST NOT revert.
function _useVirtualShares() internal view virtual returns (bool) {
return true;
}
/// @dev Returns the decimals places of the token.
///
/// - MUST NOT revert.
function decimals() public view virtual override(ERC20) returns (uint8) {
if (!_useVirtualShares()) return _underlyingDecimals();
return _underlyingDecimals() + _decimalsOffset();
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* ASSET DECIMALS GETTER HELPER */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Helper function to get the decimals of the underlying asset.
/// Useful for setting the return value of `_underlyingDecimals` during initialization.
/// If the retrieval succeeds, `success` will be true, and `result` will hold the result.
/// Otherwise, `success` will be false, and `result` will be zero.
///
/// Example usage:
/// ```
/// (bool success, uint8 result) = _tryGetAssetDecimals(underlying);
/// _decimals = success ? result : _DEFAULT_UNDERLYING_DECIMALS;
/// ```
function _tryGetAssetDecimals(address underlying)
internal
view
returns (bool success, uint8 result)
{
/// @solidity memory-safe-assembly
assembly {
// Store the function selector of `decimals()`.
mstore(0x00, 0x313ce567)
// Arguments are evaluated last to first.
success :=
and(
// Returned value is less than 256, at left-padded to 32 bytes.
and(lt(mload(0x00), 0x100), gt(returndatasize(), 0x1f)),
// The staticcall succeeds.
staticcall(gas(), underlying, 0x1c, 0x04, 0x00, 0x20)
)
result := mul(mload(0x00), success)
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* ACCOUNTING LOGIC */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Returns the total amount of the underlying asset managed by the Vault.
///
/// - SHOULD include any compounding that occurs from the yield.
/// - MUST be inclusive of any fees that are charged against assets in the Vault.
/// - MUST NOT revert.
function totalAssets() public view virtual returns (uint256 assets) {
assets = SafeTransferLib.balanceOf(asset(), address(this));
}
/// @dev Returns the amount of shares that the Vault will exchange for the amount of
/// assets provided, in an ideal scenario where all conditions are met.
///
/// - MUST NOT be inclusive of any fees that are charged against assets in the Vault.
/// - MUST NOT show any variations depending on the caller.
/// - MUST NOT reflect slippage or other on-chain conditions, during the actual exchange.
/// - MUST NOT revert.
///
/// Note: This calculation MAY NOT reflect the "per-user" price-per-share, and instead
/// should reflect the "average-user's" price-per-share, i.e. what the average user should
/// expect to see when exchanging to and from.
function convertToShares(uint256 assets) public view virtual returns (uint256 shares) {
if (!_useVirtualShares()) {
uint256 supply = totalSupply();
return _eitherIsZero(assets, supply)
? _initialConvertToShares(assets)
: FixedPointMathLib.fullMulDiv(assets, supply, totalAssets());
}
uint256 o = _decimalsOffset();
if (o == uint256(0)) {
return FixedPointMathLib.fullMulDiv(assets, totalSupply() + 1, _inc(totalAssets()));
}
return FixedPointMathLib.fullMulDiv(assets, totalSupply() + 10 ** o, _inc(totalAssets()));
}
/// @dev Returns the amount of assets that the Vault will exchange for the amount of
/// shares provided, in an ideal scenario where all conditions are met.
///
/// - MUST NOT be inclusive of any fees that are charged against assets in the Vault.
/// - MUST NOT show any variations depending on the caller.
/// - MUST NOT reflect slippage or other on-chain conditions, during the actual exchange.
/// - MUST NOT revert.
///
/// Note: This calculation MAY NOT reflect the "per-user" price-per-share, and instead
/// should reflect the "average-user's" price-per-share, i.e. what the average user should
/// expect to see when exchanging to and from.
function convertToAssets(uint256 shares) public view virtual returns (uint256 assets) {
if (!_useVirtualShares()) {
uint256 supply = totalSupply();
return supply == uint256(0)
? _initialConvertToAssets(shares)
: FixedPointMathLib.fullMulDiv(shares, totalAssets(), supply);
}
uint256 o = _decimalsOffset();
if (o == uint256(0)) {
return FixedPointMathLib.fullMulDiv(shares, totalAssets() + 1, _inc(totalSupply()));
}
return FixedPointMathLib.fullMulDiv(shares, totalAssets() + 1, totalSupply() + 10 ** o);
}
/// @dev Allows an on-chain or off-chain user to simulate the effects of their deposit
/// at the current block, given current on-chain conditions.
///
/// - MUST return as close to and no more than the exact amount of Vault shares that
/// will be minted in a deposit call in the same transaction, i.e. deposit should
/// return the same or more shares as `previewDeposit` if call in the same transaction.
/// - MUST NOT account for deposit limits like those returned from `maxDeposit` and should
/// always act as if the deposit will be accepted, regardless of approvals, etc.
/// - MUST be inclusive of deposit fees. Integrators should be aware of this.
/// - MUST not revert.
///
/// Note: Any unfavorable discrepancy between `convertToShares` and `previewDeposit` SHOULD
/// be considered slippage in share price or some other type of condition, meaning
/// the depositor will lose assets by depositing.
function previewDeposit(uint256 assets) public view virtual returns (uint256 shares) {
shares = convertToShares(assets);
}
/// @dev Allows an on-chain or off-chain user to simulate the effects of their mint
/// at the current block, given current on-chain conditions.
///
/// - MUST return as close to and no fewer than the exact amount of assets that
/// will be deposited in a mint call in the same transaction, i.e. mint should
/// return the same or fewer assets as `previewMint` if called in the same transaction.
/// - MUST NOT account for mint limits like those returned from `maxMint` and should
/// always act as if the mint will be accepted, regardless of approvals, etc.
/// - MUST be inclusive of deposit fees. Integrators should be aware of this.
/// - MUST not revert.
///
/// Note: Any unfavorable discrepancy between `convertToAssets` and `previewMint` SHOULD
/// be considered slippage in share price or some other type of condition,
/// meaning the depositor will lose assets by minting.
function previewMint(uint256 shares) public view virtual returns (uint256 assets) {
if (!_useVirtualShares()) {
uint256 supply = totalSupply();
return supply == uint256(0)
? _initialConvertToAssets(shares)
: FixedPointMathLib.fullMulDivUp(shares, totalAssets(), supply);
}
uint256 o = _decimalsOffset();
if (o == uint256(0)) {
return FixedPointMathLib.fullMulDivUp(shares, totalAssets() + 1, _inc(totalSupply()));
}
return FixedPointMathLib.fullMulDivUp(shares, totalAssets() + 1, totalSupply() + 10 ** o);
}
/// @dev Allows an on-chain or off-chain user to simulate the effects of their withdrawal
/// at the current block, given the current on-chain conditions.
///
/// - MUST return as close to and no fewer than the exact amount of Vault shares that
/// will be burned in a withdraw call in the same transaction, i.e. withdraw should
/// return the same or fewer shares as `previewWithdraw` if call in the same transaction.
/// - MUST NOT account for withdrawal limits like those returned from `maxWithdraw` and should
/// always act as if the withdrawal will be accepted, regardless of share balance, etc.
/// - MUST be inclusive of withdrawal fees. Integrators should be aware of this.
/// - MUST not revert.
///
/// Note: Any unfavorable discrepancy between `convertToShares` and `previewWithdraw` SHOULD
/// be considered slippage in share price or some other type of condition,
/// meaning the depositor will lose assets by depositing.
function previewWithdraw(uint256 assets) public view virtual returns (uint256 shares) {
if (!_useVirtualShares()) {
uint256 supply = totalSupply();
return _eitherIsZero(assets, supply)
? _initialConvertToShares(assets)
: FixedPointMathLib.fullMulDivUp(assets, supply, totalAssets());
}
uint256 o = _decimalsOffset();
if (o == uint256(0)) {
return FixedPointMathLib.fullMulDivUp(assets, totalSupply() + 1, _inc(totalAssets()));
}
return FixedPointMathLib.fullMulDivUp(assets, totalSupply() + 10 ** o, _inc(totalAssets()));
}
/// @dev Allows an on-chain or off-chain user to simulate the effects of their redemption
/// at the current block, given current on-chain conditions.
///
/// - MUST return as close to and no more than the exact amount of assets that
/// will be withdrawn in a redeem call in the same transaction, i.e. redeem should
/// return the same or more assets as `previewRedeem` if called in the same transaction.
/// - MUST NOT account for redemption limits like those returned from `maxRedeem` and should
/// always act as if the redemption will be accepted, regardless of approvals, etc.
/// - MUST be inclusive of withdrawal fees. Integrators should be aware of this.
/// - MUST NOT revert.
///
/// Note: Any unfavorable discrepancy between `convertToAssets` and `previewRedeem` SHOULD
/// be considered slippage in share price or some other type of condition,
/// meaning the depositor will lose assets by depositing.
function previewRedeem(uint256 shares) public view virtual returns (uint256 assets) {
assets = convertToAssets(shares);
}
/// @dev Private helper to return if either value is zero.
function _eitherIsZero(uint256 a, uint256 b) private pure returns (bool result) {
/// @solidity memory-safe-assembly
assembly {
result := or(iszero(a), iszero(b))
}
}
/// @dev Private helper to return `x + 1` without the overflow check.
/// Used for computing the denominator input to `FixedPointMathLib.fullMulDiv(a, b, x + 1)`.
/// When `x == type(uint256).max`, we get `x + 1 == 0` (mod 2**256 - 1),
/// and `FixedPointMathLib.fullMulDiv` will revert as the denominator is zero.
function _inc(uint256 x) private pure returns (uint256) {
unchecked {
return x + 1;
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* DEPOSIT / WITHDRAWAL LIMIT LOGIC */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Returns the maximum amount of the underlying asset that can be deposited
/// into the Vault for `to`, via a deposit call.
///
/// - MUST return a limited value if `to` is subject to some deposit limit.
/// - MUST return `2**256-1` if there is no maximum limit.
/// - MUST NOT revert.
function maxDeposit(address to) public view virtual returns (uint256 maxAssets) {
to = to; // Silence unused variable warning.
maxAssets = type(uint256).max;
}
/// @dev Returns the maximum amount of the Vault shares that can be minter for `to`,
/// via a mint call.
///
/// - MUST return a limited value if `to` is subject to some mint limit.
/// - MUST return `2**256-1` if there is no maximum limit.
/// - MUST NOT revert.
function maxMint(address to) public view virtual returns (uint256 maxShares) {
to = to; // Silence unused variable warning.
maxShares = type(uint256).max;
}
/// @dev Returns the maximum amount of the underlying asset that can be withdrawn
/// from the `owner`'s balance in the Vault, via a withdraw call.
///
/// - MUST return a limited value if `owner` is subject to some withdrawal limit or timelock.
/// - MUST NOT revert.
function maxWithdraw(address owner) public view virtual returns (uint256 maxAssets) {
maxAssets = convertToAssets(balanceOf(owner));
}
/// @dev Returns the maximum amount of Vault shares that can be redeemed
/// from the `owner`'s balance in the Vault, via a redeem call.
///
/// - MUST return a limited value if `owner` is subject to some withdrawal limit or timelock.
/// - MUST return `balanceOf(owner)` otherwise.
/// - MUST NOT revert.
function maxRedeem(address owner) public view virtual returns (uint256 maxShares) {
maxShares = balanceOf(owner);
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* DEPOSIT / WITHDRAWAL LOGIC */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Mints `shares` Vault shares to `to` by depositing exactly `assets`
/// of underlying tokens.
///
/// - MUST emit the {Deposit} event.
/// - MAY support an additional flow in which the underlying tokens are owned by the Vault
/// contract before the deposit execution, and are accounted for during deposit.
/// - MUST revert if all of `assets` cannot be deposited, such as due to deposit limit,
/// slippage, insufficient approval, etc.
///
/// Note: Most implementations will require pre-approval of the Vault with the
/// Vault's underlying `asset` token.
function deposit(uint256 assets, address to) public virtual returns (uint256 shares) {
if (assets > maxDeposit(to)) _revert(0xb3c61a83); // `DepositMoreThanMax()`.
shares = previewDeposit(assets);
_deposit(msg.sender, to, assets, shares);
}
/// @dev Mints exactly `shares` Vault shares to `to` by depositing `assets`
/// of underlying tokens.
///
/// - MUST emit the {Deposit} event.
/// - MAY support an additional flow in which the underlying tokens are owned by the Vault
/// contract before the mint execution, and are accounted for during mint.
/// - MUST revert if all of `shares` cannot be deposited, such as due to deposit limit,
/// slippage, insufficient approval, etc.
///
/// Note: Most implementations will require pre-approval of the Vault with the
/// Vault's underlying `asset` token.
function mint(uint256 shares, address to) public virtual returns (uint256 assets) {
if (shares > maxMint(to)) _revert(0x6a695959); // `MintMoreThanMax()`.
assets = previewMint(shares);
_deposit(msg.sender, to, assets, shares);
}
/// @dev Burns `shares` from `owner` and sends exactly `assets` of underlying tokens to `to`.
///
/// - MUST emit the {Withdraw} event.
/// - MAY support an additional flow in which the underlying tokens are owned by the Vault
/// contract before the withdraw execution, and are accounted for during withdraw.
/// - MUST revert if all of `assets` cannot be withdrawn, such as due to withdrawal limit,
/// slippage, insufficient balance, etc.
///
/// Note: Some implementations will require pre-requesting to the Vault before a withdrawal
/// may be performed. Those methods should be performed separately.
function withdraw(uint256 assets, address to, address owner)
public
virtual
returns (uint256 shares)
{
if (assets > maxWithdraw(owner)) _revert(0x936941fc); // `WithdrawMoreThanMax()`.
shares = previewWithdraw(assets);
_withdraw(msg.sender, to, owner, assets, shares);
}
/// @dev Burns exactly `shares` from `owner` and sends `assets` of underlying tokens to `to`.
///
/// - MUST emit the {Withdraw} event.
/// - MAY support an additional flow in which the underlying tokens are owned by the Vault
/// contract before the redeem execution, and are accounted for during redeem.
/// - MUST revert if all of shares cannot be redeemed, such as due to withdrawal limit,
/// slippage, insufficient balance, etc.
///
/// Note: Some implementations will require pre-requesting to the Vault before a redeem
/// may be performed. Those methods should be performed separately.
function redeem(uint256 shares, address to, address owner)
public
virtual
returns (uint256 assets)
{
if (shares > maxRedeem(owner)) _revert(0x4656425a); // `RedeemMoreThanMax()`.
assets = previewRedeem(shares);
_withdraw(msg.sender, to, owner, assets, shares);
}
/// @dev Internal helper for reverting efficiently.
function _revert(uint256 s) internal pure {
/// @solidity memory-safe-assembly
assembly {
mstore(0x00, s)
revert(0x1c, 0x04)
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* INTERNAL HELPERS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev For deposits and mints.
///
/// Emits a {Deposit} event.
function _deposit(address by, address to, uint256 assets, uint256 shares) internal virtual {
SafeTransferLib.safeTransferFrom(asset(), by, address(this), assets);
_mint(to, shares);
/// @solidity memory-safe-assembly
assembly {
// Emit the {Deposit} event.
mstore(0x00, assets)
mstore(0x20, shares)
let m := shr(96, not(0))
log3(0x00, 0x40, _DEPOSIT_EVENT_SIGNATURE, and(m, by), and(m, to))
}
_afterDeposit(assets, shares);
}
/// @dev For withdrawals and redemptions.
///
/// Emits a {Withdraw} event.
function _withdraw(address by, address to, address owner, uint256 assets, uint256 shares)
internal
virtual
{
if (by != owner) _spendAllowance(owner, by, shares);
_beforeWithdraw(assets, shares);
_burn(owner, shares);
SafeTransferLib.safeTransfer(asset(), to, assets);
/// @solidity memory-safe-assembly
assembly {
// Emit the {Withdraw} event.
mstore(0x00, assets)
mstore(0x20, shares)
let m := shr(96, not(0))
log4(0x00, 0x40, _WITHDRAW_EVENT_SIGNATURE, and(m, by), and(m, to), and(m, owner))
}
}
/// @dev Internal conversion function (from assets to shares) to apply when the Vault is empty.
/// Only used when {_useVirtualShares} returns false.
///
/// Note: Make sure to keep this function consistent with {_initialConvertToAssets}
/// when overriding it.
function _initialConvertToShares(uint256 assets)
internal
view
virtual
returns (uint256 shares)
{
shares = assets;
}
/// @dev Internal conversion function (from shares to assets) to apply when the Vault is empty.
/// Only used when {_useVirtualShares} returns false.
///
/// Note: Make sure to keep this function consistent with {_initialConvertToShares}
/// when overriding it.
function _initialConvertToAssets(uint256 shares)
internal
view
virtual
returns (uint256 assets)
{
assets = shares;
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* HOOKS TO OVERRIDE */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Hook that is called before any withdrawal or redemption.
function _beforeWithdraw(uint256 assets, uint256 shares) internal virtual {}
/// @dev Hook that is called after any deposit or mint.
function _afterDeposit(uint256 assets, uint256 shares) internal virtual {}
}
// contracts/libraries/PluginDelegable.sol
/// @title Curvance Plugin Delegation Manager.
/// @notice Facilitates delegated actions on behalf of a user inside Curvance.
/// @dev `PluginDelegable` allows the Curvance Protocol to be a modular system
/// that plugins can be built on top of. By delegating action authority
/// to an address or addresses users can utilize potential third-party
/// features such as limit orders, crosschain actions, reward auto
/// compounding, chained (multiple sequential) actions, etc.
abstract contract PluginDelegable is IPluginDelegable {
/// CONSTANTS ///
/// @notice Curvance DAO Hub.
ICentralRegistry public immutable centralRegistry;
/// STORAGE ///
/// @notice Status of whether a user or contract has the ability to act
/// on behalf of an account.
/// @dev Account address => approval index => Spender address => Can act
/// on behalf of account.
mapping(address => mapping(uint256 => mapping(address => bool)))
internal _isDelegate;
/// EVENTS ///
event DelegateApproval(
address indexed owner,
address indexed delegate,
uint256 approvalIndex,
bool isApproved
);
/// ERRORS ///
error PluginDelegable__Unauthorized();
error PluginDelegable__DelegatingDisabled();
error PluginDelegable_InvalidParameter();
/// CONSTRUCTOR ///
/// @param cr The address of the Central Registry contract.
constructor(ICentralRegistry cr) {
CentralRegistryLib._isCentralRegistry(cr);
centralRegistry = cr;
}
/// EXTERNAL FUNCTIONS ///
/// @notice Approves or restricts `delegate`'s authority to operate
/// on the caller's behalf.
/// @dev NOTE: Be careful who you approve here!
/// They can delay actions such as asset redemption through repeated
/// denial of service.
/// Emits a {DelegateApproval} event.
/// @param delegate The address that will be approved or restricted
/// from delegated actions on behalf of the caller.
/// @param isApproved Whether `delegate` is being approved or restricted
/// of authority to operate on behalf of caller.
function setDelegateApproval(address delegate, bool isApproved) external {
if (delegate == msg.sender) {
revert PluginDelegable_InvalidParameter();
}
// Validate that new delegation configuration is current allowed for
// the caller.
if (centralRegistry.checkNewDelegationDisabled(msg.sender)) {
revert PluginDelegable__DelegatingDisabled();
}
uint256 currentIndex = centralRegistry.userApprovalIndex(msg.sender);
_isDelegate[msg.sender][currentIndex][delegate] = isApproved;
emit DelegateApproval(msg.sender, delegate, currentIndex, isApproved);
}
/// @notice Returns `user`'s current approval index value.
/// @dev The approval index is a way to revoke approval on all tokens,
/// and features at once if a malicious delegation was allowed by
/// `user`.
/// @param user The user to check delegated approval index for.
/// @return result The `user`'s current approval index value.
function userApprovalIndex(
address user
) external view returns (uint256 result) {
result = centralRegistry.userApprovalIndex(user);
}
/// @notice Returns whether `delegate` has the ability to act on behalf of
/// `user`.
/// @param user The address to check whether `delegate` has delegation
/// permissions for.
/// @param delegate The address to check delegation permissions of `user`.
/// @return result Indicates whether `delegate` is an approved delegate or
/// not of `user`, true = is a delegate, false = is not
/// a delegate.
function isDelegate(
address user,
address delegate
) external view returns (bool result) {
result = _isDelegate[user][centralRegistry
.userApprovalIndex(user)][delegate];
}
/// @notice Returns whether a user has delegation disabled.
/// @dev This is not a silver bullet for phishing attacks, but, adds
/// an additional wall of defense.
/// @param user The user to check delegation status for.
/// @return result Indicates whether `user` has delegation disabled
/// or not, true = disabled, false = not disabled.
function checkNewDelegationDisabled(
address user
) external view returns (bool result) {
result = centralRegistry.checkNewDelegationDisabled(user);
}
/// INTERNAL FUNCTIONS ///
/// @notice Checks whether `delegate` has the ability to act on behalf of
/// `user`, reverts if they do not.
/// @param user The address to check whether `delegate` has delegation
/// permissions for.
/// @param delegate The address to check delegation permissions of `user`.
function _checkDelegate(address user, address delegate) internal view {
if (
!_isDelegate[user][centralRegistry
.userApprovalIndex(user)][delegate]
) {
revert PluginDelegable__Unauthorized();
}
}
}
// contracts/interfaces/IBorrowableCToken.sol
interface IBorrowableCToken {
/// ICToken GENERIC FUNCTIONS ///
/// @notice Starts a cToken market, executed via marketManager.
/// @dev This initial mint is a failsafe against rounding exploits,
/// although, we protect against them in many ways,
/// better safe than sorry.
/// @param by The account initializing deposits.
function initializeDeposits(address by) external returns (bool);
/// @notice Returns the decimals of the cToken.
/// @dev We pull directly from underlying incase its a proxy contract,
/// and changes decimals on us.
/// @return The number of decimals for this cToken,
/// matching the underlying token.
function decimals() external view returns (uint8);
/// @notice Returns whether the underlying token can be borrowed.
/// @dev true = Borrowable; false = Not Borrowable.
/// @return Whether this token is borrowable or not.
function isBorrowable() external view returns (bool);
/// @notice The token balance of an account.
/// @dev Account address => account token balance.
/// @param account The address of the account to query token balance for.
function balanceOf(address account) external view returns (uint256);
/// @notice Returns the address of the underlying asset.
/// @return The address of the underlying asset.
function asset() external view returns (address);
/// @notice Returns the current vesting yield information.
/// @return vestingRate % per second in `asset()`.
/// @return vestingEnd When the current vesting period ends and interest
/// rates paid will update.
/// @return lastVestingClaim Last time pending vested yield was claimed.
/// @return debtIndex The current market debt index.
function getYieldInformation() external view returns (
uint256 vestingRate,
uint256 vestingEnd,
uint256 lastVestingClaim,
uint256 debtIndex
);
/// @notice Get a snapshot of `account` data in this Curvance token.
/// @dev Used by marketManager to more efficiently perform
/// liquidity checks.
/// NOTE: Does not accrue pending interest as part of the call.
/// @param account The address of the account to snapshot.
/// @return The account snapshot of `account`.
function getSnapshot(
address account
) external view returns (AccountSnapshot memory);
/// @notice Total number of cTokens in circulation.
function totalSupply() external view returns (uint256);
/// @notice Returns the total amount of assets held by the market.
/// @return The total amount of assets held by the market.
function totalAssets() external view returns (uint256);
/// @notice Address of the Market Manager linked to this contract.
function marketManager() external view returns (IMarketManager);
/// @notice Returns the amount of assets that would be exchanged
/// by the vault for `shares` provided.
/// @param shares The number of shares to theoretically use
/// for conversion to assets.
/// @return The number of assets a user would receive for converting
/// `shares`.
function convertToAssets(uint256 shares) external view returns (uint256);
/// @notice Returns share -> asset exchange rate, in `WAD`.
/// @dev Oracle Manager calculates cToken value from this exchange rate.
function exchangeRate() external view returns (uint256);
/// @notice Executes multiple calls in a single transaction.
/// This can be used to update oracle prices before
/// a liquidity dependent action.
function multicall(
Multicall.MulticallAction[] memory calls
) external returns (bytes[] memory results);
/// @notice Caller deposits `assets` into the market and `receiver`
/// receives shares.
/// @param assets The amount of the underlying assets to deposit.
/// @param receiver The account that should receive the shares.
/// @return shares The amount of shares received by `receiver`.
function deposit(
uint256 assets,
address receiver
) external returns (uint256 shares);
/// @notice Caller deposits `assets` into the market, `receiver` receives
/// shares, and collateralization of `assets` is enabled.
/// @dev The caller must be depositing for themselves, or be managing
/// their position through a Position Manager contract.
/// If the caller is not approved to collateralize the function will
/// simply deposit assets on behalf of `receiver`.
/// @param assets The amount of the underlying assets to deposit.
/// @param receiver The account that should receive the shares.
/// @return shares The amount of shares received by `receiver`.
function depositAsCollateral(
uint256 assets,
address receiver
) external returns (uint256 shares);
/// @notice Caller deposits `assets` into the market, `receiver` receives
/// shares, and collateralization of `assets` is enabled.
/// @dev Requires that `receiver` approves the caller prior to
/// collateralize on their behalf.
/// NOTE: Be careful who you approve here!
/// They can delay redemption of assets through repeated
/// collateralization preventing withdrawal.
/// If the caller is not approved to collateralize the function will
/// simply deposit assets on behalf of `receiver`.
/// @param assets The amount of the underlying assets to deposit.
/// @param receiver The account that should receive the shares.
/// @return shares The amount of shares received by `receiver`.
function depositAsCollateralFor(
uint256 assets,
address receiver
) external returns (uint256 shares);
/// @notice Withdraws assets, quoted in `shares` from the market,
/// and burns `owner` shares.
/// @dev Does not force collateral to be withdrawn.
/// @param shares The amount of shares to be redeemed.
/// @param receiver The account that should receive the assets.
/// @param owner The account that will burn their shares to withdraw
/// assets.
/// @return assets The amount of assets redeemed by `owner`.
function redeem(
uint256 shares,
address receiver,
address owner
) external returns (uint256 assets);
/// @notice Withdraws assets, quoted in `shares` from the market,
/// and burns `owner` shares, sending assets to `receiver`.
/// @dev Does not force collateral to be withdrawn.
/// @param shares The amount of shares to redeemed.
/// @param receiver The account that should receive the assets.
/// @param owner The account that will burn their shares to withdraw
/// assets.
/// @return assets The amount of assets redeemed by `owner` and sent to
/// `receiver`.
function redeemFor(
uint256 shares,
address receiver,
address owner
) external returns (uint256 assets);
/// @notice Caller withdraws assets from the market and burns their
/// shares, on behalf of `owner`.
/// @dev Forces collateral to be withdrawn from `owner` collateralPosted.
/// @param shares The amount of shares to redeemed.
/// @param receiver The account that should receive the assets.
/// @param owner The account that will burn their shares to withdraw
/// assets.
/// @return assets The amount of assets redeemed by `owner` and sent to
/// `receiver`.
function redeemCollateralFor(
uint256 shares,
address receiver,
address owner
) external returns (uint256 assets);
/// @notice Used by a Position Manager contract to redeem assets from
/// collateralized shares by `account` to perform a complex
/// action.
/// @param assets The amount of the underlying assets to redeem.
/// @param owner The owner address of assets to redeem.
/// @param action Instructions for a deleverage action containing:
/// cToken Address of the cToken that will be redeemed from
/// and assets swapped into `borrowableCToken` asset.
/// collateralAssets The amount of `cToken` that will be
/// deleveraged, in assets.
/// borrowableCToken Address of the borrowableCToken that
/// will have its debt paid.
/// repayAssets The amount of `borrowableCToken` asset that
/// will be repaid to lenders.
/// swapActions Swap actions instructions converting
/// collateral asset into debt asset to
/// facilitate deleveraging.
/// auxData Optional auxiliary data for execution of a
/// deleverage action.
function withdrawByPositionManager(
uint256 assets,
address owner,
IPositionManager.DeleverageAction memory action
) external;
/// @notice Amount of tokens that has been posted as collateral,
/// in shares.
function marketCollateralPosted() external view returns (uint256);
/// @notice Shares of this token that an account has posted as collateral.
/// @param account The address of the account to check collateral posted
/// of.
function collateralPosted(address account) external view returns (uint256);
/// @notice Transfers tokens from `account` to `liquidator`.
/// @dev Will fail unless called by a cToken during the process
/// of liquidation.
/// @param shares An array containing the number of cToken shares
/// to seize.
/// @param liquidator The account receiving seized cTokens.
/// @param accounts An array containing the accounts having
/// collateral seized.
function seize(
uint256[] calldata shares,
address liquidator,
address[] calldata accounts
) external;
/// @notice Allows users to simulate the effects of their deposit at
/// the current block.
/// @param assets The number of assets to preview a deposit call.
/// @return The shares received for depositing `assets`.
function previewDeposit(uint256 assets) external view returns (uint256);
/// IBorrowableCToken SPECIFIC FUNCTIONS ///
/// @notice Address of the current Dynamic IRM.
function IRM() external view returns (IDynamicIRM);
/// @notice Fee that goes to protocol for interested generated for
/// lenders, in `WAD`.
function interestFee() external view returns (uint256);
/// @notice Can accrue interest yield, configure next interest accrual
/// period, and updates vesting data, if needed.
/// @dev May emit a {RatesAdjusted} event.
function accrueIfNeeded() external;
/// @notice The amount of tokens that has been borrowed as debt,
/// in assets.
function marketOutstandingDebt() external view returns (uint256);
/// @notice Returns the current debt balance for `account`.
/// @dev Note: Pending interest is not applied in this calculation.
/// @param account The address whose debt balance should be calculated.
/// @return result The current outstanding debt balance of `account`.
function debtBalance(
address account
) external view returns (uint256 result);
/// @notice Updates pending interest and returns the current outstanding
/// debt owed by `account`.
/// @param account The address whose debt balance should be calculated.
/// @return result The current outstanding debt of `account`, with pending
/// interest applied.
function debtBalanceUpdated(
address account
) external returns (uint256 result);
/// @notice Updates pending interest and returns the up-to-date exchange
/// rate from the underlying to the BorrowableCToken.
/// @return result The share -> asset exchange rate, in `WAD`.
function exchangeRateUpdated() external returns (uint256);
/// @notice Used by a delegated user to borrow underlying tokens
/// from lenders, based on collateral posted inside this market
/// by `account`.
/// @dev Updates pending interest before executing the borrow.
/// NOTE: Be careful who you approve here!
/// Not only can they take borrowed funds, but, they can delay
/// repayment through repeated borrows preventing withdrawal.
/// @param assets The amount of the underlying asset to borrow.
/// @param receiver The account who will receive the borrowed assets.
/// @param owner The account who will have their assets borrowed
/// against.
function borrowFor(
uint256 assets,
address receiver,
address owner
) external;
/// @notice Used by a Position Manager contract to borrow assets from
/// lenders, based on collateralized shares by `account` to
/// perform a complex action.
/// @param assets The amount of the underlying assets to borrow.
/// @param owner The account address to borrow on behalf of.
/// @param action Instructions for a leverage action containing:
/// borrowableCToken Address of the borrowableCToken that
/// will be borrowed from and assets
/// swapped into `cToken` asset.
/// borrowAssets The amount borrowed from
/// `borrowableCToken`, in assets.
/// cToken Curvance token assets that borrowed funds will be
/// swapped into.
/// swapAction Swap action instructions converting debt
/// asset into collateral asset to facilitate
/// leveraging.
/// auxData Optional auxiliary data for execution of a
/// leverage action.
function borrowForPositionManager(
uint256 assets,
address owner,
IPositionManager.LeverageAction memory action
) external;
/// @notice Repays underlying tokens to lenders, on behalf of `account`,
/// freeing up their collateral posted inside this market.
/// @dev Updates pending interest before executing the repay.
/// @param assets The amount to repay, or 0 for the full outstanding
/// amount.
/// @param owner The account address to repay on behalf of.
function repayFor(uint256 assets, address owner) external;
/// @notice Gets balance of this contract, in terms of the underlying.
/// @dev This excludes changes in underlying token balance by the
/// current transaction, if any.
/// @return The quantity of underlying tokens held by the market.
function assetsHeld() external view returns (uint256);
}
// contracts/interfaces/ICToken.sol
struct AccountSnapshot {
address asset;
address underlying;
uint8 decimals;
bool isCollateral;
uint256 collateralPosted;
uint256 debtBalance;
}
interface ICToken {
/// @notice Starts a cToken market, executed via marketManager.
/// @dev This initial mint is a failsafe against rounding exploits,
/// although, we protect against them in many ways,
/// better safe than sorry.
/// @param by The account initializing deposits.
function initializeDeposits(address by) external returns (bool);
/// @notice Returns the decimals of the cToken.
/// @dev We pull directly from underlying incase its a proxy contract,
/// and changes decimals on us.
/// @return The number of decimals for this cToken,
/// matching the underlying token.
function decimals() external view returns (uint8);
function name() external view returns (string memory);
function symbol() external view returns (string memory);
/// @notice Returns whether the underlying token can be borrowed.
/// @dev true = Borrowable; false = Not Borrowable.
/// @return Whether this token is borrowable or not.
function isBorrowable() external view returns (bool);
/// @notice The token balance of an account.
/// @dev Account address => account token balance.
/// @param account The address of the account to query token balance for.
function balanceOf(address account) external view returns (uint256);
/// @notice Returns the address of the underlying asset.
/// @return The address of the underlying asset.
function asset() external view returns (address);
/// @notice Updates pending assets and returns a snapshot of the cToken
/// and `account` data.
/// @dev Used by marketManager to more efficiently perform
/// liquidity checks.
/// @return result The snapshot of the cToken and `account` data.
function getSnapshotUpdated(
address account
) external returns (AccountSnapshot memory result);
/// @notice Get a snapshot of `account` data in this Curvance token.
/// @dev NOTE: Does not accrue pending assets as part of the call.
/// @param account The address of the account to snapshot.
/// @return The account snapshot of `account`.
function getSnapshot(
address account
) external view returns (AccountSnapshot memory);
/// @notice Total number of cTokens in circulation.
function totalSupply() external view returns (uint256);
/// @notice Returns the total amount of assets held by the market.
/// @return The total amount of assets held by the market.
function totalAssets() external view returns (uint256);
/// @notice Address of the Market Manager linked to this contract.
function marketManager() external view returns (IMarketManager);
/// @notice Returns the amount of assets that would be exchanged
/// by the vault for `shares` provided.
/// @param shares The number of shares to theoretically use
/// for conversion to assets.
/// @return The number of assets a user would receive for converting
/// `shares`.
function convertToAssets(uint256 shares) external view returns (uint256);
/// @notice Updates pending assets and returns the up-to-date exchange
/// rate from the underlying to the BorrowableCToken.
/// @dev Oracle Manager calculates cToken value from this exchange rate.
/// @return The share -> asset exchange rate, in `WAD`.
function exchangeRateUpdated() external returns (uint256) ;
/// @notice Returns the up-to-date exchange rate from the underlying to
/// the BorrowableCToken.
/// @dev Oracle Manager calculates cToken value from this exchange rate.
/// @return The share -> asset exchange rate, in `WAD`.
function exchangeRate() external view returns (uint256);
/// @notice Executes multiple calls in a single transaction.
/// This can be used to update oracle prices before
/// a liquidity dependent action.
function multicall(
Multicall.MulticallAction[] memory calls
) external returns (bytes[] memory results);
/// @notice Caller deposits `assets` into the market and `receiver`
/// receives shares.
/// @param assets The amount of the underlying assets to deposit.
/// @param receiver The account that should receive the shares.
/// @return shares The amount of shares received by `receiver`.
function deposit(
uint256 assets,
address receiver
) external returns (uint256 shares);
/// @notice Caller deposits `assets` into the market, `receiver` receives
/// shares, and collateralization of `assets` is enabled.
/// @dev The caller must be depositing for themselves, or be managing
/// their position through a Position Manager contract.
/// @param assets The amount of the underlying assets to deposit.
/// @param receiver The account that should receive the shares.
/// @return shares The amount of shares received by `receiver`.
function depositAsCollateral(
uint256 assets,
address receiver
) external returns (uint256 shares);
/// @notice Caller deposits `assets` into the market, `receiver` receives
/// shares, and collateralization of `assets` is enabled.
/// @dev Requires that `receiver` approves the caller prior to
/// collateralize on their behalf.
/// NOTE: Be careful who you approve here!
/// They can delay redemption of assets through repeated
/// collateralization preventing withdrawal.
/// @param assets The amount of the underlying assets to deposit.
/// @param receiver The account that should receive the shares.
/// @return shares The amount of shares received by `receiver`.
function depositAsCollateralFor(
uint256 assets,
address receiver
) external returns (uint256 shares);
/// @notice Withdraws assets, quoted in `shares` from the market,
/// and burns `owner` shares.
/// @dev Does not force collateral to be withdrawn.
/// @param shares The amount of shares to be redeemed.
/// @param receiver The account that should receive the assets.
/// @param owner The account that will burn their shares to withdraw
/// assets.
/// @return assets The amount of assets redeemed by `owner`.
function redeem(
uint256 shares,
address receiver,
address owner
) external returns (uint256 assets);
/// @notice Withdraws assets, quoted in `shares` from the market,
/// and burns `owner` shares, sending assets to `receiver`.
/// @dev Does not force collateral to be withdrawn.
/// @param shares The amount of shares to redeemed.
/// @param receiver The account that should receive the assets.
/// @param owner The account that will burn their shares to withdraw
/// assets.
/// @return assets The amount of assets redeemed by `owner` and sent to
/// `receiver`.
function redeemFor(
uint256 shares,
address receiver,
address owner
) external returns (uint256 assets);
/// @notice Caller withdraws assets from the market and burns their
/// shares, on behalf of `owner`.
/// @dev Forces collateral to be withdrawn from `owner` collateralPosted.
/// @param shares The amount of shares to redeemed.
/// @param receiver The account that should receive the assets.
/// @param owner The account that will burn their shares to withdraw
/// assets.
/// @return assets The amount of assets redeemed by `owner` and sent to
/// `receiver`.
function redeemCollateralFor(
uint256 shares,
address receiver,
address owner
) external returns (uint256 assets);
/// @notice Used by a Position Manager contract to redeem assets from
/// collateralized shares by `account` to perform a complex
/// action.
/// @param assets The amount of the underlying assets to redeem.
/// @param owner The owner address of assets to redeem.
/// @param action Instructions for a deleverage action containing:
/// cToken Address of the cToken that will be redeemed from
/// and assets swapped into `borrowableCToken` asset.
/// collateralAssets The amount of `cToken` that will be
/// deleveraged, in assets.
/// borrowableCToken Address of the borrowableCToken that
/// will have its debt paid.
/// repayAssets The amount of `borrowableCToken` asset that
/// will be repaid to lenders.
/// swapActions Swap actions instructions converting
/// collateral asset into debt asset to
/// facilitate deleveraging.
/// auxData Optional auxiliary data for execution of a
/// deleverage action.
function withdrawByPositionManager(
uint256 assets,
address owner,
IPositionManager.DeleverageAction memory action
) external;
/// @notice Amount of tokens that has been posted as collateral,
/// in shares.
function marketCollateralPosted() external view returns (uint256);
/// @notice Shares of this token that an account has posted as collateral.
/// @param account The address of the account to check collateral posted
/// of.
function collateralPosted(address account) external view returns (uint256);
/// @notice Transfers tokens from `account` to `liquidator`.
/// @dev Will fail unless called by a cToken during the process
/// of liquidation.
/// @param shares An array containing the number of cToken shares
/// to seize.
/// @param liquidator The account receiving seized cTokens.
/// @param accounts An array containing the accounts having
/// collateral seized.
function seize(
uint256[] calldata shares,
address liquidator,
address[] calldata accounts
) external;
/// @notice Allows users to simulate the effects of their deposit at
/// the current block.
/// @param assets The number of assets to preview a deposit call.
/// @return The shares received for depositing `assets`.
function previewDeposit(uint256 assets) external view returns (uint256);
}
// contracts/interfaces/IExternalCalldataChecker.sol
interface IExternalCalldataChecker {
/// @notice Inspects calldata for compliance with other swap instruction
/// parameters.
/// @dev Used on swap to inspect and validate calldata safety.
/// @param swapAction Swap action instructions including both direct
/// parameters and decodeable calldata.
/// @param expectedRecipient Address who will receive proceeds of
/// `swapAction`.
function checkCalldata(
SwapperLib.Swap memory swapAction,
address expectedRecipient
) external returns (uint256);
}
// contracts/interfaces/IOracleManager.sol
interface IOracleManager {
/// @notice Retrieves the price of a specified asset from either single
/// or dual oracles.
/// @dev If the asset has one oracle, it fetches the price from a single feed.
/// If it has two or more oracles, it fetches the price from both feeds.
/// @param asset The address of the asset to retrieve the price for.
/// @param inUSD Whether the price should be returned in USD or ETH.
/// @param getLower Whether the lower or higher price should be returned
/// if two feeds are available.
/// @return price The current price of `asset`.
/// @return errorCode An error code related to fetching the price:
/// '0' indicates no error fetching price.
/// '1' indicates that price should be taken with
/// caution.
/// '2' indicates a complete failure in receiving
/// a price.
function getPrice(
address asset,
bool inUSD,
bool getLower
) external view returns (uint256 price, uint256 errorCode);
/// @notice Retrieves the prices of a collateral token and debt token
/// underlyings.
/// @param collateralToken The cToken currently collateralized to price.
/// @param debtToken The cToken borrowed from to price.
/// @param errorCodeBreakpoint The error code that will cause liquidity
/// operations to revert.
/// @return collateralUnderlyingPrice The current price of
/// `collateralToken` underlying.
/// @return debtUnderlyingPrice The current price of `debtToken`
/// underlying.
function getPriceIsolatedPair(
address collateralToken,
address debtToken,
uint256 errorCodeBreakpoint
) external returns (uint256, uint256);
/// @notice Retrieves the prices and account data of multiple assets
/// inside a Curvance Market.
/// @param account The account to retrieve data for.
/// @param assets An array of asset addresses to retrieve the prices for.
/// @param errorCodeBreakpoint The error code that will cause liquidity
/// operations to revert.
/// @return AccountSnapshot[] Contains `assets` data for `account`
/// @return uint256[] Contains prices for `assets`.
/// @return uint256 The number of assets `account` is in.
function getPricesForMarket(
address account,
address[] calldata assets,
uint256 errorCodeBreakpoint
)
external
returns (AccountSnapshot[] memory, uint256[] memory, uint256);
/// @notice Potentially removes the dependency on pricing from `adaptor`
/// for `asset`, triggered by an adaptor's notification of a price
/// feed's removal.
/// @notice Removes a pricing adaptor for `asset` triggered by an
/// adaptor's notification of a price feed's removal.
/// @dev Requires that the adaptor is currently being used for pricing
/// for `asset`.
/// NOTE: This intentionally does not modify asset deviation values
/// because they simply wont be used if there are less than two
/// pricing adaptors in use, so no reason to delete data as
/// when a second pricing adaptor is configured the deviation
/// has the opportunity be to reconfigured anyway.
/// @param asset The address of the asset to potentially remove the
/// pricing adaptor dependency from depending on current
/// `asset` configuration.
function notifyFeedRemoval(address asset) external;
/// @notice Returns the adaptors used for pricing `asset`.
/// @param asset The address of the asset to get pricing adaptors for.
/// @return The current adaptor(s) used for pricing `asset`.
function getPricingAdaptors(
address asset
) external view returns(address[] memory);
/// @notice Address => Adaptor approval status.
/// @param adaptor The address of the adaptor to check.
/// @return True if the adaptor is supported, false otherwise.
function isApprovedAdaptor(address adaptor) external view returns (bool);
/// @notice Whether a token is recognized as a Curvance token or not,
/// if it is, will return its underlying asset address instead
/// of address (0).
/// @return The cToken's underlying asset, or address(0) if not a cToken.
function cTokens(address cToken) external view returns (address);
/// @notice Checks if a given asset is supported by the Oracle Manager.
/// @dev An asset is considered supported if it has one
/// or more associated price feeds.
/// @param asset The address of the asset to check.
/// @return True if the asset is supported, false otherwise.
function isSupportedAsset(address asset) external view returns (bool);
/// @notice Check whether L2 sequencer is valid or down.
/// @return True if sequencer is valid.
function isSequencerValid() external view returns (bool);
}
// contracts/interfaces/IPositionManager.sol
interface IPositionManager {
/// TYPES ///
/// @notice Instructions for a leverage action.
/// @param borrowableCToken Address of the borrowableCToken that will be
/// borrowed from and assets swapped into `cToken`
/// asset.
/// @param borrowAssets The amount borrowed from `borrowableCToken`,
/// in assets.
/// @param cToken Curvance token assets that borrowed funds will be
/// swapped into.
/// @param expectedShares The expected shares received from depositing
/// into `cToken` with swapped `borrowAssets`.
/// @param swapAction Swap action instructions converting debt asset into
/// collateral asset to facilitate leveraging.
/// @param auxData Optional auxiliary data for execution of a leverage
/// action.
struct LeverageAction {
IBorrowableCToken borrowableCToken;
uint256 borrowAssets;
ICToken cToken;
uint256 expectedShares;
SwapperLib.Swap swapAction;
bytes auxData;
}
/// @notice Instructions for a deleverage action.
/// @param cToken Address of the cToken that will be redeemed from and
/// assets swapped into `borrowableCToken` asset.
/// @param collateralAssets The amount of `cToken` that will be
/// deleveraged, in assets.
/// @param borrowableCToken Address of the borrowableCToken that will
/// have its debt paid.
/// @param repayAssets The amount of `borrowableCToken` asset that will
/// be repaid to lenders.
/// @param swapActions Swap actions instructions converting collateral
/// asset into debt asset to facilitate deleveraging.
/// @param auxData Optional auxiliary data for execution of a deleverage
/// action.
struct DeleverageAction {
ICToken cToken;
uint256 collateralAssets;
IBorrowableCToken borrowableCToken;
uint256 repayAssets;
SwapperLib.Swap[] swapActions;
bytes auxData;
}
/// @notice Callback function to execute post borrow of
/// `borrowableCToken`'s asset and swap it to deposit
/// new collateralized shares for `owner`.
/// @dev Measures slippage after this callback validating that `owner`
/// is still within acceptable liquidity requirements.
/// @param borrowableCToken The borrowableCToken borrowed from.
/// @param borrowAssets The amount of `borrowableCToken`'s asset borrowed.
/// @param owner The account borrowing that will be swapped into
/// collateral assets deposited into Curvance.
/// @param action Instructions for a leverage action containing:
/// borrowableCToken Address of the borrowableCToken that
/// will be borrowed from and assets
/// swapped into `cToken` asset.
/// borrowAssets The amount borrowed from
/// `borrowableCToken`, in assets.
/// cToken Curvance token assets that borrowed funds will be
/// swapped into.
/// swapAction Swap action instructions converting debt
/// asset into collateral asset to facilitate
/// leveraging.
/// auxData Optional auxiliary data for execution of a
/// leverage action.
function onBorrow(
address borrowableCToken,
uint256 borrowAssets,
address owner,
LeverageAction memory action
) external;
/// @notice Callback function to execute post redemption of `cToken`'s
/// asset and swap it to repay outstanding debt for `owner`.
/// @dev Measures slippage after this callback validating that `owner`
/// is still within acceptable liquidity requirements.
/// @param cToken The Curvance token redeemed for its underlying.
/// @param collateralAssets The amount of `cToken` underlying redeemed.
/// @param owner The account redeeming collateral that will be used to
/// repay their active debt.
/// @param action Instructions for a deleverage action containing:
/// cToken Address of the cToken that will be redeemed from
/// and assets swapped into `borrowableCToken` asset.
/// collateralAssets The amount of `cToken` that will be
/// deleveraged, in assets.
/// borrowableCToken Address of the borrowableCToken that
/// will have its debt paid.
/// repayAssets The amount of `borrowableCToken` asset that
/// will be repaid to lenders.
/// swapAction Swap actions instructions converting
/// collateral asset into debt asset to
/// facilitate deleveraging.
/// auxData Optional auxiliary data for execution of a
/// deleverage action.
function onRedeem(
address cToken,
uint256 collateralAssets,
address owner,
DeleverageAction memory action
) external;
}
// contracts/libraries/CommonLib.sol
/// @title Curvance Common Library
/// @notice A utility library for common functions used throughout the
/// Curvance Protocol.
library CommonLib {
/// @notice Returns whether `tokenA` matches `tokenB` or not.
/// @param tokenA The first token address to compare.
/// @param tokenB The second token address to compare.
/// @return Whether `tokenA` matches `tokenB` or not.
function _isMatchingToken(
address tokenA,
address tokenB
) internal pure returns (bool) {
if (tokenA == tokenB) {
return true;
}
if (_isNative(tokenA) && _isNative(tokenB)) {
return true;
}
return false;
}
/// @notice Returns whether `token` is referring to network gas token
/// or not.
/// @param token The address to review.
/// @return result Whether `token` is referring to network gas token or
/// not.
function _isNative(address token) internal pure returns (bool result) {
result = token == address(0) ||
token == 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
}
/// @notice Returns balance of `token` for this contract.
/// @param token The token address to query balance of.
/// @return b The balance of `token` inside address(this).
function _balanceOf(address token) internal view returns (uint256 b) {
b = _isNative(token) ? address(this).balance :
IERC20(token).balanceOf(address(this));
}
/// @notice Returns the Oracle Manager in interface form from `cr`.
/// @param cr The address of the Protocol Central Registry.
/// @return oracleManager The Oracle Manager in interface form.
function _oracleManager(
ICentralRegistry cr
) internal view returns (IOracleManager oracleManager) {
oracleManager = IOracleManager(cr.oracleManager());
}
}
// contracts/libraries/SwapperLib.sol
/// @title Curvance Swapper Library.
/// @notice Helper Library for performing composable swaps with varying
/// degrees of slippage tolerance. "Unsafe" swaps perform a standard
/// slippage check whereas "safe" swaps not only check for standard
/// slippage but also check against the Oracle Manager's prices as
/// well.
/// NOTE: This library does not intend to provide support for fee on
/// transfer tokens though support may be built in the future.
library SwapperLib {
/// TYPES ///
/// @notice Instructions to execute a swap, selling `inputToken` for
/// `outputToken`.
/// @param inputToken Address of input token to swap from.
/// @param inputAmount The amount of `inputToken` to swap.
/// @param outputToken Address of token to swap into.
/// @param target Address of the swapper, usually an aggregator.
/// @param slippage The amount of value-loss acceptable from swapping
/// between tokens.
/// @param call Swap instruction calldata.
struct Swap {
address inputToken;
uint256 inputAmount;
address outputToken;
address target;
uint256 slippage;
bytes call;
}
/// @notice Address identifying a chain's native token.
address public constant native =
0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
/// ERRORS ///
error SwapperLib__UnknownCalldata();
error SwapperLib__TokenPrice(address inputToken);
error SwapperLib__Slippage(uint256 slippage);
error SwapperLib__SameTokens();
/// INTERNAL FUNCTIONS ///
/// @notice Swaps `action.inputToken` into a `action.outputToken`
/// without an extra slippage check.
/// @param cr The address of the Protocol Central Registry to pull
/// addresses from.
/// @param action Instructions for a swap action containing:
/// inputToken Address of input token to swap from.
/// inputAmount The amount of `inputToken` to swap.
/// outputToken Address of token to swap into.
/// target Address of the swapper, usually an aggregator.
/// slippage The amount of value-loss acceptable from
/// swapping between tokens.
/// call Swap instruction calldata.
/// @return outAmount The output amount received from swapping.
function _swapUnsafe(
ICentralRegistry cr,
Swap memory action
) internal returns (uint256 outAmount) {
address outputToken = action.outputToken;
address inputToken = action.inputToken;
// Do not use this library if the tokens are the same.
if (CommonLib._isMatchingToken(inputToken, outputToken)) {
revert SwapperLib__SameTokens();
}
address callDataChecker = cr.externalCalldataChecker(action.target);
// Validate we know how to verify this calldata.
if (callDataChecker == address(0)) {
revert SwapperLib__UnknownCalldata();
}
// Verify calldata integrity.
uint256 minOutAmount = IExternalCalldataChecker(callDataChecker)
.checkCalldata(action, address(this));
// Approve `action.inputToken` to target contract, if necessary.
_approveIfNeeded(inputToken, action.target, action.inputAmount);
// Cache output token from struct for easier querying.
uint256 balanceBefore = CommonLib._balanceOf(outputToken);
uint256 callValue = CommonLib._isNative(inputToken) ?
action.inputAmount : 0;
// Execute the swap.
LowLevelCallsHelper._callWithNative(
action.target,
action.call,
callValue
);
// Remove any excess approval.
_removeApprovalIfNeeded(inputToken, action.target);
outAmount = CommonLib._balanceOf(outputToken) - balanceBefore;
if (outAmount < minOutAmount) {
revert SwapperLib__Slippage(minOutAmount);
}
}
/// @notice Swaps `action.inputToken` into a `action.outputToken`
/// with an extra slippage check.
/// @param cr The address of the Protocol Central Registry to pull
/// addresses from.
/// @param action Instructions for a swap action containing:
/// inputToken Address of input token to swap from.
/// inputAmount The amount of `inputToken` to swap.
/// outputToken Address of token to swap into.
/// target Address of the swapper, usually an
/// aggregator.
/// slippage The amount of value-loss acceptable from
/// swapping between tokens.
/// call Swap instruction calldata.
/// @return outAmount The output amount received from swapping.
function _swapSafe(
ICentralRegistry cr,
Swap memory action
) internal returns (uint256 outAmount) {
if (action.slippage >= WAD) {
revert SwapperLib__Slippage(action.slippage);
}
outAmount = _swapUnsafe(cr, action);
IOracleManager om = CommonLib._oracleManager(cr);
uint256 valueIn = _getValue(om, action.inputToken, action.inputAmount);
uint256 valueOut = _getValue(om, action.outputToken, outAmount);
// Check if swap received positive slippage.
if (valueOut > valueIn) {
return outAmount;
}
// Calculate % slippage from executed swap.
uint256 slippage = FixedPointMathLib.mulDivUp(
valueIn - valueOut,
WAD,
valueIn
);
if (slippage > action.slippage) {
revert SwapperLib__Slippage(slippage);
}
}
/// @notice Get the value of a token amount.
/// @notice Approves `token` spending allowance, if needed.
/// @param om The Oracle Manager address to call for pricing `token`.
/// @param token The token address to get the value of.
/// @param amount The amount of `token` to get the value of.
function _getValue(
IOracleManager om,
address token,
uint256 amount
) internal view returns (uint256 result) {
// If token is native, normalize to address(0) so it is compatible
// with the Oracle Manager.
if (token == address(0)) {
token = native;
}
(uint256 price, uint256 errorCode) = om.getPrice(token, true, true);
if (errorCode != NO_ERROR) {
revert SwapperLib__TokenPrice(token);
}
// Return price in WAD form.
result = FixedPointMathLib.mulDiv(
price,
amount,
10 ** (CommonLib._isNative(token) ? 18 : IERC20(token).decimals())
);
}
/// @notice Approves `token` spending allowance, if needed.
/// @param token The token address to approve.
/// @param spender The spender address.
/// @param amount The approval amount.
function _approveIfNeeded(
address token,
address spender,
uint256 amount
) internal {
if (!CommonLib._isNative(token)) {
SafeTransferLib.safeApprove(token, spender, amount);
}
}
/// @notice Removes `token` spending allowance, if needed.
/// @param token The token address to remove approval.
/// @param spender The spender address.
function _removeApprovalIfNeeded(address token, address spender) internal {
if (!CommonLib._isNative(token)) {
if (IERC20(token).allowance(address(this), spender) > 0) {
SafeTransferLib.safeApprove(token, spender, 0);
}
}
}
}
// contracts/market/token/BaseCToken.sol
/// @notice Curvance's cTokens (Curvance Tokens) follow their own design modifying underlying
/// mechanisms such as `totalAssets` following an asset vesting system
/// in both external strategies and lender interest accrual from
/// borrowers.
///
/// "Weird tokens" that do not properly implement ERC-20 are not
/// intended to be supported such as where name() or decimals()
/// returns in unconventional forms.
///
/// The "cToken" employs two different methods of engaging with the
/// Curvance protocol. Users can deposit an unlimited amount of assets,
/// which may or may not benefit from some form of yield.
///
/// Users can at any time, choose to "post" their cTokens as collateral
/// inside the Curvance Protocol, unlocking their ability to borrow
/// against these assets. Posting collateral carries restrictions,
/// not all assets inside Curvance can be collateralized, and if they
/// can, they have a "Collateral Cap" which restricts the total amount of
/// exogeneous risk introduced by each asset into the system.
///
/// These caps can be updated as needed by the DAO and should be
/// configured based on "sticky" onchain liquidity in the corresponding
/// asset.
///
/// Each token can have their minting, collateralization, borrowing,
/// compounding, liquidations, and redemption functionality paused.
/// Modifying the maximum mint, deposit, withdrawal, or redemptions
/// possible.
///
/// View functions are "safe" by introducing reentry and update
/// protection to minimize risks when integrating with Curvance.
///
/// @dev Curvance cTokens are partially ERC-4626 compliant:
/// - Zero-amount transfers are blocked.
/// - `convertToShares()` and `convertToAssets()` use `nonReadReentrant`, which may revert
/// under reentrancy, deviating from ERC-4626 view requirements.
/// - `maxWithdraw()` and `maxRedeem()` do not reflect global withdrawal limits.
/// These deviations are intentional to prioritize protocol-level risk controls,
/// reentrancy protection, and flexibility. Integrators should not rely on strict
/// ERC-4626 behavior.
///
/// `Asset()` Positions must have all assets ready for withdraw,
/// IE assets can NOT be locked.
/// This way assets can be easily liquidated when loans default.
abstract contract BaseCToken is
ERC4626,
PluginDelegable,
ReentrancyGuard,
Multicall,
ERC165
{
/// CONSTANTS ///
/// @dev `bytes4(keccak256(bytes("BaseCToken__Unauthorized()")))`
uint256 internal constant _UNAUTHORIZED_SELECTOR = 0x471656c5;
/// @dev `bytes4(keccak256(bytes("BaseCToken__InsufficientLiquidity()")))`
uint256 internal constant _INSUFFICIENT_LIQUIDITY_SELECTOR = 0xe6c95926;
/// @dev `keccak256(bytes("Transfer(address,address,uint256)"))`.
uint256 internal constant _TRANSFER_EVENT_SIGNATURE =
0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef;
/// @dev The balance slot of `owner` is given by:
/// ```
/// mstore(0x0c, _BALANCE_SLOT_SEED)
/// mstore(0x00, owner)
/// let balanceSlot := keccak256(0x0c, 0x20)
/// ```
uint256 internal constant _BALANCE_SLOT_SEED = 0x87a211a2;
/// @dev The base underlying asset requirement held in order to minimize
/// rounding exploits, and more generally, invariant manipulation.
uint256 internal constant _BASE_UNDERLYING_RESERVE = 77777;
/// @notice Address of the Market Manager linked to this contract.
IMarketManager public immutable marketManager;
/// @notice Underlying asset for this token.
/// @dev CANNOT be a fee-on-transfer token.
IERC20 internal immutable _asset;
/// @notice Token decimal precision.
uint8 internal immutable _decimals;
/// STORAGE ///
/// @notice Amount of tokens that has been posted as collateral,
/// in shares.
uint256 public marketCollateralPosted;
/// @notice Token name metadata.
string internal _name;
/// @notice Token symbol metadata.
string internal _symbol;
/// @notice Total amount of `asset()` in this vault, minus pending
/// vesting.
uint256 internal _totalAssets;
/// @notice Shares of this token that an account has posted as collateral.
/// @dev Account address => Collateral data.
mapping(address => uint256) public collateralPosted;
/// EVENTS ///
event CollateralUpdated(uint256 shares, bool increased, address account);
event Liquidated(uint256 shares, address liquidator, address account);
/// ERRORS ///
error BaseCToken__ZeroAmount();
error BaseCToken__TransferError();
error BaseCToken__InsufficientLiquidity();
error BaseCToken__Unauthorized();
error BaseCToken__UnsupportedChain();
error BaseCToken__InvalidMarketManager();
error BaseCToken__InvariantError();
/// CONSTRUCTOR ///
/// @param cr The address of the Protocol Central Registry.
/// @param asset_ The address of the underlying asset for this cToken.
/// @param mm The address of the MarketManager which manages liquidity
/// positions between linked cTokens inside a joint market.
constructor(
ICentralRegistry cr,
IERC20 asset_,
address mm
) PluginDelegable(cr) {
_asset = asset_;
_name = string.concat("Curvance ", asset_.name());
_symbol = string.concat("c", asset_.symbol());
_decimals = asset_.decimals();
// Validate that `mm` is configured as a Market Manager inside the
// Protocol Central Registry.
if (!centralRegistry.isMarketManager(mm)) {
revert BaseCToken__InvalidMarketManager();
}
// Set `marketManager`.
marketManager = IMarketManager(mm);
}
/// EXTERNAL FUNCTIONS ///
/// @notice Enables a token's functionality inside a market, executed
/// via marketManager.
/// @dev This initial mint is a failsafe against rounding exploits,
/// although, we protect against them in many ways,
/// better safe than sorry.
/// NOTE: ONLY CALLED ONCE DURING TOKEN LISTING BY DAO AUTHORIZED
/// ADDRESS FROM THE MARKET MANAGER.
/// @param by The account initializing deposits.
/// @return Returns with true when successful.
function initializeDeposits(
address by
) external nonReentrant returns (bool) {
_initializeDeposits(by);
return true;
}
/// @notice Used by a Position Manager contract to redeem assets from
/// collateralized shares by `account` to perform a complex
/// action.
/// @param assets The amount of the underlying assets to redeem.
/// @param owner The owner address of assets to redeem.
/// @param action Instructions for a deleverage action containing:
/// cToken Address of the cToken that will be redeemed from
/// and assets swapped into `borrowableCToken` asset.
/// collateralAssets The amount of `cToken` that will be
/// deleveraged, in assets.
/// borrowableCToken Address of the borrowableCToken that
/// will have its debt paid.
/// repayAssets The amount of `borrowableCToken` asset that
/// will be repaid to lenders.
/// swapActions Swap actions instructions converting
/// collateral asset into debt asset to
/// facilitate deleveraging.
/// auxData Optional auxiliary data for execution of a
/// deleverage action.
function withdrawByPositionManager(
uint256 assets,
address owner,
IPositionManager.DeleverageAction memory action
) external nonReentrant {
// Validate that a position manager is calling.
if (!marketManager.isPositionManager(msg.sender)) {
_revert(_UNAUTHORIZED_SELECTOR);
}
_accrueIfNeeded();
// Use up-to-date total assets including any pending vesting via getter.
uint256 ta = _getTotalAssets();
uint256 balance = _checkRedemption(assets, owner, ta);
// No need to check for rounding error, previewWithdraw rounds up.
uint256 shares = _previewWithdraw(assets, ta);
_processWithdraw(assets, shares, msg.sender, msg.sender, owner);
// Process the position manager redemption leg.
_processPositionManagerRedemption(
assets,
shares,
owner,
balance,
action
);
}
/// @notice Caller deposits `assets` into the market, `receiver` receives
/// shares, and collateralization of `assets` is enabled.
/// @dev The caller must be collateralizing for themselves, or be managing
/// their position through a Position Manager contract.
/// @param assets The amount of the underlying assets to deposit.
/// @param receiver The account that should receive the cToken shares.
/// @return shares The amount of cToken shares received by `receiver`.
function depositAsCollateral(
uint256 assets,
address receiver
) external nonReentrant returns (uint256 shares) {
if (
msg.sender != receiver &&
!marketManager.isPositionManager(msg.sender)
) {
_revert(_UNAUTHORIZED_SELECTOR);
}
shares = _deposit(assets, receiver);
// Can skip _checkPostCollateral since we know that `shares` is not
// 0 and `receiver` has shares to post as collateral due to prior
// _deposit action.
_postCollateral(shares, receiver);
}
/// @notice Caller deposits `assets` into the market, `receiver` receives
/// shares, and collateralization of `assets` is enabled.
/// @dev Requires that `receiver` approves the caller prior to
/// collateralize on their behalf.
/// NOTE: Be careful who you approve here!
/// They can delay redemption of assets through repeated
/// collateralization preventing withdrawal.
/// @param assets The amount of the underlying assets to deposit.
/// @param receiver The account that should receive the cToken shares.
/// @return shares The amount of cToken shares received by `receiver`.
function depositAsCollateralFor(
uint256 assets,
address receiver
) external nonReentrant returns (uint256 shares) {
_checkDelegate(receiver, msg.sender);
shares = _deposit(assets, receiver);
// Can skip _checkPostCollateral since we know that `shares` is not
// 0 and `receiver` has shares to post as collateral due to prior
// _deposit action.
_postCollateral(shares, receiver);
}
/// @notice Caller withdraws assets from the market and burns their shares.
/// @dev Forces collateral to be withdrawn from `owner` collateralPosted.
/// @param assets The amount of the underlying assets to withdraw.
/// @param receiver The account that should receive the assets.
/// @param owner The account that will burn their shares to withdraw assets.
/// @return shares the amount of cToken shares redeemed by `owner`.
function withdrawCollateral(
uint256 assets,
address receiver,
address owner
) external nonReentrant returns (uint256 shares) {
shares = _withdraw(assets, receiver, owner, true);
}
/// @notice Caller withdraws assets from the market and burns their shares.
/// @dev Forces collateral to be withdrawn from `owner` collateralPosted.
/// @param shares The amount of shares to redeemed.
/// @param receiver The account that should receive the assets.
/// @param owner The account that will burn their shares to withdraw assets.
/// @return assets the amount of assets redeemed by `owner`.
function redeemCollateral(
uint256 shares,
address receiver,
address owner
) external nonReentrant returns (uint256 assets) {
assets = _redeem(shares, receiver, owner, false, true);
}
/// @notice Caller withdraws assets from the market and burns their
/// shares, on behalf of `owner`.
/// @dev Forces collateral to be withdrawn from `owner` collateralPosted.
/// @param shares The amount of shares to redeemed.
/// @param receiver The account that should receive the assets.
/// @param owner The account that will burn their shares to withdraw
/// assets.
/// @return assets The amount of assets redeemed by `owner` and sent to
/// `receiver`.
function redeemCollateralFor(
uint256 shares,
address receiver,
address owner
) external nonReentrant returns (uint256 assets) {
assets = _redeem(shares, receiver, owner, true, true);
}
/// @notice Posts `shares` as collateral inside this market.
/// @dev The cToken must have collateralization enabled (collRatio > 0),
/// and its collateral cap set (above 0).
/// @param shares The amount of shares to post as collateral.
function postCollateral(uint256 shares) external nonReentrant {
_checkPostCollateral(shares, msg.sender);
_postCollateral(shares, msg.sender);
}
/// @notice Posts `shares` as collateral inside this market
/// for `account`.
/// @dev The cToken must have collateralization enabled (collRatio > 0),
/// and its collateral cap set (above 0).
/// @param shares The number of shares to post as collateral from `owner`.
/// @param owner The address of the account posting `shares`
/// as collateral.
function postCollateralFor(
uint256 shares,
address owner
) external nonReentrant {
_checkDelegate(owner, msg.sender);
_checkPostCollateral(shares, owner);
_postCollateral(shares, owner);
}
/// @notice Removes `shares` of collateral posted inside this market.
/// @param shares The number of shares that are posted of collateral
/// that will be removed.
function removeCollateral(uint256 shares) external nonReentrant {
_checkRemoveCollateral(shares, msg.sender);
_removeCollateral(shares, msg.sender);
}
/// @notice Removes `shares` of collateral posted inside this market
/// for `account`.
/// @param shares The number of shares to remove as collateral
/// from `owner`.
/// @param owner The address of the account removing `shares`
/// as collateral.
function removeCollateralFor(
uint256 shares,
address owner
) external nonReentrant {
_checkDelegate(owner, msg.sender);
_checkRemoveCollateral(shares, owner);
_removeCollateral(shares, owner);
}
/// @notice Transfers collateralized cToken shares from `accounts`
/// to `liquidator` as part of a liquidation.
/// @dev Will fail unless called by a different listed cToken
/// during the process of liquidation.
/// May emit {CollateralUpdated} and {Liquidated} events.
/// @param liquidatedShares An array containing the number of
/// collateralized cTokens to seize, in shares.
/// @param liquidator The account receiving `liquidatedShares` cTokens.
/// @param accounts An array containing the accounts having collateral
/// seized.
function seize(
uint256[] calldata liquidatedShares,
address liquidator,
address[] calldata accounts
) external nonReentrant {
// Fails if seizure not allowed.
marketManager.canSeize(address(this), msg.sender);
// We know that `accounts` and `liquidatedShares` arrays are the same
// length since we validate it inside the cToken getting debt repaid
// as part of this liquidation.
uint256 numAccounts = accounts.length;
uint256 totalShares;
uint256 shares;
address account;
for (uint256 i; i < numAccounts; ++i) {
shares = liquidatedShares[i];
// If theres no shares to liquidate for this account can
// skip them.
if (shares == 0) {
continue;
}
account = accounts[i];
// Execute any prior liquidation action.
_beforeLiqAction(shares, liquidator, account);
totalShares += shares;
// Update `account` collateral posted invariant and transfer
// their collateral shares.
collateralPosted[account] = collateralPosted[account] - shares;
emit CollateralUpdated(shares, false, account);
// Transfer liquidated shares from `account` to `liquidator`.
_transferFromWithoutAllowance(account, liquidator, shares);
emit Liquidated(shares, liquidator, account);
}
// Update market collateral posted invariant for the liquidated
// shares.
marketCollateralPosted = marketCollateralPosted - totalShares;
}
/// @notice Updates pending assets and returns the up-to-date exchange
/// rate from the underlying to the BorrowableCToken.
/// @dev Oracle Manager calculates cToken value from this exchange rate.
/// @return result The share -> asset exchange rate, in `WAD`.
function exchangeRateUpdated() external returns (uint256 result) {
_accrueIfNeeded();
result = _convertToAssets(WAD, _getTotalAssets());
}
/// @notice Returns the up-to-date exchange rate from the underlying to
/// the BorrowableCToken.
/// @return result The share -> asset exchange rate, in `WAD`.
function exchangeRate() external view returns (uint256 result) {
result = _convertToAssets(WAD, _getTotalAssets());
}
/// @notice Updates pending assets and returns a snapshot of the cToken
/// and `account` data.
/// @dev Used by MarketManager to efficiently perform liquidity checks.
/// NOTE: debtBalance always return 0 except in `borrowableCToken`.
/// @return result The snapshot of the cToken and `account` data.
function getSnapshotUpdated(
address account
) external returns (AccountSnapshot memory result) {
_accrueIfNeeded();
result = getSnapshot(account);
}
/// PUBLIC FUNCTIONS ///
/// @notice Returns a snapshot of the cToken and `account` data.
/// @dev debtBalance always return 0 except in `borrowableCToken`.
/// NOTE: Does not accrue pending assets as part of the call.
/// @return result The snapshot of the cToken and `account` data.
function getSnapshot(
address account
) public view virtual returns (AccountSnapshot memory result) {
result.asset = address(this);
result.underlying = address(_asset);
result.decimals = decimals();
// Can only be true for non-BorrowableCTokens.
result.isCollateral = true;
result.collateralPosted = collateralPosted[account];
// result.debtBalance is 0 for non-BorrowableCTokens, no need to set.
}
/// @notice Returns the name of the token.
/// @return The name of the token.
function name() public view override returns (string memory) {
return _name;
}
/// @notice Returns the symbol of the token.
/// @return The symbol of the token.
function symbol() public view override returns (string memory) {
return _symbol;
}
/// @notice Returns the address of the underlying asset.
/// @return result The address of the underlying asset.
function asset() public view override returns (address result) {
result = address(_asset);
}
/// @notice Returns the maximum assets that can be deposited at a time.
/// @dev If depositing is disabled maxAssets should be equal to 0,
/// according to ERC4626 spec.
/// @param receiver The address who would receive minted shares.
/// @return maxAssets The maximum assets that can be deposited at a time.
function maxDeposit(
address receiver
) public view override returns (uint256 maxAssets) {
(bool mintPaused, , ) = marketManager.actionsPaused(address(this));
if (!marketManager.isListed(address(this)) || mintPaused) {
// We do not need to set maxAssets here since its initialized
// as 0 so we can just return.
return maxAssets;
}
maxAssets = super.maxDeposit(receiver);
}
/// @notice Returns the maximum shares that can be minted at a time.
/// @dev If depositing is disabled minMint should be equal to 0,
/// according to ERC4626 spec.
/// @param receiver The address who would receive minted shares.
/// @return maxShares The maximum shares that can be minted at a time.
function maxMint(
address receiver
) public view override returns (uint256 maxShares) {
(bool mintPaused, , ) = marketManager.actionsPaused(address(this));
if (!marketManager.isListed(address(this)) || mintPaused) {
// We do not need to set maxShares here since its initialized
// as 0 so we can just return.
return maxShares;
}
maxShares = super.maxMint(receiver);
}
/// @notice Caller deposits `assets` into the market and `receiver`
/// receives shares.
/// @param assets The amount of the underlying assets to deposit.
/// @param receiver The account that should receive the cToken shares.
/// @return shares The amount of cToken shares received by `receiver`.
function deposit(
uint256 assets,
address receiver
) public override nonReentrant returns (uint256 shares) {
shares = _deposit(assets, receiver);
}
/// @notice Caller deposits `shares` into the market and `receiver`
/// receives shares.
/// @param shares The amount of the underlying assets quoted in shares
/// to deposit.
/// @param receiver The account that should receive the cToken shares.
/// @return assets The amount of cToken shares quoted in assets received
/// by `receiver`.
function mint(
uint256 shares,
address receiver
) public override nonReentrant returns (uint256 assets) {
assets = _mint(shares, receiver);
}
/// @notice Withdraws `assets` from the market, and burns `owner` shares.
/// @dev Does not force collateral posted to be withdrawn.
/// @param assets The amount of the underlying assets to withdraw.
/// @param receiver The account that should receive the assets.
/// @param owner The account that will burn their shares to withdraw
/// assets.
/// @return shares The amount of cToken shares redeemed by `owner`.
function withdraw(
uint256 assets,
address receiver,
address owner
) public override nonReentrant returns (uint256 shares) {
shares = _withdraw(assets, receiver, owner, false);
}
/// @notice Withdraws assets, quoted in `shares` from the market,
/// and burns `owner` shares.
/// @dev Does not force collateral to be withdrawn.
/// @param shares The amount of shares to be redeemed.
/// @param receiver The account that should receive the assets.
/// @param owner The account that will burn their shares to withdraw
/// assets.
/// @return assets The amount of assets redeemed by `owner`.
function redeem(
uint256 shares,
address receiver,
address owner
) public override nonReentrant returns (uint256 assets) {
assets = _redeem(shares, receiver, owner, false, false);
}
/// @notice Withdraws assets, quoted in `shares` from the market,
/// and burns `owner` shares, sending assets to `receiver`.
/// @dev Does not force collateral to be withdrawn.
/// @param shares The amount of shares to redeemed.
/// @param receiver The account that should receive the assets.
/// @param owner The account that will burn their shares to withdraw
/// assets.
/// @return assets The amount of assets redeemed by `owner` and sent to
/// `receiver`.
function redeemFor(
uint256 shares,
address receiver,
address owner
) public nonReentrant returns (uint256 assets) {
assets = _redeem(shares, receiver, owner, true, false);
}
/// @notice Transfers `amount` tokens from caller to `to`.
/// @param receiver The address of the destination account to receive
/// `shares` shares.
/// @param shares The number of shares to transfer from caller to
/// `receiver`.
/// @return Whether or not the transfer succeeded or not.
function transfer(
address receiver,
uint256 shares
) public override nonReentrant returns (bool) {
_checkTransfer(shares, receiver, msg.sender);
// Execute transfer.
super.transfer(receiver, shares);
return true;
}
/// @notice Transfers `amount` tokens from `owner` to `receiver`.
/// @param owner The address of the account transferring `shares`
/// shares from.
/// @param receiver The address of the destination account to receive
/// `shares` shares.
/// @param shares The number of shares to transfer from `owner` to
/// `receiver`.
/// @return Whether or not the transfer succeeded or not.
function transferFrom(
address owner,
address receiver,
uint256 shares
) public override nonReentrant returns (bool) {
_checkTransfer(shares, receiver, owner);
// Execute transfer.
super.transferFrom(owner, receiver, shares);
return true;
}
/// @notice Returns whether the underlying token can be borrowed.
/// @dev true = Borrowable; false = Not Borrowable.
/// @return result Whether this token is borrowable or not.
function isBorrowable() public pure virtual returns (bool result) {
result = false;
}
/// @dev Returns true that this contract implements both ERC4626
/// and ICToken interfaces.
/// @param interfaceId The interface ID to check.
/// @return result Whether the contract implements the interface.
function supportsInterface(
bytes4 interfaceId
) public view virtual override returns (bool result) {
result = interfaceId == type(ICToken).interfaceId ||
interfaceId == type(ERC4626).interfaceId ||
super.supportsInterface(interfaceId);
}
/// @notice Returns the total number of assets backing shares.
/// @return result The total number of assets backing shares.
function totalAssets() public view nonReadReentrant override returns (
uint256 result
) {
result = _getTotalAssets();
}
/// @notice Returns the amount of shares that would be exchanged
/// by the vault for `assets` provided.
/// @param assets The number of assets to theoretically use
/// for conversion to shares.
/// @return The number of shares a user would receive for converting
/// `assets`.
function convertToShares(
uint256 assets
) public view nonReadReentrant override returns (uint256) {
return _convertToShares(assets, _getTotalAssets());
}
/// @notice Returns the amount of assets that would be exchanged
/// by the vault for `shares` provided.
/// @param shares The number of shares to theoretically use
/// for conversion to assets.
/// @return The number of assets a user would receive for converting
/// `shares`.
function convertToAssets(
uint256 shares
) public view nonReadReentrant override returns (uint256) {
return _convertToAssets(shares, _getTotalAssets());
}
/// @notice Allows users to simulate the effects of their deposit at
/// the current block.
/// @param assets The number of assets to preview a deposit call.
/// @return The shares received for depositing `assets`.
function previewDeposit(
uint256 assets
) public view override returns (uint256) {
return _convertToShares(assets, _getTotalAssets());
}
/// @notice Allows users to simulate the effects of their mint at
/// the current block.
/// @param shares The number of assets, quoted as shares to preview
/// a mint call.
/// @return The shares received quoted as assets for depositing `shares`.
function previewMint(
uint256 shares
) public view override returns (uint256) {
return _previewMint(shares, _getTotalAssets());
}
/// @notice Allows users to simulate the effects of their withdraw
/// at the current block.
/// @param assets The number of assets to preview a withdraw call.
/// @return The assets received quoted as shares for withdrawing `assets`.
function previewWithdraw(
uint256 assets
) public view virtual override returns (uint256) {
return _previewWithdraw(assets, _getTotalAssets());
}
/// @notice Allows users to simulate the effects of their redeem at
/// the current block.
/// @param shares The number of assets, quoted as shares to preview
/// a redeem call.
/// @return The assets received for withdrawing `shares`.
function previewRedeem(
uint256 shares
) public view virtual override returns (uint256) {
return _convertToAssets(shares, _getTotalAssets());
}
/// @notice Can accrue pending yield, configure next vesting
/// period, and updates vesting data, if needed.
/// @dev May emit a {RatesAdjusted} event.
function accrueIfNeeded() external nonReentrant {
_accrueIfNeeded();
}
/// INTERNAL FUNCTIONS ///
/// @notice Deposits `assets` and mints shares to `receiver`.
/// @param assets The amount of the underlying asset to supply.
/// @param receiver The account that should receive the cToken shares.
/// @return shares The amount of cToken shares received by `receiver`.
function _deposit(
uint256 assets,
address receiver
) internal virtual returns (uint256 shares) {
_accrueIfNeeded();
// Check for rounding error by converting assets to shares,
// since we round down in previewDeposit.
_checkZeroAmount(shares = _convertToShares(assets, _getTotalAssets()));
// Fails if deposit not allowed, this stands in for a maxDeposit
// check reviewing isListed and mintPaused != 2.
marketManager.canMint(address(this));
// Execute deposit.
_processDeposit(assets, shares, msg.sender, receiver);
}
/// @notice Deposits assets and mints `shares` to `receiver`.
/// @param shares The amount of the underlying assets quoted in shares
/// to supply.
/// @param receiver The account that should receive the cToken shares.
/// @return assets The amount of cToken shares quoted in assets received
/// by `receiver`.
function _mint(
uint256 shares,
address receiver
) internal virtual returns (uint256 assets) {
_accrueIfNeeded();
_checkZeroAmount(shares);
// Fail if mint not allowed, this stands in for a maxMint
// check reviewing isListed and mintPaused != 2.
marketManager.canMint(address(this));
// Execute deposit.
// No need to check for rounding error, previewMint rounds up.
_processDeposit(
assets = _previewMint(shares, _getTotalAssets()),
shares,
msg.sender,
receiver
);
}
/// @notice Withdraws `assets` to `receiver` from the market and burns
/// `owner` shares.
/// @dev Withdraw calls do not support the delegation system intentionally
/// to minimize code attack surface.
/// @param assets The amount of the underlying asset to withdraw.
/// @param receiver The account that should receive the assets.
/// @param owner The account that will burn their shares to withdraw
/// assets.
/// @param forceRedeemCollateral Whether the collateral should be always
/// reduced from `owner`'s collateralPosted.
/// @return shares The amount of assets, quoted in shares received
/// by `receiver`.
function _withdraw(
uint256 assets,
address receiver,
address owner,
bool forceRedeemCollateral
) internal virtual returns (uint256 shares) {
_accrueIfNeeded();
// Use up-to-date total assets including any pending vesting via getter.
uint256 ta = _getTotalAssets();
uint256 balance = _checkRedemption(assets, owner, ta);
// Validate caller is allowed to withdraw `shares` on behalf of
// `owner`.
_updateAllowance(owner, shares = _previewWithdraw(assets, ta));
// Validate that `owner` can redeem `shares`.
uint256 collateralRedeemed = marketManager.canRedeemWithCollateralRemoval(
address(this),
shares,
owner,
balance,
collateralPosted[owner],
forceRedeemCollateral
);
if (collateralRedeemed > 0) {
_removeCollateral(collateralRedeemed, owner);
}
// Execute withdrawal.
_processWithdraw(
assets,
shares,
msg.sender,
receiver,
owner
);
}
/// @notice Redeems assets to `receiver` from the market and burns
/// `owner` `shares`.
/// @dev Redemption calls support the delegation system, allowing
/// an alternative approval system in parallel with the native
/// erc20 system.
/// @param shares The amount of shares to burn to withdraw assets.
/// @param receiver The account that should receive the assets.
/// @param owner The account that will burn their shares to withdraw
/// assets.
/// @param delegatedAction Whether the action is delegated and should
/// use delegation system instead of normal
/// approval system.
/// @param forceRedeemCollateral Whether the collateral should be always
/// reduced from `owner`'s collateralPosted.
/// @return assets The amount of assets received by `receiver`.
function _redeem(
uint256 shares,
address receiver,
address owner,
bool delegatedAction,
bool forceRedeemCollateral
) internal virtual returns (uint256 assets) {
_accrueIfNeeded();
// Use up-to-date total assets including any pending vesting via getter.
uint256 ta = _getTotalAssets();
uint256 balance = _checkRedemption(
assets = _convertToAssets(shares, ta),
owner,
ta
);
// Validate caller is allowed to withdraw `shares` on behalf of
// `owner`. Or whether the caller has delegated approval
// via plugin system or not.
if (delegatedAction) {
_checkDelegate(owner, msg.sender);
} else {
_updateAllowance(owner, shares);
}
// Validate that `owner` can redeem `shares`.
uint256 collateralRedeemed = marketManager.canRedeemWithCollateralRemoval(
address(this),
shares,
owner,
balance,
collateralPosted[owner],
forceRedeemCollateral
);
if (collateralRedeemed > 0) {
_removeCollateral(collateralRedeemed, owner);
}
// Execute withdrawal.
_processWithdraw(assets, shares, msg.sender, receiver, owner);
}
/// @notice Helper function for posting `shares` as collateral
/// for `account` inside this market.
/// @dev Emits {CollateralUpdated} event.
/// May emit {PositionUpdated} event inside Market Manager.
/// @param owner The account posting collateral.
/// @param shares The amount of shares to post as collateral.
function _postCollateral(
uint256 shares,
address owner
) internal virtual {
uint256 newNetCollateral = marketCollateralPosted + shares;
marketManager.canCollateralize(address(this), owner, newNetCollateral);
// Update user and market collateral posted invariants.
collateralPosted[owner] = collateralPosted[owner] + shares;
marketCollateralPosted = newNetCollateral;
emit CollateralUpdated(shares, true, owner);
}
/// @notice Helper function for removing `shares` collateral posted for
/// `account` inside this market.
/// @dev Emits a {CollateralUpdated} event.
/// May emit {PositionUpdated} event inside Market Manager.
/// @param shares The number of shares that are posted of collateral
/// that should be removed.
/// @param owner The address of the account to reduce collateral
/// posted from.
function _removeCollateral(uint256 shares, address owner) internal {
// Update user and market collateral posted invariants.
collateralPosted[owner] = collateralPosted[owner] - shares;
marketCollateralPosted = marketCollateralPosted - shares;
emit CollateralUpdated(shares, false, owner);
}
/// @notice Can accrue yield, configure next vesting
/// period, and updates vesting data, if needed.
function _accrueIfNeeded() internal virtual {}
/// @notice Processes a deposit of `assets` from the market and mints
/// shares to `owner`, then increases `ta` by `assets`,
/// and vests rewards if `pending` > 0.
/// @dev Emits a {Deposit} event.
/// @param assets The amount of the underlying asset to deposit.
/// @param shares The amount of shares minted to `to`.
/// @param by The account that is executing the deposit.
/// @param receiver The account that should receive `shares`.
function _processDeposit(
uint256 assets,
uint256 shares,
address by,
address receiver
) internal {
// Transfer the underlying assets to the contract.
SafeTransferLib.safeTransferFrom(asset(), by, address(this), assets);
// Vests any rewards,if there are any, then update `_totalAssets`
// invariant and prepare assets for withdrawal.
_updateAssetsForDeposit(assets);
// Mint `shares` to `receiver`.
// NOTE: This is the erc20 mint function, meaning this is effectively
// super._mint().
_mint(receiver, shares);
emit Deposit(by, receiver, assets, shares);
_afterDepositAction(shares, receiver);
}
/// @notice Processes a withdrawal of `shares` from the market by burning
/// `owner` shares and transferring `assets` to `receiver`, then
/// decreases `ta` by `assets`, and vests rewards if
/// `pending` > 0.
/// @dev Emits a {Withdraw} event.
/// @param assets The amount of the underlying asset to withdraw.
/// @param shares The amount of shares redeemed from `owner`.
/// @param by The account that is executing the withdrawal.
/// @param receiver The account that should receive `assets`.
/// @param owner The account that will have `shares` burned to withdraw
/// `assets`.
function _processWithdraw(
uint256 assets,
uint256 shares,
address by,
address receiver,
address owner
) internal virtual {
_beforeWithdrawAction(shares, owner);
// Burn `owner` `shares`.
_burn(owner, shares);
// Vests any rewards, if there are any, then update `_totalAssets`.
// invariant and prepare assets for withdrawal.
_updateAssetsForWithdrawal(assets);
// Transfer the underlying assets to `receiver`.
SafeTransferLib.safeTransfer(asset(), receiver, assets);
emit Withdraw(by, receiver, owner, assets, shares);
}
/// @notice Used by a Position Manager contract to redeem assets from
/// collateralized shares by `account` to perform a complex
/// action.
/// @param assets The amount of the underlying assets to redeem.
/// @param shares The amount of the shares to redeem.
/// @param owner The owner address of assets to redeem.
/// @param balancePrior The balance of shares `owner` has before this
/// redemption.
/// @param action Instructions for a deleverage action containing:
/// cToken Address of the cToken that will be redeemed from
/// and assets swapped into `borrowableCToken` asset.
/// collateralAssets The amount of `cToken` that will be
/// deleveraged, in assets.
/// borrowableCToken Address of the borrowableCToken that
/// will have its debt paid.
/// repayAssets The amount of `borrowableCToken` asset that
/// will be repaid to lenders.
/// swapActions Swap actions instructions converting
/// collateral asset into debt asset to
/// facilitate deleveraging.
/// auxData Optional auxiliary data for execution of a
/// deleverage action.
function _processPositionManagerRedemption(
uint256 assets,
uint256 shares,
address owner,
uint256 balancePrior,
IPositionManager.DeleverageAction memory action
) internal virtual {
// Callback to Position Manager to execute remaining deleverage logic.
IPositionManager(msg.sender).onRedeem(
address(this),
assets,
owner,
action
);
if (balancePrior != balanceOf(owner) + shares) {
revert BaseCToken__InvariantError();
}
// Fails if redemption not allowed.
uint256 collateralRedeemed = marketManager.canRedeemWithCollateralRemoval(
address(this),
shares,
owner,
balancePrior,
collateralPosted[owner],
false
);
if (collateralRedeemed > 0) {
_removeCollateral(collateralRedeemed, owner);
}
}
/// @notice Helper function to efficiently transfers cToken balances
/// without checking approvals.
/// @dev This is only used in liquidations where maximal gas
/// optimization improves protocol MEV competitiveness,
/// improving protocol safety.
/// Emits a {Transfer} event.
/// @param from The address of the account transferring `amount`
/// shares from.
/// @param to The address of the destination account to receive `amount`
/// shares.
/// @param amount The number of tokens to transfer from `from` to `to`.
function _transferFromWithoutAllowance(
address from,
address to,
uint256 amount
) internal {
/// @solidity memory-safe-assembly
assembly {
let from_ := shl(96, from)
// Compute the balance slot and load its value.
mstore(0x0c, or(from_, _BALANCE_SLOT_SEED))
let fromBalanceSlot := keccak256(0x0c, 0x20)
let fromBalance := sload(fromBalanceSlot)
// Revert if insufficient balance.
if gt(amount, fromBalance) {
mstore(0x00, 0xf4d678b8) // `InsufficientBalance()`.
revert(0x1c, 0x04)
}
// Subtract and store the updated balance.
sstore(fromBalanceSlot, sub(fromBalance, amount))
// Compute the balance slot of `to`.
mstore(0x00, to)
let toBalanceSlot := keccak256(0x0c, 0x20)
// Add and store the updated balance of `to`.
// Will not overflow because the sum of all user balances
// cannot exceed the maximum uint256 value.
sstore(toBalanceSlot, add(sload(toBalanceSlot), amount))
// Emit the {Transfer} event.
mstore(0x20, amount)
log3(
0x20,
0x20,
_TRANSFER_EVENT_SIGNATURE,
shr(96, from_),
shr(96, mload(0x0c))
)
}
}
/// @notice Starts a cToken market, executed via marketManager.
/// @dev This initial mint is a failsafe against rounding exploits,
/// although, we protect against them in many ways,
/// better safe than sorry.
/// @dev Emits a {Deposit} event.
/// @param by The account initializing deposits.
function _initializeDeposits(address by) internal virtual {
if (msg.sender != address(marketManager)) {
_revert(_UNAUTHORIZED_SELECTOR);
}
address cTokenAddress = address(this);
uint256 assets = _BASE_UNDERLYING_RESERVE;
SafeTransferLib.safeTransferFrom(asset(), by, cTokenAddress, assets);
// Because nobody can deposit into the market before initializeDeposits()
// is called, this will always be the initial call.
uint256 shares = _initialConvertToShares(assets);
_mint(address(0), shares);
_totalAssets = assets;
emit Deposit(by, address(0), assets, shares);
_afterDepositAction(shares, address(0));
}
/// @notice Updates the allowance for the caller.
/// @param owner The owner of the allowance.
/// @param amount The spent amount of the allowance.
function _updateAllowance(address owner, uint256 amount) internal {
if (msg.sender != owner) {
_spendAllowance(owner, msg.sender, amount);
}
}
/// @dev Returns the decimals of the underlying asset.
function _underlyingDecimals() internal view override returns (uint8) {
return _decimals;
}
/// @dev Override to disable virtual shares since _decimalsOffset is 0.
function _useVirtualShares() internal pure override returns (bool) {
return false;
}
/// @notice Returns the total amount of the underlying asset in the vault,
/// including pending rewards that are vested.
/// @return result The total number of underlying assets.
function _getTotalAssets() internal view virtual returns (uint256 result) {
result = _totalAssets;
}
/// @notice Returns the amount of shares that would be exchanged by the
/// vault for `assets` provided.
/// @param assets The number of assets to theoretically use
/// for conversion to shares.
/// @param ta The total number of assets to theoretically use
/// for conversion to shares.
/// @return shares The number of shares a user would receive for
/// converting `assets`.
function _convertToShares(
uint256 assets,
uint256 ta
) internal view returns (uint256 shares) {
uint256 totalShares = totalSupply();
shares = totalShares == 0
? assets
: FixedPointMathLib.fullMulDiv(assets, totalShares, ta);
}
/// @notice Returns the amount of assets that would be exchanged by the
/// vault for `shares` provided.
/// @param shares The number of shares to theoretically use
/// for conversion to assets.
/// @param ta The total number of assets to theoretically use
/// for conversion to assets.
/// @return assets The number of assets a user would receive for
/// converting `shares`.
function _convertToAssets(
uint256 shares,
uint256 ta
) internal view returns (uint256 assets) {
uint256 totalShares = totalSupply();
assets = totalShares == 0
? shares
: FixedPointMathLib.fullMulDiv(shares, ta, totalShares);
}
/// @notice Simulates the effects of a user mint at the current
/// block.
/// @param shares The number of shares to preview a mint call.
/// @param ta The total number of assets to simulate a mint at the
/// current block.
/// @return assets The assets received for minting `shares`.
function _previewMint(
uint256 shares,
uint256 ta
) internal view returns (uint256 assets) {
uint256 totalShares = totalSupply();
assets = totalShares == 0
? shares
: FixedPointMathLib.fullMulDivUp(shares, ta, totalShares);
}
/// @notice Simulates the effects of a user withdrawal at the current
/// block.
/// @param assets The number of assets to preview a withdrawal call.
/// @param ta The total number of assets to simulate a withdrawal at the
/// current block.
/// @return shares The shares received for withdrawing `assets`.
function _previewWithdraw(
uint256 assets,
uint256 ta
) internal view returns (uint256 shares) {
uint256 totalShares = totalSupply();
shares = totalShares == 0
? assets
: FixedPointMathLib.fullMulDivUp(assets, totalShares, ta);
}
/// @notice Updates asset values for a pending deposit.
/// @param assets The amount of `asset()` to deposit.
function _updateAssetsForDeposit(uint256 assets) internal virtual {
// Document addition of `assets` to `ta` due to deposit.
_totalAssets = _totalAssets + assets;
}
/// @notice Updates asset values for a pending withdrawal.
/// @param assets The amount of `asset()` to withdraw.
function _updateAssetsForWithdrawal(uint256 assets) internal virtual {
// Document removal of `assets` from `ta` due to withdrawal.
_totalAssets = _totalAssets - assets;
}
/// @dev from Multicall
/// @return The central registry.
function _getCentralRegistry()
internal
view
override
returns (ICentralRegistry)
{
return centralRegistry;
}
/// @notice Helper function to check validity of a proposed posting
/// of collateral.
/// @param shares The number of shares to post as collateral from `owner`.
/// @param owner The address of the account posting `shares`
/// as collateral.
function _checkPostCollateral(
uint256 shares,
address owner
) internal view {
_checkZeroAmount(shares);
if (collateralPosted[owner] + shares > balanceOf(owner)) {
_revert(_INSUFFICIENT_LIQUIDITY_SELECTOR);
}
}
/// @notice Helper function to check validity of a proposed removal
/// of collateral.
/// @param shares The number of shares to remove as collateral
/// from `owner`.
/// @param owner The address of the account removing `shares`
/// as collateral.
function _checkRemoveCollateral(
uint256 shares,
address owner
) internal {
_checkZeroAmount(shares);
uint256 collateralOf = collateralPosted[owner];
if (collateralOf < shares) {
_revert(_INSUFFICIENT_LIQUIDITY_SELECTOR);
}
marketManager.canRedeemWithCollateralRemoval(
address(this),
shares,
owner,
balanceOf(owner),
collateralOf,
true
);
}
/// @notice Helper function to prepare for a transfer.
/// @param shares The number of shares to transfer from `owner` to
/// `receiver`.
/// @param receiver The address of the destination account to receive
/// `shares` shares.y
/// @param owner The address of the account transferring `shares`
/// shares from.
function _checkTransfer(
uint256 shares,
address receiver,
address owner
) internal {
_accrueIfNeeded();
_checkZeroAmount(shares);
if (owner == receiver) {
revert BaseCToken__TransferError();
}
uint256 collateralOf = collateralPosted[owner];
// Fails if transfer not allowed.
uint256 collateralRedeemed = marketManager.canTransfer(
address(this),
shares,
owner,
balanceOf(owner),
collateralOf,
collateralOf > 0 ? true : false
);
if (collateralRedeemed > 0) {
_removeCollateral(collateralRedeemed, owner);
}
_beforeTransferAction(shares, receiver, owner);
}
/// @notice Returns the total assets invariant, any pending rewards for
/// depositors and other values to process a withdrawal.
/// @param assets The amount of the underlying asset to withdraw.
/// @param owner The account that will burn their shares to withdraw
/// assets.
/// @param ta The current total amount of assets inside this vault.
/// @return balance The balance of shares `owner`.
function _checkRedemption(
uint256 assets,
address owner,
uint256 ta
) internal view returns (uint256 balance) {
_checkZeroAmount(assets);
// Check whether `assets` is above their allowed redemption limit.
if (assets > _convertToAssets(balance = balanceOf(owner), ta)) {
_revert(_INSUFFICIENT_LIQUIDITY_SELECTOR);
}
_checkAssetsHeld(assets);
}
/// @notice Checks to make sure an action is not an empty action.
function _checkZeroAmount(uint256 assets) internal pure {
/// @solidity memory-safe-assembly
assembly {
if iszero(assets) {
mstore(0x00, 0xc0883a55) // Revert BaseCToken__ZeroAmount().
// Return bytes 29-32 for the selector.
revert(0x1c, 0x04)
}
}
}
/// @notice An optional set of instructions to check before processing
/// a redemption of assets.
function _checkAssetsHeld(uint256 /* assets */) internal view virtual {}
/// @dev Checks whether the caller has sufficient permissioning.
function _checkDaoPermissions() internal view {
if (!centralRegistry.hasDaoPermissions(msg.sender)) {
_revert(_UNAUTHORIZED_SELECTOR);
}
}
/// @dev Checks whether the caller has sufficient permissioning.
function _checkElevatedPermissions() internal view {
if (!centralRegistry.hasElevatedPermissions(msg.sender)) {
_revert(_UNAUTHORIZED_SELECTOR);
}
}
/// @dev Returns `ceil(x * y / d)`.
/// Reverts if `x * y` overflows, or `d` is zero.
function _mulDivUp(
uint256 x,
uint256 y,
uint256 d
) internal pure returns (uint256 z) {
z = FixedPointMathLib.mulDivUp(x, y, d);
}
/// @dev Returns `floor(x * y / d)`.
/// Reverts if `x * y` overflows, or `d` is zero.
function _mulDiv(
uint256 x,
uint256 y,
uint256 d
) internal pure returns (uint256 z) {
z = FixedPointMathLib.mulDiv(x, y, d);
}
/// INTERNAL HOOK FUNCTIONS WHICH MAY BE OVERRIDDEN ///
/// @notice An optional set of instructions to execute before processing
/// a deposit of `receiver`'s shares.
function _afterDepositAction(uint256, address) internal virtual {}
/// @notice An optional set of instructions to execute before processing
/// a withdrawal of `owners`'s shares.
function _beforeWithdrawAction(uint256, address) internal virtual {}
/// @notice An optional set of instructions to execute before processing
/// a transfer of `owner`'s shares to `receiver`.
function _beforeTransferAction(uint256, address, address) internal virtual {}
/// @notice An optional set of instructions to execute before processing
/// liquidation of `account`'s collateral.
function _beforeLiqAction(uint256, address, address) internal virtual {}
}
// contracts/market/token/BaseCTokenWithYield.sol
abstract contract BaseCTokenWithYield is BaseCToken {
/// CONSTANTS ///
/// @notice The maximum length of time between vesting periods.
/// @dev Though this is inherited by both `BorrowableCToken` and
/// `StrategyCToken` it is only primarily interacted with by
/// `StrategyCToken` this is because `vestingPeriod` is equal to
/// `ADJUSTMENT_RATE` inside the attached `dynamicIRM` which is
/// currently set to always be 10 minutes. This means we have this
/// maximum value check and `vestingPeriod` mainly to create a
/// consistent interface for frontends or other data aggregators
/// to query.
uint256 internal constant _MAXIMUM_VESTING_PERIOD = 3 days;
/// STORAGE ///
/// @notice The period of time harvested rewards are vested over,
/// in seconds.
/// @dev See `_MAXIMUM_VESTING_PERIOD` dev comment for information on how
/// this is only interacted with by `StrategyCToken` and not
/// `BorrowableCToken`.
uint256 public vestingPeriod;
/// @dev Internal packed vesting data:
/// `StrategyCToken` Bits Layout:
/// - [0..127] `VESTING_RATE`.
/// - [128..191] `VEST_END`.
/// - [192..255] `LAST_VEST`.
///
/// `BorrowableCToken` Bits Layout:
/// - [0..95] `VESTING_RATE`.
/// - [96..135] `VEST_END`.
/// - [136..175] `LAST_VEST`.
/// - [176..255] Market `DEBT_INDEX`.
uint256 internal _vestingData;
/// ERRORS ///
error BaseCTokenWithYield__InvalidVestingPeriod();
/// CONSTRUCTOR ///
/// @param cr The address of the Protocol Central Registry.
/// @param asset_ The address of the underlying asset for this cToken.
/// @param mm The address of the MarketManager which manages liquidity
/// positions between linked cTokens inside a joint market.
/// @param vestingPeriod_ The length of time a vesting period will last,
/// in seconds.
constructor(
ICentralRegistry cr,
IERC20 asset_,
address mm,
uint256 vestingPeriod_
) BaseCToken(cr, asset_, mm) {
_checkVestingPeriod(vestingPeriod_);
vestingPeriod = vestingPeriod_;
}
/// INTERNAL FUNCTIONS ///
/// @notice Validates whether `newPeriod` is a valid value for
/// `vestingPeriod`.
function _checkVestingPeriod(uint256 newPeriod) internal pure {
if (newPeriod > _MAXIMUM_VESTING_PERIOD || newPeriod == 0) {
revert BaseCTokenWithYield__InvalidVestingPeriod();
}
}
/// @notice Returns the total amount of the underlying asset in the vault,
/// including pending rewards that are vested.
/// @return r The total number of underlying assets.
function _getTotalAssets() internal view override returns (uint256 r) {
r = _totalAssets + _assetsToVest();
}
/// @notice Calculates pending assets that have been vested.
/// @dev If there are no pending assets or the vesting period has ended,
/// it returns 0.
/// @return The calculated pending assets to vest.
function _assetsToVest() internal view virtual returns (uint256);
}
// contracts/market/token/BorrowableCToken.sol
contract BorrowableCToken is BaseCTokenWithYield {
/// CONSTANTS ///
/// @notice Maximum percentage fee that can be taken from interest accrued
/// from outstanding debt, in `basis points`.
/// @dev 6000 = 60%.
uint256 public constant MAX_INTEREST_ACCRUAL_FEE = 6000;
/// @notice Percentage (%) fee on loan taken during a flashloan, in `BPS`.
/// @dev 4 bps = 0.04%.
uint256 public constant FLASHLOAN_FEE = 4;
/// @dev Mask of `VESTING_RATE` entry in `_vestingData`.
uint256 internal constant _BITMASK_VESTING_RATE = (1 << 96) - 1;
/// @dev The bit position of `VEST_END` in `_vestingData`.
uint256 internal constant _BITPOS_VEST_END = 96;
/// @dev The bit position of `LAST_VEST` in `_vestingData`.
uint256 internal constant _BITPOS_LAST_VEST = 136;
/// @dev The bit position of `DEBT_INDEX` in `_vestingData` and `_debtOf`.
uint256 internal constant _BITPOS_DEBT_INDEX = 176;
/// @dev `bytes4(keccak256(bytes("BorrowableCToken__InvalidParameter()")))`
uint256 internal constant _INVALID_PARAMETER_SELECTOR = 0x8b5fe5a3;
/// STORAGE ///
/// @notice Address of the current Interest Rate Model used to determine
/// interest paid by borrowers to lenders for outstanding debt.
IDynamicIRM public IRM;
/// @notice The amount of `asset` that has been borrowed as outstanding
/// debt, in assets.
/// @dev We do not need to worry about uint240 overflow here since we
/// limit debt caps to type(uint136).max in the Market Manager.
uint240 public marketOutstandingDebt;
/// @notice The portion of interest paid by borrowers that goes to the
/// protocol, in `BPS`.
uint16 public interestFee;
/// @notice Active debt information associated with an account.
/// @dev Bits Layout:
/// - [0..175] Account `DEBT`.
/// - [176..255] Account `DEBT_INDEX`.
mapping(address => uint256) internal _debtOf;
/// EVENTS ///
event DebtAccrued(uint256 newDebtAssets, uint256 protocolFeeAssets);
event RatesAdjusted(uint256 debtPerSecond, uint256 nextAdjustment);
event Borrow(uint256 assets, uint256 debtAssetsOwed, address account);
event Repay(uint256 assets, uint256 debtAssetsOwed, address payer, address account);
event Flashloan(uint256 assets, uint256 assetsFee, address account);
event BadDebtRecognized(uint256 assets, address liquidator);
event NewIRM(address oldIRM, address newIRM, uint256 newVestingPeriod);
event NewInterestFee(uint256 oldInterestFee, uint256 newInterestFee);
event ExcessRecovered(uint256 assets, address recipient);
/// ERRORS ///
error BorrowableCToken__CollateralPositionActive();
error BorrowableCToken__DebtPositionActive();
error BorrowableCToken__InvalidParameter();
error BorrowableCToken__InsufficientAssetsHeld();
error BorrowableCToken__DepositsNotInitialized();
/// CONSTRUCTOR ///
/// @param cr The address of the Protocol Central Registry.
/// @param asset_ The address of the underlying asset for this cToken.
/// @param mm The address of the MarketManager which manages liquidity
/// positions between linked cTokens inside a joint market.
/// @param IRM_ The interest rate model to determine interest
/// paid by borrowers to lenders for outstanding debt.
constructor(
ICentralRegistry cr,
IERC20 asset_,
address mm,
address IRM_
) BaseCTokenWithYield(cr, asset_, mm, IDynamicIRM(IRM_).ADJUSTMENT_RATE()) {
// We configure `vestingRate` via both `BaseCTokenWithYield()` and
// `_setIRM()` but this is only for frontends on onchain contracts to
// call, its more efficient for us to call `ADJUSTMENT_RATE` inside
// `IRM` to avoid an sLOAD cost on every adjustment period.
_setIRM(IDynamicIRM(IRM_));
// Assign the portion of interest paid by borrowers that goes to the
// protocol.
_setInterestFee(centralRegistry.defaultProtocolInterestFee());
}
/// @notice Returns the current vesting yield information.
/// @return vestingRate % per second in `asset()`.
/// @return vestingEnd When the current vesting period ends and interest
/// rates paid will update.
/// @return lastVestingClaim Last time pending vested yield was claimed.
/// @return debtIndex The current market debt index.
function getYieldInformation() external view nonReadReentrant returns (
uint256 vestingRate,
uint256 vestingEnd,
uint256 lastVestingClaim,
uint256 debtIndex
) {
// Cache `_vestingData`, the packed vesting data storage value.
uint256 vestingData = _vestingData;
vestingRate = uint96(vestingData);
vestingEnd = uint40(vestingData >> _BITPOS_VEST_END);
lastVestingClaim = uint40(vestingData >> _BITPOS_LAST_VEST);
debtIndex = uint80(vestingData >> _BITPOS_DEBT_INDEX);
}
/// @notice Accrues pending interest and updates the interest rate
/// model (`IRM`) used by this borrowableCToken.
/// @dev Admin function to update the interest rate model.
/// Emits a {NewIRM} event.
/// @param newIRM The new interest rate model to determine interest
/// paid by borrowers to lenders for outstanding debt.
function setIRM(address newIRM) external nonReentrant {
_checkElevatedPermissions();
// Accrue interest if needed.
_accrueIfNeeded();
// Validate that the adjustment rate has not changed from the previous
// one, which would go against user assumptions.
if (IDynamicIRM(newIRM).ADJUSTMENT_RATE() != vestingPeriod) {
revert BaseCTokenWithYield__InvalidVestingPeriod();
}
_setIRM(IDynamicIRM(newIRM));
}
/// @notice Accrues pending interest and updates the fee that the protocol
/// takes on interest paid by borrowers.
/// @dev Admin function to update `interestFee`.
/// Emits a {NewInterestFee} event.
/// @param newInterestFee The portion of interest paid by borrowers that
/// goes to the protocol.
function setInterestFee(uint256 newInterestFee) external nonReentrant {
_checkElevatedPermissions();
// Accrue interest if needed.
_accrueIfNeeded();
_setInterestFee(newInterestFee);
}
/// @notice Borrows underlying tokens from lenders, based on collateral
/// posted inside this market by the caller.
/// @dev Updates pending interest before executing the borrow.
/// @param assets The amount of the underlying asset to borrow.
/// @param receiver The account who will receive the borrowed assets.
function borrow(uint256 assets, address receiver) external nonReentrant {
// Accrue interest if needed.
_accrueIfNeeded();
// Reverts if borrow not allowed.
// Notifies the Market Manager that a user is taking on more debt,
// and to pause user redemptions for 20 minutes.
marketManager.canBorrowWithNotify(
address(this),
assets,
msg.sender,
marketOutstandingDebt + assets
);
_borrow(assets, receiver, msg.sender);
}
/// @notice Used by a delegated user to borrow underlying tokens
/// from lenders, based on collateral posted inside this market
/// by `account`.
/// @dev Updates pending interest before executing the borrow.
/// NOTE: Be careful who you approve here!
/// Not only can they take borrowed funds, but, they can delay
/// repayment through repeated borrows preventing withdrawal.
/// @param assets The amount of the underlying asset to borrow.
/// @param receiver The account who will receive the borrowed assets.
/// @param owner The account who will have their assets borrowed
/// against.
function borrowFor(
uint256 assets,
address receiver,
address owner
) external nonReentrant {
_checkDelegate(owner, msg.sender);
// Accrue interest if needed.
_accrueIfNeeded();
// Reverts if borrow not allowed.
// Notifies the Market Manager that a user is taking on more debt,
// and to pause user redemptions for 20 minutes.
marketManager.canBorrowWithNotify(
address(this),
assets,
owner,
marketOutstandingDebt + assets
);
_borrow(assets, receiver, owner);
}
/// @notice Used by a Position Manager contract to borrow assets from
/// lenders, based on collateralized shares by `account` to
/// perform a complex action.
/// @dev Only Position Manager contract can call this function.
/// Updates pending interest before executing the borrow.
/// @param assets The amount of the underlying asset to borrow.
/// @param action Instructions for a leverage action containing:
/// borrowableCToken Address of the borrowableCToken that
/// will be borrowed from and assets
/// swapped into `cToken` asset.
/// borrowAssets The amount borrowed from
/// `borrowableCToken`, in assets.
/// cToken Curvance token assets that borrowed funds will be
/// swapped into.
/// swapAction Swap action instructions converting debt
/// asset into collateral asset to facilitate
/// leveraging.
/// auxData Optional auxiliary data for execution of a
/// leverage action.
/// @param owner The account address to borrow on behalf of.
function borrowForPositionManager(
uint256 assets,
address owner,
IPositionManager.LeverageAction memory action
) external nonReentrant {
if (!marketManager.isPositionManager(msg.sender)) {
_revert(_UNAUTHORIZED_SELECTOR);
}
// Accrue interest if needed.
// This generally is a redundant check due to interest accrual
// done inside `checkSlippage` modifier inside position manager
// contracts, but we keep this check in for invariant
// protection in the case of a incorrectly implemented contract.
_accrueIfNeeded();
// Notifies the Market Manager that a user is taking on more debt,
// and to pause user redemptions for 20 minutes.
marketManager.notifyBorrow(address(this), owner);
_borrow(assets, msg.sender, owner);
// Callback to Position Manager to execute remaining leverage logic.
IPositionManager(msg.sender).onBorrow(
address(this),
assets,
owner,
action
);
// Fail if terminal position is not allowed with no additional
// adjustment.
marketManager.canBorrow(
address(this),
0,
owner,
marketOutstandingDebt
);
}
/// @notice Repays outstanding debt to lenders, freeing up their
/// collateral posted inside this market.
/// @dev Updates interest before executing the repayment.
/// @param assets The amount to repay, or 0 for the full outstanding
/// amount.
function repay(uint256 assets) external nonReentrant {
_repay(assets, msg.sender, msg.sender);
}
/// @notice Repays outstanding debt to lenders, on behalf of `owner`,
/// freeing up their collateral posted inside this market.
/// @dev Updates pending interest before executing the repay.
/// @param assets The amount to repay, or 0 for the full outstanding
/// amount.
/// @param owner The account address to repay on behalf of.
function repayFor(uint256 assets, address owner) external nonReentrant {
_repay(assets, msg.sender, owner);
}
/// @notice Liquidates `accounts`' collateral by repaying `amount` debt
/// and transferring the liquidated collateral to the liquidator.
/// @dev Updates pending interest before executing the liquidation.
/// @param debtAmounts The amounts of outstanding debt the liquidator
/// wishes to repay, in underlying assets, empty if
/// intention is to liquidate maximum amount possible
/// for each account.
/// @param accounts The addresses of the accounts to be liquidated.
/// @param collateralToken The market in which to seize collateral
/// from `accounts`.
function liquidateExact(
uint256[] calldata debtAmounts,
address[] calldata accounts,
address collateralToken
) external nonReentrant {
uint256 numAccounts = accounts.length;
if (numAccounts != debtAmounts.length) {
_revert(_INVALID_PARAMETER_SELECTOR);
}
_liquidate(
debtAmounts,
msg.sender,
accounts,
collateralToken,
numAccounts,
true
);
}
/// @notice Liquidates `accounts` for as much collateral as possible by
/// repaying debt and transferring the liquidated collateral
/// to the liquidator.
/// @dev Updates pending interest before executing the liquidation.
/// @param accounts The addresses of the accounts to be liquidated.
/// @param collateralToken The market in which to seize collateral
/// from `accounts`.
function liquidate(
address[] calldata accounts,
address collateralToken
) external nonReentrant {
uint256 numAccounts = accounts.length;
// `debtAmounts` array is empty since the max amount possible
// will be liquidated.
uint256[] memory debtAmounts = new uint256[](numAccounts);
_liquidate(
debtAmounts,
msg.sender,
accounts,
collateralToken,
numAccounts,
false
);
}
/// @notice Lends a caller `assets` for a transaction to execute
/// desired programmatic logic, full return of lent
/// assets + a fee by the end of the transaction is
/// required.
/// @param assets The amount of `asset()` loaned during the flashloan.
/// @param data Arbitrary calldata passed to flashloan callback to execute
/// desired action during the flashloan.
function flashLoan(uint256 assets, bytes calldata data) external {
_accrueIfNeeded();
_checkZeroAmount(assets);
if (assets > _asset.balanceOf(address(this))) {
revert BorrowableCToken__InsufficientAssetsHeld();
}
address token = address(_asset);
uint256 fee = flashFee(assets);
uint256 assetsReturned = assets + fee;
SafeTransferLib.safeTransfer(token, msg.sender, assets);
IFlashLoan(msg.sender).onFlashLoan(assets, assetsReturned, data);
SafeTransferLib.safeTransferFrom(
token,
msg.sender,
address(this),
assetsReturned
);
_totalAssets = _totalAssets + fee;
emit Flashloan(assets, fee, msg.sender);
}
/// @notice Updates pending interest and then returns the current
/// market-wide outstanding debt.
/// @dev Used for third party integrations.
/// @return result Total market-wide outstanding debt of asset(), with
/// pending interest applied.
function marketOutstandingDebtUpdated()
external
nonReentrant
returns (uint256 result)
{
// Accrue interest if needed.
_accrueIfNeeded();
result = marketOutstandingDebt;
}
/// @notice Updates pending interest and returns the current outstanding
/// debt owed by `account`.
/// @dev Used for third party integrations.
/// @param account The address whose debt balance should be calculated.
/// @return result The current outstanding debt of `account`, with pending
/// interest applied.
function debtBalanceUpdated(
address account
) external nonReentrant returns (uint256 result) {
// Accrue interest if needed.
_accrueIfNeeded();
result = debtBalance(account);
}
/// @notice Recovers any accumulated excess underlying from rounding or
/// unsolicited donations, to the DAO address.
/// @dev Does not modify `_totalAssets` or any accounting to avoid
/// invariant manipulation.
/// Computed as:
/// debtPlusBalance = marketOutstandingDebt + underlyingBalance
/// excess = debtPlusBalance - totalAssets.
/// Requires DAO permissions.
function skim() external nonReentrant {
_checkDaoPermissions();
uint256 excess = skimAvailable();
address daoAddress = centralRegistry.daoAddress();
SafeTransferLib.safeTransfer(asset(), daoAddress, excess);
emit ExcessRecovered(excess, daoAddress);
}
/// PUBLIC FUNCTIONS ///
/// @notice Returns the amount of excess underlying that can be safely
/// recovered without impacting user accounting.
/// @dev Computed as:
/// marketOutstandingDebt + underlyingBalance - totalAssets.
/// @return excess The recoverable excess underlying amount.
/// Reverts with BaseCToken__ZeroAmount() if none.
function skimAvailable() public view returns (uint256 excess) {
uint256 cachedAssets = _totalAssets;
uint256 debtPlusBalance =
marketOutstandingDebt + IERC20(_asset).balanceOf(address(this));
if (debtPlusBalance <= cachedAssets) {
revert BaseCToken__ZeroAmount();
}
excess = debtPlusBalance - cachedAssets;
}
/// @notice Get a snapshot of the cToken and `account` data.
/// @dev Used by marketManager to more efficiently perform
/// liquidity checks.
/// NOTE: Does not accrue pending interest as part of the call.
/// @param account The address of the account to snapshot.
/// @return result The account snapshot of `account`.
function getSnapshot(
address account
) public view override returns (AccountSnapshot memory result) {
uint256 outstandingDebt = debtBalance(account);
result.asset = address(this);
result.underlying = address(_asset);
result.decimals = decimals();
result.isCollateral = outstandingDebt > 0 ? false : true;
result.collateralPosted = collateralPosted[account];
result.debtBalance = outstandingDebt;
}
/// @notice Returns the current debt balance for `account`.
/// @dev Note: Pending interest is not applied in this calculation.
/// @param account The address whose debt balance should be calculated.
/// @return r The current outstanding debt balance of `account`.
function debtBalance(address account) public view returns (uint256 r) {
// Cache `_debtOf`, the packed account active debt storage value.
uint256 debtOf = _debtOf[account];
uint256 outstandingDebt = uint176(debtOf);
// If theres no outstanding debt, can return immediately with 0.
if (outstandingDebt == 0) {
return r;
}
// Calculate `account` active debt balance using:
// `(Account's outstanding debt * Market's `DEBT_INDEX`) /
// Account's `DEBT_INDEX``.
r = _mulDivUp(
outstandingDebt,
uint80(_vestingData >> _BITPOS_DEBT_INDEX),
uint80(debtOf >> _BITPOS_DEBT_INDEX)
);
}
/// @notice The fee to be charged for a given flashloan.
/// @param assets The amount of `asset()` lent during the flashloan.
/// return The assets of `asset()` to be charged for the flashloan.
function flashFee(uint256 assets) public pure returns (uint256 fee) {
fee = _mulDivUp(assets, FLASHLOAN_FEE, BPS);
}
/// @notice Gets balance of borrowable assets held by this
/// borrowableCToken contract.
/// @dev This excludes changes in assets by the current transaction,
/// if any.
/// @return result The quantity of borrowable assets held by the market.
function assetsHeld() public view returns (uint256 result) {
uint256 currentAssets = _totalAssets;
if (currentAssets == 0) {
revert BorrowableCToken__DepositsNotInitialized();
}
// We add _BASE_UNDERLYING_RESERVE to the calculation to ensure that
// the market never actually runs out of assets and may introduce
// invariant manipulation.
// This also acts as a protective mechanism against trying to
// manipulate marketOutstandingDebt above total underlying assets
// inside the system since there will always be at least
// _BASE_UNDERLYING_RESERVE excess inside the market.
result = currentAssets - marketOutstandingDebt - _BASE_UNDERLYING_RESERVE;
}
/// @notice Returns whether the underlying token can be borrowed.
/// @dev true = Borrowable; false = Not Borrowable.
/// @return result Whether this token is borrowable or not.
function isBorrowable() public pure override returns (bool result) {
result = true;
}
/// INTERNAL FUNCTIONS ///
/// @notice Executes borrowing of assets for `account` from lenders.
/// @dev Emits a {Borrow} event.
/// @param assets The amount of the underlying asset to borrow.
/// @param receiver The account receiving the borrowed assets.
/// @param owner The account borrowing assets.
function _borrow(
uint256 assets,
address receiver,
address owner
) internal {
_checkZeroAmount(assets);
_checkAssetsHeld(assets);
// Cannot borrow if `account` already has posted collateral in this
// market.
if (collateralPosted[owner] > 0) {
revert BorrowableCToken__CollateralPositionActive();
}
// Calculate current account debt then add `assets`.
// Then update account exchange rate, and total borrow balances.
uint256 debtOf = debtBalance(owner) + assets;
_setDebtOf(
owner,
uint176(debtOf),
uint80(_vestingData >> _BITPOS_DEBT_INDEX)
);
marketOutstandingDebt = uint240(marketOutstandingDebt + assets);
// Transfer underlying to `receiver`.
SafeTransferLib.safeTransfer(asset(), receiver, assets);
emit Borrow(assets, debtOf, owner);
}
/// @notice Repays an outstanding loan of `account` through repayment
/// by `payer`, who usually is themselves.
/// @dev Emits a {Repay} event.
/// @param assets The amount the payer wishes to repay,
/// or 0 for the full outstanding amount.
/// @param payer The address paying down the account debt.
/// @param owner The account with the debt being paid down.
/// @return The assets of underlying token debt repaid for `account`.
function _repay(
uint256 assets,
address payer,
address owner
) internal returns (uint256) {
// Accrue interest if needed.
_accrueIfNeeded();
// Cache how much the account has to save gas.
uint256 debtOf = debtBalance(owner);
// If assets == 0, repay max; assets = debtOf.
assets = assets == 0 ? debtOf : assets;
_checkZeroAmount(assets);
// Validate repayment amount is not excessive.
if (assets > debtOf) {
_revert(_INVALID_PARAMETER_SELECTOR);
}
SafeTransferLib.safeTransferFrom(asset(), payer, address(this), assets);
// Validate that the payer is allowed to repay the loan, then update
// account data.
marketManager.canRepayWithReview(
address(this),
debtOf = debtOf - assets,
asset(),
decimals(),
owner
);
_setDebtOf(
owner,
uint176(debtOf),
uint80(_vestingData >> _BITPOS_DEBT_INDEX)
);
// We round user debt in favor of the protocol to prevent exchange
// rate manipulation, as a result in some cases the last user cannot
// fully repay their debt.
if (marketOutstandingDebt < assets) {
marketOutstandingDebt = 0;
} else {
marketOutstandingDebt = uint240(marketOutstandingDebt - assets);
}
emit Repay(assets, debtOf, payer, owner);
return assets;
}
/// @notice Facilitates a liquidator liquidating the borrowers collateral
/// by repaying a portion of their debt. The collateral seized
/// is transferred to the liquidator.
/// @dev Emits {Repay} and {Liquidated} events.
/// @param debtAmounts The amounts of outstanding debt the liquidator
/// wishes to repay, in underlying assets, empty if
/// intention is to liquidate maximum amount possible
/// for each account.
/// @param liquidator The address repaying the borrow and seizing
/// collateral.
/// @param accounts The accounts to be liquidated.
/// @param collateralToken The market in which to seize collateral from
/// the account.
/// @param numAccounts The number of accounts to be potentially
/// liquidated.
/// @param exactAmount Whether a specific amount of debt token assets
/// should be liquidated inputting false will attempt
/// to liquidate the maximum amount possible.
function _liquidate(
uint256[] memory debtAmounts,
address liquidator,
address[] calldata accounts,
address collateralToken,
uint256 numAccounts,
bool exactAmount
) internal {
// Cannot have debt and collateral in the same token, so can revert
// immediately if someone tries.
if (collateralToken == address(this)) {
_revert(_INVALID_PARAMETER_SELECTOR);
}
// Accrue interest if needed.
_accrueIfNeeded();
IMarketManager.LiqResult memory result;
// Fails if liquidation not allowed, trying to repay too much debt
// will revert.
(result, debtAmounts) = marketManager.canLiquidate(
debtAmounts,
liquidator,
accounts,
IMarketManager.LiqAction({
collateralToken: collateralToken,
debtToken: address(this),
numAccounts: numAccounts,
liquidateExact: exactAmount,
liquidatedShares: 0,
debtRepaid: 0,
badDebt: 0
})
);
SafeTransferLib.safeTransferFrom(
asset(),
liquidator,
address(this),
result.debtRepaid
);
uint80 cachedDebtIndex = uint80(_vestingData >> _BITPOS_DEBT_INDEX);
uint256 debtAmount;
uint256 debtOf;
address account;
for (uint256 i; i < numAccounts; ++i) {
// Cache the liquidation repayment amount.
debtAmount = debtAmounts[i];
// If theres no debt to repay for this user can
// skip them.
if (debtAmount == 0) {
continue;
}
account = accounts[i];
// Calculate the new `account` outstanding debt, then update the
// account's debt balance and debt index value.
// Update the account and market outstanding debt balance data.
debtOf = debtBalance(account) - debtAmount;
_setDebtOf(
account,
uint176(debtOf),
cachedDebtIndex
);
emit Repay(debtAmount, debtOf, liquidator, account);
}
// We need to update marketOutstandingDebt for the total debt repaid
// by the liquidator, plus the bad debt being realized. We can reuse
// debtRepaid variable since the original debt repayment value
// was already used earlier.
result.debtRepaid += result.badDebtRealized;
if (marketOutstandingDebt < result.debtRepaid) {
// We round user debt in favor of the protocol to prevent exchange
// rate manipulation, as a result in some cases the last user
// cannot fully repay their debt.
marketOutstandingDebt = 0;
} else {
marketOutstandingDebt =
uint240(marketOutstandingDebt - result.debtRepaid);
}
// Update total assets to recognize that lenders wont be getting
// `result.badDebtRealized` back due to realized bad debt.
// Emit corresponding event recognizing bad debt.
if (result.badDebtRealized > 0) {
uint256 ta = _totalAssets;
if (ta < result.badDebtRealized + _BASE_UNDERLYING_RESERVE) {
revert BorrowableCToken__InsufficientAssetsHeld();
}
_totalAssets = ta - result.badDebtRealized;
emit BadDebtRecognized(result.badDebtRealized, liquidator);
}
ICToken(collateralToken).seize(
result.liquidatedShares,
liquidator,
accounts
);
}
/// @notice Helper function for posting `shares` as collateral
/// for `account` inside this market.
/// @dev Cannot post collateral if `account` already has outstanding
/// debt in this token.
/// Emits {CollateralUpdated} event.
/// May emit {PositionUpdated} event inside Market Manager.
/// @param shares The amount of shares to post as collateral.
/// @param owner The account posting collateral.
function _postCollateral(uint256 shares, address owner) internal override {
// Cannot post collateral if `owner` already has outstanding debt
// in this token.
if (uint176(_debtOf[owner]) > 0) {
revert BorrowableCToken__DebtPositionActive();
}
super._postCollateral(shares, owner);
}
/// @notice Can accrue interest yield, configure next interest accrual
/// period, and updates vesting data, if needed.
/// @dev May emit a {RatesAdjusted} event.
function _accrueIfNeeded() internal override {
// Cache `_vestingData`, the packed vesting data storage value.
uint256 vestingData = _vestingData;
uint256 lastVestingClaim = uint40(vestingData >> _BITPOS_LAST_VEST);
// If no time has passed since `lastVestingClaim` can exit immediately.
if (block.timestamp == lastVestingClaim) {
return;
}
uint256 rate = uint96(vestingData);
uint256 vestingEnd = uint40(vestingData >> _BITPOS_VEST_END);
uint256 marketDebtIndex = uint80(vestingData >> _BITPOS_DEBT_INDEX);
uint256 outstandingDebt = marketOutstandingDebt;
uint256 cachedTa = _totalAssets;
uint256 assetsToVest = _assetsToVest(
rate,
outstandingDebt,
vestingEnd,
lastVestingClaim
);
// Check if it is time to start a new vesting period.
if (block.timestamp >= vestingEnd) {
// Update `lastVestingClaim`, to `vestingEnd` so we can vest any
// pending assets from the new accrual period.
lastVestingClaim = vestingEnd;
uint256 adjustmentRate;
// Calculate the new interest rate for borrowers, in seconds.
(rate, adjustmentRate) = IRM.adjustedBorrowRate(
assetsHeld(),
outstandingDebt + assetsToVest
);
// The multiplication logic here is to round down to
// discrete `adjustmentRate` cycles, e.g. if block.timestamp is 3
// `adjustmentRate`'s ahead then begin vesting all of them for
// users at once.
adjustmentRate = (((block.timestamp - vestingEnd) /
adjustmentRate) * adjustmentRate) + adjustmentRate;
vestingEnd = vestingEnd + adjustmentRate;
emit RatesAdjusted(rate, vestingEnd);
// Check if theres new yield to be vested from the new vesting
// period, which could happen if the previous vesting period ended
// and block.timestamp extends into the new vesting period.
assetsToVest += _assetsToVest(
rate,
outstandingDebt + assetsToVest,
vestingEnd,
lastVestingClaim
);
}
// Calculate any protocol fee on `assetsToVest`, in assets.
// If theres fees we need to mint new shares for the protocol.
uint256 protocolFee = _mulDivUp(assetsToVest, interestFee, BPS);
if (protocolFee > 0) {
// We can calculate how many shares the protocol should receive
// from its fee on assetsToVest by using the formula:
// (fee * totalSupply) / (totalAssets + assetsToVest - fee).
// This means that that shares minted will result in an exchange
// rate matching the amount of vested assets lenders should
// benefit from.
uint256 protocolFeeShares = FixedPointMathLib.fullMulDivUp(
protocolFee,
totalSupply(),
cachedTa + assetsToVest - protocolFee
);
// Cache `daoAddress` then mint shares to dao operator address.
address daoAddress = centralRegistry.daoAddress();
_mint(daoAddress, protocolFeeShares);
_afterDepositAction(protocolFeeShares, daoAddress);
}
// Vest pending assets, if there is any.
if (assetsToVest > 0) {
// `assetsToVest` is new outstanding debt in assets so we
// need to divide by `outstandingDebt` so its in % form.
// Rounding up here can cause individual user debt to be increased
// more heavily than expected when a cToken has extremely low
// borrow utilization, this is intentional.
marketDebtIndex =
_mulDivUp(assetsToVest, marketDebtIndex, outstandingDebt)
+ marketDebtIndex;
// Update marketOutstandingDebt invariant with vested assets.
marketOutstandingDebt = uint240(outstandingDebt + assetsToVest);
// Update _totalAssets based on new assets recognized by protocol.
_totalAssets = cachedTa + assetsToVest;
emit DebtAccrued(assetsToVest, protocolFee);
}
assembly {
// Mask `rate` to the lower 96 bits, in case the upper bits
// somehow are not clean.
rate := and(rate, _BITMASK_VESTING_RATE)
// Equals `rate | (vestingEnd << _BITPOS_VEST_END) |
// block.timestamp << _BITPOS_LAST_VEST | marketDebtIndex`.
vestingData := or(
rate,
or(
or(
shl(_BITPOS_VEST_END, vestingEnd),
shl(_BITPOS_LAST_VEST, timestamp())
),
shl(_BITPOS_DEBT_INDEX, marketDebtIndex)
)
)
// Update packed `_vestingData` based on new vesting config.
sstore(_vestingData.slot, vestingData)
}
}
/// @notice Updates the interest rate model (`IRM`) used
/// by this borrowableCToken.
/// @dev Emits a {NewIRM} event.
/// @param newIRM The new interest rate model to determine interest paid
/// by borrowers to lenders for outstanding debt.
function _setIRM(IDynamicIRM newIRM) internal {
// Ensure we are switching to an actual Interest Rate Model.
if (
!ERC165Checker.supportsInterface(
address(newIRM),
type(IDynamicIRM).interfaceId
)
) {
_revert(_INVALID_PARAMETER_SELECTOR);
}
// Cache the current interest rate model for event emission.
address oldIRM = address(IRM);
// Set new interest rate model and compound rate.
IRM = newIRM;
uint256 newPeriod = newIRM.ADJUSTMENT_RATE();
vestingPeriod = newPeriod;
emit NewIRM(oldIRM, address(newIRM), newPeriod);
}
/// @notice Updates the fee that the protocol takes on interest paid
/// by borrowers.
/// @dev Emits a {NewInterestFee} event.
/// @param newInterestFee The portion of interest paid by borrowers that
/// goes to the protocol, in `BPS`.
function _setInterestFee(uint256 newInterestFee) internal {
// The DAO cannot take more than `MAX_INTEREST_ACCRUAL_FEE` of
// interest collected.
if (newInterestFee > MAX_INTEREST_ACCRUAL_FEE) {
_revert(_INVALID_PARAMETER_SELECTOR);
}
// Cache the old interest fee for event emission.
uint256 oldInterestFee = interestFee;
interestFee = uint16(newInterestFee);
emit NewInterestFee(oldInterestFee, interestFee);
}
/// @notice Packs `newOutstandingDebt` with current `marketDebtIndex` to
/// create new packed `_debtOf` for `account`.
/// @param account The account to set `_debtOf` value for.
/// @param newOutstandingDebt The new outstanding debt of `account`.
/// @param marketDebtIndex The current market debt index value.
function _setDebtOf(
address account,
uint176 newOutstandingDebt,
uint80 marketDebtIndex
) internal {
uint256 newDebtOf;
// Cast `newDebtOf` with assembly to avoid redundant masking.
/// @solidity memory-safe-assembly
assembly {
newDebtOf := newOutstandingDebt
// `newDebtOf | marketDebtIndex`.
newDebtOf := or(
newDebtOf,
shl(_BITPOS_DEBT_INDEX, marketDebtIndex)
)
}
_debtOf[account] = newDebtOf;
}
/// @notice Starts a cToken market, executed via marketManager.
/// @dev This initial mint is a failsafe against rounding exploits,
/// although, we protect against them in many ways,
/// better safe than sorry.
/// @dev Emits a {Deposit} event.
/// @param by The account initializing deposits.
function _initializeDeposits(address by) internal override {
// Validate that the interest rate model is linked to this token.
if (IRM.linkedToken() != address(this)) {
_revert(_UNAUTHORIZED_SELECTOR);
}
super._initializeDeposits(by);
// Calculate `_vestingData` invariant to intended start values.
_vestingData = (_vestingData & _BITMASK_VESTING_RATE) |
(block.timestamp << _BITPOS_VEST_END) |
(block.timestamp << _BITPOS_LAST_VEST) |
(WAD << _BITPOS_DEBT_INDEX);
}
/// @notice Calculates pending assets that have been vested.
/// @dev If there are no pending assets or the vesting period has ended,
/// it returns 0.
/// @return assets The calculated pending assets to vest.
function _assetsToVest() internal view override returns (uint256 assets) {
// Cache `_vestingData`, the packed vesting data storage value.
uint256 vestingData = _vestingData;
assets = _assetsToVest(
uint96(vestingData),
marketOutstandingDebt,
uint40(vestingData >> _BITPOS_VEST_END),
uint40(vestingData >> _BITPOS_LAST_VEST)
);
}
/// @notice Calculates pending assets that have been vested.
/// @dev If there are no pending assets or the vesting period has ended,
/// it returns 0.
/// @return assets The calculated pending assets to vest.
function _assetsToVest(
uint256 vestingRate,
uint256 outstandingDebt,
uint256 vestingEnd,
uint256 lastVestingClaim
) internal view returns (uint256 assets) {
// Check whether there are pending assets vesting.
if (vestingRate > 0 && lastVestingClaim < vestingEnd) {
// When calculating pending assets to vest, if the vesting period
// has not ended:
// assets = vestingRate * (block.timestamp - lastVestingClaim).
// If the vesting period has ended:
// assets = vestingRate * (vestingEnd - lastVestingClaim).
// Then in either case:
// Divide the pending yield by `WAD` (1e18) for precision.
assets = _mulDiv(
block.timestamp < vestingEnd
? vestingRate * (block.timestamp - lastVestingClaim)
: vestingRate * (vestingEnd - lastVestingClaim),
outstandingDebt,
WAD
);
}
}
/// @notice Checks whether there is sufficient assets to handle
/// a withdrawal of `assets` based on assets currently held in
/// this contract.
/// @param assets The amount of assets to withdraw which is checked
/// against current assets held in the contract.
function _checkAssetsHeld(uint256 assets) internal view override {
if (assetsHeld() < assets) {
revert BorrowableCToken__InsufficientAssetsHeld();
}
}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"contract ICentralRegistry","name":"cr","type":"address"},{"internalType":"contract IERC20","name":"asset_","type":"address"},{"internalType":"address","name":"mm","type":"address"},{"internalType":"address","name":"IRM_","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AllowanceOverflow","type":"error"},{"inputs":[],"name":"AllowanceUnderflow","type":"error"},{"inputs":[],"name":"BaseCTokenWithYield__InvalidVestingPeriod","type":"error"},{"inputs":[],"name":"BaseCToken__InsufficientLiquidity","type":"error"},{"inputs":[],"name":"BaseCToken__InvalidMarketManager","type":"error"},{"inputs":[],"name":"BaseCToken__InvariantError","type":"error"},{"inputs":[],"name":"BaseCToken__TransferError","type":"error"},{"inputs":[],"name":"BaseCToken__Unauthorized","type":"error"},{"inputs":[],"name":"BaseCToken__UnsupportedChain","type":"error"},{"inputs":[],"name":"BaseCToken__ZeroAmount","type":"error"},{"inputs":[],"name":"BorrowableCToken__CollateralPositionActive","type":"error"},{"inputs":[],"name":"BorrowableCToken__DebtPositionActive","type":"error"},{"inputs":[],"name":"BorrowableCToken__DepositsNotInitialized","type":"error"},{"inputs":[],"name":"BorrowableCToken__InsufficientAssetsHeld","type":"error"},{"inputs":[],"name":"BorrowableCToken__InvalidParameter","type":"error"},{"inputs":[],"name":"CentralRegistryLib__InvalidCentralRegistry","type":"error"},{"inputs":[],"name":"DepositMoreThanMax","type":"error"},{"inputs":[],"name":"InsufficientAllowance","type":"error"},{"inputs":[],"name":"InsufficientBalance","type":"error"},{"inputs":[],"name":"InvalidPermit","type":"error"},{"inputs":[],"name":"LowLevelCallsHelper__CallFailed","type":"error"},{"inputs":[],"name":"MintMoreThanMax","type":"error"},{"inputs":[],"name":"Multicall__InvalidTarget","type":"error"},{"inputs":[],"name":"Multicall__UnknownCalldata","type":"error"},{"inputs":[],"name":"PermitExpired","type":"error"},{"inputs":[],"name":"PluginDelegable_InvalidParameter","type":"error"},{"inputs":[],"name":"PluginDelegable__DelegatingDisabled","type":"error"},{"inputs":[],"name":"PluginDelegable__Unauthorized","type":"error"},{"inputs":[],"name":"RedeemMoreThanMax","type":"error"},{"inputs":[],"name":"Reentrancy","type":"error"},{"inputs":[],"name":"TotalSupplyOverflow","type":"error"},{"inputs":[],"name":"WithdrawMoreThanMax","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"assets","type":"uint256"},{"indexed":false,"internalType":"address","name":"liquidator","type":"address"}],"name":"BadDebtRecognized","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"assets","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"debtAssetsOwed","type":"uint256"},{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Borrow","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"shares","type":"uint256"},{"indexed":false,"internalType":"bool","name":"increased","type":"bool"},{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"CollateralUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"newDebtAssets","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"protocolFeeAssets","type":"uint256"}],"name":"DebtAccrued","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"delegate","type":"address"},{"indexed":false,"internalType":"uint256","name":"approvalIndex","type":"uint256"},{"indexed":false,"internalType":"bool","name":"isApproved","type":"bool"}],"name":"DelegateApproval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"by","type":"address"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"assets","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"shares","type":"uint256"}],"name":"Deposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"assets","type":"uint256"},{"indexed":false,"internalType":"address","name":"recipient","type":"address"}],"name":"ExcessRecovered","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"assets","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"assetsFee","type":"uint256"},{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Flashloan","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"shares","type":"uint256"},{"indexed":false,"internalType":"address","name":"liquidator","type":"address"},{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Liquidated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldIRM","type":"address"},{"indexed":false,"internalType":"address","name":"newIRM","type":"address"},{"indexed":false,"internalType":"uint256","name":"newVestingPeriod","type":"uint256"}],"name":"NewIRM","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldInterestFee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newInterestFee","type":"uint256"}],"name":"NewInterestFee","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"debtPerSecond","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"nextAdjustment","type":"uint256"}],"name":"RatesAdjusted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"assets","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"debtAssetsOwed","type":"uint256"},{"indexed":false,"internalType":"address","name":"payer","type":"address"},{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Repay","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"by","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"assets","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"shares","type":"uint256"}],"name":"Withdraw","type":"event"},{"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"internalType":"bytes32","name":"result","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FLASHLOAN_FEE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"IRM","outputs":[{"internalType":"contract IDynamicIRM","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_INTEREST_ACCRUAL_FEE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"accrueIfNeeded","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"result","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"asset","outputs":[{"internalType":"address","name":"result","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"assetsHeld","outputs":[{"internalType":"uint256","name":"result","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"result","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"}],"name":"borrow","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"address","name":"owner","type":"address"}],"name":"borrowFor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"},{"internalType":"address","name":"owner","type":"address"},{"components":[{"internalType":"contract IBorrowableCToken","name":"borrowableCToken","type":"address"},{"internalType":"uint256","name":"borrowAssets","type":"uint256"},{"internalType":"contract ICToken","name":"cToken","type":"address"},{"internalType":"uint256","name":"expectedShares","type":"uint256"},{"components":[{"internalType":"address","name":"inputToken","type":"address"},{"internalType":"uint256","name":"inputAmount","type":"uint256"},{"internalType":"address","name":"outputToken","type":"address"},{"internalType":"address","name":"target","type":"address"},{"internalType":"uint256","name":"slippage","type":"uint256"},{"internalType":"bytes","name":"call","type":"bytes"}],"internalType":"struct SwapperLib.Swap","name":"swapAction","type":"tuple"},{"internalType":"bytes","name":"auxData","type":"bytes"}],"internalType":"struct IPositionManager.LeverageAction","name":"action","type":"tuple"}],"name":"borrowForPositionManager","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"centralRegistry","outputs":[{"internalType":"contract ICentralRegistry","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"checkNewDelegationDisabled","outputs":[{"internalType":"bool","name":"result","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"collateralPosted","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"name":"convertToAssets","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"name":"convertToShares","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"debtBalance","outputs":[{"internalType":"uint256","name":"r","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"debtBalanceUpdated","outputs":[{"internalType":"uint256","name":"result","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"}],"name":"deposit","outputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"}],"name":"depositAsCollateral","outputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"}],"name":"depositAsCollateralFor","outputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"exchangeRate","outputs":[{"internalType":"uint256","name":"result","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"exchangeRateUpdated","outputs":[{"internalType":"uint256","name":"result","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"name":"flashFee","outputs":[{"internalType":"uint256","name":"fee","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"flashLoan","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"getSnapshot","outputs":[{"components":[{"internalType":"address","name":"asset","type":"address"},{"internalType":"address","name":"underlying","type":"address"},{"internalType":"uint8","name":"decimals","type":"uint8"},{"internalType":"bool","name":"isCollateral","type":"bool"},{"internalType":"uint256","name":"collateralPosted","type":"uint256"},{"internalType":"uint256","name":"debtBalance","type":"uint256"}],"internalType":"struct AccountSnapshot","name":"result","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"getSnapshotUpdated","outputs":[{"components":[{"internalType":"address","name":"asset","type":"address"},{"internalType":"address","name":"underlying","type":"address"},{"internalType":"uint8","name":"decimals","type":"uint8"},{"internalType":"bool","name":"isCollateral","type":"bool"},{"internalType":"uint256","name":"collateralPosted","type":"uint256"},{"internalType":"uint256","name":"debtBalance","type":"uint256"}],"internalType":"struct AccountSnapshot","name":"result","type":"tuple"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getYieldInformation","outputs":[{"internalType":"uint256","name":"vestingRate","type":"uint256"},{"internalType":"uint256","name":"vestingEnd","type":"uint256"},{"internalType":"uint256","name":"lastVestingClaim","type":"uint256"},{"internalType":"uint256","name":"debtIndex","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"by","type":"address"}],"name":"initializeDeposits","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"interestFee","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isBorrowable","outputs":[{"internalType":"bool","name":"result","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"address","name":"delegate","type":"address"}],"name":"isDelegate","outputs":[{"internalType":"bool","name":"result","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"accounts","type":"address[]"},{"internalType":"address","name":"collateralToken","type":"address"}],"name":"liquidate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"debtAmounts","type":"uint256[]"},{"internalType":"address[]","name":"accounts","type":"address[]"},{"internalType":"address","name":"collateralToken","type":"address"}],"name":"liquidateExact","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"marketCollateralPosted","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"marketManager","outputs":[{"internalType":"contract IMarketManager","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"marketOutstandingDebt","outputs":[{"internalType":"uint240","name":"","type":"uint240"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"marketOutstandingDebtUpdated","outputs":[{"internalType":"uint256","name":"result","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"receiver","type":"address"}],"name":"maxDeposit","outputs":[{"internalType":"uint256","name":"maxAssets","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"receiver","type":"address"}],"name":"maxMint","outputs":[{"internalType":"uint256","name":"maxShares","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"maxRedeem","outputs":[{"internalType":"uint256","name":"maxShares","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"maxWithdraw","outputs":[{"internalType":"uint256","name":"maxAssets","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"}],"name":"mint","outputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"target","type":"address"},{"internalType":"bool","name":"isPriceUpdate","type":"bool"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct Multicall.MulticallAction[]","name":"calls","type":"tuple[]"}],"name":"multicall","outputs":[{"internalType":"bytes[]","name":"results","type":"bytes[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"nonces","outputs":[{"internalType":"uint256","name":"result","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","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":"permit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"name":"postCollateral","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"},{"internalType":"address","name":"owner","type":"address"}],"name":"postCollateralFor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"name":"previewDeposit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"name":"previewMint","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"name":"previewRedeem","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"name":"previewWithdraw","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"address","name":"owner","type":"address"}],"name":"redeem","outputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"address","name":"owner","type":"address"}],"name":"redeemCollateral","outputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"address","name":"owner","type":"address"}],"name":"redeemCollateralFor","outputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"address","name":"owner","type":"address"}],"name":"redeemFor","outputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"name":"removeCollateral","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"},{"internalType":"address","name":"owner","type":"address"}],"name":"removeCollateralFor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"name":"repay","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"},{"internalType":"address","name":"owner","type":"address"}],"name":"repayFor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"liquidatedShares","type":"uint256[]"},{"internalType":"address","name":"liquidator","type":"address"},{"internalType":"address[]","name":"accounts","type":"address[]"}],"name":"seize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"delegate","type":"address"},{"internalType":"bool","name":"isApproved","type":"bool"}],"name":"setDelegateApproval","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newIRM","type":"address"}],"name":"setIRM","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newInterestFee","type":"uint256"}],"name":"setInterestFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"skim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"skimAvailable","outputs":[{"internalType":"uint256","name":"excess","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"result","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalAssets","outputs":[{"internalType":"uint256","name":"result","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"result","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint256","name":"shares","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint256","name":"shares","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"userApprovalIndex","outputs":[{"internalType":"uint256","name":"result","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"vestingPeriod","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"address","name":"owner","type":"address"}],"name":"withdraw","outputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"},{"internalType":"address","name":"owner","type":"address"},{"components":[{"internalType":"contract ICToken","name":"cToken","type":"address"},{"internalType":"uint256","name":"collateralAssets","type":"uint256"},{"internalType":"contract IBorrowableCToken","name":"borrowableCToken","type":"address"},{"internalType":"uint256","name":"repayAssets","type":"uint256"},{"components":[{"internalType":"address","name":"inputToken","type":"address"},{"internalType":"uint256","name":"inputAmount","type":"uint256"},{"internalType":"address","name":"outputToken","type":"address"},{"internalType":"address","name":"target","type":"address"},{"internalType":"uint256","name":"slippage","type":"uint256"},{"internalType":"bytes","name":"call","type":"bytes"}],"internalType":"struct SwapperLib.Swap[]","name":"swapActions","type":"tuple[]"},{"internalType":"bytes","name":"auxData","type":"bytes"}],"internalType":"struct IPositionManager.DeleverageAction","name":"action","type":"tuple"}],"name":"withdrawByPositionManager","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"address","name":"owner","type":"address"}],"name":"withdrawCollateral","outputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"stateMutability":"nonpayable","type":"function"}]Contract Creation Code
610100604052348015610010575f5ffd5b506040516169d03803806169d083398101604081905261002f91610630565b838383836001600160a01b03166367e860cd6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561006e573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610092919061068c565b8383838261009f8161035c565b6001600160a01b03908116608052821660c0819052604080516306fdde0360e01b815290516306fdde03916004808201925f929091908290030181865afa1580156100ec573d5f5f3e3d5ffd5b505050506040513d5f823e601f3d908101601f1916820160405261011391908101906106b7565b604051602001610123919061077e565b60405160208183030381529060405260029081610140919061081f565b50816001600160a01b03166395d89b416040518163ffffffff1660e01b81526004015f60405180830381865afa15801561017c573d5f5f3e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526101a391908101906106b7565b6040516020016101b391906108d9565b604051602081830303815290604052600390816101d0919061081f565b50816001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa15801561020d573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061023191906108ee565b60ff1660e052608051604051637d5528bd60e01b81526001600160a01b03838116600483015290911690637d5528bd90602401602060405180830381865afa15801561027f573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906102a3919061090e565b6102c0576040516365c906df60e11b815260040160405180910390fd5b6001600160a01b031660a052506102d890508161038d565b600655506102e991508290506103ba565b6103536080516001600160a01b031663d68dbfe46040518163ffffffff1660e01b8152600401602060405180830381865afa15801561032a573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061034e919061068c565b6104b7565b5050505061092d565b61036d816399011ef160e01b610538565b61038a576040516369b5e45b60e11b815260040160405180910390fd5b50565b6203f48081118061039c575080155b1561038a57604051631961405760e31b815260040160405180910390fd5b6103cb81638ec124b360e01b610538565b6103dc576103dc638b5fe5a361055a565b600880546001600160a01b031981166001600160a01b03848116918217909355604080516367e860cd60e01b8152905193909216925f926367e860cd9160048083019260209291908290030181865afa15801561043b573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061045f919061068c565b6006819055604080516001600160a01b038086168252861660208201529081018290529091507f6ceb115a1597bd916163fc3cca894b15a8a1dc485d02079de9de8bbfda37a0329060600160405180910390a1505050565b6117708111156104ce576104ce638b5fe5a361055a565b6009805461ffff838116600160f01b9081026001600160f01b038416179384905560408051938290048316808552919094049091166020830152917f27a0956e997c69164a0c4cc2fb19bd083ae33e1abbc2165b43398d899b51fd0b910160405180910390a15050565b5f61054283610563565b801561055357506105538383610596565b9392505050565b805f526004601cfd5b5f610575826301ffc9a760e01b610596565b8015610590575061058e826001600160e01b0319610596565b155b92915050565b6040516001600160e01b0319821660248201525f90819060440160408051601f19818403018152919052602080820180516001600160e01b03166301ffc9a760e01b17815282519293505f9283928392909183918a617530fa92503d91505f519050828015610606575060208210155b801561061157505f81115b979650505050505050565b6001600160a01b038116811461038a575f5ffd5b5f5f5f5f60808587031215610643575f5ffd5b845161064e8161061c565b602086015190945061065f8161061c565b60408601519093506106708161061c565b60608601519092506106818161061c565b939692955090935050565b5f6020828403121561069c575f5ffd5b5051919050565b634e487b7160e01b5f52604160045260245ffd5b5f602082840312156106c7575f5ffd5b81516001600160401b038111156106dc575f5ffd5b8201601f810184136106ec575f5ffd5b80516001600160401b03811115610705576107056106a3565b604051601f8201601f19908116603f011681016001600160401b0381118282101715610733576107336106a3565b60405281815282820160200186101561074a575f5ffd5b8160208401602083015e5f91810160200191909152949350505050565b5f81518060208401855e5f93019283525090919050565b68021bab93b30b731b2960bd1b81525f6105536009830184610767565b600181811c908216806107af57607f821691505b6020821081036107cd57634e487b7160e01b5f52602260045260245ffd5b50919050565b601f82111561081a57805f5260205f20601f840160051c810160208510156107f85750805b601f840160051c820191505b81811015610817575f8155600101610804565b50505b505050565b81516001600160401b03811115610838576108386106a3565b61084c81610846845461079b565b846107d3565b6020601f82116001811461087e575f83156108675750848201515b5f19600385901b1c1916600184901b178455610817565b5f84815260208120601f198516915b828110156108ad578785015182556020948501946001909201910161088d565b50848210156108ca57868401515f19600387901b60f8161c191681555b50505050600190811b01905550565b606360f81b81525f6105536001830184610767565b5f602082840312156108fe575f5ffd5b815160ff81168114610553575f5ffd5b5f6020828403121561091e575f5ffd5b81518015158114610553575f5ffd5b60805160a05160c05160e051615f2e610aa25f395f818161061701528181610f7a015261378101525f818161068401528181610e9301528181610f51015281816115dd0152818161167001528181612c6401528181612ed2015281816136fa0152818161376001528181613e1e0152818161448f015281816149900152614c8601525f81816106db0152818161108a0152818161130f01528181611392015281816114b6015281816117c501528181611b8901528181611e1d01528181611ecc01528181611fc00152818161237b01528181612def015281816132be01528181613471015281816135610152818161372b01528181614099015281816141a30152818161432f015281816145d901528181614a630152614c4a01525f81816108e501528181610e0e01528181611aa6015281816120e0015281816124970152818161253d0152818161296b015281816129da0152818161319b0152818161392e01528181613c130152613f710152615f2e5ff3fe608060405234801561000f575f5ffd5b506004361061047a575f3560e01c806372d46ac211610258578063b3d7f6b91161014b578063d4bb0c73116100ca578063e28d591d1161008f578063e28d591d14610ad9578063e6248d5514610af8578063e8bbf5d714610b0b578063ef8b30f714610b2b578063f0c00c4114610b3e578063f411029114610b46575f5ffd5b8063d4bb0c7314610a6f578063d505accf14610a82578063d905777e14610a95578063dd62ed3e14610aa8578063deee770414610ad0575f5ffd5b8063c63d75b611610110578063c63d75b6146106b0578063c6e6f59214610a23578063cd88c07214610a36578063ce96cb7714610a49578063cf6af22d14610a5c575f5ffd5b8063b3d7f6b9146109c4578063b460af94146109d7578063ba087652146109ea578063bdca6723146109fd578063c3c854b614610a10575f5ffd5b806394bf804d116101d7578063a7af467a1161019c578063a7af467a14610970578063a9059cbb14610983578063ab21e62814610996578063ad9d3683146109a9578063b3bffb45146109b1575f5ffd5b806394bf804d1461090757806395d89b411461091a5780639616756e146109225780639e591a4414610935578063a75df49814610948575f5ffd5b80637ecebe001161021d5780637ecebe001461089757806380fd997f146108bc57806385b13080146108c557806387367d71146108d85780638f73dcfa146108e0575f5ffd5b806372d46ac2146108385780637313ee5a1461084b578063775a814a146108545780637ada7a091461085c5780637c0e0c8c1461086f575f5ffd5b806338d52e0f116103705780635722baf3116102ef578063635d9771116102b4578063635d9771146107af578063640fef7b146107da5780636779db5b146107ed5780636e553f651461080057806370a0823114610813575f5ffd5b80635722baf31461075057806357d159d5146107635780635b56d6f5146107765780635c0bfa88146107895780635fec5d0b1461079c575f5ffd5b806345d7b97a1161033557806345d7b97a146106fd5780634b3fd148146107045780634cdad5061461071757806350f2012f1461072a5780635296a4311461073d575f5ffd5b806338d52e0f146106825780633ba0b9a9146106a8578063402d267d146106b057806340c09eba146106c357806341ed2c12146106d6575f5ffd5b80631dd19cb4116103fc578063313ce567116103c1578063313ce567146106105780633237c158146106415780633644e51514610654578063371fd8e61461065c57806338c0f3091461066f575f5ffd5b80631dd19cb41461054a5780631e75db1614610552578063215702561461057d57806323b872dd146105ea5780632f4a61d9146105fd575f5ffd5b80630a28a477116104425780630a28a477146104f75780630f0f54361461050a57806311005b071461051f578063176679671461053257806318160ddd1461053a575f5ffd5b806301e1d1141461047e57806301ffc9a71461049957806306fdde03146104bc57806307a2d13a146104d1578063095ea7b3146104e4575b5f5ffd5b610486610b4e565b6040519081526020015b60405180910390f35b6104ac6104a7366004614f3a565b610b79565b6040519015158152602001610490565b6104c4610bca565b6040516104909190614f8f565b6104866104df366004614fa1565b610c5a565b6104ac6104f2366004614fcc565b610c8e565b610486610505366004614fa1565b610cdd565b61051d61051836600461503d565b610cef565b005b61048661052d36600461508f565b610d80565b610486600481565b6805345cdf77eb68f44c54610486565b61051d610dcf565b600854610565906001600160a01b031681565b6040516001600160a01b039091168152602001610490565b61059061058b36600461508f565b610f0a565b604051610490919081516001600160a01b0390811682526020808401519091169082015260408083015160ff16908201526060808301511515908201526080808301519082015260a0918201519181019190915260c00190565b6104ac6105f83660046150aa565b610fdf565b61048661060b3660046150e8565b611037565b60405160ff7f0000000000000000000000000000000000000000000000000000000000000000168152602001610490565b61051d61064f366004614fa1565b611137565b610486611183565b61051d61066a366004614fa1565b6111ff565b61051d61067d366004615116565b611243565b7f0000000000000000000000000000000000000000000000000000000000000000610565565b6104866112d9565b6104866106be36600461508f565b6112ee565b61051d6106d13660046150e8565b611421565b6105657f000000000000000000000000000000000000000000000000000000000000000081565b60016104ac565b61051d6107123660046150e8565b611478565b610486610725366004614fa1565b61156d565b61051d610738366004614fa1565b61157a565b61051d61074b366004615197565b6115b7565b61051d61075e36600461520c565b611781565b61048661077136600461508f565b611994565b61051d610784366004614fa1565b6119e2565b61048661079736600461528c565b611a24565b6104ac6107aa3660046152c0565b611a71565b6009546107c2906001600160f01b031681565b6040516001600160f01b039091168152602001610490565b61051d6107e836600461528c565b611b41565b6104866107fb36600461528c565b611c51565b61048661080e3660046150e8565b611c89565b61048661082136600461508f565b6387a211a2600c9081525f91909152602090205490565b61048661084636600461528c565b611cd1565b61048660065481565b61051d611d08565b6104ac61086a36600461508f565b611d47565b610877611d8e565b604080519485526020850193909352918301526060820152608001610490565b6104866108a536600461508f565b6338377508600c9081525f91909152602090205490565b61048661177081565b61051d6108d3366004615481565b611ddf565b61048661202c565b6105657f000000000000000000000000000000000000000000000000000000000000000081565b6104866109153660046150e8565b61207c565b6104c46120b0565b6104ac61093036600461508f565b6120bf565b61051d6109433660046150e8565b61214b565b60095461095d90600160f01b900461ffff1681565b60405161ffff9091168152602001610490565b61048661097e366004614fa1565b612190565b6104ac610991366004614fcc565b61219f565b61051d6109a43660046150e8565b6121f5565b61048661223c565b6104866109bf3660046150e8565b61228a565b6104866109d2366004614fa1565b6122be565b6104866109e536600461528c565b6122d0565b6104866109f836600461528c565b612306565b61051d610a0b366004615617565b61233d565b61051d610a1e3660046156cf565b612459565b610486610a31366004614fa1565b612626565b610486610a4436600461528c565b612655565b610486610a5736600461508f565b61268d565b610590610a6a36600461508f565b6126aa565b61051d610a7d36600461508f565b6126ec565b61051d610a903660046156fb565b6127af565b610486610aa336600461508f565b612931565b610486610ab63660046152c0565b602052637f5e9f20600c9081525f91909152603490205490565b61048660015481565b610486610ae736600461508f565b60056020525f908152604090205481565b610486610b0636600461508f565b61294a565b610b1e610b1936600461576c565b6129d6565b60405161049091906157aa565b610486610b39366004614fa1565b612c38565b610486612c45565b610486612d1e565b5f688000000000ab143c065c15610b6c5763ab143c065f526004601cfd5b610b74612d37565b905090565b5f6001600160e01b03198216630934615b60e01b1480610ba957506001600160e01b0319821663b6e300c760e01b145b80610bc457506301ffc9a760e01b6001600160e01b03198316145b92915050565b606060028054610bd99061580d565b80601f0160208091040260200160405190810160405280929190818152602001828054610c059061580d565b8015610c505780601f10610c2757610100808354040283529160200191610c50565b820191905f5260205f20905b815481529060010190602001808311610c3357829003601f168201915b5050505050905090565b5f688000000000ab143c065c15610c785763ab143c065f526004601cfd5b610bc482610c84612d37565b612d4d565b919050565b5f82602052637f5e9f20600c52335f52816034600c2055815f52602c5160601c337f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560205fa350600192915050565b5f610bc482610cea612d37565b612d80565b688000000000ab143c065c15610d0c5763ab143c065f526004601cfd5b30688000000000ab143c065d815f816001600160401b03811115610d3257610d326152ec565b604051908082528060200260200182016040528015610d5b578160200160208202803683370190505b509050610d6d8133878787875f612da6565b50505f688000000000ab143c065d505050565b6001600160a01b0381165f908152600a60205260408120546001600160b01b038116808303610db0575050919050565b600754610dc790829060b090811c9085901c61317a565b949350505050565b688000000000ab143c065c15610dec5763ab143c065f526004601cfd5b30688000000000ab143c065d610e00613186565b5f610e09612c45565b90505f7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316632131c68c6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610e68573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610e8c9190615845565b9050610eb97f00000000000000000000000000000000000000000000000000000000000000008284613220565b604080518381526001600160a01b03831660208201527f88fc2578c4b534418a67792f942c22deab48988e8f00bf87d4f8b0d0a8655772910160405180910390a150505f688000000000ab143c065d565b6040805160c0810182525f80825260208201819052918101829052606081018290526080810182905260a0810182905290610f4483610d80565b3083526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016602084015290507f000000000000000000000000000000000000000000000000000000000000000060ff16604083015280610fad576001610faf565b5f5b151560608301526001600160a01b039092165f90815260056020526040902054608082015260a081019190915290565b5f688000000000ab143c065c15610ffd5763ab143c065f526004601cfd5b30688000000000ab143c065d611014828486613260565b61101f84848461338c565b50600190505f688000000000ab143c065d9392505050565b5f688000000000ab143c065c156110555763ab143c065f526004601cfd5b30688000000000ab143c065d336001600160a01b038316148015906110fd5750604051630a73e39160e01b81523360048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690630a73e39190602401602060405180830381865afa1580156110d7573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906110fb9190615860565b155b1561110f5761110f63471656c5613433565b611119838361343c565b905061112581836134dc565b5f688000000000ab143c065d92915050565b688000000000ab143c065c156111545763ab143c065f526004601cfd5b30688000000000ab143c065d61116a8133613529565b6111748133613616565b5f688000000000ab143c065d50565b5f8061118d610bca565b8051906020012090506040517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f81528160208201527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc6604082015246606082015230608082015260a081209250505090565b688000000000ab143c065c1561121c5763ab143c065f526004601cfd5b30688000000000ab143c065d6112338133336136b2565b505f688000000000ab143c065d50565b688000000000ab143c065c156112605763ab143c065f526004601cfd5b30688000000000ab143c065d8184811461128157611281638b5fe5a3613433565b6112c58686808060200260200160405190810160405280939291908181526020018383602002808284375f9201919091525033925088915087905086866001612da6565b505f688000000000ab143c065d5050505050565b5f610b74670de0b6b3a7640000610c84612d37565b60405163699ba8b360e01b81523060048201525f9081906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063699ba8b390602401606060405180830381865afa158015611354573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611378919061588f565b5050604051637bca031760e11b81523060048201529091507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063f794062e90602401602060405180830381865afa1580156113df573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906114039190615860565b158061140c5750805b156114175750919050565b5f195b9392505050565b688000000000ab143c065c1561143e5763ab143c065f526004601cfd5b30688000000000ab143c065d61145481336138fc565b61145e82826139df565b61146882826134dc565b5f688000000000ab143c065d5050565b688000000000ab143c065c156114955763ab143c065f526004601cfd5b30688000000000ab143c065d6114a9613a31565b6009546001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063f96492c9903090859033906114f79083906001600160f01b03166158ce565b6040516001600160e01b031960e087901b1681526001600160a01b03948516600482015260248101939093529216604482015260648101919091526084015f604051808303815f87803b15801561154c575f5ffd5b505af115801561155e573d5f5f3e3d5ffd5b50505050611468828233613d59565b5f610bc482610c84612d37565b688000000000ab143c065c156115975763ab143c065f526004601cfd5b30688000000000ab143c065d6115ad81336139df565b61117481336134dc565b6115bf613a31565b6115c883613e92565b6040516370a0823160e01b81523060048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa15801561162a573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061164e91906158e1565b83111561166e5760405163ab2169c760e01b815260040160405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000005f61169985612190565b90505f6116a682876158ce565b90506116b3833388613220565b604051637924fd7d60e01b81523390637924fd7d906116dc90899085908a908a906004016158f8565b6020604051808303815f875af11580156116f8573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061171c91906158e1565b5061172983333084613ea7565b8160045461173791906158ce565b6004556040805187815260208101849052338183015290517fb216ab52d7988a2a0e79070667f92d2ade5e6464ee97984d5983afe3572348269181900360600190a1505050505050565b688000000000ab143c065c1561179e5763ab143c065f526004601cfd5b30688000000000ab143c065d604051630eaa39a960e31b81523060048201523360248201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690637551cd48906044015f604051808303815f87803b15801561180e575f5ffd5b505af1158015611820573d5f5f3e3d5ffd5b508392505f915081905080805b848110156119695789898281811061184757611847615934565b905060200201359250825f03156119615786868281811061186a5761186a615934565b905060200201602081019061187f919061508f565b915061188b83856158ce565b6001600160a01b0383165f908152600560205260409020549094506118b1908490615948565b6001600160a01b0383165f81815260056020908152604080832094909455835187815290810191909152918201527f26d61a36a46ca0b5adc9f8ae98359690cb59381d060151d48afcfa01e079eda69060600160405180910390a1611917828985613ef6565b604080518481526001600160a01b038a8116602083015284168183015290517f6ee556dbce23a24ad3b539ee42191a2dd262b16ecb4d0ef20dbeb4bb5a9a23839181900360600190a15b60010161182d565b50826001546119789190615948565b600155505f9250688000000000ab143c069150505d5050505050565b5f688000000000ab143c065c156119b25763ab143c065f526004601cfd5b30688000000000ab143c065d6119c6613a31565b6119cf82610d80565b90505f688000000000ab143c065d919050565b688000000000ab143c065c156119ff5763ab143c065f526004601cfd5b30688000000000ab143c065d611a13613f5c565b611a1b613a31565b61117481613fa8565b5f688000000000ab143c065c15611a425763ab143c065f526004601cfd5b30688000000000ab143c065d611a5c84848460015f614022565b90505f688000000000ab143c065d9392505050565b6001600160a01b038281165f81815260208190526040808220905163e6248d5560e01b815260048101939093529092909183917f0000000000000000000000000000000000000000000000000000000000000000169063e6248d5590602401602060405180830381865afa158015611aeb573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611b0f91906158e1565b815260208082019290925260409081015f9081206001600160a01b039095168152939091529091205460ff1692915050565b688000000000ab143c065c15611b5e5763ab143c065f526004601cfd5b30688000000000ab143c065d611b7481336138fc565b611b7c613a31565b6009546001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063f96492c990309086908590611bca9083906001600160f01b03166158ce565b6040516001600160e01b031960e087901b1681526001600160a01b03948516600482015260248101939093529216604482015260648101919091526084015f604051808303815f87803b158015611c1f575f5ffd5b505af1158015611c31573d5f5f3e3d5ffd5b50505050611c40838383613d59565b5f688000000000ab143c065d505050565b5f688000000000ab143c065c15611c6f5763ab143c065f526004601cfd5b30688000000000ab143c065d611a5c848484600180614022565b5f688000000000ab143c065c15611ca75763ab143c065f526004601cfd5b30688000000000ab143c065d611cbd838361343c565b90505f688000000000ab143c065d92915050565b5f688000000000ab143c065c15611cef5763ab143c065f526004601cfd5b30688000000000ab143c065d611a5c8484846001614141565b688000000000ab143c065c15611d255763ab143c065f526004601cfd5b30688000000000ab143c065d611d39613a31565b5f688000000000ab143c065d565b5f688000000000ab143c065c15611d655763ab143c065f526004601cfd5b30688000000000ab143c065d611d7a8261424a565b5060015f688000000000ab143c065d919050565b5f5f5f5f688000000000ab143c065c15611daf5763ab143c065f526004601cfd5b50506007546001600160601b0381169364ffffffffff606083901c81169450608883901c16925060b09190911c90565b688000000000ab143c065c15611dfc5763ab143c065f526004601cfd5b30688000000000ab143c065d604051630a73e39160e01b81523360048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690630a73e39190602401602060405180830381865afa158015611e6a573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611e8e9190615860565b611e9f57611e9f63471656c5613433565b611ea7613a31565b60405163463aea7f60e11b81523060048201526001600160a01b0383811660248301527f00000000000000000000000000000000000000000000000000000000000000001690638c75d4fe906044015f604051808303815f87803b158015611f0d575f5ffd5b505af1158015611f1f573d5f5f3e3d5ffd5b50505050611f2e833384613d59565b6040516318f9a83960e21b815233906363e6a0e490611f579030908790879087906004016159b3565b5f604051808303815f87803b158015611f6e575f5ffd5b505af1158015611f80573d5f5f3e3d5ffd5b5050600954604051630967a76b60e31b81523060048201525f60248201526001600160a01b0386811660448301526001600160f01b0390921660648201527f00000000000000000000000000000000000000000000000000000000000000009091169250634b3d3b5891506084015f604051808303815f87803b158015612005575f5ffd5b505af1158015612017573d5f5f3e3d5ffd5b505050505f688000000000ab143c065d505050565b6004545f90808203612051576040516354e9f59b60e01b815260040160405180910390fd5b60095462012fd19061206c906001600160f01b031683615948565b6120769190615948565b91505090565b5f688000000000ab143c065c1561209a5763ab143c065f526004601cfd5b30688000000000ab143c065d611cbd8383614308565b606060038054610bd99061580d565b604051634b0b3ab760e11b81526001600160a01b0382811660048301525f917f000000000000000000000000000000000000000000000000000000000000000090911690639616756e90602401602060405180830381865afa158015612127573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610bc49190615860565b688000000000ab143c065c156121685763ab143c065f526004601cfd5b30688000000000ab143c065d61217f8233836136b2565b505f688000000000ab143c065d5050565b5f610bc482600461271061317a565b5f688000000000ab143c065c156121bd5763ab143c065f526004601cfd5b30688000000000ab143c065d6121d4828433613260565b6121de83836143a8565b50600190505f688000000000ab143c065d92915050565b688000000000ab143c065c156122125763ab143c065f526004601cfd5b30688000000000ab143c065d61222881336138fc565b6122328282613529565b6114688282613616565b5f688000000000ab143c065c1561225a5763ab143c065f526004601cfd5b30688000000000ab143c065d61226e613a31565b506009546001600160f01b03165f688000000000ab143c065d90565b5f688000000000ab143c065c156122a85763ab143c065f526004601cfd5b30688000000000ab143c065d61110f82336138fc565b5f610bc4826122cb612d37565b61440c565b5f688000000000ab143c065c156122ee5763ab143c065f526004601cfd5b30688000000000ab143c065d611a5c8484845f614141565b5f688000000000ab143c065c156123245763ab143c065f526004601cfd5b30688000000000ab143c065d611a5c8484845f5f614022565b688000000000ab143c065c1561235a5763ab143c065f526004601cfd5b30688000000000ab143c065d604051630a73e39160e01b81523360048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690630a73e39190602401602060405180830381865afa1580156123c8573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906123ec9190615860565b6123fd576123fd63471656c5613433565b612405613a31565b5f61240e612d37565b90505f61241c858584614432565b90505f6124298684612d80565b90506124388682333389614477565b612445868287858861451c565b5050505f688000000000ab143c065d505050565b336001600160a01b0383160361248257604051636eef2f3f60e11b815260040160405180910390fd5b604051634b0b3ab760e11b81523360048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690639616756e90602401602060405180830381865afa1580156124e4573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906125089190615860565b15612526576040516302d5da9f60e01b815260040160405180910390fd5b60405163e6248d5560e01b81523360048201525f907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063e6248d5590602401602060405180830381865afa15801561258a573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906125ae91906158e1565b335f8181526020818152604080832085845282528083206001600160a01b03891680855290835292819020805460ff191688151590811790915581518681529283015293945090927ffeeb3502e62327bd3fece59983b972dc941e6abedd652971aac3adea23cf7e17910160405180910390a3505050565b5f688000000000ab143c065c156126445763ab143c065f526004601cfd5b610bc482612650612d37565b614670565b5f688000000000ab143c065c156126735763ab143c065f526004601cfd5b30688000000000ab143c065d611a5c8484845f6001614022565b6387a211a2600c9081525f828152602090912054610bc490610c5a565b6040805160c0810182525f80825260208201819052918101829052606081018290526080810182905260a08101919091526126e3613a31565b610bc482610f0a565b688000000000ab143c065c156127095763ab143c065f526004601cfd5b30688000000000ab143c065d61271d613f5c565b612725613a31565b600654816001600160a01b03166367e860cd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612764573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061278891906158e1565b146127a657604051631961405760e31b815260040160405180910390fd5b61117481614696565b5f6127b8610bca565b805190602001209050844211156127d657631a15a3cc5f526004601cfd5b6040518860601b60601c98508760601b60601c975065383775081901600e52885f526020600c2080547f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f83528360208401527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc6604084015246606084015230608084015260a08320602e527f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c983528a60208401528960408401528860608401528060808401528760a084015260c08320604e526042602c205f528660ff16602052856040528460605260208060805f60015afa8b3d51146128de5763ddafbaef5f526004601cfd5b0190556303faf4f960a51b88176040526034602c2087905587897f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925602060608501a360405250505f606052505050505050565b6387a211a2600c9081525f828152602090912054610bc4565b60405163e6248d5560e01b81526001600160a01b0382811660048301525f917f00000000000000000000000000000000000000000000000000000000000000009091169063e6248d5590602401602060405180830381865afa1580156129b2573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610bc491906158e1565b60607f000000000000000000000000000000000000000000000000000000000000000082806001600160401b03811115612a1257612a126152ec565b604051908082528060200260200182016040528015612a4557816020015b6060815260200190600190039081612a305790505b5060408051606080820183525f80835260208301819052928201529194505b82811015612c2e57868682818110612a7e57612a7e615934565b9050602002810190612a909190615a54565b612a9990615a72565b9150816020015115612bd057815160405163191d0cc560e11b81526001600160a01b0391821660048201525f9186169063323a198a90602401602060405180830381865afa158015612aed573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612b119190615845565b90506001600160a01b038116612b3a57604051632f3285fb60e21b815260040160405180910390fd5b8251604080850151905163bd0226d760e01b81526001600160a01b0384169263bd0226d792612b6f9233929190600401615ada565b5f604051808303815f87803b158015612b86575f5ffd5b505af1158015612b98573d5f5f3e3d5ffd5b50505050612bad835f01518460400151614794565b868381518110612bbf57612bbf615934565b602002602001018190525050612c26565b81516001600160a01b03163014612bfa57604051637720ccd960e01b815260040160405180910390fd5b612c08308360400151614809565b858281518110612c1a57612c1a615934565b60200260200101819052505b600101612a64565b5050505092915050565b5f610bc482612650612d37565b600480546040516370a0823160e01b815230928101929092525f9182907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa158015612cb1573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612cd591906158e1565b600954612ceb91906001600160f01b03166158ce565b9050818111612d0d5760405163c0883a5560e01b815260040160405180910390fd5b612d178282615948565b9250505090565b5f612d27613a31565b610b74670de0b6b3a7640000610c845b5f612d4061485d565b600454610b7491906158ce565b5f5f612d606805345cdf77eb68f44c5490565b90508015612d7857612d73848483614897565b610dc7565b509192915050565b5f5f612d936805345cdf77eb68f44c5490565b90508015612d7857612d73848285614933565b306001600160a01b03841603612dc357612dc3638b5fe5a3613433565b612dcb613a31565b612ded6040518060600160405280606081526020015f81526020015f81525090565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663da11ee23898989896040518060e001604052808b6001600160a01b03168152602001306001600160a01b031681526020018a815260200189151581526020015f81526020015f81526020015f8152506040518663ffffffff1660e01b8152600401612e87959493929190615b7d565b5f604051808303815f875af1158015612ea2573d5f5f3e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052612ec99190810190615c72565b98509050612efd7f000000000000000000000000000000000000000000000000000000000000000088308460200151613ea7565b60075460b01c5f8080805b87811015612ff1578c8181518110612f2257612f22615934565b60200260200101519350835f0315612fe9578a8a82818110612f4657612f46615934565b9050602002016020810190612f5b919061508f565b915083612f6783610d80565b612f719190615948565b6001600160a01b0383165f908152600a6020526040902060b087901b82179055925060408051858152602081018590526001600160a01b03808f169282019290925290831660608201527f21afd5f303208e3668ecf03cf3aa4036a5f71fbdd357478968cfd1502c25953d9060800160405180910390a15b600101612f08565b5084604001518560200181815161300891906158ce565b90525060208501516009546001600160f01b0316101561303757600980546001600160f01b0319169055613073565b602085015160095461305291906001600160f01b0316615948565b600980546001600160f01b0319166001600160f01b03929092169190911790555b60408501511561310c5760045460408601516130939062012fd1906158ce565b8110156130b35760405163ab2169c760e01b815260040160405180910390fd5b60408601516130c29082615948565b60045560408681015181519081526001600160a01b038e1660208201527f92fa6dfbfde0da658c7f8f7d12d2019a8b1972ebf52e449498652ade0455ba2c910160405180910390a1505b8451604051635722baf360e01b81526001600160a01b038a1691635722baf39161313f91908f908f908f90600401615d1c565b5f604051808303815f87803b158015613156575f5ffd5b505af1158015613168573d5f5f3e3d5ffd5b50505050505050505050505050505050565b5f610dc784848461495f565b6040516355eaece960e11b81523360048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063abd5d9d2906024015b602060405180830381865afa1580156131e9573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061320d9190615860565b61321e5761321e63471656c5613433565b565b816014528060345263a9059cbb60601b5f5260205f604460105f875af13d1560015f51141716613257576390b8ec185f526004601cfd5b5f603452505050565b613268613a31565b61327183613e92565b816001600160a01b0316816001600160a01b0316036132a25760405162640b4560e41b815260040160405180910390fd5b6001600160a01b038082165f90815260056020526040812054917f00000000000000000000000000000000000000000000000000000000000000001663b7b7f260308786613301816387a211a2600c9081525f91909152602090205490565b875f891161330f575f613312565b60015b6040518763ffffffff1660e01b815260040161333396959493929190615d50565b6020604051808303815f875af115801561334f573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061337391906158e1565b90508015613385576133858184613616565b5050505050565b5f8360601b33602052637f5e9f208117600c526034600c20805460018101156133ca57808511156133c4576313be252b5f526004601cfd5b84810382555b50506387a211a28117600c526020600c208054808511156133f25763f4d678b85f526004601cfd5b84810382555050835f526020600c208381540181555082602052600c5160601c8160601c5f516020615ed95f395f51905f52602080a3505060019392505050565b805f526004601cfd5b5f613445613a31565b61345c61345484612650612d37565b915081613e92565b6040516330ae91d160e21b81523060048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063c2ba4744906024015f604051808303815f87803b1580156134ba575f5ffd5b505af11580156134cc573d5f5f3e3d5ffd5b50505050610bc48382338561498b565b6001600160a01b0381165f908152600a60205260409020546001600160b01b03161561351b576040516311dd629d60e21b815260040160405180910390fd5b6135258282614a25565b5050565b61353282613e92565b6001600160a01b0381165f908152600560205260409020548281101561355f5761355f63e6c95926613433565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316632076d8e73085856135ac876387a211a2600c9081525f91909152602090205490565b8660016040518763ffffffff1660e01b81526004016135d096959493929190615d50565b6020604051808303815f875af11580156135ec573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061361091906158e1565b50505050565b6001600160a01b0381165f90815260056020526040902054613639908390615948565b6001600160a01b0382165f9081526005602052604090205560015461365f908390615948565b600155604080518381525f60208201526001600160a01b038316918101919091527f26d61a36a46ca0b5adc9f8ae98359690cb59381d060151d48afcfa01e079eda6906060015b60405180910390a15050565b5f6136bb613a31565b5f6136c583610d80565b905084156136d357846136d5565b805b94506136e085613e92565b808511156136f5576136f5638b5fe5a3613433565b6137217f0000000000000000000000000000000000000000000000000000000000000000853088613ea7565b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016634b0319523061375b8885615948565b9350837f00000000000000000000000000000000000000000000000000000000000000007f00000000000000000000000000000000000000000000000000000000000000006040516001600160e01b031960e087901b1681526001600160a01b0394851660048201526024810193909352908316604483015260ff166064820152908616608482015260a4015f6040518083038186803b1580156137fd575f5ffd5b505afa15801561380f573d5f5f3e3d5ffd5b50506007546001600160a01b0386165f908152600a602052604090206001600160b01b031990911684179055506138439050565b6009546001600160f01b031685111561386b57600980546001600160f01b03191690556138a3565b6009546138829086906001600160f01b0316615948565b600980546001600160f01b0319166001600160f01b03929092169190911790555b60408051868152602081018390526001600160a01b03868116828401528516606082015290517f21afd5f303208e3668ecf03cf3aa4036a5f71fbdd357478968cfd1502c25953d9181900360800190a150929392505050565b6001600160a01b038281165f81815260208190526040808220905163e6248d5560e01b815260048101939093529290917f00000000000000000000000000000000000000000000000000000000000000009091169063e6248d5590602401602060405180830381865afa158015613975573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061399991906158e1565b815260208082019290925260409081015f9081206001600160a01b038516825290925290205460ff16613525576040516367ee2b0160e11b815260040160405180910390fd5b6139e882613e92565b6387a211a2600c9081525f82905260209020546001600160a01b0382165f90815260056020526040902054613a1e9084906158ce565b11156135255761352563e6c95926613433565b60075464ffffffffff608882901c1642819003613a4c575050565b6009546004546001600160601b0384169164ffffffffff606086901c169160b086901c916001600160f01b0316905f613a878684878a614b39565b9050844210613bb85760085494965086945f906001600160a01b031663589dc77b613ab061202c565b613aba85886158ce565b6040516001600160e01b031960e085901b1681526004810192909252602482015260440160408051808303815f875af1158015613af9573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613b1d9190615d89565b9097509050808080613b2f8942615948565b613b399190615dab565b613b439190615dca565b613b4d91906158ce565b9050613b5981876158ce565b60408051898152602081018390529197507f6ca03c3e1f9f2693eb4277ee4f449b9838fad99c363f5d54bacaf5f71a34afec910160405180910390a1613baa87613ba384876158ce565b888b614b39565b613bb490836158ce565b9150505b6009545f90613bd6908390600160f01b900461ffff1661271061317a565b90508015613ca0575f613c0e82613bf46805345cdf77eb68f44c5490565b84613bff87896158ce565b613c099190615948565b614933565b90505f7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316632131c68c6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613c6d573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613c919190615845565b9050613c9d8183614b93565b50505b8115613d2f5784613cb283878761317a565b613cbc91906158ce565b9450613cc882856158ce565b600980546001600160f01b0319166001600160f01b0392909216919091179055613cf282846158ce565b60045560408051838152602081018390527f4e32a70f9f06da2cec9f0079d5658935775123a5ce8d0d68de35d019a8d1c19c910160405180910390a15b5050505060609190911b4260881b1760b09190911b176001600160601b0391909116176007555050565b613d6283613e92565b613d6b83614bfc565b6001600160a01b0381165f9081526005602052604090205415613da157604051635d00c4f360e11b815260040160405180910390fd5b5f83613dac83610d80565b613db691906158ce565b6007546001600160a01b0384165f908152600a602052604090206001600160b01b0319909116821790559050600954613df99085906001600160f01b03166158ce565b600980546001600160f01b0319166001600160f01b0392909216919091179055613e447f00000000000000000000000000000000000000000000000000000000000000008486613220565b60408051858152602081018390526001600160a01b0384168183015290517fbec1750eb40c00e8dc2e1c84babbddd5779eaa06c951ab2c66416d05910e7a739181900360600190a150505050565b80613ea45763c0883a555f526004601cfd5b50565b60405181606052826040528360601b602c526323b872dd60601b600c5260205f6064601c5f895af13d1560015f51141716613ee957637939f4245f526004601cfd5b5f60605260405250505050565b8260601b6387a211a28117600c526020600c20805480841115613f205763f4d678b85f526004601cfd5b83810382555050825f526020600c208281540181555081602052600c5160601c8160601c5f516020615ed95f395f51905f52602080a350505050565b60405163de0c7a7160e01b81523360048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063de0c7a71906024016131ce565b611770811115613fbf57613fbf638b5fe5a3613433565b6009805461ffff838116600160f01b9081026001600160f01b038416179384905560408051938290048316808552919094049091166020830152917f27a0956e997c69164a0c4cc2fb19bd083ae33e1abbc2165b43398d899b51fd0b91016136a6565b5f61402b613a31565b5f614034612d37565b90505f61404e6140448984612d4d565b9350838784614432565b905084156140655761406086336138fc565b61406f565b61406f8689614c24565b6001600160a01b038681165f90815260056020526040808220549051632076d8e760e01b815291927f00000000000000000000000000000000000000000000000000000000000000001691632076d8e7916140d69130918e918d9189918d90600401615d50565b6020604051808303815f875af11580156140f2573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061411691906158e1565b90508015614128576141288188613616565b614135848a338b8b614477565b50505095945050505050565b5f61414a613a31565b5f614153612d37565b90505f614161878684614432565b9050614179856141718985612d80565b945084614c24565b6001600160a01b038581165f90815260056020526040808220549051632076d8e760e01b815291927f00000000000000000000000000000000000000000000000000000000000000001691632076d8e7916141e091309189918c9189918d90600401615d50565b6020604051808303815f875af11580156141fc573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061422091906158e1565b90508015614232576142328187613616565b61423f8885338a8a614477565b505050949350505050565b6008546040805163ea12489f60e01b8152905130926001600160a01b03169163ea12489f9160048083019260209291908290030181865afa158015614291573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906142b59190615845565b6001600160a01b0316146142d0576142d063471656c5613433565b6142d981614c3f565b60b0670de0b6b3a7640000901b608842901b606042901b6001600160601b036007541617171760078190555050565b5f614311613a31565b61431a83613e92565b6040516330ae91d160e21b81523060048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063c2ba4744906024015f604051808303815f87803b158015614378575f5ffd5b505af115801561438a573d5f5f3e3d5ffd5b50505050610bc461439d846122cb612d37565b91508184338561498b565b5f6387a211a2600c52335f526020600c208054808411156143d05763f4d678b85f526004601cfd5b83810382555050825f526020600c208281540181555081602052600c5160601c335f516020615ed95f395f51905f52602080a350600192915050565b5f5f61441f6805345cdf77eb68f44c5490565b90508015612d7857612d73848483614933565b5f61443c84613e92565b506387a211a2600c9081525f839052602090205461445a8183612d4d565b84111561446e5761446e63e6c95926613433565b61141a84614bfc565b6144818185614d00565b61448a85614d61565b6144b57f00000000000000000000000000000000000000000000000000000000000000008387613220565b806001600160a01b0316826001600160a01b0316846001600160a01b03167ffbde797d201c681b91056529119e0b02407c7bb96a4a2c75c01fc9667232c8db888860405161450d929190918252602082015260400190565b60405180910390a45050505050565b604051632748468360e11b81523390634e908d0690614545903090899088908790600401615de1565b5f604051808303815f87803b15801561455c575f5ffd5b505af115801561456e573d5f5f3e3d5ffd5b50506387a211a2600c9081525f869052602090205461459092508691506158ce565b82146145af5760405163350385ad60e11b815260040160405180910390fd5b6001600160a01b038381165f90815260056020526040808220549051632076d8e760e01b815291927f00000000000000000000000000000000000000000000000000000000000000001691632076d8e7916146169130918a918a918a918990600401615d50565b6020604051808303815f875af1158015614632573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061465691906158e1565b90508015614668576146688185613616565b505050505050565b5f5f6146836805345cdf77eb68f44c5490565b90508015612d7857612d73848285614897565b6146a781638ec124b360e01b614d75565b6146b8576146b8638b5fe5a3613433565b600880546001600160a01b031981166001600160a01b03848116918217909355604080516367e860cd60e01b8152905193909216925f926367e860cd9160048083019260209291908290030181865afa158015614717573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061473b91906158e1565b6006819055604080516001600160a01b038086168252861660208201529081018290529091507f6ceb115a1597bd916163fc3cca894b15a8a1dc485d02079de9de8bbfda37a032906060015b60405180910390a1505050565b60605f5f846001600160a01b03165f856040516147b19190615ec2565b5f6040518083038185875af1925050503d805f81146147eb576040519150601f19603f3d011682016040523d82523d5f602084013e6147f0565b606091505b5091509150614800858383614d90565b95945050505050565b60605f5f846001600160a01b0316846040516148259190615ec2565b5f60405180830381855af49150503d805f81146147eb576040519150601f19603f3d011682016040523d82523d5f602084013e6147f0565b6007546009545f9190612076906001600160601b038316906001600160f01b031664ffffffffff606085901c811690608886901c16614b39565b8282025f1983850981811082019003806148c657826148bd5763ae47f7025f526004601cfd5b5081900461141a565b8083116148da5763ae47f7025f526004601cfd5b828486095f84810385169485900494848311909303908390038390046001010292030417600260038302811880840282030280840282030280840282030280840282030280840282030280840290910302029392505050565b5f61493f848484614897565b9050818385091561141a576001018061141a5763ae47f7025f526004601cfd5b5f825f19048411830215820261497c5763ad251c275f526004601cfd5b50910281810615159190040190565b6149b77f0000000000000000000000000000000000000000000000000000000000000000833087613ea7565b6149c084614dd8565b6149ca8184614b93565b806001600160a01b0316826001600160a01b03167fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d78686604051614a18929190918252602082015260400190565b60405180910390a3613610565b5f82600154614a3491906158ce565b6040516301ac71bb60e11b81523060048201526001600160a01b038481166024830152604482018390529192507f000000000000000000000000000000000000000000000000000000000000000090911690630358e376906064015f604051808303815f87803b158015614aa6575f5ffd5b505af1158015614ab8573d5f5f3e3d5ffd5b5050506001600160a01b0383165f90815260056020526040902054614adf915084906158ce565b6001600160a01b0383165f818152600560209081526040918290209390935560018481558151878152938401528201527f26d61a36a46ca0b5adc9f8ae98359690cb59381d060151d48afcfa01e079eda690606001614787565b5f5f85118015614b4857508282105b15610dc757614800834210614b7057614b618385615948565b614b6b9087615dca565b614b84565b614b7a8342615948565b614b849087615dca565b85670de0b6b3a7640000614de6565b6805345cdf77eb68f44c5481810181811015614bb65763e5cfe9575f526004601cfd5b806805345cdf77eb68f44c5550506387a211a2600c52815f526020600c208181540181555080602052600c5160601c5f5f516020615ed95f395f51905f52602080a35050565b80614c0561202c565b1015613ea45760405163ab2169c760e01b815260040160405180910390fd5b336001600160a01b0383161461352557613525823383614df2565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614614c7c57614c7c63471656c5613433565b3062012fd1614cad7f0000000000000000000000000000000000000000000000000000000000000000848484613ea7565b80614cb85f82614b93565b600482905560408051838152602081018390525f916001600160a01b038716917fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d79101614a18565b6387a211a2600c52815f526020600c20805480831115614d275763f4d678b85f526004601cfd5b82900390556805345cdf77eb68f44c805482900390555f8181526001600160a01b0383165f516020615ed95f395f51905f52602083a35050565b80600454614d6f9190615948565b60045550565b5f614d7f83614e30565b801561141a575061141a8383614e62565b6060614d9c8383614ee8565b8151158015614db357506001600160a01b0384163b155b15614dd1576040516314859aeb60e21b815260040160405180910390fd5b5092915050565b80600454614d6f91906158ce565b5f610dc7848484614f16565b81602052637f5e9f20600c52825f526034600c20805460018101156133855780831115614e26576313be252b5f526004601cfd5b9190910390555050565b5f614e42826301ffc9a760e01b614e62565b8015610bc45750614e5b826001600160e01b0319614e62565b1592915050565b6040516001600160e01b0319821660248201525f90819060440160408051601f19818403018152919052602080820180516001600160e01b03166301ffc9a760e01b17815282519293505f9283928392909183918a617530fa92503d91505f519050828015614ed2575060208210155b8015614edd57505f81115b979650505050505050565b816135255780515f03614f0e576040516314859aeb60e21b815260040160405180910390fd5b805181602001fd5b5f825f190484118302158202614f335763ad251c275f526004601cfd5b5091020490565b5f60208284031215614f4a575f5ffd5b81356001600160e01b03198116811461141a575f5ffd5b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b602081525f61141a6020830184614f61565b5f60208284031215614fb1575f5ffd5b5035919050565b6001600160a01b0381168114613ea4575f5ffd5b5f5f60408385031215614fdd575f5ffd5b8235614fe881614fb8565b946020939093013593505050565b5f5f83601f840112615006575f5ffd5b5081356001600160401b0381111561501c575f5ffd5b6020830191508360208260051b8501011115615036575f5ffd5b9250929050565b5f5f5f6040848603121561504f575f5ffd5b83356001600160401b03811115615064575f5ffd5b61507086828701614ff6565b909450925050602084013561508481614fb8565b809150509250925092565b5f6020828403121561509f575f5ffd5b813561141a81614fb8565b5f5f5f606084860312156150bc575f5ffd5b83356150c781614fb8565b925060208401356150d781614fb8565b929592945050506040919091013590565b5f5f604083850312156150f9575f5ffd5b82359150602083013561510b81614fb8565b809150509250929050565b5f5f5f5f5f6060868803121561512a575f5ffd5b85356001600160401b0381111561513f575f5ffd5b61514b88828901614ff6565b90965094505060208601356001600160401b03811115615169575f5ffd5b61517588828901614ff6565b909450925050604086013561518981614fb8565b809150509295509295909350565b5f5f5f604084860312156151a9575f5ffd5b8335925060208401356001600160401b038111156151c5575f5ffd5b8401601f810186136151d5575f5ffd5b80356001600160401b038111156151ea575f5ffd5b8660208284010111156151fb575f5ffd5b939660209190910195509293505050565b5f5f5f5f5f60608688031215615220575f5ffd5b85356001600160401b03811115615235575f5ffd5b61524188828901614ff6565b909650945050602086013561525581614fb8565b925060408601356001600160401b0381111561526f575f5ffd5b61527b88828901614ff6565b969995985093965092949392505050565b5f5f5f6060848603121561529e575f5ffd5b8335925060208401356152b081614fb8565b9150604084013561508481614fb8565b5f5f604083850312156152d1575f5ffd5b82356152dc81614fb8565b9150602083013561510b81614fb8565b634e487b7160e01b5f52604160045260245ffd5b60405160c081016001600160401b0381118282101715615322576153226152ec565b60405290565b604051606081016001600160401b0381118282101715615322576153226152ec565b604051601f8201601f191681016001600160401b0381118282101715615372576153726152ec565b604052919050565b8035610c8981614fb8565b5f82601f830112615394575f5ffd5b81356001600160401b038111156153ad576153ad6152ec565b6153c0601f8201601f191660200161534a565b8181528460208386010111156153d4575f5ffd5b816020850160208301375f918101602001919091529392505050565b5f60c08284031215615400575f5ffd5b615408615300565b9050813561541581614fb8565b815260208281013590820152604082013561542f81614fb8565b6040820152606082013561544281614fb8565b60608201526080828101359082015260a08201356001600160401b03811115615469575f5ffd5b61547584828501615385565b60a08301525092915050565b5f5f5f60608486031215615493575f5ffd5b8335925060208401356154a581614fb8565b915060408401356001600160401b038111156154bf575f5ffd5b840160c081870312156154d0575f5ffd5b6154d8615300565b6154e18261537a565b8152602082810135908201526154f96040830161537a565b60408201526060828101359082015260808201356001600160401b03811115615520575f5ffd5b61552c888285016153f0565b60808301525060a08201356001600160401b0381111561554a575f5ffd5b61555688828501615385565b60a08301525080925050509250925092565b5f6001600160401b03821115615580576155806152ec565b5060051b60200190565b5f82601f830112615599575f5ffd5b81356155ac6155a782615568565b61534a565b8082825260208201915060208360051b8601019250858311156155cd575f5ffd5b602085015b8381101561560d5780356001600160401b038111156155ef575f5ffd5b6155fe886020838a01016153f0565b845250602092830192016155d2565b5095945050505050565b5f5f5f60608486031215615629575f5ffd5b83359250602084013561563b81614fb8565b915060408401356001600160401b03811115615655575f5ffd5b840160c08187031215615666575f5ffd5b61566e615300565b6156778261537a565b81526020828101359082015261568f6040830161537a565b60408201526060828101359082015260808201356001600160401b038111156156b6575f5ffd5b61552c8882850161558a565b8015158114613ea4575f5ffd5b5f5f604083850312156156e0575f5ffd5b82356156eb81614fb8565b9150602083013561510b816156c2565b5f5f5f5f5f5f5f60e0888a031215615711575f5ffd5b873561571c81614fb8565b9650602088013561572c81614fb8565b95506040880135945060608801359350608088013560ff8116811461574f575f5ffd5b9699959850939692959460a0840135945060c09093013592915050565b5f5f6020838503121561577d575f5ffd5b82356001600160401b03811115615792575f5ffd5b61579e85828601614ff6565b90969095509350505050565b5f602082016020835280845180835260408501915060408160051b8601019250602086015f5b8281101561580157603f198786030184526157ec858351614f61565b945060209384019391909101906001016157d0565b50929695505050505050565b600181811c9082168061582157607f821691505b60208210810361583f57634e487b7160e01b5f52602260045260245ffd5b50919050565b5f60208284031215615855575f5ffd5b815161141a81614fb8565b5f60208284031215615870575f5ffd5b815161141a816156c2565b634e487b7160e01b5f52601160045260245ffd5b5f5f5f606084860312156158a1575f5ffd5b83516158ac816156c2565b60208501519093506158bd816156c2565b6040850151909250615084816156c2565b80820180821115610bc457610bc461587b565b5f602082840312156158f1575f5ffd5b5051919050565b84815283602082015260606040820152816060820152818360808301375f818301608090810191909152601f909201601f191601019392505050565b634e487b7160e01b5f52603260045260245ffd5b81810381811115610bc457610bc461587b565b80516001600160a01b03908116835260208083015190840152604080830151821690840152606080830151909116908301526080808201519083015260a08181015160c09184018290525f91610dc790850182614f61565b60018060a01b038516815283602082015260018060a01b03831660408201526080606082015260018060a01b038251166080820152602082015160a082015260018060a01b0360408301511660c0820152606082015160e08201525f608083015160c0610100840152615a2a61014084018261595b565b905060a0840151607f1984830301610120850152615a488282614f61565b98975050505050505050565b5f8235605e19833603018112615a68575f5ffd5b9190910192915050565b5f60608236031215615a82575f5ffd5b615a8a615328565b8235615a9581614fb8565b81526020830135615aa5816156c2565b602082015260408301356001600160401b03811115615ac2575f5ffd5b615ace36828601615385565b60408301525092915050565b6001600160a01b038481168252831660208201526060604082018190525f9061480090830184614f61565b5f8151808452602084019350602083015f5b82811015615b35578151865260209586019590910190600101615b17565b5093949350505050565b8183526020830192505f815f5b84811015615b35578135615b5f81614fb8565b6001600160a01b031686526020958601959190910190600101615b4c565b61014081525f615b91610140830188615b05565b6001600160a01b03871660208401528281036040840152615bb3818688615b3f565b91505060018060a01b03835116606083015260018060a01b036020840151166080830152604083015160a08301526060830151151560c0830152608083015160e083015260a083015161010083015260c08301516101208301529695505050505050565b5f82601f830112615c26575f5ffd5b8151615c346155a782615568565b8082825260208201915060208360051b860101925085831115615c55575f5ffd5b602085015b8381101561560d578051835260209283019201615c5a565b5f5f60408385031215615c83575f5ffd5b82516001600160401b03811115615c98575f5ffd5b830160608186031215615ca9575f5ffd5b615cb1615328565b81516001600160401b03811115615cc6575f5ffd5b615cd287828501615c17565b8252506020828101518183015260409283015192820192909252908401519092506001600160401b03811115615d06575f5ffd5b615d1285828601615c17565b9150509250929050565b606081525f615d2e6060830187615b05565b6001600160a01b03861660208401528281036040840152614edd818587615b3f565b6001600160a01b03968716815260208101959095529290941660408401526060830152608082019290925290151560a082015260c00190565b5f5f60408385031215615d9a575f5ffd5b505080516020909101519092909150565b5f82615dc557634e487b7160e01b5f52601260045260245ffd5b500490565b8082028115828204841417610bc457610bc461587b565b60018060a01b038516815283602082015260018060a01b0383166040820152608060608201525f610140820160018060a01b038451166080840152602084015160a084015260018060a01b0360408501511660c0840152606084015160e0840152608084015160c0610100850152818151808452610160860191506101608160051b87010193506020830192505f5b81811015615ea25761015f19878603018352615e8d85855161595b565b94506020938401939290920191600101615e70565b5050505060a0840151838203607f1901610120850152615a488282614f61565b5f82518060208501845e5f92019182525091905056feddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa26469706673582212209d1af0ba86ae344133dffce36c4b91ce925fb4117300ef90c85021d81eaa96f664736f6c634300081c00330000000000000000000000001310f352f1389969ece6741671c4b919523912ff000000000000000000000000484be0540ad49f351eaa04eeb35df0f937d4e73f00000000000000000000000090fc1a4abc4ee5f8a9560de069067d9606d2909c0000000000000000000000000a8c317c25a000000296673bd75ca3f5c1e8c57c
Deployed Bytecode
0x608060405234801561000f575f5ffd5b506004361061047a575f3560e01c806372d46ac211610258578063b3d7f6b91161014b578063d4bb0c73116100ca578063e28d591d1161008f578063e28d591d14610ad9578063e6248d5514610af8578063e8bbf5d714610b0b578063ef8b30f714610b2b578063f0c00c4114610b3e578063f411029114610b46575f5ffd5b8063d4bb0c7314610a6f578063d505accf14610a82578063d905777e14610a95578063dd62ed3e14610aa8578063deee770414610ad0575f5ffd5b8063c63d75b611610110578063c63d75b6146106b0578063c6e6f59214610a23578063cd88c07214610a36578063ce96cb7714610a49578063cf6af22d14610a5c575f5ffd5b8063b3d7f6b9146109c4578063b460af94146109d7578063ba087652146109ea578063bdca6723146109fd578063c3c854b614610a10575f5ffd5b806394bf804d116101d7578063a7af467a1161019c578063a7af467a14610970578063a9059cbb14610983578063ab21e62814610996578063ad9d3683146109a9578063b3bffb45146109b1575f5ffd5b806394bf804d1461090757806395d89b411461091a5780639616756e146109225780639e591a4414610935578063a75df49814610948575f5ffd5b80637ecebe001161021d5780637ecebe001461089757806380fd997f146108bc57806385b13080146108c557806387367d71146108d85780638f73dcfa146108e0575f5ffd5b806372d46ac2146108385780637313ee5a1461084b578063775a814a146108545780637ada7a091461085c5780637c0e0c8c1461086f575f5ffd5b806338d52e0f116103705780635722baf3116102ef578063635d9771116102b4578063635d9771146107af578063640fef7b146107da5780636779db5b146107ed5780636e553f651461080057806370a0823114610813575f5ffd5b80635722baf31461075057806357d159d5146107635780635b56d6f5146107765780635c0bfa88146107895780635fec5d0b1461079c575f5ffd5b806345d7b97a1161033557806345d7b97a146106fd5780634b3fd148146107045780634cdad5061461071757806350f2012f1461072a5780635296a4311461073d575f5ffd5b806338d52e0f146106825780633ba0b9a9146106a8578063402d267d146106b057806340c09eba146106c357806341ed2c12146106d6575f5ffd5b80631dd19cb4116103fc578063313ce567116103c1578063313ce567146106105780633237c158146106415780633644e51514610654578063371fd8e61461065c57806338c0f3091461066f575f5ffd5b80631dd19cb41461054a5780631e75db1614610552578063215702561461057d57806323b872dd146105ea5780632f4a61d9146105fd575f5ffd5b80630a28a477116104425780630a28a477146104f75780630f0f54361461050a57806311005b071461051f578063176679671461053257806318160ddd1461053a575f5ffd5b806301e1d1141461047e57806301ffc9a71461049957806306fdde03146104bc57806307a2d13a146104d1578063095ea7b3146104e4575b5f5ffd5b610486610b4e565b6040519081526020015b60405180910390f35b6104ac6104a7366004614f3a565b610b79565b6040519015158152602001610490565b6104c4610bca565b6040516104909190614f8f565b6104866104df366004614fa1565b610c5a565b6104ac6104f2366004614fcc565b610c8e565b610486610505366004614fa1565b610cdd565b61051d61051836600461503d565b610cef565b005b61048661052d36600461508f565b610d80565b610486600481565b6805345cdf77eb68f44c54610486565b61051d610dcf565b600854610565906001600160a01b031681565b6040516001600160a01b039091168152602001610490565b61059061058b36600461508f565b610f0a565b604051610490919081516001600160a01b0390811682526020808401519091169082015260408083015160ff16908201526060808301511515908201526080808301519082015260a0918201519181019190915260c00190565b6104ac6105f83660046150aa565b610fdf565b61048661060b3660046150e8565b611037565b60405160ff7f0000000000000000000000000000000000000000000000000000000000000012168152602001610490565b61051d61064f366004614fa1565b611137565b610486611183565b61051d61066a366004614fa1565b6111ff565b61051d61067d366004615116565b611243565b7f000000000000000000000000484be0540ad49f351eaa04eeb35df0f937d4e73f610565565b6104866112d9565b6104866106be36600461508f565b6112ee565b61051d6106d13660046150e8565b611421565b6105657f00000000000000000000000090fc1a4abc4ee5f8a9560de069067d9606d2909c81565b60016104ac565b61051d6107123660046150e8565b611478565b610486610725366004614fa1565b61156d565b61051d610738366004614fa1565b61157a565b61051d61074b366004615197565b6115b7565b61051d61075e36600461520c565b611781565b61048661077136600461508f565b611994565b61051d610784366004614fa1565b6119e2565b61048661079736600461528c565b611a24565b6104ac6107aa3660046152c0565b611a71565b6009546107c2906001600160f01b031681565b6040516001600160f01b039091168152602001610490565b61051d6107e836600461528c565b611b41565b6104866107fb36600461528c565b611c51565b61048661080e3660046150e8565b611c89565b61048661082136600461508f565b6387a211a2600c9081525f91909152602090205490565b61048661084636600461528c565b611cd1565b61048660065481565b61051d611d08565b6104ac61086a36600461508f565b611d47565b610877611d8e565b604080519485526020850193909352918301526060820152608001610490565b6104866108a536600461508f565b6338377508600c9081525f91909152602090205490565b61048661177081565b61051d6108d3366004615481565b611ddf565b61048661202c565b6105657f0000000000000000000000001310f352f1389969ece6741671c4b919523912ff81565b6104866109153660046150e8565b61207c565b6104c46120b0565b6104ac61093036600461508f565b6120bf565b61051d6109433660046150e8565b61214b565b60095461095d90600160f01b900461ffff1681565b60405161ffff9091168152602001610490565b61048661097e366004614fa1565b612190565b6104ac610991366004614fcc565b61219f565b61051d6109a43660046150e8565b6121f5565b61048661223c565b6104866109bf3660046150e8565b61228a565b6104866109d2366004614fa1565b6122be565b6104866109e536600461528c565b6122d0565b6104866109f836600461528c565b612306565b61051d610a0b366004615617565b61233d565b61051d610a1e3660046156cf565b612459565b610486610a31366004614fa1565b612626565b610486610a4436600461528c565b612655565b610486610a5736600461508f565b61268d565b610590610a6a36600461508f565b6126aa565b61051d610a7d36600461508f565b6126ec565b61051d610a903660046156fb565b6127af565b610486610aa336600461508f565b612931565b610486610ab63660046152c0565b602052637f5e9f20600c9081525f91909152603490205490565b61048660015481565b610486610ae736600461508f565b60056020525f908152604090205481565b610486610b0636600461508f565b61294a565b610b1e610b1936600461576c565b6129d6565b60405161049091906157aa565b610486610b39366004614fa1565b612c38565b610486612c45565b610486612d1e565b5f688000000000ab143c065c15610b6c5763ab143c065f526004601cfd5b610b74612d37565b905090565b5f6001600160e01b03198216630934615b60e01b1480610ba957506001600160e01b0319821663b6e300c760e01b145b80610bc457506301ffc9a760e01b6001600160e01b03198316145b92915050565b606060028054610bd99061580d565b80601f0160208091040260200160405190810160405280929190818152602001828054610c059061580d565b8015610c505780601f10610c2757610100808354040283529160200191610c50565b820191905f5260205f20905b815481529060010190602001808311610c3357829003601f168201915b5050505050905090565b5f688000000000ab143c065c15610c785763ab143c065f526004601cfd5b610bc482610c84612d37565b612d4d565b919050565b5f82602052637f5e9f20600c52335f52816034600c2055815f52602c5160601c337f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560205fa350600192915050565b5f610bc482610cea612d37565b612d80565b688000000000ab143c065c15610d0c5763ab143c065f526004601cfd5b30688000000000ab143c065d815f816001600160401b03811115610d3257610d326152ec565b604051908082528060200260200182016040528015610d5b578160200160208202803683370190505b509050610d6d8133878787875f612da6565b50505f688000000000ab143c065d505050565b6001600160a01b0381165f908152600a60205260408120546001600160b01b038116808303610db0575050919050565b600754610dc790829060b090811c9085901c61317a565b949350505050565b688000000000ab143c065c15610dec5763ab143c065f526004601cfd5b30688000000000ab143c065d610e00613186565b5f610e09612c45565b90505f7f0000000000000000000000001310f352f1389969ece6741671c4b919523912ff6001600160a01b0316632131c68c6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610e68573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610e8c9190615845565b9050610eb97f000000000000000000000000484be0540ad49f351eaa04eeb35df0f937d4e73f8284613220565b604080518381526001600160a01b03831660208201527f88fc2578c4b534418a67792f942c22deab48988e8f00bf87d4f8b0d0a8655772910160405180910390a150505f688000000000ab143c065d565b6040805160c0810182525f80825260208201819052918101829052606081018290526080810182905260a0810182905290610f4483610d80565b3083526001600160a01b037f000000000000000000000000484be0540ad49f351eaa04eeb35df0f937d4e73f16602084015290507f000000000000000000000000000000000000000000000000000000000000001260ff16604083015280610fad576001610faf565b5f5b151560608301526001600160a01b039092165f90815260056020526040902054608082015260a081019190915290565b5f688000000000ab143c065c15610ffd5763ab143c065f526004601cfd5b30688000000000ab143c065d611014828486613260565b61101f84848461338c565b50600190505f688000000000ab143c065d9392505050565b5f688000000000ab143c065c156110555763ab143c065f526004601cfd5b30688000000000ab143c065d336001600160a01b038316148015906110fd5750604051630a73e39160e01b81523360048201527f00000000000000000000000090fc1a4abc4ee5f8a9560de069067d9606d2909c6001600160a01b031690630a73e39190602401602060405180830381865afa1580156110d7573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906110fb9190615860565b155b1561110f5761110f63471656c5613433565b611119838361343c565b905061112581836134dc565b5f688000000000ab143c065d92915050565b688000000000ab143c065c156111545763ab143c065f526004601cfd5b30688000000000ab143c065d61116a8133613529565b6111748133613616565b5f688000000000ab143c065d50565b5f8061118d610bca565b8051906020012090506040517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f81528160208201527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc6604082015246606082015230608082015260a081209250505090565b688000000000ab143c065c1561121c5763ab143c065f526004601cfd5b30688000000000ab143c065d6112338133336136b2565b505f688000000000ab143c065d50565b688000000000ab143c065c156112605763ab143c065f526004601cfd5b30688000000000ab143c065d8184811461128157611281638b5fe5a3613433565b6112c58686808060200260200160405190810160405280939291908181526020018383602002808284375f9201919091525033925088915087905086866001612da6565b505f688000000000ab143c065d5050505050565b5f610b74670de0b6b3a7640000610c84612d37565b60405163699ba8b360e01b81523060048201525f9081906001600160a01b037f00000000000000000000000090fc1a4abc4ee5f8a9560de069067d9606d2909c169063699ba8b390602401606060405180830381865afa158015611354573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611378919061588f565b5050604051637bca031760e11b81523060048201529091507f00000000000000000000000090fc1a4abc4ee5f8a9560de069067d9606d2909c6001600160a01b03169063f794062e90602401602060405180830381865afa1580156113df573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906114039190615860565b158061140c5750805b156114175750919050565b5f195b9392505050565b688000000000ab143c065c1561143e5763ab143c065f526004601cfd5b30688000000000ab143c065d61145481336138fc565b61145e82826139df565b61146882826134dc565b5f688000000000ab143c065d5050565b688000000000ab143c065c156114955763ab143c065f526004601cfd5b30688000000000ab143c065d6114a9613a31565b6009546001600160a01b037f00000000000000000000000090fc1a4abc4ee5f8a9560de069067d9606d2909c169063f96492c9903090859033906114f79083906001600160f01b03166158ce565b6040516001600160e01b031960e087901b1681526001600160a01b03948516600482015260248101939093529216604482015260648101919091526084015f604051808303815f87803b15801561154c575f5ffd5b505af115801561155e573d5f5f3e3d5ffd5b50505050611468828233613d59565b5f610bc482610c84612d37565b688000000000ab143c065c156115975763ab143c065f526004601cfd5b30688000000000ab143c065d6115ad81336139df565b61117481336134dc565b6115bf613a31565b6115c883613e92565b6040516370a0823160e01b81523060048201527f000000000000000000000000484be0540ad49f351eaa04eeb35df0f937d4e73f6001600160a01b0316906370a0823190602401602060405180830381865afa15801561162a573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061164e91906158e1565b83111561166e5760405163ab2169c760e01b815260040160405180910390fd5b7f000000000000000000000000484be0540ad49f351eaa04eeb35df0f937d4e73f5f61169985612190565b90505f6116a682876158ce565b90506116b3833388613220565b604051637924fd7d60e01b81523390637924fd7d906116dc90899085908a908a906004016158f8565b6020604051808303815f875af11580156116f8573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061171c91906158e1565b5061172983333084613ea7565b8160045461173791906158ce565b6004556040805187815260208101849052338183015290517fb216ab52d7988a2a0e79070667f92d2ade5e6464ee97984d5983afe3572348269181900360600190a1505050505050565b688000000000ab143c065c1561179e5763ab143c065f526004601cfd5b30688000000000ab143c065d604051630eaa39a960e31b81523060048201523360248201527f00000000000000000000000090fc1a4abc4ee5f8a9560de069067d9606d2909c6001600160a01b031690637551cd48906044015f604051808303815f87803b15801561180e575f5ffd5b505af1158015611820573d5f5f3e3d5ffd5b508392505f915081905080805b848110156119695789898281811061184757611847615934565b905060200201359250825f03156119615786868281811061186a5761186a615934565b905060200201602081019061187f919061508f565b915061188b83856158ce565b6001600160a01b0383165f908152600560205260409020549094506118b1908490615948565b6001600160a01b0383165f81815260056020908152604080832094909455835187815290810191909152918201527f26d61a36a46ca0b5adc9f8ae98359690cb59381d060151d48afcfa01e079eda69060600160405180910390a1611917828985613ef6565b604080518481526001600160a01b038a8116602083015284168183015290517f6ee556dbce23a24ad3b539ee42191a2dd262b16ecb4d0ef20dbeb4bb5a9a23839181900360600190a15b60010161182d565b50826001546119789190615948565b600155505f9250688000000000ab143c069150505d5050505050565b5f688000000000ab143c065c156119b25763ab143c065f526004601cfd5b30688000000000ab143c065d6119c6613a31565b6119cf82610d80565b90505f688000000000ab143c065d919050565b688000000000ab143c065c156119ff5763ab143c065f526004601cfd5b30688000000000ab143c065d611a13613f5c565b611a1b613a31565b61117481613fa8565b5f688000000000ab143c065c15611a425763ab143c065f526004601cfd5b30688000000000ab143c065d611a5c84848460015f614022565b90505f688000000000ab143c065d9392505050565b6001600160a01b038281165f81815260208190526040808220905163e6248d5560e01b815260048101939093529092909183917f0000000000000000000000001310f352f1389969ece6741671c4b919523912ff169063e6248d5590602401602060405180830381865afa158015611aeb573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611b0f91906158e1565b815260208082019290925260409081015f9081206001600160a01b039095168152939091529091205460ff1692915050565b688000000000ab143c065c15611b5e5763ab143c065f526004601cfd5b30688000000000ab143c065d611b7481336138fc565b611b7c613a31565b6009546001600160a01b037f00000000000000000000000090fc1a4abc4ee5f8a9560de069067d9606d2909c169063f96492c990309086908590611bca9083906001600160f01b03166158ce565b6040516001600160e01b031960e087901b1681526001600160a01b03948516600482015260248101939093529216604482015260648101919091526084015f604051808303815f87803b158015611c1f575f5ffd5b505af1158015611c31573d5f5f3e3d5ffd5b50505050611c40838383613d59565b5f688000000000ab143c065d505050565b5f688000000000ab143c065c15611c6f5763ab143c065f526004601cfd5b30688000000000ab143c065d611a5c848484600180614022565b5f688000000000ab143c065c15611ca75763ab143c065f526004601cfd5b30688000000000ab143c065d611cbd838361343c565b90505f688000000000ab143c065d92915050565b5f688000000000ab143c065c15611cef5763ab143c065f526004601cfd5b30688000000000ab143c065d611a5c8484846001614141565b688000000000ab143c065c15611d255763ab143c065f526004601cfd5b30688000000000ab143c065d611d39613a31565b5f688000000000ab143c065d565b5f688000000000ab143c065c15611d655763ab143c065f526004601cfd5b30688000000000ab143c065d611d7a8261424a565b5060015f688000000000ab143c065d919050565b5f5f5f5f688000000000ab143c065c15611daf5763ab143c065f526004601cfd5b50506007546001600160601b0381169364ffffffffff606083901c81169450608883901c16925060b09190911c90565b688000000000ab143c065c15611dfc5763ab143c065f526004601cfd5b30688000000000ab143c065d604051630a73e39160e01b81523360048201527f00000000000000000000000090fc1a4abc4ee5f8a9560de069067d9606d2909c6001600160a01b031690630a73e39190602401602060405180830381865afa158015611e6a573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611e8e9190615860565b611e9f57611e9f63471656c5613433565b611ea7613a31565b60405163463aea7f60e11b81523060048201526001600160a01b0383811660248301527f00000000000000000000000090fc1a4abc4ee5f8a9560de069067d9606d2909c1690638c75d4fe906044015f604051808303815f87803b158015611f0d575f5ffd5b505af1158015611f1f573d5f5f3e3d5ffd5b50505050611f2e833384613d59565b6040516318f9a83960e21b815233906363e6a0e490611f579030908790879087906004016159b3565b5f604051808303815f87803b158015611f6e575f5ffd5b505af1158015611f80573d5f5f3e3d5ffd5b5050600954604051630967a76b60e31b81523060048201525f60248201526001600160a01b0386811660448301526001600160f01b0390921660648201527f00000000000000000000000090fc1a4abc4ee5f8a9560de069067d9606d2909c9091169250634b3d3b5891506084015f604051808303815f87803b158015612005575f5ffd5b505af1158015612017573d5f5f3e3d5ffd5b505050505f688000000000ab143c065d505050565b6004545f90808203612051576040516354e9f59b60e01b815260040160405180910390fd5b60095462012fd19061206c906001600160f01b031683615948565b6120769190615948565b91505090565b5f688000000000ab143c065c1561209a5763ab143c065f526004601cfd5b30688000000000ab143c065d611cbd8383614308565b606060038054610bd99061580d565b604051634b0b3ab760e11b81526001600160a01b0382811660048301525f917f0000000000000000000000001310f352f1389969ece6741671c4b919523912ff90911690639616756e90602401602060405180830381865afa158015612127573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610bc49190615860565b688000000000ab143c065c156121685763ab143c065f526004601cfd5b30688000000000ab143c065d61217f8233836136b2565b505f688000000000ab143c065d5050565b5f610bc482600461271061317a565b5f688000000000ab143c065c156121bd5763ab143c065f526004601cfd5b30688000000000ab143c065d6121d4828433613260565b6121de83836143a8565b50600190505f688000000000ab143c065d92915050565b688000000000ab143c065c156122125763ab143c065f526004601cfd5b30688000000000ab143c065d61222881336138fc565b6122328282613529565b6114688282613616565b5f688000000000ab143c065c1561225a5763ab143c065f526004601cfd5b30688000000000ab143c065d61226e613a31565b506009546001600160f01b03165f688000000000ab143c065d90565b5f688000000000ab143c065c156122a85763ab143c065f526004601cfd5b30688000000000ab143c065d61110f82336138fc565b5f610bc4826122cb612d37565b61440c565b5f688000000000ab143c065c156122ee5763ab143c065f526004601cfd5b30688000000000ab143c065d611a5c8484845f614141565b5f688000000000ab143c065c156123245763ab143c065f526004601cfd5b30688000000000ab143c065d611a5c8484845f5f614022565b688000000000ab143c065c1561235a5763ab143c065f526004601cfd5b30688000000000ab143c065d604051630a73e39160e01b81523360048201527f00000000000000000000000090fc1a4abc4ee5f8a9560de069067d9606d2909c6001600160a01b031690630a73e39190602401602060405180830381865afa1580156123c8573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906123ec9190615860565b6123fd576123fd63471656c5613433565b612405613a31565b5f61240e612d37565b90505f61241c858584614432565b90505f6124298684612d80565b90506124388682333389614477565b612445868287858861451c565b5050505f688000000000ab143c065d505050565b336001600160a01b0383160361248257604051636eef2f3f60e11b815260040160405180910390fd5b604051634b0b3ab760e11b81523360048201527f0000000000000000000000001310f352f1389969ece6741671c4b919523912ff6001600160a01b031690639616756e90602401602060405180830381865afa1580156124e4573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906125089190615860565b15612526576040516302d5da9f60e01b815260040160405180910390fd5b60405163e6248d5560e01b81523360048201525f907f0000000000000000000000001310f352f1389969ece6741671c4b919523912ff6001600160a01b03169063e6248d5590602401602060405180830381865afa15801561258a573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906125ae91906158e1565b335f8181526020818152604080832085845282528083206001600160a01b03891680855290835292819020805460ff191688151590811790915581518681529283015293945090927ffeeb3502e62327bd3fece59983b972dc941e6abedd652971aac3adea23cf7e17910160405180910390a3505050565b5f688000000000ab143c065c156126445763ab143c065f526004601cfd5b610bc482612650612d37565b614670565b5f688000000000ab143c065c156126735763ab143c065f526004601cfd5b30688000000000ab143c065d611a5c8484845f6001614022565b6387a211a2600c9081525f828152602090912054610bc490610c5a565b6040805160c0810182525f80825260208201819052918101829052606081018290526080810182905260a08101919091526126e3613a31565b610bc482610f0a565b688000000000ab143c065c156127095763ab143c065f526004601cfd5b30688000000000ab143c065d61271d613f5c565b612725613a31565b600654816001600160a01b03166367e860cd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612764573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061278891906158e1565b146127a657604051631961405760e31b815260040160405180910390fd5b61117481614696565b5f6127b8610bca565b805190602001209050844211156127d657631a15a3cc5f526004601cfd5b6040518860601b60601c98508760601b60601c975065383775081901600e52885f526020600c2080547f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f83528360208401527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc6604084015246606084015230608084015260a08320602e527f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c983528a60208401528960408401528860608401528060808401528760a084015260c08320604e526042602c205f528660ff16602052856040528460605260208060805f60015afa8b3d51146128de5763ddafbaef5f526004601cfd5b0190556303faf4f960a51b88176040526034602c2087905587897f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925602060608501a360405250505f606052505050505050565b6387a211a2600c9081525f828152602090912054610bc4565b60405163e6248d5560e01b81526001600160a01b0382811660048301525f917f0000000000000000000000001310f352f1389969ece6741671c4b919523912ff9091169063e6248d5590602401602060405180830381865afa1580156129b2573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610bc491906158e1565b60607f0000000000000000000000001310f352f1389969ece6741671c4b919523912ff82806001600160401b03811115612a1257612a126152ec565b604051908082528060200260200182016040528015612a4557816020015b6060815260200190600190039081612a305790505b5060408051606080820183525f80835260208301819052928201529194505b82811015612c2e57868682818110612a7e57612a7e615934565b9050602002810190612a909190615a54565b612a9990615a72565b9150816020015115612bd057815160405163191d0cc560e11b81526001600160a01b0391821660048201525f9186169063323a198a90602401602060405180830381865afa158015612aed573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612b119190615845565b90506001600160a01b038116612b3a57604051632f3285fb60e21b815260040160405180910390fd5b8251604080850151905163bd0226d760e01b81526001600160a01b0384169263bd0226d792612b6f9233929190600401615ada565b5f604051808303815f87803b158015612b86575f5ffd5b505af1158015612b98573d5f5f3e3d5ffd5b50505050612bad835f01518460400151614794565b868381518110612bbf57612bbf615934565b602002602001018190525050612c26565b81516001600160a01b03163014612bfa57604051637720ccd960e01b815260040160405180910390fd5b612c08308360400151614809565b858281518110612c1a57612c1a615934565b60200260200101819052505b600101612a64565b5050505092915050565b5f610bc482612650612d37565b600480546040516370a0823160e01b815230928101929092525f9182907f000000000000000000000000484be0540ad49f351eaa04eeb35df0f937d4e73f6001600160a01b0316906370a0823190602401602060405180830381865afa158015612cb1573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612cd591906158e1565b600954612ceb91906001600160f01b03166158ce565b9050818111612d0d5760405163c0883a5560e01b815260040160405180910390fd5b612d178282615948565b9250505090565b5f612d27613a31565b610b74670de0b6b3a7640000610c845b5f612d4061485d565b600454610b7491906158ce565b5f5f612d606805345cdf77eb68f44c5490565b90508015612d7857612d73848483614897565b610dc7565b509192915050565b5f5f612d936805345cdf77eb68f44c5490565b90508015612d7857612d73848285614933565b306001600160a01b03841603612dc357612dc3638b5fe5a3613433565b612dcb613a31565b612ded6040518060600160405280606081526020015f81526020015f81525090565b7f00000000000000000000000090fc1a4abc4ee5f8a9560de069067d9606d2909c6001600160a01b031663da11ee23898989896040518060e001604052808b6001600160a01b03168152602001306001600160a01b031681526020018a815260200189151581526020015f81526020015f81526020015f8152506040518663ffffffff1660e01b8152600401612e87959493929190615b7d565b5f604051808303815f875af1158015612ea2573d5f5f3e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052612ec99190810190615c72565b98509050612efd7f000000000000000000000000484be0540ad49f351eaa04eeb35df0f937d4e73f88308460200151613ea7565b60075460b01c5f8080805b87811015612ff1578c8181518110612f2257612f22615934565b60200260200101519350835f0315612fe9578a8a82818110612f4657612f46615934565b9050602002016020810190612f5b919061508f565b915083612f6783610d80565b612f719190615948565b6001600160a01b0383165f908152600a6020526040902060b087901b82179055925060408051858152602081018590526001600160a01b03808f169282019290925290831660608201527f21afd5f303208e3668ecf03cf3aa4036a5f71fbdd357478968cfd1502c25953d9060800160405180910390a15b600101612f08565b5084604001518560200181815161300891906158ce565b90525060208501516009546001600160f01b0316101561303757600980546001600160f01b0319169055613073565b602085015160095461305291906001600160f01b0316615948565b600980546001600160f01b0319166001600160f01b03929092169190911790555b60408501511561310c5760045460408601516130939062012fd1906158ce565b8110156130b35760405163ab2169c760e01b815260040160405180910390fd5b60408601516130c29082615948565b60045560408681015181519081526001600160a01b038e1660208201527f92fa6dfbfde0da658c7f8f7d12d2019a8b1972ebf52e449498652ade0455ba2c910160405180910390a1505b8451604051635722baf360e01b81526001600160a01b038a1691635722baf39161313f91908f908f908f90600401615d1c565b5f604051808303815f87803b158015613156575f5ffd5b505af1158015613168573d5f5f3e3d5ffd5b50505050505050505050505050505050565b5f610dc784848461495f565b6040516355eaece960e11b81523360048201527f0000000000000000000000001310f352f1389969ece6741671c4b919523912ff6001600160a01b03169063abd5d9d2906024015b602060405180830381865afa1580156131e9573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061320d9190615860565b61321e5761321e63471656c5613433565b565b816014528060345263a9059cbb60601b5f5260205f604460105f875af13d1560015f51141716613257576390b8ec185f526004601cfd5b5f603452505050565b613268613a31565b61327183613e92565b816001600160a01b0316816001600160a01b0316036132a25760405162640b4560e41b815260040160405180910390fd5b6001600160a01b038082165f90815260056020526040812054917f00000000000000000000000090fc1a4abc4ee5f8a9560de069067d9606d2909c1663b7b7f260308786613301816387a211a2600c9081525f91909152602090205490565b875f891161330f575f613312565b60015b6040518763ffffffff1660e01b815260040161333396959493929190615d50565b6020604051808303815f875af115801561334f573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061337391906158e1565b90508015613385576133858184613616565b5050505050565b5f8360601b33602052637f5e9f208117600c526034600c20805460018101156133ca57808511156133c4576313be252b5f526004601cfd5b84810382555b50506387a211a28117600c526020600c208054808511156133f25763f4d678b85f526004601cfd5b84810382555050835f526020600c208381540181555082602052600c5160601c8160601c5f516020615ed95f395f51905f52602080a3505060019392505050565b805f526004601cfd5b5f613445613a31565b61345c61345484612650612d37565b915081613e92565b6040516330ae91d160e21b81523060048201527f00000000000000000000000090fc1a4abc4ee5f8a9560de069067d9606d2909c6001600160a01b03169063c2ba4744906024015f604051808303815f87803b1580156134ba575f5ffd5b505af11580156134cc573d5f5f3e3d5ffd5b50505050610bc48382338561498b565b6001600160a01b0381165f908152600a60205260409020546001600160b01b03161561351b576040516311dd629d60e21b815260040160405180910390fd5b6135258282614a25565b5050565b61353282613e92565b6001600160a01b0381165f908152600560205260409020548281101561355f5761355f63e6c95926613433565b7f00000000000000000000000090fc1a4abc4ee5f8a9560de069067d9606d2909c6001600160a01b0316632076d8e73085856135ac876387a211a2600c9081525f91909152602090205490565b8660016040518763ffffffff1660e01b81526004016135d096959493929190615d50565b6020604051808303815f875af11580156135ec573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061361091906158e1565b50505050565b6001600160a01b0381165f90815260056020526040902054613639908390615948565b6001600160a01b0382165f9081526005602052604090205560015461365f908390615948565b600155604080518381525f60208201526001600160a01b038316918101919091527f26d61a36a46ca0b5adc9f8ae98359690cb59381d060151d48afcfa01e079eda6906060015b60405180910390a15050565b5f6136bb613a31565b5f6136c583610d80565b905084156136d357846136d5565b805b94506136e085613e92565b808511156136f5576136f5638b5fe5a3613433565b6137217f000000000000000000000000484be0540ad49f351eaa04eeb35df0f937d4e73f853088613ea7565b6001600160a01b037f00000000000000000000000090fc1a4abc4ee5f8a9560de069067d9606d2909c16634b0319523061375b8885615948565b9350837f000000000000000000000000484be0540ad49f351eaa04eeb35df0f937d4e73f7f00000000000000000000000000000000000000000000000000000000000000126040516001600160e01b031960e087901b1681526001600160a01b0394851660048201526024810193909352908316604483015260ff166064820152908616608482015260a4015f6040518083038186803b1580156137fd575f5ffd5b505afa15801561380f573d5f5f3e3d5ffd5b50506007546001600160a01b0386165f908152600a602052604090206001600160b01b031990911684179055506138439050565b6009546001600160f01b031685111561386b57600980546001600160f01b03191690556138a3565b6009546138829086906001600160f01b0316615948565b600980546001600160f01b0319166001600160f01b03929092169190911790555b60408051868152602081018390526001600160a01b03868116828401528516606082015290517f21afd5f303208e3668ecf03cf3aa4036a5f71fbdd357478968cfd1502c25953d9181900360800190a150929392505050565b6001600160a01b038281165f81815260208190526040808220905163e6248d5560e01b815260048101939093529290917f0000000000000000000000001310f352f1389969ece6741671c4b919523912ff9091169063e6248d5590602401602060405180830381865afa158015613975573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061399991906158e1565b815260208082019290925260409081015f9081206001600160a01b038516825290925290205460ff16613525576040516367ee2b0160e11b815260040160405180910390fd5b6139e882613e92565b6387a211a2600c9081525f82905260209020546001600160a01b0382165f90815260056020526040902054613a1e9084906158ce565b11156135255761352563e6c95926613433565b60075464ffffffffff608882901c1642819003613a4c575050565b6009546004546001600160601b0384169164ffffffffff606086901c169160b086901c916001600160f01b0316905f613a878684878a614b39565b9050844210613bb85760085494965086945f906001600160a01b031663589dc77b613ab061202c565b613aba85886158ce565b6040516001600160e01b031960e085901b1681526004810192909252602482015260440160408051808303815f875af1158015613af9573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613b1d9190615d89565b9097509050808080613b2f8942615948565b613b399190615dab565b613b439190615dca565b613b4d91906158ce565b9050613b5981876158ce565b60408051898152602081018390529197507f6ca03c3e1f9f2693eb4277ee4f449b9838fad99c363f5d54bacaf5f71a34afec910160405180910390a1613baa87613ba384876158ce565b888b614b39565b613bb490836158ce565b9150505b6009545f90613bd6908390600160f01b900461ffff1661271061317a565b90508015613ca0575f613c0e82613bf46805345cdf77eb68f44c5490565b84613bff87896158ce565b613c099190615948565b614933565b90505f7f0000000000000000000000001310f352f1389969ece6741671c4b919523912ff6001600160a01b0316632131c68c6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613c6d573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613c919190615845565b9050613c9d8183614b93565b50505b8115613d2f5784613cb283878761317a565b613cbc91906158ce565b9450613cc882856158ce565b600980546001600160f01b0319166001600160f01b0392909216919091179055613cf282846158ce565b60045560408051838152602081018390527f4e32a70f9f06da2cec9f0079d5658935775123a5ce8d0d68de35d019a8d1c19c910160405180910390a15b5050505060609190911b4260881b1760b09190911b176001600160601b0391909116176007555050565b613d6283613e92565b613d6b83614bfc565b6001600160a01b0381165f9081526005602052604090205415613da157604051635d00c4f360e11b815260040160405180910390fd5b5f83613dac83610d80565b613db691906158ce565b6007546001600160a01b0384165f908152600a602052604090206001600160b01b0319909116821790559050600954613df99085906001600160f01b03166158ce565b600980546001600160f01b0319166001600160f01b0392909216919091179055613e447f000000000000000000000000484be0540ad49f351eaa04eeb35df0f937d4e73f8486613220565b60408051858152602081018390526001600160a01b0384168183015290517fbec1750eb40c00e8dc2e1c84babbddd5779eaa06c951ab2c66416d05910e7a739181900360600190a150505050565b80613ea45763c0883a555f526004601cfd5b50565b60405181606052826040528360601b602c526323b872dd60601b600c5260205f6064601c5f895af13d1560015f51141716613ee957637939f4245f526004601cfd5b5f60605260405250505050565b8260601b6387a211a28117600c526020600c20805480841115613f205763f4d678b85f526004601cfd5b83810382555050825f526020600c208281540181555081602052600c5160601c8160601c5f516020615ed95f395f51905f52602080a350505050565b60405163de0c7a7160e01b81523360048201527f0000000000000000000000001310f352f1389969ece6741671c4b919523912ff6001600160a01b03169063de0c7a71906024016131ce565b611770811115613fbf57613fbf638b5fe5a3613433565b6009805461ffff838116600160f01b9081026001600160f01b038416179384905560408051938290048316808552919094049091166020830152917f27a0956e997c69164a0c4cc2fb19bd083ae33e1abbc2165b43398d899b51fd0b91016136a6565b5f61402b613a31565b5f614034612d37565b90505f61404e6140448984612d4d565b9350838784614432565b905084156140655761406086336138fc565b61406f565b61406f8689614c24565b6001600160a01b038681165f90815260056020526040808220549051632076d8e760e01b815291927f00000000000000000000000090fc1a4abc4ee5f8a9560de069067d9606d2909c1691632076d8e7916140d69130918e918d9189918d90600401615d50565b6020604051808303815f875af11580156140f2573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061411691906158e1565b90508015614128576141288188613616565b614135848a338b8b614477565b50505095945050505050565b5f61414a613a31565b5f614153612d37565b90505f614161878684614432565b9050614179856141718985612d80565b945084614c24565b6001600160a01b038581165f90815260056020526040808220549051632076d8e760e01b815291927f00000000000000000000000090fc1a4abc4ee5f8a9560de069067d9606d2909c1691632076d8e7916141e091309189918c9189918d90600401615d50565b6020604051808303815f875af11580156141fc573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061422091906158e1565b90508015614232576142328187613616565b61423f8885338a8a614477565b505050949350505050565b6008546040805163ea12489f60e01b8152905130926001600160a01b03169163ea12489f9160048083019260209291908290030181865afa158015614291573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906142b59190615845565b6001600160a01b0316146142d0576142d063471656c5613433565b6142d981614c3f565b60b0670de0b6b3a7640000901b608842901b606042901b6001600160601b036007541617171760078190555050565b5f614311613a31565b61431a83613e92565b6040516330ae91d160e21b81523060048201527f00000000000000000000000090fc1a4abc4ee5f8a9560de069067d9606d2909c6001600160a01b03169063c2ba4744906024015f604051808303815f87803b158015614378575f5ffd5b505af115801561438a573d5f5f3e3d5ffd5b50505050610bc461439d846122cb612d37565b91508184338561498b565b5f6387a211a2600c52335f526020600c208054808411156143d05763f4d678b85f526004601cfd5b83810382555050825f526020600c208281540181555081602052600c5160601c335f516020615ed95f395f51905f52602080a350600192915050565b5f5f61441f6805345cdf77eb68f44c5490565b90508015612d7857612d73848483614933565b5f61443c84613e92565b506387a211a2600c9081525f839052602090205461445a8183612d4d565b84111561446e5761446e63e6c95926613433565b61141a84614bfc565b6144818185614d00565b61448a85614d61565b6144b57f000000000000000000000000484be0540ad49f351eaa04eeb35df0f937d4e73f8387613220565b806001600160a01b0316826001600160a01b0316846001600160a01b03167ffbde797d201c681b91056529119e0b02407c7bb96a4a2c75c01fc9667232c8db888860405161450d929190918252602082015260400190565b60405180910390a45050505050565b604051632748468360e11b81523390634e908d0690614545903090899088908790600401615de1565b5f604051808303815f87803b15801561455c575f5ffd5b505af115801561456e573d5f5f3e3d5ffd5b50506387a211a2600c9081525f869052602090205461459092508691506158ce565b82146145af5760405163350385ad60e11b815260040160405180910390fd5b6001600160a01b038381165f90815260056020526040808220549051632076d8e760e01b815291927f00000000000000000000000090fc1a4abc4ee5f8a9560de069067d9606d2909c1691632076d8e7916146169130918a918a918a918990600401615d50565b6020604051808303815f875af1158015614632573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061465691906158e1565b90508015614668576146688185613616565b505050505050565b5f5f6146836805345cdf77eb68f44c5490565b90508015612d7857612d73848285614897565b6146a781638ec124b360e01b614d75565b6146b8576146b8638b5fe5a3613433565b600880546001600160a01b031981166001600160a01b03848116918217909355604080516367e860cd60e01b8152905193909216925f926367e860cd9160048083019260209291908290030181865afa158015614717573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061473b91906158e1565b6006819055604080516001600160a01b038086168252861660208201529081018290529091507f6ceb115a1597bd916163fc3cca894b15a8a1dc485d02079de9de8bbfda37a032906060015b60405180910390a1505050565b60605f5f846001600160a01b03165f856040516147b19190615ec2565b5f6040518083038185875af1925050503d805f81146147eb576040519150601f19603f3d011682016040523d82523d5f602084013e6147f0565b606091505b5091509150614800858383614d90565b95945050505050565b60605f5f846001600160a01b0316846040516148259190615ec2565b5f60405180830381855af49150503d805f81146147eb576040519150601f19603f3d011682016040523d82523d5f602084013e6147f0565b6007546009545f9190612076906001600160601b038316906001600160f01b031664ffffffffff606085901c811690608886901c16614b39565b8282025f1983850981811082019003806148c657826148bd5763ae47f7025f526004601cfd5b5081900461141a565b8083116148da5763ae47f7025f526004601cfd5b828486095f84810385169485900494848311909303908390038390046001010292030417600260038302811880840282030280840282030280840282030280840282030280840282030280840290910302029392505050565b5f61493f848484614897565b9050818385091561141a576001018061141a5763ae47f7025f526004601cfd5b5f825f19048411830215820261497c5763ad251c275f526004601cfd5b50910281810615159190040190565b6149b77f000000000000000000000000484be0540ad49f351eaa04eeb35df0f937d4e73f833087613ea7565b6149c084614dd8565b6149ca8184614b93565b806001600160a01b0316826001600160a01b03167fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d78686604051614a18929190918252602082015260400190565b60405180910390a3613610565b5f82600154614a3491906158ce565b6040516301ac71bb60e11b81523060048201526001600160a01b038481166024830152604482018390529192507f00000000000000000000000090fc1a4abc4ee5f8a9560de069067d9606d2909c90911690630358e376906064015f604051808303815f87803b158015614aa6575f5ffd5b505af1158015614ab8573d5f5f3e3d5ffd5b5050506001600160a01b0383165f90815260056020526040902054614adf915084906158ce565b6001600160a01b0383165f818152600560209081526040918290209390935560018481558151878152938401528201527f26d61a36a46ca0b5adc9f8ae98359690cb59381d060151d48afcfa01e079eda690606001614787565b5f5f85118015614b4857508282105b15610dc757614800834210614b7057614b618385615948565b614b6b9087615dca565b614b84565b614b7a8342615948565b614b849087615dca565b85670de0b6b3a7640000614de6565b6805345cdf77eb68f44c5481810181811015614bb65763e5cfe9575f526004601cfd5b806805345cdf77eb68f44c5550506387a211a2600c52815f526020600c208181540181555080602052600c5160601c5f5f516020615ed95f395f51905f52602080a35050565b80614c0561202c565b1015613ea45760405163ab2169c760e01b815260040160405180910390fd5b336001600160a01b0383161461352557613525823383614df2565b336001600160a01b037f00000000000000000000000090fc1a4abc4ee5f8a9560de069067d9606d2909c1614614c7c57614c7c63471656c5613433565b3062012fd1614cad7f000000000000000000000000484be0540ad49f351eaa04eeb35df0f937d4e73f848484613ea7565b80614cb85f82614b93565b600482905560408051838152602081018390525f916001600160a01b038716917fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d79101614a18565b6387a211a2600c52815f526020600c20805480831115614d275763f4d678b85f526004601cfd5b82900390556805345cdf77eb68f44c805482900390555f8181526001600160a01b0383165f516020615ed95f395f51905f52602083a35050565b80600454614d6f9190615948565b60045550565b5f614d7f83614e30565b801561141a575061141a8383614e62565b6060614d9c8383614ee8565b8151158015614db357506001600160a01b0384163b155b15614dd1576040516314859aeb60e21b815260040160405180910390fd5b5092915050565b80600454614d6f91906158ce565b5f610dc7848484614f16565b81602052637f5e9f20600c52825f526034600c20805460018101156133855780831115614e26576313be252b5f526004601cfd5b9190910390555050565b5f614e42826301ffc9a760e01b614e62565b8015610bc45750614e5b826001600160e01b0319614e62565b1592915050565b6040516001600160e01b0319821660248201525f90819060440160408051601f19818403018152919052602080820180516001600160e01b03166301ffc9a760e01b17815282519293505f9283928392909183918a617530fa92503d91505f519050828015614ed2575060208210155b8015614edd57505f81115b979650505050505050565b816135255780515f03614f0e576040516314859aeb60e21b815260040160405180910390fd5b805181602001fd5b5f825f190484118302158202614f335763ad251c275f526004601cfd5b5091020490565b5f60208284031215614f4a575f5ffd5b81356001600160e01b03198116811461141a575f5ffd5b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b602081525f61141a6020830184614f61565b5f60208284031215614fb1575f5ffd5b5035919050565b6001600160a01b0381168114613ea4575f5ffd5b5f5f60408385031215614fdd575f5ffd5b8235614fe881614fb8565b946020939093013593505050565b5f5f83601f840112615006575f5ffd5b5081356001600160401b0381111561501c575f5ffd5b6020830191508360208260051b8501011115615036575f5ffd5b9250929050565b5f5f5f6040848603121561504f575f5ffd5b83356001600160401b03811115615064575f5ffd5b61507086828701614ff6565b909450925050602084013561508481614fb8565b809150509250925092565b5f6020828403121561509f575f5ffd5b813561141a81614fb8565b5f5f5f606084860312156150bc575f5ffd5b83356150c781614fb8565b925060208401356150d781614fb8565b929592945050506040919091013590565b5f5f604083850312156150f9575f5ffd5b82359150602083013561510b81614fb8565b809150509250929050565b5f5f5f5f5f6060868803121561512a575f5ffd5b85356001600160401b0381111561513f575f5ffd5b61514b88828901614ff6565b90965094505060208601356001600160401b03811115615169575f5ffd5b61517588828901614ff6565b909450925050604086013561518981614fb8565b809150509295509295909350565b5f5f5f604084860312156151a9575f5ffd5b8335925060208401356001600160401b038111156151c5575f5ffd5b8401601f810186136151d5575f5ffd5b80356001600160401b038111156151ea575f5ffd5b8660208284010111156151fb575f5ffd5b939660209190910195509293505050565b5f5f5f5f5f60608688031215615220575f5ffd5b85356001600160401b03811115615235575f5ffd5b61524188828901614ff6565b909650945050602086013561525581614fb8565b925060408601356001600160401b0381111561526f575f5ffd5b61527b88828901614ff6565b969995985093965092949392505050565b5f5f5f6060848603121561529e575f5ffd5b8335925060208401356152b081614fb8565b9150604084013561508481614fb8565b5f5f604083850312156152d1575f5ffd5b82356152dc81614fb8565b9150602083013561510b81614fb8565b634e487b7160e01b5f52604160045260245ffd5b60405160c081016001600160401b0381118282101715615322576153226152ec565b60405290565b604051606081016001600160401b0381118282101715615322576153226152ec565b604051601f8201601f191681016001600160401b0381118282101715615372576153726152ec565b604052919050565b8035610c8981614fb8565b5f82601f830112615394575f5ffd5b81356001600160401b038111156153ad576153ad6152ec565b6153c0601f8201601f191660200161534a565b8181528460208386010111156153d4575f5ffd5b816020850160208301375f918101602001919091529392505050565b5f60c08284031215615400575f5ffd5b615408615300565b9050813561541581614fb8565b815260208281013590820152604082013561542f81614fb8565b6040820152606082013561544281614fb8565b60608201526080828101359082015260a08201356001600160401b03811115615469575f5ffd5b61547584828501615385565b60a08301525092915050565b5f5f5f60608486031215615493575f5ffd5b8335925060208401356154a581614fb8565b915060408401356001600160401b038111156154bf575f5ffd5b840160c081870312156154d0575f5ffd5b6154d8615300565b6154e18261537a565b8152602082810135908201526154f96040830161537a565b60408201526060828101359082015260808201356001600160401b03811115615520575f5ffd5b61552c888285016153f0565b60808301525060a08201356001600160401b0381111561554a575f5ffd5b61555688828501615385565b60a08301525080925050509250925092565b5f6001600160401b03821115615580576155806152ec565b5060051b60200190565b5f82601f830112615599575f5ffd5b81356155ac6155a782615568565b61534a565b8082825260208201915060208360051b8601019250858311156155cd575f5ffd5b602085015b8381101561560d5780356001600160401b038111156155ef575f5ffd5b6155fe886020838a01016153f0565b845250602092830192016155d2565b5095945050505050565b5f5f5f60608486031215615629575f5ffd5b83359250602084013561563b81614fb8565b915060408401356001600160401b03811115615655575f5ffd5b840160c08187031215615666575f5ffd5b61566e615300565b6156778261537a565b81526020828101359082015261568f6040830161537a565b60408201526060828101359082015260808201356001600160401b038111156156b6575f5ffd5b61552c8882850161558a565b8015158114613ea4575f5ffd5b5f5f604083850312156156e0575f5ffd5b82356156eb81614fb8565b9150602083013561510b816156c2565b5f5f5f5f5f5f5f60e0888a031215615711575f5ffd5b873561571c81614fb8565b9650602088013561572c81614fb8565b95506040880135945060608801359350608088013560ff8116811461574f575f5ffd5b9699959850939692959460a0840135945060c09093013592915050565b5f5f6020838503121561577d575f5ffd5b82356001600160401b03811115615792575f5ffd5b61579e85828601614ff6565b90969095509350505050565b5f602082016020835280845180835260408501915060408160051b8601019250602086015f5b8281101561580157603f198786030184526157ec858351614f61565b945060209384019391909101906001016157d0565b50929695505050505050565b600181811c9082168061582157607f821691505b60208210810361583f57634e487b7160e01b5f52602260045260245ffd5b50919050565b5f60208284031215615855575f5ffd5b815161141a81614fb8565b5f60208284031215615870575f5ffd5b815161141a816156c2565b634e487b7160e01b5f52601160045260245ffd5b5f5f5f606084860312156158a1575f5ffd5b83516158ac816156c2565b60208501519093506158bd816156c2565b6040850151909250615084816156c2565b80820180821115610bc457610bc461587b565b5f602082840312156158f1575f5ffd5b5051919050565b84815283602082015260606040820152816060820152818360808301375f818301608090810191909152601f909201601f191601019392505050565b634e487b7160e01b5f52603260045260245ffd5b81810381811115610bc457610bc461587b565b80516001600160a01b03908116835260208083015190840152604080830151821690840152606080830151909116908301526080808201519083015260a08181015160c09184018290525f91610dc790850182614f61565b60018060a01b038516815283602082015260018060a01b03831660408201526080606082015260018060a01b038251166080820152602082015160a082015260018060a01b0360408301511660c0820152606082015160e08201525f608083015160c0610100840152615a2a61014084018261595b565b905060a0840151607f1984830301610120850152615a488282614f61565b98975050505050505050565b5f8235605e19833603018112615a68575f5ffd5b9190910192915050565b5f60608236031215615a82575f5ffd5b615a8a615328565b8235615a9581614fb8565b81526020830135615aa5816156c2565b602082015260408301356001600160401b03811115615ac2575f5ffd5b615ace36828601615385565b60408301525092915050565b6001600160a01b038481168252831660208201526060604082018190525f9061480090830184614f61565b5f8151808452602084019350602083015f5b82811015615b35578151865260209586019590910190600101615b17565b5093949350505050565b8183526020830192505f815f5b84811015615b35578135615b5f81614fb8565b6001600160a01b031686526020958601959190910190600101615b4c565b61014081525f615b91610140830188615b05565b6001600160a01b03871660208401528281036040840152615bb3818688615b3f565b91505060018060a01b03835116606083015260018060a01b036020840151166080830152604083015160a08301526060830151151560c0830152608083015160e083015260a083015161010083015260c08301516101208301529695505050505050565b5f82601f830112615c26575f5ffd5b8151615c346155a782615568565b8082825260208201915060208360051b860101925085831115615c55575f5ffd5b602085015b8381101561560d578051835260209283019201615c5a565b5f5f60408385031215615c83575f5ffd5b82516001600160401b03811115615c98575f5ffd5b830160608186031215615ca9575f5ffd5b615cb1615328565b81516001600160401b03811115615cc6575f5ffd5b615cd287828501615c17565b8252506020828101518183015260409283015192820192909252908401519092506001600160401b03811115615d06575f5ffd5b615d1285828601615c17565b9150509250929050565b606081525f615d2e6060830187615b05565b6001600160a01b03861660208401528281036040840152614edd818587615b3f565b6001600160a01b03968716815260208101959095529290941660408401526060830152608082019290925290151560a082015260c00190565b5f5f60408385031215615d9a575f5ffd5b505080516020909101519092909150565b5f82615dc557634e487b7160e01b5f52601260045260245ffd5b500490565b8082028115828204841417610bc457610bc461587b565b60018060a01b038516815283602082015260018060a01b0383166040820152608060608201525f610140820160018060a01b038451166080840152602084015160a084015260018060a01b0360408501511660c0840152606084015160e0840152608084015160c0610100850152818151808452610160860191506101608160051b87010193506020830192505f5b81811015615ea25761015f19878603018352615e8d85855161595b565b94506020938401939290920191600101615e70565b5050505060a0840151838203607f1901610120850152615a488282614f61565b5f82518060208501845e5f92019182525091905056feddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa26469706673582212209d1af0ba86ae344133dffce36c4b91ce925fb4117300ef90c85021d81eaa96f664736f6c634300081c0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000001310f352f1389969ece6741671c4b919523912ff000000000000000000000000484be0540ad49f351eaa04eeb35df0f937d4e73f00000000000000000000000090fc1a4abc4ee5f8a9560de069067d9606d2909c0000000000000000000000000a8c317c25a000000296673bd75ca3f5c1e8c57c
-----Decoded View---------------
Arg [0] : cr (address): 0x1310f352f1389969Ece6741671c4B919523912fF
Arg [1] : asset_ (address): 0x484be0540aD49f351eaa04eeB35dF0f937D4E73f
Arg [2] : mm (address): 0x90fc1A4abC4ee5f8a9560dE069067D9606d2909C
Arg [3] : IRM_ (address): 0x0A8c317C25A000000296673Bd75cA3f5c1E8C57c
-----Encoded View---------------
4 Constructor Arguments found :
Arg [0] : 0000000000000000000000001310f352f1389969ece6741671c4b919523912ff
Arg [1] : 000000000000000000000000484be0540ad49f351eaa04eeb35df0f937d4e73f
Arg [2] : 00000000000000000000000090fc1a4abc4ee5f8a9560de069067d9606d2909c
Arg [3] : 0000000000000000000000000a8c317c25a000000296673bd75ca3f5c1e8c57c
Deployed Bytecode Sourcemap
248582:43078:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;214585:147;;;:::i;:::-;;;160:25:1;;;148:2;133:18;214585:147:0;;;;;;;;214150:292;;;;;;:::i;:::-;;:::i;:::-;;;652:14:1;;645:22;627:41;;615:2;600:18;214150:292:0;487:187:1;206754:92:0;;;:::i;:::-;;;;;;;:::i;215606:182::-;;;;;;:::i;:::-;;:::i;52585:586::-;;;;;;:::i;:::-;;:::i;216934:173::-;;;;;;:::i;:::-;;:::i;262760:539::-;;;;;;:::i;:::-;;:::i;:::-;;268395:743;;;;;;:::i;:::-;;:::i;249001:41::-;;249041:1;249001:41;;51401:200;51564:18;51558:25;51401:200;;266148:305;;;:::i;249897:22::-;;;;;-1:-1:-1;;;;;249897:22:0;;;;;;-1:-1:-1;;;;;3321:32:1;;;3303:51;;3291:2;3276:18;249897:22:0;3138:222:1;267620:482:0;;;;;;:::i;:::-;;:::i;:::-;;;;;;3600:13:1;;-1:-1:-1;;;;;3596:39:1;;;3578:58;;3696:4;3684:17;;;3678:24;3674:50;;;3652:20;;;3645:80;3785:4;3773:17;;;3767:24;3793:4;3763:35;3741:20;;;3734:65;3869:4;3857:17;;;3851:24;3844:32;3837:40;3815:20;;;3808:70;3934:4;3922:17;;;3916:24;3894:20;;;3887:54;3623:3;3985:17;;;3979:24;3957:20;;;3950:54;;;;3565:3;3550:19;;3365:645;213293:315:0;;;;;;:::i;:::-;;:::i;196249:599::-;;;;;;:::i;:::-;;:::i;111441:204::-;;;5072:4:1;234707:9:0;5060:17:1;5042:36;;5030:2;5015:18;111441:204:0;4900:184:1;201433:175:0;;;;;;:::i;:::-;;:::i;61973:707::-;;;:::i;260450:110::-;;;;;;:::i;:::-;;:::i;261781:517::-;;;;;;:::i;:::-;;:::i;207173:106::-;207264:6;207173:106;;205191:131;;;:::i;207626:467::-;;;;;;:::i;:::-;;:::i;200985:246::-;;;;;;:::i;:::-;;:::i;190363:45::-;;;;;270750:99;270837:4;270750:99;;255574:550;;;;;;:::i;:::-;;:::i;217398:171::-;;;;;;:::i;:::-;;:::i;200398:169::-;;;;;;:::i;:::-;;:::i;263748:812::-;;;;;;:::i;:::-;;:::i;202836:1695::-;;;;;;:::i;:::-;;:::i;265473:225::-;;;;;;:::i;:::-;;:::i;254990:229::-;;;;;;:::i;:::-;;:::i;211962:220::-;;;;;;:::i;:::-;;:::i;136726:223::-;;;;;;:::i;:::-;;:::i;250186:36::-;;;;;-1:-1:-1;;;;;250186:36:0;;;;;;-1:-1:-1;;;;;9300:32:1;;;9282:51;;9270:2;9255:18;250186:36:0;9136:203:1;256821:638:0;;;;;;:::i;:::-;;:::i;199896:231::-;;;;;;:::i;:::-;;:::i;209231:184::-;;;;;;:::i;:::-;;:::i;51670:293::-;;;;;;:::i;:::-;51841:18;51835:4;51828:32;;;51733:14;51874:19;;;;51939:4;51923:21;;51917:28;;51670:293;198449:226;;;;;;:::i;:::-;;:::i;246257:28::-;;;;;;217753:84;;;:::i;193272:157::-;;;;;;:::i;:::-;;:::i;253162:567::-;;;:::i;:::-;;;;9575:25:1;;;9631:2;9616:18;;9609:34;;;;9659:18;;;9652:34;9717:2;9702:18;;9695:34;9562:3;9547:19;253162:567:0;9344:391:1;58067:348:0;;;;;;:::i;:::-;58294:17;58288:4;58281:31;;;58127:14;58326:19;;;;58391:4;58375:21;;58369:28;;58067:348;248828:55;;248879:4;248828:55;;258790:1359;;;;;;:::i;:::-;;:::i;269775:774::-;;;:::i;133368:49::-;;;;;209834:178;;;;;;:::i;:::-;;:::i;206946:96::-;;;:::i;137347:178::-;;;;;;:::i;:::-;;:::i;260952:123::-;;;;;;:::i;:::-;;:::i;250342:25::-;;;;;-1:-1:-1;;;250342:25:0;;;;;;;;;14263:6:1;14251:19;;;14233:38;;14221:2;14206:18;250342:25:0;14089:188:1;269355:130:0;;;;;;:::i;:::-;;:::i;212540:281::-;;;;;;:::i;:::-;;:::i;201931:252::-;;;;;;:::i;:::-;;:::i;264861:237::-;;;:::i;197517:468::-;;;;;;:::i;:::-;;:::i;216506:157::-;;;;;;:::i;:::-;;:::i;210481:224::-;;;;;;:::i;:::-;;:::i;211183:227::-;;;;;;:::i;:::-;;:::i;194722:1000::-;;;;;;:::i;:::-;;:::i;135016:666::-;;;;;;:::i;:::-;;:::i;215078:182::-;;;;;;:::i;:::-;;:::i;199117:229::-;;;;;;:::i;:::-;;:::i;124557:148::-;;;;;;:::i;:::-;;:::i;205665:188::-;;;;;;:::i;:::-;;:::i;254120:497::-;;;;;;:::i;:::-;;:::i;58605:3284::-;;;;;;:::i;:::-;;:::i;125049:129::-;;;;;;:::i;:::-;;:::i;52061:388::-;;;;;;:::i;:::-;52284:4;52277:21;52325:20;52319:4;52312:34;;;52177:14;52360:19;;;;52425:4;52409:21;;52403:28;;52061:388;190761:37;;;;;;191209:51;;;;;;:::i;:::-;;;;;;;;;;;;;;136064:163;;;;;;:::i;:::-;;:::i;105161:1590::-;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;216039:164::-;;;;;;:::i;:::-;;:::i;266866:387::-;;;:::i;204828:171::-;;;:::i;214585:147::-;214665:14;44820:22;44814:29;44811:146;;;44876:10;44870:4;44863:24;44937:4;44931;44924:18;44811:146;214707:17:::1;:15;:17::i;:::-;214698:26;;214585:147:::0;:::o;214150:292::-;214251:11;-1:-1:-1;;;;;;214284:40:0;;-1:-1:-1;;;214284:40:0;;:97;;-1:-1:-1;;;;;;;214341:40:0;;-1:-1:-1;;;214341:40:0;214284:97;:150;;;-1:-1:-1;;;;;;;;;;99872:40:0;;;214398:36;214275:159;214150:292;-1:-1:-1;;214150:292:0:o;206754:92::-;206800:13;206833:5;206826:12;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;206754:92;:::o;215606:182::-;215710:7;44820:22;44814:29;44811:146;;;44876:10;44870:4;44863:24;44937:4;44931;44924:18;44811:146;215737:43:::1;215754:6;215762:17;:15;:17::i;:::-;215737:16;:43::i;44978:1::-;215606:182:::0;;;:::o;52585:586::-;52659:4;52822:7;52816:4;52809:21;52857:20;52851:4;52844:34;52905:8;52899:4;52892:22;52958:6;52951:4;52945;52935:21;52928:37;53035:6;53029:4;53022:20;53124:4;53118:11;53114:2;53110:20;53100:8;53073:25;53067:4;53061;53056:75;-1:-1:-1;53159:4:0;52585:586;;;;:::o;216934:173::-;217029:7;217056:43;217073:6;217081:17;:15;:17::i;:::-;217056:16;:43::i;262760:539::-;44280:22;44274:29;44271:146;;;44336:10;44330:4;44323:24;44397:4;44391;44384:18;44271:146;44462:9;44438:22;44431:41;262913:8;262891:19:::1;262913:8:::0;-1:-1:-1;;;;;263073:26:0;::::1;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;-1:-1:-1;263073:26:0::1;;263042:57;;263120:171;263145:11;263171:10;263196:8;;263219:15;263249:11;263275:5;263120:10;:171::i;:::-;262880:419;;44604:1:::0;44580:22;44573:33;262760:539;;;:::o;268395:743::-;-1:-1:-1;;;;;268568:16:0;;268454:9;268568:16;;;:7;:16;;;;;;-1:-1:-1;;;;;268595:41:0;;268735:20;;;268731:61;;268772:8;;268395:743;;;:::o;268731:61::-;269033:12;;268972:158;;268996:15;;249549:3;269033:34;;;;269090:28;;;268972:9;:158::i;:::-;268968:162;268395:743;-1:-1:-1;;;;268395:743:0:o;266148:305::-;44280:22;44274:29;44271:146;;;44336:10;44330:4;44323:24;44397:4;44391;44384:18;44271:146;44462:9;44438:22;44431:41;266197:22:::1;:20;:22::i;:::-;266230:14;266247:15;:13;:15::i;:::-;266230:32;;266275:18;266296:15;-1:-1:-1::0;;;;;266296:26:0::1;;:28;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;266275:49:::0;-1:-1:-1;266335:57:0::1;207264:6:::0;266373:10:::1;266385:6;266335:28;:57::i;:::-;266410:35;::::0;;20431:25:1;;;-1:-1:-1;;;;;20492:32:1;;20487:2;20472:18;;20465:60;266410:35:0::1;::::0;20404:18:1;266410:35:0::1;;;;;;;266186:267;;44604:1:::0;44580:22;44573:33;266148:305::o;267620:482::-;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;267772:20:0;267784:7;267772:11;:20::i;:::-;267828:4;267805:28;;-1:-1:-1;;;;;267872:6:0;267844:35;:17;;;:35;267746:46;-1:-1:-1;234707:9:0;267890:28;;:15;;;:28;267951:19;:34;;267981:4;267951:34;;;267973:5;267951:34;267929:56;;:19;;;:56;-1:-1:-1;;;;;268022:25:0;;;;;;;:16;:25;;;;;;267996:23;;;:51;268058:18;;;:36;;;;267929:6;267620:482::o;213293:315::-;213436:4;44280:22;44274:29;44271:146;;;44336:10;44330:4;44323:24;44397:4;44391;44384:18;44271:146;44462:9;44438:22;44431:41;213453:39:::1;213468:6;213476:8;213486:5;213453:14;:39::i;:::-;213535:43;213554:5;213561:8;213571:6;213535:18;:43::i;:::-;;213596:4;213589:11;;44604:1:::0;44580:22;44573:33;213293:315;;;;;:::o;196249:599::-;196368:14;44280:22;44274:29;44271:146;;;44336:10;44330:4;44323:24;44397:4;44391;44384:18;44271:146;44462:9;44438:22;44431:41;196413:10:::1;-1:-1:-1::0;;;;;196413:22:0;::::1;;::::0;::::1;::::0;:83:::1;;-1:-1:-1::0;196453:43:0::1;::::0;-1:-1:-1;;;196453:43:0;;196485:10:::1;196453:43;::::0;::::1;3303:51:1::0;196453:13:0::1;-1:-1:-1::0;;;;;196453:31:0::1;::::0;::::1;::::0;3276:18:1;;196453:43:0::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;196452:44;196413:83;196395:171;;;196523:31;189409:10;196523:7;:31::i;:::-;196587:26;196596:6;196604:8;196587;:26::i;:::-;196578:35;;196807:33;196823:6;196831:8;196807:15;:33::i;:::-;44604:1:::0;44580:22;44573:33;196249:599;;;;:::o;201433:175::-;44280:22;44274:29;44271:146;;;44336:10;44330:4;44323:24;44397:4;44391;44384:18;44271:146;44462:9;44438:22;44431:41;201508:42:::1;201531:6;201539:10;201508:22;:42::i;:::-;201563:37;201581:6;201589:10;201563:17;:37::i;:::-;44604:1:::0;44580:22;44573:33;201433:175;:::o;61973:707::-;62030:14;;62256:6;:4;:6::i;:::-;62240:24;;;;;;62229:35;;62358:4;62352:11;62420:16;62417:1;62410:27;62472:8;62465:4;62462:1;62458:12;62451:30;62516:13;62509:4;62506:1;62502:12;62495:35;62565:9;62558:4;62555:1;62551:12;62544:31;62610:9;62603:4;62600:1;62596:12;62589:31;62657:4;62654:1;62644:18;62634:28;;;62328:345;61973:707;:::o;260450:110::-;44280:22;44274:29;44271:146;;;44336:10;44330:4;44323:24;44397:4;44391;44384:18;44271:146;44462:9;44438:22;44431:41;260514:38:::1;260521:6;260529:10;260541;260514:6;:38::i;:::-;;44604:1:::0;44580:22;44573:33;260450:110;:::o;261781:517::-;44280:22;44274:29;44271:146;;;44336:10;44330:4;44323:24;44397:4;44391;44384:18;44271:146;44462:9;44438:22;44431:41;261980:8;262010:33;;::::1;262006:102;;262060:36;249696:10;262060:7;:36::i;:::-;262120:170;262145:11;;262120:170;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::1;::::0;;;;-1:-1:-1;262171:10:0::1;::::0;-1:-1:-1;262196:8:0;;-1:-1:-1;262196:8:0;;-1:-1:-1;262219:15:0;262249:11;262275:4:::1;262120:10;:170::i;:::-;261947:351;44604:1:::0;44580:22;44573:33;261781:517;;;;;:::o;205191:131::-;205238:14;205274:40;37633:4;205296:17;:15;:17::i;207626:467::-;207764:42;;-1:-1:-1;;;207764:42:0;;207800:4;207764:42;;;3303:51:1;207710:17:0;;;;-1:-1:-1;;;;;207764:13:0;:27;;;;3276:18:1;;207764:42:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;207822:37:0;;-1:-1:-1;;;207822:37:0;;207853:4;207822:37;;;3303:51:1;207740:66:0;;-1:-1:-1;207822:13:0;-1:-1:-1;;;;;207822:22:0;;;;3276:18:1;;207822:37:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;207821:38;:52;;;;207863:10;207821:52;207817:220;;;208009:16;207626:467;;;:::o;207817:220::-;-1:-1:-1;;208059:26:0;208047:38;207626:467;-1:-1:-1;;;207626:467:0:o;200985:246::-;44280:22;44274:29;44271:146;;;44336:10;44330:4;44323:24;44397:4;44391;44384:18;44271:146;44462:9;44438:22;44431:41;201101:33:::1;201116:5;201123:10;201101:14;:33::i;:::-;201145:35;201166:6;201174:5;201145:20;:35::i;:::-;201193:30;201209:6;201217:5;201193:15;:30::i;:::-;44604:1:::0;44580:22;44573:33;200985:246;;:::o;255574:550::-;44280:22;44274:29;44271:146;;;44336:10;44330:4;44323:24;44397:4;44391;44384:18;44271:146;44462:9;44438:22;44431:41;255696:17:::1;:15;:17::i;:::-;256025:21;::::0;-1:-1:-1;;;;;255903:13:0::1;:33;::::0;::::1;::::0;255959:4:::1;::::0;255979:6;;256000:10:::1;::::0;256025:30:::1;::::0;255979:6;;-1:-1:-1;;;;;256025:21:0::1;:30;:::i;:::-;255903:163;::::0;-1:-1:-1;;;;;;255903:163:0::1;::::0;;;;;;-1:-1:-1;;;;;21956:32:1;;;255903:163:0::1;::::0;::::1;21938:51:1::0;22005:18;;;21998:34;;;;22068:32;;22048:18;;;22041:60;22117:18;;;22110:34;;;;21910:19;;255903:163:0::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;256079:37;256087:6;256095:8;256105:10;256079:7;:37::i;217398:171::-:0;217491:7;217518:43;217535:6;217543:17;:15;:17::i;200398:169::-;44280:22;44274:29;44271:146;;;44336:10;44330:4;44323:24;44397:4;44391;44384:18;44271:146;44462:9;44438:22;44431:41;200471:40:::1;200492:6;200500:10;200471:20;:40::i;:::-;200524:35;200540:6;200548:10;200524:15;:35::i;263748:812::-:0;263824:17;:15;:17::i;:::-;263854:24;263871:6;263854:16;:24::i;:::-;263902:31;;-1:-1:-1;;;263902:31:0;;263927:4;263902:31;;;3303:51:1;263902:6:0;-1:-1:-1;;;;;263902:16:0;;;;3276:18:1;;263902:31:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;263893:6;:40;263889:122;;;263957:42;;-1:-1:-1;;;263957:42:0;;;;;;;;;;;263889:122;264047:6;264023:13;264079:16;264088:6;264079:8;:16::i;:::-;264065:30;-1:-1:-1;264106:22:0;264131:12;264065:30;264131:6;:12;:::i;:::-;264106:37;;264164:55;264193:5;264200:10;264212:6;264164:28;:55::i;:::-;264232:64;;-1:-1:-1;;;264232:64:0;;264243:10;;264232:34;;:64;;264267:6;;264275:14;;264291:4;;;;264232:64;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;264309:145;264356:5;264376:10;264409:4;264429:14;264309:32;:145::i;:::-;264497:3;264482:12;;:18;;;;:::i;:::-;264467:12;:33;264518:34;;;23319:25:1;;;23375:2;23360:18;;23353:34;;;264541:10:0;23403:18:1;;;23396:60;264518:34:0;;;;;;;23307:2:1;264518:34:0;;;263813:747;;;263748:812;;;:::o;202836:1695::-;44280:22;44274:29;44271:146;;;44336:10;44330:4;44323:24;44397:4;44391;44384:18;44271:146;44462:9;44438:22;44431:41;203046:49:::1;::::0;-1:-1:-1;;;203046:49:0;;203077:4:::1;203046:49;::::0;::::1;23641:51:1::0;203084:10:0::1;23708:18:1::0;;;23701:60;203046:13:0::1;-1:-1:-1::0;;;;;203046:22:0::1;::::0;::::1;::::0;23614:18:1;;203046:49:0::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1::0;203330:8:0;;-1:-1:-1;203308:19:0::1;::::0;-1:-1:-1;203308:19:0;;-1:-1:-1;203308:19:0;;203439:918:::1;203459:11;203455:1;:15;203439:918;;;203501:16;;203518:1;203501:19;;;;;;;:::i;:::-;;;;;;;203492:28;;203636:6;203646:1;203636:11:::0;203632:60;203668:8:::1;203632:60;203718:8;;203727:1;203718:11;;;;;;;:::i;:::-;;;;;;;;;;;;;;:::i;:::-;203708:21;;203860;203875:6:::0;203860:21;::::1;:::i;:::-;-1:-1:-1::0;;;;;204041:25:0;::::1;;::::0;;;:16:::1;:25;::::0;;;;;203860:21;;-1:-1:-1;204041:34:0::1;::::0;204069:6;;204041:34:::1;:::i;:::-;-1:-1:-1::0;;;;;204013:25:0;::::1;;::::0;;;:16:::1;:25;::::0;;;;;;;:62;;;;204095:41;;24233:25:1;;;24274:18;;;24267:50;;;;24333:18;;;24326:60;204095:41:0::1;::::0;24221:2:1;24206:18;204095:41:0::1;;;;;;;204228:58;204258:7;204267:10;204279:6;204228:29;:58::i;:::-;204306:39;::::0;;24599:25:1;;;-1:-1:-1;;;;;24660:32:1;;;24655:2;24640:18;;24633:60;24729:32;;24709:18;;;24702:60;204306:39:0;;::::1;::::0;;;;24587:2:1;204306:39:0;;::::1;203439:918;203472:3;;203439:918;;;;204512:11;204487:22;;:36;;;;:::i;:::-;204462:22;:61:::0;-1:-1:-1;44604:1:0;;-1:-1:-1;44580:22:0;;-1:-1:-1;;44573:33:0;202836:1695;;;;;:::o;265473:225::-;265565:14;44280:22;44274:29;44271:146;;;44336:10;44330:4;44323:24;44397:4;44391;44384:18;44271:146;44462:9;44438:22;44431:41;265631:17:::1;:15;:17::i;:::-;265670:20;265682:7;265670:11;:20::i;:::-;265661:29;;44604:1:::0;44580:22;44573:33;265473:225;;;:::o;254990:229::-;44280:22;44274:29;44271:146;;;44336:10;44330:4;44323:24;44397:4;44391;44384:18;44271:146;44462:9;44438:22;44431:41;255071:27:::1;:25;:27::i;:::-;255150:17;:15;:17::i;:::-;255180:31;255196:14;255180:15;:31::i;211962:220::-:0;212093:14;44280:22;44274:29;44271:146;;;44336:10;44330:4;44323:24;44397:4;44391;44384:18;44271:146;44462:9;44438:22;44431:41;212129:45:::1;212137:6;212145:8;212155:5;212162:4;212168:5;212129:7;:45::i;:::-;212120:54;;44604:1:::0;44580:22;44573:33;211962:220;;;;;:::o;136726:223::-;-1:-1:-1;;;;;136859:17:0;;;136826:11;136859:17;;;;;;;;;;;136877:53;;-1:-1:-1;;;136877:53:0;;;;;3303:51:1;;;;136826:11:0;;136859:17;;136826:11;;136877:15;:47;;;;3276:18:1;;136877:53:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;136859:72;;;;;;;;;;;;;;-1:-1:-1;136859:72:0;;;-1:-1:-1;;;;;136859:82:0;;;;;;;;;;;;;;;;136726:223;-1:-1:-1;;136726:223:0:o;256821:638::-;44280:22;44274:29;44271:146;;;44336:10;44330:4;44323:24;44397:4;44391;44384:18;44271:146;44462:9;44438:22;44431:41;256956:33:::1;256971:5;256978:10;256956:14;:33::i;:::-;257041:17;:15;:17::i;:::-;257365:21;::::0;-1:-1:-1;;;;;257248:13:0::1;:33;::::0;::::1;::::0;257304:4:::1;::::0;257324:6;;257345:5;;257365:30:::1;::::0;257324:6;;-1:-1:-1;;;;;257365:21:0::1;:30;:::i;:::-;257248:158;::::0;-1:-1:-1;;;;;;257248:158:0::1;::::0;;;;;;-1:-1:-1;;;;;21956:32:1;;;257248:158:0::1;::::0;::::1;21938:51:1::0;22005:18;;;21998:34;;;;22068:32;;22048:18;;;22041:60;22117:18;;;22110:34;;;;21910:19;;257248:158:0::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;257419:32;257427:6;257435:8;257445:5;257419:7;:32::i;:::-;44604:1:::0;44580:22;44573:33;256821:638;;;:::o;199896:231::-;200039:14;44280:22;44274:29;44271:146;;;44336:10;44330:4;44323:24;44397:4;44391;44384:18;44271:146;44462:9;44438:22;44431:41;200075:44:::1;200083:6;200091:8;200101:5;200108:4;200114::::0;200075:7:::1;:44::i;209231:184::-:0;209345:14;44280:22;44274:29;44271:146;;;44336:10;44330:4;44323:24;44397:4;44391;44384:18;44271:146;44462:9;44438:22;44431:41;209381:26:::1;209390:6;209398:8;209381;:26::i;:::-;209372:35;;44604:1:::0;44580:22;44573:33;209231:184;;;;:::o;198449:226::-;198591:14;44280:22;44274:29;44271:146;;;44336:10;44330:4;44323:24;44397:4;44391;44384:18;44271:146;44462:9;44438:22;44431:41;198627:40:::1;198637:6;198645:8;198655:5;198662:4;198627:9;:40::i;217753:84::-:0;44280:22;44274:29;44271:146;;;44336:10;44330:4;44323:24;44397:4;44391;44384:18;44271:146;44462:9;44438:22;44431:41;217812:17:::1;:15;:17::i;:::-;44604:1:::0;44580:22;44573:33;217753:84::o;193272:157::-;193359:4;44280:22;44274:29;44271:146;;;44336:10;44330:4;44323:24;44397:4;44391;44384:18;44271:146;44462:9;44438:22;44431:41;193376:23:::1;193396:2;193376:19;:23::i;:::-;-1:-1:-1::0;193417:4:0::1;44604:1:::0;44580:22;44573:33;193272:157;;;:::o;253162:567::-;253243:19;253273:18;253302:24;253337:17;44820:22;44814:29;44811:146;;;44876:10;44870:4;44863:24;44937:4;44931;44924:18;44811:146;-1:-1:-1;;253468:12:0::1;::::0;-1:-1:-1;;;;;253491:33:0;::::1;::::0;253535:52:::1;249292:2;253555:31:::0;;::::1;253535:52:::0;::::1;::::0;-1:-1:-1;249412:3:0::1;253624:32:::0;;::::1;253598:59;::::0;-1:-1:-1;249549:3:0::1;253687:33:::0;;;::::1;::::0;253162:567::o;258790:1359::-;44280:22;44274:29;44271:146;;;44336:10;44330:4;44323:24;44397:4;44391;44384:18;44271:146;44462:9;44438:22;44431:41;258974:43:::1;::::0;-1:-1:-1;;;258974:43:0;;259006:10:::1;258974:43;::::0;::::1;3303:51:1::0;258974:13:0::1;-1:-1:-1::0;;;;;258974:31:0::1;::::0;::::1;::::0;3276:18:1;;258974:43:0::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;258969:108;;259034:31;189409:10;259034:7;:31::i;:::-;259410:17;:15;:17::i;:::-;259574:48;::::0;-1:-1:-1;;;259574:48:0;;259609:4:::1;259574:48;::::0;::::1;23641:51:1::0;-1:-1:-1;;;;;23728:32:1;;;23708:18;;;23701:60;259574:13:0::1;:26;::::0;::::1;::::0;23614:18:1;;259574:48:0::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;259635:34;259643:6;259651:10;259663:5;259635:7;:34::i;:::-;259760:138;::::0;-1:-1:-1;;;259760:138:0;;259777:10:::1;::::0;259760:37:::1;::::0;:138:::1;::::0;259820:4:::1;::::0;259840:6;;259861:5;;259881:6;;259760:138:::1;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1::0;;260109:21:0::1;::::0;260007:134:::1;::::0;-1:-1:-1;;;260007:134:0;;260053:4:::1;260007:134;::::0;::::1;26685:51:1::0;260073:1:0::1;26752:18:1::0;;;26745:34;-1:-1:-1;;;;;26815:32:1;;;26795:18;;;26788:60;-1:-1:-1;;;;;260109:21:0;;::::1;26864:18:1::0;;;26857:60;260007:13:0::1;:23:::0;;::::1;::::0;-1:-1:-1;260007:23:0::1;::::0;-1:-1:-1;26657:19:1;;260007:134:0::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;44604:1:::0;44580:22;44573:33;258790:1359;;;:::o;269775:774::-;269869:12;;269818:14;;269896:18;;;269892:100;;269938:42;;-1:-1:-1;;;269938:42:0;;;;;;;;;;;269892:100;270493:21;;190277:5;;270477:37;;-1:-1:-1;;;;;270493:21:0;270477:13;:37;:::i;:::-;:64;;;;:::i;:::-;270468:73;;269834:715;269775:774;:::o;209834:178::-;209945:14;44280:22;44274:29;44271:146;;;44336:10;44330:4;44323:24;44397:4;44391;44384:18;44271:146;44462:9;44438:22;44431:41;209981:23:::1;209987:6;209995:8;209981:5;:23::i;206946:96::-:0;206994:13;207027:7;207020:14;;;;;:::i;137347:178::-;137469:48;;-1:-1:-1;;;137469:48:0;;-1:-1:-1;;;;;3321:32:1;;;137469:48:0;;;3303:51:1;137436:11:0;;137469:15;:42;;;;;;3276:18:1;;137469:48:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;260952:123::-;44280:22;44274:29;44271:146;;;44336:10;44330:4;44323:24;44397:4;44391;44384:18;44271:146;44462:9;44438:22;44431:41;261034:33:::1;261041:6;261049:10;261061:5;261034:6;:33::i;:::-;;44604:1:::0;44580:22;44573:33;260952:123;;:::o;269355:130::-;269410:11;269440:37;269450:6;249041:1;37742:3;269440:9;:37::i;212540:281::-;212655:4;44280:22;44274:29;44271:146;;;44336:10;44330:4;44323:24;44397:4;44391;44384:18;44271:146;44462:9;44438:22;44431:41;212672:44:::1;212687:6;212695:8;212705:10;212672:14;:44::i;:::-;212759:32;212774:8;212784:6;212759:14;:32::i;:::-;;212809:4;212802:11;;44604:1:::0;44580:22;44573:33;212540:281;;;;:::o;201931:252::-;44280:22;44274:29;44271:146;;;44336:10;44330:4;44323:24;44397:4;44391;44384:18;44271:146;44462:9;44438:22;44431:41;202049:33:::1;202064:5;202071:10;202049:14;:33::i;:::-;202093:37;202116:6;202124:5;202093:22;:37::i;:::-;202143:32;202161:6;202169:5;202143:17;:32::i;264861:237::-:0;264959:14;44280:22;44274:29;44271:146;;;44336:10;44330:4;44323:24;44397:4;44391;44384:18;44271:146;44462:9;44438:22;44431:41;265030:17:::1;:15;:17::i;:::-;-1:-1:-1::0;265069:21:0::1;::::0;-1:-1:-1;;;;;265069:21:0::1;;44580:22:::0;44573:33;264861:237;:::o;197517:468::-;197639:14;44280:22;44274:29;44271:146;;;44336:10;44330:4;44323:24;44397:4;44391;44384:18;44271:146;44462:9;44438:22;44431:41;197666:36:::1;197681:8;197691:10;197666:14;:36::i;216506:157::-:0;216589:7;216616:39;216629:6;216637:17;:15;:17::i;:::-;216616:12;:39::i;210481:224::-;210620:14;44280:22;44274:29;44271:146;;;44336:10;44330:4;44323:24;44397:4;44391;44384:18;44271:146;44462:9;44438:22;44431:41;210656::::1;210666:6;210674:8;210684:5;210691;210656:9;:41::i;211183:227::-:0;211320:14;44280:22;44274:29;44271:146;;;44336:10;44330:4;44323:24;44397:4;44391;44384:18;44271:146;44462:9;44438:22;44431:41;211356:46:::1;211364:6;211372:8;211382:5;211389;211396;211356:7;:46::i;194722:1000::-:0;44280:22;44274:29;44271:146;;;44336:10;44330:4;44323:24;44397:4;44391;44384:18;44271:146;44462:9;44438:22;44431:41;194966:43:::1;::::0;-1:-1:-1;;;194966:43:0;;194998:10:::1;194966:43;::::0;::::1;3303:51:1::0;194966:13:0::1;-1:-1:-1::0;;;;;194966:31:0::1;::::0;::::1;::::0;3276:18:1;;194966:43:0::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;194961:108;;195026:31;189409:10;195026:7;:31::i;:::-;195081:17;:15;:17::i;:::-;195193:10;195206:17;:15;:17::i;:::-;195193:30;;195234:15;195252:35;195269:6;195277:5;195284:2;195252:16;:35::i;:::-;195234:53;;195374:14;195391:28;195408:6;195416:2;195391:16;:28::i;:::-;195374:45;;195432:63;195449:6;195457;195465:10;195477;195489:5;195432:16;:63::i;:::-;195565:149;195613:6;195634;195655:5;195675:7;195697:6;195565:33;:149::i;:::-;194893:829;;;44604:1:::0;44580:22;44573:33;194722:1000;;;:::o;135016:666::-;135116:10;-1:-1:-1;;;;;135104:22:0;;;135100:96;;135150:34;;-1:-1:-1;;;135150:34:0;;;;;;;;;;;135100:96;135314:54;;-1:-1:-1;;;135314:54:0;;135357:10;135314:54;;;3303:51:1;135314:15:0;-1:-1:-1;;;;;135314:42:0;;;;3276:18:1;;135314:54:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;135310:131;;;135392:37;;-1:-1:-1;;;135392:37:0;;;;;;;;;;;135310:131;135476:45;;-1:-1:-1;;;135476:45:0;;135510:10;135476:45;;;3303:51:1;135453:20:0;;135476:15;-1:-1:-1;;;;;135476:33:0;;;;3276:18:1;;135476:45:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;135544:10;135532:11;:23;;;;;;;;;;;:37;;;;;;;;-1:-1:-1;;;;;135532:47:0;;;;;;;;;;;;:60;;-1:-1:-1;;135532:60:0;;;;;;;;;;135610:64;;27096:25:1;;;27137:18;;;27130:50;135532:37:0;;-1:-1:-1;135532:47:0;;135610:64;;27069:18:1;135610:64:0;;;;;;;135089:593;135016:666;;:::o;215078:182::-;215182:7;44820:22;44814:29;44811:146;;;44876:10;44870:4;44863:24;44937:4;44931;44924:18;44811:146;215209:43:::1;215226:6;215234:17;:15;:17::i;:::-;215209:16;:43::i;199117:229::-:0;199257:14;44280:22;44274:29;44271:146;;;44336:10;44330:4;44323:24;44397:4;44391;44384:18;44271:146;44462:9;44438:22;44431:41;199293:45:::1;199301:6;199309:8;199319:5;199326;199333:4;199293:7;:45::i;124557:148::-:0;51841:18;51835:4;51828:32;;;124622:17;51874:19;;;51939:4;51923:21;;;51917:28;124664:33;;215606:182;:::i;205665:188::-;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;205786:17:0;:15;:17::i;:::-;205825:20;205837:7;205825:11;:20::i;254120:497::-;44280:22;44274:29;44271:146;;;44336:10;44330:4;44323:24;44397:4;44391;44384:18;44271:146;44462:9;44438:22;44431:41;254185:27:::1;:25;:27::i;:::-;254264:17;:15;:17::i;:::-;254477:13;;254448:6;-1:-1:-1::0;;;;;254436:35:0::1;;:37;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:54;254432:137;;254514:43;;-1:-1:-1::0;;;254514:43:0::1;;;;;;;;;;;254432:137;254581:28;254601:6;254581:7;:28::i;58605:3284::-:0;58813:16;59012:6;:4;:6::i;:::-;58996:24;;;;;;58985:35;;59192:8;59179:11;59176:25;59173:145;;;59234:10;59228:4;59221:24;59298:4;59292;59285:18;59173:145;59347:4;59341:11;59465:5;59461:2;59457:14;59453:2;59449:23;59440:32;;59513:7;59509:2;59505:16;59501:2;59497:25;59486:36;;59608:39;59602:4;59595:53;59675:5;59669:4;59662:19;59728:4;59722;59712:21;59771:9;59765:16;59851;59848:1;59841:27;59903:8;59896:4;59893:1;59889:12;59882:30;59947:13;59940:4;59937:1;59933:12;59926:35;59996:9;59989:4;59986:1;59982:12;59975:31;60041:9;60034:4;60031:1;60027:12;60020:31;60091:4;60088:1;60078:18;60072:4;60065:32;60162:16;60159:1;60152:27;60214:5;60207:4;60204:1;60200:12;60193:27;60255:7;60248:4;60245:1;60241:12;60234:29;60298:5;60291:4;60288:1;60284:12;60277:27;60339:10;60332:4;60329:1;60325:12;60318:32;60385:8;60378:4;60375:1;60371:12;60364:30;60434:4;60431:1;60421:18;60415:4;60408:32;60531:4;60525;60515:21;60509:4;60502:35;60574:1;60568:4;60564:12;60558:4;60551:26;60604:1;60598:4;60591:15;60633:1;60627:4;60620:15;60694:4;60688;60682;60679:1;60676;60669:5;60658:41;61121:5;61102:16;61096:23;61093:34;61083:162;;61161:10;61155:4;61148:24;61225:4;61219;61212:18;61083:162;61332:18;61314:37;;-1:-1:-1;;;61530:43:0;;61524:4;61517:57;61611:4;61605;61595:21;61588:36;;;61565:7;61733:5;61706:25;-1:-1:-1;61693:4:0;61686:12;;61681:67;61769:4;61762:15;-1:-1:-1;;61840:1:0;61834:4;61827:15;-1:-1:-1;;;;;;58605:3284:0:o;125049:129::-;51841:18;51835:4;51828:32;;;125112:17;51874:19;;;51939:4;51923:21;;;51917:28;125154:16;51670:293;136064:163;136180:39;;-1:-1:-1;;;136180:39:0;;-1:-1:-1;;;;;3321:32:1;;;136180:39:0;;;3303:51:1;136144:14:0;;136180:15;:33;;;;;;3276:18:1;;136180:39:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;105161:1590::-;105248:22;238941:15;105356:5;;-1:-1:-1;;;;;105389:21:0;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;105379:31:0;;-1:-1:-1;105467:1277:0;105487:8;105483:1;:12;105467:1277;;;105530:5;;105536:1;105530:8;;;;;;;:::i;:::-;;;;;;;;;;;;:::i;:::-;105517:21;;;:::i;:::-;;;105571:10;:24;;;105567:810;;;105799:17;;105779:38;;-1:-1:-1;;;105779:38:0;;-1:-1:-1;;;;;3321:32:1;;;105779:38:0;;;3303:51:1;105761:15:0;;105779:19;;;;;3276:18:1;;105779:38:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;105761:56;-1:-1:-1;;;;;;105908:21:0;;105904:105;;105961:28;;-1:-1:-1;;;105961:28:0;;;;;;;;;;;105904:105;106125:17;;106165:15;;;;;106029:170;;-1:-1:-1;;;106029:170:0;;-1:-1:-1;;;;;106029:40:0;;;;;:170;;106092:10;;106125:17;106165:15;106029:170;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;106233:83;106281:10;:17;;;106300:10;:15;;;106233:47;:83::i;:::-;106220:7;106228:1;106220:10;;;;;;;;:::i;:::-;;;;;;:96;;;;106353:8;;;105567:810;106533:17;;-1:-1:-1;;;;;106516:34:0;106524:4;106516:34;106512:108;;106578:26;;-1:-1:-1;;;106578:26:0;;;;;;;;;;;106512:108;106649:83;106709:4;106716:10;:15;;;106649:51;:83::i;:::-;106636:7;106644:1;106636:10;;;;;;;;:::i;:::-;;;;;;:96;;;;105467:1277;105497:3;;105467:1277;;;;105272:1479;;;105161:1590;;;;:::o;216039:164::-;216125:7;216152:43;216169:6;216177:17;:15;:17::i;266866:387::-;266962:12;;;267048:39;;-1:-1:-1;;;267048:39:0;;267081:4;267048:39;;;3303:51:1;;;;266912:14:0;;;;267055:6;-1:-1:-1;;;;;267048:24:0;;;;3276:18:1;;267048:39:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;267024:21;;:63;;;-1:-1:-1;;;;;267024:21:0;:63;:::i;:::-;266985:102;;267121:12;267102:15;:31;267098:95;;267157:24;;-1:-1:-1;;;267157:24:0;;;;;;;;;;;267098:95;267214:30;267232:12;267214:15;:30;:::i;:::-;267205:39;;266928:325;;266866:387;:::o;204828:171::-;204877:14;204904:17;:15;:17::i;:::-;204951:40;37633:4;204973:17;248101:123;248160:9;248201:15;:13;:15::i;:::-;248186:12;;:30;;;;:::i;236477:301::-;236579:14;236606:19;236628:13;51564:18;51558:25;;51401:200;236628:13;236606:35;-1:-1:-1;236663:16:0;;:107;;236717:53;236746:6;236754:2;236758:11;236717:28;:53::i;:::-;236663:107;;;-1:-1:-1;236695:6:0;;236654:116;-1:-1:-1;;236477:301:0:o;237781:303::-;237883:14;237910:19;237932:13;51564:18;51558:25;;51401:200;237932:13;237910:35;-1:-1:-1;237967:16:0;;:109;;238021:55;238052:6;238060:11;238073:2;238021:30;:55::i;275415:3823::-;275809:4;-1:-1:-1;;;;;275782:32:0;;;275778:101;;275831:36;249696:10;275831:7;:36::i;:::-;275930:17;:15;:17::i;:::-;275960:38;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;275960:38:0;276136:13;-1:-1:-1;;;;;276136:26:0;;276177:11;276203:10;276228:8;;276251:323;;;;;;;;276312:15;-1:-1:-1;;;;;276251:323:0;;;;;276365:4;-1:-1:-1;;;;;276251:323:0;;;;;276402:11;276251:323;;;;276448:11;276251:323;;;;;;276496:1;276251:323;;;;276528:1;276251:323;;;;276557:1;276251:323;;;276136:449;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;276136:449:0;;;;;;;;;;;;:::i;:::-;276112:473;-1:-1:-1;276112:473:0;-1:-1:-1;276598:150:0;207264:6;276667:10;276700:4;276720:6;:17;;;276598:32;:150::i;:::-;276793:12;;249549:3;276793:34;276761:22;;;;276921:827;276941:11;276937:1;:15;276921:827;;;277043:11;277055:1;277043:14;;;;;;;;:::i;:::-;;;;;;;277030:27;;277164:10;277178:1;277164:15;277160:64;277200:8;277160:64;277250:8;;277259:1;277250:11;;;;;;;:::i;:::-;;;;;;;;;;;;;;:::i;:::-;277240:21;;277526:10;277503:20;277515:7;277503:11;:20::i;:::-;:33;;;;:::i;:::-;-1:-1:-1;;;;;288226:16:0;;287821:17;288226:16;;;:7;:16;;;;;288152:18;288148:40;;;288099:104;;288226:28;;277494:42;-1:-1:-1;277690:46:0;;;32811:25:1;;;32867:2;32852:18;;32845:34;;;-1:-1:-1;;;;;32915:32:1;;;32895:18;;;32888:60;;;;32984:32;;;32979:2;32964:18;;32957:60;277690:46:0;;32798:3:1;32783:19;277690:46:0;;;;;;;276921:827;276954:3;;276921:827;;;;278047:6;:22;;;278026:6;:17;;:43;;;;;;;:::i;:::-;;;-1:-1:-1;278108:17:0;;;;278084:21;;-1:-1:-1;;;;;278084:21:0;:41;278080:425;;;278344:21;:25;;-1:-1:-1;;;;;;278344:25:0;;;278080:425;;;278475:17;;;;278451:21;;:41;;278475:17;-1:-1:-1;;;;;278451:21:0;:41;:::i;:::-;278402:21;:91;;-1:-1:-1;;;;;;278402:91:0;-1:-1:-1;;;;;278402:91:0;;;;;;;;;;278080:425;278722:22;;;;:26;278718:372;;278778:12;;278814:22;;;;:49;;190277:5;;278814:49;:::i;:::-;278809:2;:54;278805:144;;;278891:42;;-1:-1:-1;;;278891:42:0;;;;;;;;;;;278805:144;278983:22;;;;278978:27;;:2;:27;:::i;:::-;278963:12;:42;279043:22;;;;;279025:53;;20431:25:1;;;-1:-1:-1;;;;;20492:32:1;;20487:2;20472:18;;20465:60;279025:53:0;;20404:18:1;279025:53:0;;;;;;;278750:340;278718:372;279147:23;;279102:128;;-1:-1:-1;;;279102:128:0;;-1:-1:-1;;;;;279102:30:0;;;;;:128;;279147:23;279185:10;;279210:8;;;;279102:128;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;275648:3590;;;;;275415:3823;;;;;;;:::o;243762:178::-;243871:9;243897:35;243924:1;243927;243930;243897:26;:35::i;243222:174::-;243284:45;;-1:-1:-1;;;243284:45:0;;243318:10;243284:45;;;3303:51:1;243284:15:0;-1:-1:-1;;;;;243284:33:0;;;;3276:18:1;;243284:45:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;243279:110;;243346:31;189409:10;243346:7;:31::i;:::-;243222:174::o;92395:957::-;92561:2;92555:4;92548:16;92619:6;92613:4;92606:20;-1:-1:-1;;;92679:4:0;92672:48;93079:4;93073;93067;93061;93058:1;93051:5;93044;93039:45;92972:16;92965:24;92961:1;92954:4;92948:11;92945:18;92942:48;92856:247;92828:408;;93151:10;93145:4;93138:24;93216:4;93210;93203:18;92828:408;93263:1;93257:4;93250:15;92395:957;;;:::o;240779:830::-;240906:17;:15;:17::i;:::-;240936:24;240953:6;240936:16;:24::i;:::-;240984:8;-1:-1:-1;;;;;240975:17:0;:5;-1:-1:-1;;;;;240975:17:0;;240971:84;;241016:27;;-1:-1:-1;;;241016:27:0;;;;;;;;;;;240971:84;-1:-1:-1;;;;;241098:23:0;;;241075:20;241098:23;;;:16;:23;;;;;;;241214:13;:25;;241262:4;241282:6;241115:5;241323:16;241115:5;51841:18;51835:4;51828:32;;;51733:14;51874:19;;;;51939:4;51923:21;;51917:28;;51670:293;241323:16;241354:12;241396:1;241381:12;:16;:31;;241407:5;241381:31;;;241400:4;241381:31;241214:209;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;241185:238;-1:-1:-1;241440:22:0;;241436:99;;241479:44;241497:18;241517:5;241479:17;:44::i;:::-;240895:714;;240779:830;;;:::o;55180:2235::-;55268:4;55423;55419:2;55415:13;55518:8;55512:4;55505:22;55564:20;55557:5;55554:31;55548:4;55541:45;55637:4;55631;55621:21;55680:13;55674:20;55794:1;55782:10;55778:18;55775:426;;;55912:10;55904:6;55901:22;55898:162;;;55960:10;55954:4;55947:24;56036:4;56030;56023:18;55898:162;56178:6;56166:10;56162:23;56147:13;56140:46;55775:426;;;56299:18;56292:5;56289:29;56283:4;56276:43;56372:4;56366;56356:21;56416:15;56410:22;56508:11;56500:6;56497:23;56494:149;;;56553:10;56547:4;56540:24;56623:4;56617;56610:18;56494:149;56754:6;56741:11;56737:24;56720:15;56713:49;;;56839:2;56833:4;56826:16;56893:4;56887;56877:21;57147:6;57131:13;57125:20;57121:33;57106:13;57099:56;;57225:6;57219:4;57212:20;57320:4;57314:11;57310:2;57306:20;57298:5;57294:2;57290:14;-1:-1:-1;;;;;;;;;;;57257:4:0;57251;57246:81;;-1:-1:-1;57403:4:0;55180:2235;;;;;:::o;129307:186::-;129441:1;129435:4;129428:15;129470:4;129464;129457:18;218167:634;218270:14;218297:17;:15;:17::i;:::-;218447:70;218473:43;218490:6;218498:17;:15;:17::i;218473:43::-;218464:52;;;218447:16;:70::i;:::-;218662:36;;-1:-1:-1;;;218662:36:0;;218692:4;218662:36;;;3303:51:1;218662:13:0;-1:-1:-1;;;;;218662:21:0;;;;3276:18:1;;218662:36:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;218740:53;218756:6;218764;218772:10;218784:8;218740:15;:53::i;279711:348::-;-1:-1:-1;;;;;279910:14:0;;279928:1;279910:14;;;:7;:14;;;;;;-1:-1:-1;;;;;279902:27:0;;279898:105;;279953:38;;-1:-1:-1;;;279953:38:0;;;;;;;;;;;279898:105;280015:36;280037:6;280045:5;280015:21;:36::i;:::-;279711:348;;:::o;239862:518::-;239970:24;239987:6;239970:16;:24::i;:::-;-1:-1:-1;;;;;240030:23:0;;240007:20;240030:23;;;:16;:23;;;;;;240068:21;;;240064:95;;;240106:41;189567:10;240106:7;:41::i;:::-;240171:13;-1:-1:-1;;;;;240171:44:0;;240238:4;240258:6;240279:5;240299:16;240309:5;51841:18;51835:4;51828:32;;;51733:14;51874:19;;;;51939:4;51923:21;;51917:28;;51670:293;240299:16;240330:12;240357:4;240171:201;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;239959:421;239862:518;;:::o;225439:331::-;-1:-1:-1;;;;;225608:23:0;;;;;;:16;:23;;;;;;:32;;225634:6;;225608:32;:::i;:::-;-1:-1:-1;;;;;225582:23:0;;;;;;:16;:23;;;;;:58;225676:22;;:31;;225701:6;;225676:31;:::i;:::-;225651:22;:56;225723:39;;;24233:25:1;;;225749:5:0;24289:2:1;24274:18;;24267:50;-1:-1:-1;;;;;24353:32:1;;24333:18;;;24326:60;;;;225723:39:0;;24221:2:1;24206:18;225723:39:0;;;;;;;;225439:331;;:::o;272677:1576::-;272791:7;272850:17;:15;:17::i;:::-;272936:14;272953:18;272965:5;272953:11;:18::i;:::-;272936:35;-1:-1:-1;273049:11:0;;:29;;273072:6;273049:29;;;273063:6;273049:29;273040:38;;273089:24;273106:6;273089:16;:24::i;:::-;273195:6;273186;:15;273182:84;;;273218:36;249696:10;273218:7;:36::i;:::-;273278:71;207264:6;273320:5;273335:4;273342:6;273278:32;:71::i;:::-;-1:-1:-1;;;;;273466:13:0;:32;;273521:4;273550:15;273559:6;273550;:15;:::i;:::-;273541:24;-1:-1:-1;273541:24:0;207264:6;234707:9;273466:177;;-1:-1:-1;;;;;;273466:177:0;;;;;;;-1:-1:-1;;;;;34499:32:1;;;273466:177:0;;;34481:51:1;34548:18;;;34541:34;;;;34611:32;;;34591:18;;;34584:60;34692:4;34680:17;34660:18;;;34653:45;34735:32;;;34714:19;;;34707:61;34453:19;;273466:177:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;273736:12:0;;-1:-1:-1;;;;;288226:16:0;;287821:17;288226:16;;;:7;:16;;;;;-1:-1:-1;;;;;;288148:40:0;;;288099:104;;288226:28;;-1:-1:-1;273654:128:0;;-1:-1:-1;287678:584:0;273654:128;273989:21;;-1:-1:-1;;;;;273989:21:0;:30;-1:-1:-1;273985:184:0;;;274036:21;:25;;-1:-1:-1;;;;;;274036:25:0;;;273985:184;;;274126:21;;:30;;274150:6;;-1:-1:-1;;;;;274126:21:0;:30;:::i;:::-;274094:21;:63;;-1:-1:-1;;;;;;274094:63:0;-1:-1:-1;;;;;274094:63:0;;;;;;;;;;273985:184;274186:35;;;32811:25:1;;;32867:2;32852:18;;32845:34;;;-1:-1:-1;;;;;32915:32:1;;;32895:18;;;32888:60;32984:32;;32979:2;32964:18;;32957:60;274186:35:0;;;;;;;32798:3:1;274186:35:0;;;-1:-1:-1;274239:6:0;;272677:1576;-1:-1:-1;;;272677:1576:0:o;137889:270::-;-1:-1:-1;;;;;137989:17:0;;;:11;:17;;;;;;;;;;;138007:57;;-1:-1:-1;;;138007:57:0;;;;;3303:51:1;;;;137989:17:0;:11;;138007:15;:51;;;;;;3276:18:1;;138007:57:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;137989:76;;;;;;;;;;;;;;-1:-1:-1;137989:76:0;;;-1:-1:-1;;;;;137989:86:0;;;;;;;;;;;;137970:182;;138109:31;;-1:-1:-1;;;138109:31:0;;;;;;;;;;;239260:280;239371:24;239388:6;239371:16;:24::i;:::-;51841:18;51835:4;51828:32;;;51733:14;51874:19;;;51939:4;51923:21;;51917:28;-1:-1:-1;;;;;239412:23:0;;;;;;:16;:23;;;;;;:32;;239438:6;;239412:32;:::i;:::-;:51;239408:125;;;239480:41;189567:10;239480:7;:41::i;280253:5263::-;280404:12;;280427:67;249412:3;280461:32;;;280427:67;280592:15;:35;;;280588:74;;280644:7;;280253:5263::o;280588:74::-;280894:21;;280945:12;;-1:-1:-1;;;;;280674:34:0;;;280719:60;249292:2;280747:31;;;280719:60;;249549:3;280823:33;;;;-1:-1:-1;;;;;280894:21:0;;280674:12;280991:129;280674:34;280894:21;280719:60;281093:16;280991:13;:129::i;:::-;280968:152;;281219:10;281200:15;:29;281196:1434;;281579:3;;281403:10;;-1:-1:-1;281403:10:0;;281428:22;;-1:-1:-1;;;;;281579:3:0;:22;281620:12;:10;:12::i;:::-;281651:30;281669:12;281651:15;:30;:::i;:::-;281579:117;;-1:-1:-1;;;;;;281579:117:0;;;;;;;;;;34953:25:1;;;;34994:18;;;34987:34;34926:18;;281579:117:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;281554:142;;-1:-1:-1;281554:142:0;-1:-1:-1;281554:142:0;;;281985:28;282003:10;281985:15;:28;:::i;:::-;281984:64;;;;:::i;:::-;281983:83;;;;:::i;:::-;281982:102;;;;:::i;:::-;281965:119;-1:-1:-1;282112:27:0;281965:119;282112:10;:27;:::i;:::-;282161:31;;;34953:25:1;;;35009:2;34994:18;;34987:34;;;282099:40:0;;-1:-1:-1;282161:31:0;;34926:18:1;282161:31:0;;;;;;;282454:164;282486:4;282509:30;282527:12;282509:15;:30;:::i;:::-;282558:10;282587:16;282454:13;:164::i;:::-;282438:180;;;;:::i;:::-;;;281231:1399;281196:1434;282829:11;;282783:19;;282805:41;;282815:12;;-1:-1:-1;;;282829:11:0;;;;37742:3;282805:9;:41::i;:::-;282783:63;-1:-1:-1;282861:15:0;;282857:895;;283292:25;283320:163;283369:11;283399:13;51564:18;51558:25;;51401:200;283399:13;283457:11;283431:23;283442:12;283431:8;:23;:::i;:::-;:37;;;;:::i;:::-;283320:30;:163::i;:::-;283292:191;;283575:18;283596:15;-1:-1:-1;;;;;283596:26:0;;:28;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;283575:49;;283639:36;283645:10;283657:17;283639:5;:36::i;:::-;282878:874;;282857:895;283818:16;;283814:879;;284320:15;284239:57;284249:12;284263:15;284280;284239:9;:57::i;:::-;:96;;;;:::i;:::-;284204:131;-1:-1:-1;284457:30:0;284475:12;284457:15;:30;:::i;:::-;284425:21;:63;;-1:-1:-1;;;;;;284425:63:0;-1:-1:-1;;;;;284425:63:0;;;;;;;;;;284598:23;284609:12;284598:8;:23;:::i;:::-;284583:12;:38;284643;;;34953:25:1;;;35009:2;34994:18;;34987:34;;;284643:38:0;;34926:18:1;284643:38:0;;;;;;;283814:879;-1:-1:-1;;;;285159:16:0;285155:33;;;;285238:11;285219:17;285215:35;285126:147;285300:18;285296:40;;;;285101:254;-1:-1:-1;;;;;284849:32:0;;;;285057:315;285467:17;285460:38;-1:-1:-1;;280253:5263:0:o;271192:983::-;271312:24;271329:6;271312:16;:24::i;:::-;271347;271364:6;271347:16;:24::i;:::-;-1:-1:-1;;;;;271493:23:0;;271519:1;271493:23;;;:16;:23;;;;;;:27;271489:111;;271544:44;;-1:-1:-1;;;271544:44:0;;;;;;;;;;;271489:111;271748:14;271786:6;271765:18;271777:5;271765:11;:18::i;:::-;:27;;;;:::i;:::-;271885:12;;-1:-1:-1;;;;;288226:16:0;;287821:17;288226:16;;;:7;:16;;;;;-1:-1:-1;;;;;;288148:40:0;;;288099:104;;288226:28;;271748:44;-1:-1:-1;271974:21:0;;:30;;271998:6;;-1:-1:-1;;;;;271974:21:0;:30;:::i;:::-;271942:21;:63;;-1:-1:-1;;;;;;271942:63:0;-1:-1:-1;;;;;271942:63:0;;;;;;;;;;272065:55;207264:6;272103:8;272113:6;272065:28;:55::i;:::-;272138:29;;;23319:25:1;;;23375:2;23360:18;;23353:34;;;-1:-1:-1;;;;;23423:32:1;;23403:18;;;23396:60;272138:29:0;;;;;;;23307:2:1;272138:29:0;;;271301:874;271192:983;;;:::o;242589:358::-;242734:6;242724:205;;242774:10;242768:4;242761:24;242909:4;242903;242896:18;242724:205;242589:358;:::o;89134:1160::-;89320:4;89314:11;89386:6;89380:4;89373:20;89452:2;89446:4;89439:16;89518:4;89514:2;89510:13;89504:4;89497:27;-1:-1:-1;;;89575:4:0;89568:48;89987:4;89981;89975;89969;89966:1;89959:5;89952;89947:45;89880:16;89873:24;89869:1;89862:4;89856:11;89853:18;89850:48;89764:247;89736:412;;90059:10;90053:4;90046:24;90128:4;90122;90115:18;89736:412;90175:1;90169:4;90162:15;90232:4;90225:15;-1:-1:-1;;;;89134:1160:0:o;231637:1473::-;231861:4;231857:2;231853:13;231964:18;231957:5;231954:29;231948:4;231941:43;232037:4;232031;232021:21;232081:15;232075:22;232173:11;232165:6;232162:23;232159:149;;;232218:10;232212:4;232205:24;232288:4;232282;232275:18;232159:149;232419:6;232406:11;232402:24;232385:15;232378:49;;;232504:2;232498:4;232491:16;232558:4;232552;232542:21;232812:6;232796:13;232790:20;232786:33;232771:13;232764:56;;232890:6;232884:4;232877:20;233071:4;233065:11;233061:2;233057:20;233032:5;233028:2;233024:14;-1:-1:-1;;;;;;;;;;;232957:4:0;232934;232911:181;;231637:1473;;;:::o;243474:184::-;243541:50;;-1:-1:-1;;;243541:50:0;;243580:10;243541:50;;;3303:51:1;243541:15:0;-1:-1:-1;;;;;243541:38:0;;;;3276:18:1;;243541:50:0;3138:222:1;286817:508:0;248879:4;286994:14;:41;286990:110;;;287052:36;249696:10;287052:7;:36::i;:::-;287196:11;;;;287220:36;;;-1:-1:-1;;;287220:36:0;;;-1:-1:-1;;;;;287220:36:0;;;;;;;287274:43;;;287196:11;;;;;;35948:25:1;;;287305:11:0;;;;;;;36004:2:1;35989:18;;35982:47;287196:11:0;287274:43;;35921:18:1;287274:43:0;35775:260:1;222709:1392:0;222903:14;222930:17;:15;:17::i;:::-;223042:10;223055:17;:15;:17::i;:::-;223042:30;;223083:15;223101:116;223141:28;223158:6;223166:2;223141:16;:28::i;:::-;223132:37;;;223184:5;223204:2;223101:16;:116::i;:::-;223083:134;;223419:15;223415:145;;;223451:33;223466:5;223473:10;223451:14;:33::i;:::-;223415:145;;;223517:31;223534:5;223541:6;223517:16;:31::i;:::-;-1:-1:-1;;;;;223806:23:0;;;223627:26;223806:23;;;:16;:23;;;;;;;223656:220;;-1:-1:-1;;;223656:220:0;;223627:26;;223656:13;:44;;;;:220;;223723:4;;223743:6;;223764:5;;223784:7;;223844:21;;223656:220;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;223627:249;-1:-1:-1;223893:22:0;;223889:99;;223932:44;223950:18;223970:5;223932:17;:44::i;:::-;224032:61;224049:6;224057;224065:10;224077:8;224087:5;224032:16;:61::i;:::-;222919:1182;;;222709:1392;;;;;;;:::o;220570:1185::-;220735:14;220762:17;:15;:17::i;:::-;220874:10;220887:17;:15;:17::i;:::-;220874:30;;220915:15;220933:35;220950:6;220958:5;220965:2;220933:16;:35::i;:::-;220915:53;;221075:62;221092:5;221108:28;221125:6;221133:2;221108:16;:28::i;:::-;221099:37;;;221075:16;:62::i;:::-;-1:-1:-1;;;;;221384:23:0;;;221205:26;221384:23;;;:16;:23;;;;;;;221234:220;;-1:-1:-1;;;221234:220:0;;221205:26;;221234:13;:44;;;;:220;;221301:4;;221321:6;;221342:5;;221362:7;;221422:21;;221234:220;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;221205:249;-1:-1:-1;221471:22:0;;221467:99;;221510:44;221528:18;221548:5;221510:17;:44::i;:::-;221610:137;221641:6;221662;221683:10;221708:8;221731:5;221610:16;:137::i;:::-;220751:1004;;;220570:1185;;;;;;:::o;288605:581::-;288754:3;;:17;;;-1:-1:-1;;;288754:17:0;;;;288783:4;;-1:-1:-1;;;;;288754:3:0;;:15;;:17;;;;;;;;;;;;;;:3;:17;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;288754:34:0;;288750:98;;288805:31;189409:10;288805:7;:31::i;:::-;288860:29;288886:2;288860:25;:29::i;:::-;249549:3;37633:4;289152:25;;249412:3;289098:15;:36;;249292:2;289045:15;:35;;-1:-1:-1;;;;;288991:12:0;;:36;288990:91;:145;:188;288975:12;:203;;;;288605:581;:::o;219179:635::-;219279:14;219306:17;:15;:17::i;:::-;219336:24;219353:6;219336:16;:24::i;:::-;219498:36;;-1:-1:-1;;;219498:36:0;;219528:4;219498:36;;;3303:51:1;219498:13:0;-1:-1:-1;;;;;219498:21:0;;;;3276:18:1;;219498:36:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;219648:158;219687:39;219700:6;219708:17;:15;:17::i;219687:39::-;219678:48;;;219741:6;219762:10;219787:8;219648:15;:158::i;53366:1435::-;53436:4;53650:18;53644:4;53637:32;53696:8;53690:4;53683:22;53758:4;53752;53742:21;53802:15;53796:22;53894:11;53886:6;53883:23;53880:149;;;53939:10;53933:4;53926:24;54009:4;54003;53996:18;53880:149;54140:6;54127:11;54123:24;54106:15;54099:49;;;54225:2;54219:4;54212:16;54279:4;54273;54263:21;54533:6;54517:13;54511:20;54507:33;54492:13;54485:56;;54611:6;54605:4;54598:20;54700:4;54694:11;54690:2;54686:20;54676:8;-1:-1:-1;;;;;;;;;;;54643:4:0;54637;54632:75;-1:-1:-1;54789:4:0;53366:1435;;;;:::o;237119:299::-;237217:14;237244:19;237266:13;51564:18;51558:25;;51401:200;237266:13;237244:35;-1:-1:-1;237301:16:0;;:109;;237355:55;237386:6;237394:2;237398:11;237355:30;:55::i;242068:442::-;242194:15;242222:24;242239:6;242222:16;:24::i;:::-;-1:-1:-1;51841:18:0;51835:4;51828:32;;;51733:14;51874:19;;;51939:4;51923:21;;51917:28;242348:48;51917:28;242393:2;242348:16;:48::i;:::-;242339:6;:57;242335:131;;;242413:41;189567:10;242413:7;:41::i;:::-;242478:24;242495:6;242478:16;:24::i;227883:665::-;228150:20;228156:5;228163:6;228150:5;:20::i;:::-;228317:34;228344:6;228317:26;:34::i;:::-;228422:55;207264:6;228460:8;228470:6;228422:28;:55::i;:::-;228518:5;-1:-1:-1;;;;;228495:45:0;228508:8;-1:-1:-1;;;;;228495:45:0;228504:2;-1:-1:-1;;;;;228495:45:0;;228525:6;228533;228495:45;;;;;;34953:25:1;;;35009:2;34994:18;;34987:34;34941:2;34926:18;;34779:248;228495:45:0;;;;;;;;227883:665;;;;;:::o;230016:995::-;230337:138;;-1:-1:-1;;;230337:138:0;;230354:10;;230337:37;;:138;;230397:4;;230417:6;;230438:5;;230458:6;;230337:138;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;51841:18:0;51835:4;51828:32;;;51733:14;51874:19;;;51939:4;51923:21;;51917:28;230508:25;;-1:-1:-1;230527:6:0;;-1:-1:-1;230508:25:0;:::i;:::-;230492:12;:41;230488:109;;230557:28;;-1:-1:-1;;;230557:28:0;;;;;;;;;;;230488:109;-1:-1:-1;;;;;230838:23:0;;;230654:26;230838:23;;;:16;:23;;;;;;;230683:209;;-1:-1:-1;;;230683:209:0;;230654:26;;230683:13;:44;;;;:209;;230750:4;;230770:6;;230791:5;;230811:12;;230654:26;;230683:209;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;230654:238;-1:-1:-1;230909:22:0;;230905:99;;230948:44;230966:18;230986:5;230948:17;:44::i;:::-;230246:765;230016:995;;;;;:::o;235704:301::-;235806:14;235833:19;235855:13;51564:18;51558:25;;51401:200;235855:13;235833:35;-1:-1:-1;235890:16:0;;:107;;235944:53;235973:6;235981:11;235994:2;235944:28;:53::i;285814:703::-;285960:128;286018:6;-1:-1:-1;;;285960:31:0;:128::i;:::-;285941:222;;286115:36;249696:10;286115:7;:36::i;:::-;286270:3;;;-1:-1:-1;;;;;;286346:12:0;;-1:-1:-1;;;;;286346:12:0;;;;;;;;;286389:24;;;-1:-1:-1;;;286389:24:0;;;;286270:3;;;;;-1:-1:-1;;286389:22:0;;:24;;;;;;;;;;;;;;286346:12;286389:24;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;286424:13;:25;;;286467:42;;;-1:-1:-1;;;;;37874:32:1;;;37856:51;;37943:32;;37938:2;37923:18;;37916:60;37992:18;;;37985:34;;;286369:44:0;;-1:-1:-1;286467:42:0;;37844:2:1;37829:18;286467:42:0;;;;;;;;285860:657;;285814:703;:::o;39111:265::-;39204:12;39230;39244:23;39271:6;-1:-1:-1;;;;;39271:11:0;39290:1;39293:4;39271:27;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;39229:69;;;;39326:42;39340:6;39348:7;39357:10;39326:13;:42::i;:::-;39319:49;39111:265;-1:-1:-1;;;;;39111:265:0:o;40991:263::-;41092:12;41118;41132:23;41159:6;-1:-1:-1;;;;;41159:19:0;41179:4;41159:25;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;289429:423;289608:12;;289703:21;;289486:14;;289608:12;289641:203;;-1:-1:-1;;;;;289641:203:0;;;-1:-1:-1;;;;;289703:21:0;289641:203;249292:2;289746:31;;;289641:203;;;249412:3;289800:32;;;289641:203;:13;:203::i;72005:3640::-;72628:9;;;-1:-1:-1;;72635:1:0;72632;72714:20;72844:14;;;72832:27;;72824:36;;;72948:285;;72995:1;72985:156;;73038:10;73032:4;73025:24;73113:4;73107;73100:18;72985:156;-1:-1:-1;73173:14:0;;;73209:5;;72948:285;73357:2;73354:1;73351:9;73341:152;;73398:10;73392:4;73385:24;73469:4;73463;73456:18;73341:152;73756:1;73753;73750;73743:15;73907:1;73903:9;;;73896:17;;74000:9;;;;;75341:13;;;75333:22;;;75365:9;;;;75361:17;;;75380:1;75357:25;75329:54;75418:14;;75414:22;75296:167;74381:1;74388;74384:9;;74377:17;;74667:11;;;74660:19;;74651:29;74741:11;;;74734:19;;74725:29;74816:11;;;74809:19;;74800:29;74891:11;;;74884:19;;74875:29;74966:11;;;74959:19;;74950:29;75553:11;;;75546:19;;;75537:29;75050:539;72005:3640;;;;;:::o;75933:474::-;76011:14;76047:19;76058:1;76061;76064;76047:10;:19::i;:::-;76038:28;;76161:1;76158;76155;76148:15;76145:244;;;76205:1;76193:14;;76225:149;;76279:10;76273:4;76266:24;76350:4;76344;76337:18;77092:518;77166:9;77393:1;77389;77385:6;77381:14;77378:1;77375:21;77372:1;77368:29;77361:37;77358:1;77354:45;77344:172;;77433:10;77427:4;77420:24;77496:4;77490;77483:18;77344:172;-1:-1:-1;77578:9:0;;77553:17;;;77546:25;77539:33;77574:17;;;77535:57;;77092:518::o;226447:754::-;226657:68;207264:6;226699:2;226711:4;226718:6;226657:32;:68::i;:::-;226870:31;226894:6;226870:23;:31::i;:::-;227067:23;227073:8;227083:6;227067:5;:23::i;:::-;227120:8;-1:-1:-1;;;;;227108:37:0;227116:2;-1:-1:-1;;;;;227108:37:0;;227130:6;227138;227108:37;;;;;;34953:25:1;;;35009:2;34994:18;;34987:34;34941:2;34926:18;;34779:248;227108:37:0;;;;;;;;227156;279711:348;224466:496;224575:24;224627:6;224602:22;;:31;;;;:::i;:::-;224644:70;;-1:-1:-1;;;224644:70:0;;224683:4;224644:70;;;37856:51:1;-1:-1:-1;;;;;37943:32:1;;;37923:18;;;37916:60;37992:18;;;37985:34;;;224575:58:0;;-1:-1:-1;224644:13:0;:30;;;;;;37829:18:1;;224644:70:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;;;;224816:23:0;;;;;;:16;:23;;;;;;:32;;-1:-1:-1;224842:6:0;;224816:32;:::i;:::-;-1:-1:-1;;;;;224790:23:0;;;;;;:16;:23;;;;;;;;;:58;;;;224859:22;:41;;;224916:38;;24233:25:1;;;24274:18;;;24267:50;24333:18;;24326:60;224916:38:0;;24221:2:1;24206:18;224916:38:0;24037:355:1;290095:1050:0;290276:14;290381:1;290367:11;:15;:48;;;;;290405:10;290386:16;:29;290367:48;290363:775;;;290858:268;290902:10;290884:15;:28;:171;;291025:29;291038:16;291025:10;:29;:::i;:::-;291010:45;;:11;:45;:::i;:::-;290884:171;;;290951:34;290969:16;290951:15;:34;:::i;:::-;290936:50;;:11;:50;:::i;:::-;291074:15;37633:4;290858:7;:268::i;63093:1196::-;63318:18;63312:25;63398:6;63379:17;63375:30;63497:17;63479:16;63476:39;63473:165;;;63548:10;63542:4;63535:24;63618:4;63612;63605:18;63473:165;63727:16;63707:18;63700:44;;;63832:18;63826:4;63819:32;63878:2;63872:4;63865:16;63932:4;63926;63916:21;64050:6;64034:13;64028:20;64024:33;64009:13;64002:56;;64128:6;64122:4;64115:20;64210:4;64204:11;64200:2;64196:20;64193:1;-1:-1:-1;;;;;;;;;;;64160:4:0;64154;64149:68;279711:348;;:::o;291471:186::-;291566:6;291551:12;:10;:12::i;:::-;:21;291547:103;;;291596:42;;-1:-1:-1;;;291596:42:0;;;;;;;;;;;234373:178;234454:10;-1:-1:-1;;;;;234454:19:0;;;234450:94;;234490:42;234506:5;234513:10;234525:6;234490:15;:42::i;233453:749::-;233526:10;-1:-1:-1;;;;;233548:13:0;233526:36;;233522:100;;233579:31;189409:10;233579:7;:31::i;:::-;233666:4;190277:5;233744:68;207264:6;233786:2;233790:13;233805:6;233744:32;:68::i;:::-;234010:6;234030:25;233969:14;234010:6;234030:5;:25::i;:::-;234066:12;:21;;;234105:39;;;34953:25:1;;;35009:2;34994:18;;34987:34;;;234125:1:0;;-1:-1:-1;;;;;234105:39:0;;;;;34926:18:1;234105:39:0;34779:248:1;64704:1142:0;64976:18;64970:4;64963:32;65022:4;65016;65009:18;65080:4;65074;65064:21;65124:15;65118:22;65216:11;65208:6;65205:23;65202:149;;;65261:10;65255:4;65248:24;65331:4;65325;65318:18;65202:149;65445:24;;;65421:49;;65582:18;65576:25;;65572:38;;;65545:66;;-1:-1:-1;65668:20:0;;;-1:-1:-1;;;;;65746:22:0;;-1:-1:-1;;;;;;;;;;;65713:4:0;-1:-1:-1;65702:70:0;279711:348;;:::o;238531:194::-;238711:6;238696:12;;:21;;;;:::i;:::-;238681:12;:36;-1:-1:-1;238531:194:0:o;101326:336::-;101438:4;101560:23;101575:7;101560:14;:23::i;:::-;:94;;;;;101600:54;101633:7;101642:11;101600:32;:54::i;41468:513::-;41603:12;41628:36;41644:7;41653:10;41628:15;:36::i;:::-;41826:17;;:22;:49;;;;-1:-1:-1;;;;;;41852:18:0;;;:23;41826:49;41822:122;;;41899:33;;-1:-1:-1;;;41899:33:0;;;;;;;;;;;41822:122;-1:-1:-1;41963:10:0;41468:513;-1:-1:-1;;41468:513:0:o;238212:187::-;238385:6;238370:12;;:21;;;;:::i;244045:174::-;244152:9;244178:33;244203:1;244206;244209;244178:24;:33::i;68006:967::-;68251:7;68245:4;68238:21;68286:20;68280:4;68273:34;68334:5;68328:4;68321:19;68391:4;68385;68375:21;68434:13;68428:20;68548:1;68536:10;68532:18;68529:426;;;68666:10;68658:6;68655:22;68652:162;;;68714:10;68708:4;68701:24;68790:4;68784;68777:18;68652:162;68916:23;;;;68894:46;;-1:-1:-1;;68006:967:0:o;100618:482::-;100682:4;100893:117;100944:7;-1:-1:-1;;;100893:32:0;:117::i;:::-;:199;;;;-1:-1:-1;101028:64:0;101061:7;-1:-1:-1;;;;;;101028:32:0;:64::i;:::-;101027:65;100873:219;100618:482;-1:-1:-1;;100618:482:0:o;102507:826::-;102705:93;;-1:-1:-1;;;;;;38498:33:1;;102705:93:0;;;38480:52:1;102634:4:0;;;;38453:18:1;;102705:93:0;;;-1:-1:-1;;102705:93:0;;;;;;;;;;;;;;;-1:-1:-1;;;;;102705:93:0;-1:-1:-1;;;102705:93:0;;;103082:20;;102705:93;;-1:-1:-1;;;;;;;102705:93:0;;-1:-1:-1;;103013:7:0;102989:5;102960:203;102949:214;;103191:16;103177:30;;103242:4;103236:11;103221:26;;103277:7;:29;;;;;103302:4;103288:10;:18;;103277:29;:48;;;;;103324:1;103310:11;:15;103277:48;103270:55;102507:826;-1:-1:-1;;;;;;;102507:826:0:o;42157:425::-;42276:7;42271:304;;42304:10;:17;42325:1;42304:22;42300:103;;42354:33;;-1:-1:-1;;;42354:33:0;;;;;;;;;;;42300:103;42537:10;42531:17;42518:10;42514:2;42510:19;42503:46;76512:476;76584:9;76811:1;76807;76803:6;76799:14;76796:1;76793:21;76790:1;76786:29;76779:37;76776:1;76772:45;76762:172;;76851:10;76845:4;76838:24;76914:4;76908;76901:18;76762:172;-1:-1:-1;76957:9:0;;76953:17;;76512:476::o;196:286:1:-;254:6;307:2;295:9;286:7;282:23;278:32;275:52;;;323:1;320;313:12;275:52;349:23;;-1:-1:-1;;;;;;401:32:1;;391:43;;381:71;;448:1;445;438:12;679:289;721:3;759:5;753:12;786:6;781:3;774:19;842:6;835:4;828:5;824:16;817:4;812:3;808:14;802:47;894:1;887:4;878:6;873:3;869:16;865:27;858:38;957:4;950:2;946:7;941:2;933:6;929:15;925:29;920:3;916:39;912:50;905:57;;;679:289;;;;:::o;973:220::-;1122:2;1111:9;1104:21;1085:4;1142:45;1183:2;1172:9;1168:18;1160:6;1142:45;:::i;1198:226::-;1257:6;1310:2;1298:9;1289:7;1285:23;1281:32;1278:52;;;1326:1;1323;1316:12;1278:52;-1:-1:-1;1371:23:1;;1198:226;-1:-1:-1;1198:226:1:o;1429:131::-;-1:-1:-1;;;;;1504:31:1;;1494:42;;1484:70;;1550:1;1547;1540:12;1565:367;1633:6;1641;1694:2;1682:9;1673:7;1669:23;1665:32;1662:52;;;1710:1;1707;1700:12;1662:52;1749:9;1736:23;1768:31;1793:5;1768:31;:::i;:::-;1818:5;1896:2;1881:18;;;;1868:32;;-1:-1:-1;;;1565:367:1:o;1937:::-;2000:8;2010:6;2064:3;2057:4;2049:6;2045:17;2041:27;2031:55;;2082:1;2079;2072:12;2031:55;-1:-1:-1;2105:20:1;;-1:-1:-1;;;;;2137:30:1;;2134:50;;;2180:1;2177;2170:12;2134:50;2217:4;2209:6;2205:17;2193:29;;2277:3;2270:4;2260:6;2257:1;2253:14;2245:6;2241:27;2237:38;2234:47;2231:67;;;2294:1;2291;2284:12;2231:67;1937:367;;;;;:::o;2309:572::-;2404:6;2412;2420;2473:2;2461:9;2452:7;2448:23;2444:32;2441:52;;;2489:1;2486;2479:12;2441:52;2529:9;2516:23;-1:-1:-1;;;;;2554:6:1;2551:30;2548:50;;;2594:1;2591;2584:12;2548:50;2633:70;2695:7;2686:6;2675:9;2671:22;2633:70;:::i;:::-;2722:8;;-1:-1:-1;2607:96:1;-1:-1:-1;;2807:2:1;2792:18;;2779:32;2820:31;2779:32;2820:31;:::i;:::-;2870:5;2860:15;;;2309:572;;;;;:::o;2886:247::-;2945:6;2998:2;2986:9;2977:7;2973:23;2969:32;2966:52;;;3014:1;3011;3004:12;2966:52;3053:9;3040:23;3072:31;3097:5;3072:31;:::i;4015:508::-;4092:6;4100;4108;4161:2;4149:9;4140:7;4136:23;4132:32;4129:52;;;4177:1;4174;4167:12;4129:52;4216:9;4203:23;4235:31;4260:5;4235:31;:::i;:::-;4285:5;-1:-1:-1;4342:2:1;4327:18;;4314:32;4355:33;4314:32;4355:33;:::i;:::-;4015:508;;4407:7;;-1:-1:-1;;;4487:2:1;4472:18;;;;4459:32;;4015:508::o;4528:367::-;4596:6;4604;4657:2;4645:9;4636:7;4632:23;4628:32;4625:52;;;4673:1;4670;4663:12;4625:52;4718:23;;;-1:-1:-1;4817:2:1;4802:18;;4789:32;4830:33;4789:32;4830:33;:::i;:::-;4882:7;4872:17;;;4528:367;;;;;:::o;5271:903::-;5402:6;5410;5418;5426;5434;5487:2;5475:9;5466:7;5462:23;5458:32;5455:52;;;5503:1;5500;5493:12;5455:52;5543:9;5530:23;-1:-1:-1;;;;;5568:6:1;5565:30;5562:50;;;5608:1;5605;5598:12;5562:50;5647:70;5709:7;5700:6;5689:9;5685:22;5647:70;:::i;:::-;5736:8;;-1:-1:-1;5621:96:1;-1:-1:-1;;5824:2:1;5809:18;;5796:32;-1:-1:-1;;;;;5840:32:1;;5837:52;;;5885:1;5882;5875:12;5837:52;5924:72;5988:7;5977:8;5966:9;5962:24;5924:72;:::i;:::-;6015:8;;-1:-1:-1;5898:98:1;-1:-1:-1;;6100:2:1;6085:18;;6072:32;6113:31;6072:32;6113:31;:::i;:::-;6163:5;6153:15;;;5271:903;;;;;;;;:::o;6617:700::-;6696:6;6704;6712;6765:2;6753:9;6744:7;6740:23;6736:32;6733:52;;;6781:1;6778;6771:12;6733:52;6826:23;;;-1:-1:-1;6924:2:1;6909:18;;6896:32;-1:-1:-1;;;;;6940:30:1;;6937:50;;;6983:1;6980;6973:12;6937:50;7006:22;;7059:4;7051:13;;7047:27;-1:-1:-1;7037:55:1;;7088:1;7085;7078:12;7037:55;7128:2;7115:16;-1:-1:-1;;;;;7146:6:1;7143:30;7140:50;;;7186:1;7183;7176:12;7140:50;7231:7;7226:2;7217:6;7213:2;7209:15;7205:24;7202:37;7199:57;;;7252:1;7249;7242:12;7199:57;6617:700;;7283:2;7275:11;;;;;-1:-1:-1;7305:6:1;;-1:-1:-1;;;6617:700:1:o;7322:903::-;7453:6;7461;7469;7477;7485;7538:2;7526:9;7517:7;7513:23;7509:32;7506:52;;;7554:1;7551;7544:12;7506:52;7594:9;7581:23;-1:-1:-1;;;;;7619:6:1;7616:30;7613:50;;;7659:1;7656;7649:12;7613:50;7698:70;7760:7;7751:6;7740:9;7736:22;7698:70;:::i;:::-;7787:8;;-1:-1:-1;7672:96:1;-1:-1:-1;;7872:2:1;7857:18;;7844:32;7885:31;7844:32;7885:31;:::i;:::-;7935:5;-1:-1:-1;7993:2:1;7978:18;;7965:32;-1:-1:-1;;;;;8009:32:1;;8006:52;;;8054:1;8051;8044:12;8006:52;8093:72;8157:7;8146:8;8135:9;8131:24;8093:72;:::i;:::-;7322:903;;;;-1:-1:-1;7322:903:1;;-1:-1:-1;8184:8:1;;8067:98;7322:903;-1:-1:-1;;;7322:903:1:o;8230:508::-;8307:6;8315;8323;8376:2;8364:9;8355:7;8351:23;8347:32;8344:52;;;8392:1;8389;8382:12;8344:52;8437:23;;;-1:-1:-1;8536:2:1;8521:18;;8508:32;8549:33;8508:32;8549:33;:::i;:::-;8601:7;-1:-1:-1;8660:2:1;8645:18;;8632:32;8673:33;8632:32;8673:33;:::i;8743:388::-;8811:6;8819;8872:2;8860:9;8851:7;8847:23;8843:32;8840:52;;;8888:1;8885;8878:12;8840:52;8927:9;8914:23;8946:31;8971:5;8946:31;:::i;:::-;8996:5;-1:-1:-1;9053:2:1;9038:18;;9025:32;9066:33;9025:32;9066:33;:::i;9740:127::-;9801:10;9796:3;9792:20;9789:1;9782:31;9832:4;9829:1;9822:15;9856:4;9853:1;9846:15;9872:253;9944:2;9938:9;9986:4;9974:17;;-1:-1:-1;;;;;10006:34:1;;10042:22;;;10003:62;10000:88;;;10068:18;;:::i;:::-;10104:2;10097:22;9872:253;:::o;10130:::-;10202:2;10196:9;10244:4;10232:17;;-1:-1:-1;;;;;10264:34:1;;10300:22;;;10261:62;10258:88;;;10326:18;;:::i;10388:275::-;10459:2;10453:9;10524:2;10505:13;;-1:-1:-1;;10501:27:1;10489:40;;-1:-1:-1;;;;;10544:34:1;;10580:22;;;10541:62;10538:88;;;10606:18;;:::i;:::-;10642:2;10635:22;10388:275;;-1:-1:-1;10388:275:1:o;10668:153::-;10755:20;;10784:31;10755:20;10784:31;:::i;10826:558::-;10868:5;10921:3;10914:4;10906:6;10902:17;10898:27;10888:55;;10939:1;10936;10929:12;10888:55;10979:6;10966:20;-1:-1:-1;;;;;11001:6:1;10998:30;10995:56;;;11031:18;;:::i;:::-;11075:59;11122:2;11099:17;;-1:-1:-1;;11095:31:1;11128:4;11091:42;11075:59;:::i;:::-;11159:6;11150:7;11143:23;11213:3;11206:4;11197:6;11189;11185:19;11181:30;11178:39;11175:59;;;11230:1;11227;11220:12;11175:59;11295:6;11288:4;11280:6;11276:17;11269:4;11260:7;11256:18;11243:59;11351:1;11322:20;;;11344:4;11318:31;11311:42;;;;11326:7;10826:558;-1:-1:-1;;;10826:558:1:o;11389:993::-;11440:5;11488:4;11476:9;11471:3;11467:19;11463:30;11460:50;;;11506:1;11503;11496:12;11460:50;11528:22;;:::i;:::-;11519:31;;11587:9;11574:23;11606:33;11631:7;11606:33;:::i;:::-;11648:22;;11743:2;11728:18;;;11715:32;11763:14;;;11756:31;11839:2;11824:18;;11811:32;11852:33;11811:32;11852:33;:::i;:::-;11912:2;11901:14;;11894:31;11977:2;11962:18;;11949:32;11990:33;11949:32;11990:33;:::i;:::-;12050:2;12039:14;;12032:31;12136:3;12121:19;;;12108:33;12157:15;;;12150:32;12233:3;12218:19;;12205:33;-1:-1:-1;;;;;12250:30:1;;12247:50;;;12293:1;12290;12283:12;12247:50;12330:45;12371:3;12362:6;12351:9;12347:22;12330:45;:::i;:::-;12324:3;12317:5;12313:15;12306:70;;11389:993;;;;:::o;12387:1465::-;12496:6;12504;12512;12565:2;12553:9;12544:7;12540:23;12536:32;12533:52;;;12581:1;12578;12571:12;12533:52;12626:23;;;-1:-1:-1;12725:2:1;12710:18;;12697:32;12738:33;12697:32;12738:33;:::i;:::-;12790:7;-1:-1:-1;12848:2:1;12833:18;;12820:32;-1:-1:-1;;;;;12864:30:1;;12861:50;;;12907:1;12904;12897:12;12861:50;12930:22;;12986:4;12968:16;;;12964:27;12961:47;;;13004:1;13001;12994:12;12961:47;13032:22;;:::i;:::-;13079:41;13117:2;13079:41;:::i;:::-;13063:58;;13187:2;13179:11;;;13166:25;13207:16;;;13200:33;13267:50;13313:2;13305:11;;13267:50;:::i;:::-;13262:2;13249:16;;13242:76;13384:2;13376:11;;;13363:25;13404:16;;;13397:33;13476:3;13468:12;;13455:26;-1:-1:-1;;;;;13493:32:1;;13490:52;;;13538:1;13535;13528:12;13490:52;13577:50;13619:7;13608:8;13604:2;13600:17;13577:50;:::i;:::-;13571:3;13562:7;13558:17;13551:77;;13674:3;13670:2;13666:12;13653:26;-1:-1:-1;;;;;13694:8:1;13691:32;13688:52;;;13736:1;13733;13726:12;13688:52;13775:44;13811:7;13800:8;13796:2;13792:17;13775:44;:::i;:::-;13769:3;13760:7;13756:17;13749:71;;13839:7;13829:17;;;;12387:1465;;;;;:::o;14282:187::-;14346:4;-1:-1:-1;;;;;14371:6:1;14368:30;14365:56;;;14401:18;;:::i;:::-;-1:-1:-1;14446:1:1;14442:14;14458:4;14438:25;;14282:187::o;14474:841::-;14532:5;14585:3;14578:4;14570:6;14566:17;14562:27;14552:55;;14603:1;14600;14593:12;14552:55;14643:6;14630:20;14670:68;14686:51;14730:6;14686:51;:::i;:::-;14670:68;:::i;:::-;14762:3;14786:6;14781:3;14774:19;14818:4;14813:3;14809:14;14802:21;;14879:4;14869:6;14866:1;14862:14;14854:6;14850:27;14846:38;14832:52;;14907:3;14899:6;14896:15;14893:35;;;14924:1;14921;14914:12;14893:35;14960:4;14952:6;14948:17;14974:310;14990:6;14985:3;14982:15;14974:310;;;15078:3;15065:17;-1:-1:-1;;;;;15101:11:1;15098:35;15095:55;;;15146:1;15143;15136:12;15095:55;15175:64;15235:3;15228:4;15214:11;15206:6;15202:24;15198:35;15175:64;:::i;:::-;15163:77;;-1:-1:-1;15269:4:1;15260:14;;;;15007;14974:310;;;-1:-1:-1;15302:7:1;14474:841;-1:-1:-1;;;;;14474:841:1:o;15320:1477::-;15431:6;15439;15447;15500:2;15488:9;15479:7;15475:23;15471:32;15468:52;;;15516:1;15513;15506:12;15468:52;15561:23;;;-1:-1:-1;15660:2:1;15645:18;;15632:32;15673:33;15632:32;15673:33;:::i;:::-;15725:7;-1:-1:-1;15783:2:1;15768:18;;15755:32;-1:-1:-1;;;;;15799:30:1;;15796:50;;;15842:1;15839;15832:12;15796:50;15865:22;;15921:4;15903:16;;;15899:27;15896:47;;;15939:1;15936;15929:12;15896:47;15967:22;;:::i;:::-;16014:41;16052:2;16014:41;:::i;:::-;15998:58;;16122:2;16114:11;;;16101:25;16142:16;;;16135:33;16202:50;16248:2;16240:11;;16202:50;:::i;:::-;16197:2;16184:16;;16177:76;16319:2;16311:11;;;16298:25;16339:16;;;16332:33;16411:3;16403:12;;16390:26;-1:-1:-1;;;;;16428:32:1;;16425:52;;;16473:1;16470;16463:12;16425:52;16512:60;16564:7;16553:8;16549:2;16545:17;16512:60;:::i;16802:118::-;16888:5;16881:13;16874:21;16867:5;16864:32;16854:60;;16910:1;16907;16900:12;16925:382;16990:6;16998;17051:2;17039:9;17030:7;17026:23;17022:32;17019:52;;;17067:1;17064;17057:12;17019:52;17106:9;17093:23;17125:31;17150:5;17125:31;:::i;:::-;17175:5;-1:-1:-1;17232:2:1;17217:18;;17204:32;17245:30;17204:32;17245:30;:::i;17312:1037::-;17423:6;17431;17439;17447;17455;17463;17471;17524:3;17512:9;17503:7;17499:23;17495:33;17492:53;;;17541:1;17538;17531:12;17492:53;17580:9;17567:23;17599:31;17624:5;17599:31;:::i;:::-;17649:5;-1:-1:-1;17706:2:1;17691:18;;17678:32;17719:33;17678:32;17719:33;:::i;:::-;17771:7;-1:-1:-1;17851:2:1;17836:18;;17823:32;;-1:-1:-1;17954:2:1;17939:18;;17926:32;;-1:-1:-1;18036:3:1;18021:19;;18008:33;18085:4;18072:18;;18060:31;;18050:59;;18105:1;18102;18095:12;18050:59;17312:1037;;;;-1:-1:-1;17312:1037:1;;;;18128:7;18208:3;18193:19;;18180:33;;-1:-1:-1;18312:3:1;18297:19;;;18284:33;;17312:1037;-1:-1:-1;;17312:1037:1:o;18354:472::-;18475:6;18483;18536:2;18524:9;18515:7;18511:23;18507:32;18504:52;;;18552:1;18549;18542:12;18504:52;18592:9;18579:23;-1:-1:-1;;;;;18617:6:1;18614:30;18611:50;;;18657:1;18654;18647:12;18611:50;18696:70;18758:7;18749:6;18738:9;18734:22;18696:70;:::i;:::-;18785:8;;18670:96;;-1:-1:-1;18354:472:1;-1:-1:-1;;;;18354:472:1:o;18831:780::-;18991:4;19039:2;19028:9;19024:18;19069:2;19058:9;19051:21;19092:6;19127;19121:13;19158:6;19150;19143:22;19196:2;19185:9;19181:18;19174:25;;19258:2;19248:6;19245:1;19241:14;19230:9;19226:30;19222:39;19208:53;;19296:2;19288:6;19284:15;19317:1;19327:255;19341:6;19338:1;19335:13;19327:255;;;19434:2;19430:7;19418:9;19410:6;19406:22;19402:36;19397:3;19390:49;19462:40;19495:6;19486;19480:13;19462:40;:::i;:::-;19452:50;-1:-1:-1;19537:2:1;19560:12;;;;19525:15;;;;;19363:1;19356:9;19327:255;;;-1:-1:-1;19599:6:1;;18831:780;-1:-1:-1;;;;;;18831:780:1:o;19616:380::-;19695:1;19691:12;;;;19738;;;19759:61;;19813:4;19805:6;19801:17;19791:27;;19759:61;19866:2;19858:6;19855:14;19835:18;19832:38;19829:161;;19912:10;19907:3;19903:20;19900:1;19893:31;19947:4;19944:1;19937:15;19975:4;19972:1;19965:15;19829:161;;19616:380;;;:::o;20001:251::-;20071:6;20124:2;20112:9;20103:7;20099:23;20095:32;20092:52;;;20140:1;20137;20130:12;20092:52;20172:9;20166:16;20191:31;20216:5;20191:31;:::i;20536:245::-;20603:6;20656:2;20644:9;20635:7;20631:23;20627:32;20624:52;;;20672:1;20669;20662:12;20624:52;20704:9;20698:16;20723:28;20745:5;20723:28;:::i;20786:127::-;20847:10;20842:3;20838:20;20835:1;20828:31;20878:4;20875:1;20868:15;20902:4;20899:1;20892:15;21071:501;21150:6;21158;21166;21219:2;21207:9;21198:7;21194:23;21190:32;21187:52;;;21235:1;21232;21225:12;21187:52;21267:9;21261:16;21286:28;21308:5;21286:28;:::i;:::-;21383:2;21368:18;;21362:25;21333:5;;-1:-1:-1;21396:30:1;21362:25;21396:30;:::i;:::-;21497:2;21482:18;;21476:25;21445:7;;-1:-1:-1;21510:30:1;21476:25;21510:30;:::i;21577:125::-;21642:9;;;21663:10;;;21660:36;;;21676:18;;:::i;22155:230::-;22225:6;22278:2;22266:9;22257:7;22253:23;22249:32;22246:52;;;22294:1;22291;22284:12;22246:52;-1:-1:-1;22339:16:1;;22155:230;-1:-1:-1;22155:230:1:o;22390:533::-;22603:6;22592:9;22585:25;22646:6;22641:2;22630:9;22626:18;22619:34;22689:2;22684;22673:9;22669:18;22662:30;22728:6;22723:2;22712:9;22708:18;22701:34;22786:6;22778;22772:3;22761:9;22757:19;22744:49;22843:1;22813:22;;;22837:3;22809:32;;;22802:43;;;;22906:2;22885:15;;;-1:-1:-1;;22881:29:1;22866:45;22862:55;;22390:533;-1:-1:-1;;;22390:533:1:o;23772:127::-;23833:10;23828:3;23824:20;23821:1;23814:31;23864:4;23861:1;23854:15;23888:4;23885:1;23878:15;23904:128;23971:9;;;23992:11;;;23989:37;;;24006:18;;:::i;24773:550::-;24854:12;;-1:-1:-1;;;;;24850:38:1;;;24838:51;;24938:4;24927:16;;;24921:23;24905:14;;;24898:47;24998:4;24987:16;;;24981:23;24977:49;;24961:14;;;24954:73;25080:4;25069:16;;;25063:23;25059:49;;;25043:14;;;25036:73;25158:4;25147:16;;;25141:23;25125:14;;;25118:47;24876:3;25200:16;;;25194:23;25249:4;25233:14;;;25226:28;;;-1:-1:-1;;25270:47:1;;25302:14;;25194:23;25270:47;:::i;25328:1113::-;25634:1;25630;25625:3;25621:11;25617:19;25609:6;25605:32;25594:9;25587:51;25674:6;25669:2;25658:9;25654:18;25647:34;25746:1;25742;25737:3;25733:11;25729:19;25721:6;25717:32;25712:2;25701:9;25697:18;25690:60;25786:3;25781:2;25770:9;25766:18;25759:31;25863:1;25859;25854:3;25850:11;25846:19;25837:6;25831:13;25827:39;25821:3;25810:9;25806:19;25799:68;25922:2;25914:6;25910:15;25904:22;25898:3;25887:9;25883:19;25876:51;26010:1;26006;26001:3;25997:11;25993:19;25987:2;25979:6;25975:15;25969:22;25965:48;25958:4;25947:9;25943:20;25936:78;26069:2;26061:6;26057:15;26051:22;26045:3;26034:9;26030:19;26023:51;25568:4;26121:3;26113:6;26109:16;26103:23;26163:4;26157:3;26146:9;26142:19;26135:33;26191:57;26243:3;26232:9;26228:19;26214:12;26191:57;:::i;:::-;26177:71;;26297:3;26289:6;26285:16;26279:23;26371:3;26367:8;26355:9;26347:6;26343:22;26339:37;26333:3;26322:9;26318:19;26311:66;26394:41;26428:6;26412:14;26394:41;:::i;:::-;26386:49;25328:1113;-1:-1:-1;;;;;;;;25328:1113:1:o;27191:332::-;27292:4;27350:11;27337:25;27444:2;27440:7;27429:8;27413:14;27409:29;27405:43;27385:18;27381:68;27371:96;;27463:1;27460;27453:12;27371:96;27484:33;;;;;27191:332;-1:-1:-1;;27191:332:1:o;27528:728::-;27646:9;27705:4;27697:5;27681:14;27677:26;27673:37;27670:57;;;27723:1;27720;27713:12;27670:57;27751:22;;:::i;:::-;27810:5;27797:19;27825:33;27850:7;27825:33;:::i;:::-;27867:24;;27939:2;27928:14;;27915:28;27952:30;27915:28;27952:30;:::i;:::-;28011:2;27998:16;;27991:33;28071:2;28060:14;;28047:28;-1:-1:-1;;;;;28087:30:1;;28084:50;;;28130:1;28127;28120:12;28084:50;28168:52;28205:14;28196:6;28189:5;28185:18;28168:52;:::i;:::-;28163:2;28150:16;;28143:78;-1:-1:-1;28154:7:1;27528:728;-1:-1:-1;;27528:728:1:o;28261:412::-;-1:-1:-1;;;;;28464:32:1;;;28446:51;;28533:32;;28528:2;28513:18;;28506:60;28602:2;28597;28582:18;;28575:30;;;-1:-1:-1;;28622:45:1;;28648:18;;28640:6;28622:45;:::i;28678:420::-;28731:3;28769:5;28763:12;28796:6;28791:3;28784:19;28828:4;28823:3;28819:14;28812:21;;28867:4;28860:5;28856:16;28890:1;28900:173;28914:6;28911:1;28908:13;28900:173;;;28975:13;;28963:26;;29018:4;29009:14;;;;29046:17;;;;28936:1;28929:9;28900:173;;;-1:-1:-1;29089:3:1;;28678:420;-1:-1:-1;;;;28678:420:1:o;29103:505::-;29203:6;29198:3;29191:19;29235:4;29230:3;29226:14;29219:21;;29173:3;29263:5;29286:1;29296:287;29310:6;29307:1;29304:13;29296:287;;;29387:6;29374:20;29407:33;29432:7;29407:33;:::i;:::-;-1:-1:-1;;;;;29465:33:1;29453:46;;29528:4;29519:14;;;;29556:17;;;;;29495:1;29325:9;29296:287;;29613:1152;29988:3;29977:9;29970:22;29951:4;30015:57;30067:3;30056:9;30052:19;30044:6;30015:57;:::i;:::-;-1:-1:-1;;;;;30108:32:1;;30103:2;30088:18;;30081:60;30177:22;;;30172:2;30157:18;;30150:50;30217:61;30181:6;30263;30255;30217:61;:::i;:::-;30209:69;;;30350:1;30346;30341:3;30337:11;30333:19;30324:6;30318:13;30314:39;30309:2;30298:9;30294:18;30287:67;30436:1;30432;30427:3;30423:11;30419:19;30413:2;30405:6;30401:15;30395:22;30391:48;30385:3;30374:9;30370:19;30363:77;30495:2;30487:6;30483:15;30477:22;30471:3;30460:9;30456:19;30449:51;30569:2;30561:6;30557:15;30551:22;30544:30;30537:38;30531:3;30520:9;30516:19;30509:67;30631:3;30623:6;30619:16;30613:23;30607:3;30596:9;30592:19;30585:52;30692:3;30684:6;30680:16;30674:23;30668:3;30657:9;30653:19;30646:52;30753:3;30745:6;30741:16;30735:23;30729:3;30718:9;30714:19;30707:52;29613:1152;;;;;;;;:::o;30770:724::-;30835:5;30888:3;30881:4;30873:6;30869:17;30865:27;30855:55;;30906:1;30903;30896:12;30855:55;30939:6;30933:13;30966:68;30982:51;31026:6;30982:51;:::i;30966:68::-;31058:3;31082:6;31077:3;31070:19;31114:4;31109:3;31105:14;31098:21;;31175:4;31165:6;31162:1;31158:14;31150:6;31146:27;31142:38;31128:52;;31203:3;31195:6;31192:15;31189:35;;;31220:1;31217;31210:12;31189:35;31256:4;31248:6;31244:17;31270:193;31286:6;31281:3;31278:15;31270:193;;;31378:10;;31401:18;;31448:4;31439:14;;;;31303;31270:193;;31499:1076;31629:6;31637;31690:2;31678:9;31669:7;31665:23;31661:32;31658:52;;;31706:1;31703;31696:12;31658:52;31739:9;31733:16;-1:-1:-1;;;;;31764:6:1;31761:30;31758:50;;;31804:1;31801;31794:12;31758:50;31827:22;;31883:4;31865:16;;;31861:27;31858:47;;;31901:1;31898;31891:12;31858:47;31927:22;;:::i;:::-;31980:2;31974:9;-1:-1:-1;;;;;31998:8:1;31995:32;31992:52;;;32040:1;32037;32030:12;31992:52;32067:67;32126:7;32115:8;32111:2;32107:17;32067:67;:::i;:::-;32053:82;;-1:-1:-1;32194:2:1;32186:11;;;32180:18;32214:14;;;32207:31;32297:2;32289:11;;;32283:18;32317:14;;;32310:31;;;;32396:18;;;32390:25;32060:5;;-1:-1:-1;;;;;;32427:32:1;;32424:52;;;32472:1;32469;32462:12;32424:52;32495:74;32561:7;32550:8;32539:9;32535:24;32495:74;:::i;:::-;32485:84;;;31499:1076;;;;;:::o;33028:589::-;33323:2;33312:9;33305:21;33286:4;33349:56;33401:2;33390:9;33386:18;33378:6;33349:56;:::i;:::-;-1:-1:-1;;;;;33441:32:1;;33436:2;33421:18;;33414:60;33510:22;;;33505:2;33490:18;;33483:50;33550:61;33514:6;33596;33588;33550:61;:::i;33622:597::-;-1:-1:-1;;;;;33921:32:1;;;33903:51;;33985:2;33970:18;;33963:34;;;;34033:32;;;;34028:2;34013:18;;34006:60;34097:2;34082:18;;34075:34;34140:3;34125:19;;34118:35;;;;34197:14;;34190:22;33941:3;34169:19;;34162:51;33890:3;33875:19;;33622:597::o;35032:343::-;35111:6;35119;35172:2;35160:9;35151:7;35147:23;35143:32;35140:52;;;35188:1;35185;35178:12;35140:52;-1:-1:-1;;35233:16:1;;35339:2;35324:18;;;35318:25;35233:16;;35318:25;;-1:-1:-1;35032:343:1:o;35380:217::-;35420:1;35446;35436:132;;35490:10;35485:3;35481:20;35478:1;35471:31;35525:4;35522:1;35515:15;35553:4;35550:1;35543:15;35436:132;-1:-1:-1;35582:9:1;;35380:217::o;35602:168::-;35675:9;;;35706;;35723:15;;;35717:22;;35703:37;35693:71;;35744:18;;:::i;36040:1609::-;36350:1;36346;36341:3;36337:11;36333:19;36325:6;36321:32;36310:9;36303:51;36390:6;36385:2;36374:9;36370:18;36363:34;36462:1;36458;36453:3;36449:11;36445:19;36437:6;36433:32;36428:2;36417:9;36413:18;36406:60;36502:3;36497:2;36486:9;36482:18;36475:31;36284:4;36544:3;36533:9;36529:19;36621:1;36617;36612:3;36608:11;36604:19;36595:6;36589:13;36585:39;36579:3;36568:9;36564:19;36557:68;36680:2;36672:6;36668:15;36662:22;36656:3;36645:9;36641:19;36634:51;36768:1;36764;36759:3;36755:11;36751:19;36745:2;36737:6;36733:15;36727:22;36723:48;36716:4;36705:9;36701:20;36694:78;36827:2;36819:6;36815:15;36809:22;36803:3;36792:9;36788:19;36781:51;36879:3;36871:6;36867:16;36861:23;36921:4;36915:3;36904:9;36900:19;36893:33;36946:6;36981:12;36975:19;37018:6;37010;37003:22;37056:3;37045:9;37041:19;37034:26;;37119:3;37109:6;37106:1;37102:14;37091:9;37087:30;37083:40;37069:54;;37164:2;37150:12;37146:21;37132:35;;37185:1;37195:261;37209:6;37206:1;37203:13;37195:261;;;37302:3;37298:8;37286:9;37278:6;37274:22;37270:37;37265:3;37258:50;37331:45;37369:6;37360;37354:13;37331:45;:::i;:::-;37321:55;-1:-1:-1;37411:2:1;37399:15;;;;37434:12;;;;;37231:1;37224:9;37195:261;;;-1:-1:-1;;;;37505:3:1;37493:16;;37487:23;37551:22;;;-1:-1:-1;;37547:37:1;37541:3;37526:19;;37519:66;37602:41;37555:6;37487:23;37602:41;:::i;38030:301::-;38159:3;38197:6;38191:13;38243:6;38236:4;38228:6;38224:17;38219:3;38213:37;38305:1;38269:16;;38294:13;;;-1:-1:-1;38269:16:1;38030:301;-1:-1:-1;38030:301:1:o
Swarm Source
ipfs://9d1af0ba86ae344133dffce36c4b91ce925fb4117300ef90c85021d81eaa96f6
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in MON
Multichain Portfolio | 33 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
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.