Source Code
Latest 15 from a total of 15 transactions
| Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
| Add Position Man... | 44626306 | 29 days ago | IN | 0 MON | 0.01122316 | ||||
| Remove Position ... | 44626275 | 29 days ago | IN | 0 MON | 0.00722334 | ||||
| Add Position Man... | 42757128 | 37 days ago | IN | 0 MON | 0.0112708 | ||||
| Remove Position ... | 42757117 | 37 days ago | IN | 0 MON | 0.007254 | ||||
| Update Token Con... | 40087353 | 50 days ago | IN | 0 MON | 0.05120232 | ||||
| Update Token Con... | 39431912 | 53 days ago | IN | 0 MON | 0.05204305 | ||||
| Update Token Con... | 39431759 | 53 days ago | IN | 0 MON | 0.0512044 | ||||
| Set Mint Paused | 37955692 | 60 days ago | IN | 0 MON | 0.00744732 | ||||
| Set Mint Paused | 37955686 | 60 days ago | IN | 0 MON | 0.00744732 | ||||
| Update Token Con... | 37832934 | 60 days ago | IN | 0 MON | 0.05925369 | ||||
| Update Token Con... | 37832929 | 60 days ago | IN | 0 MON | 0.04696548 | ||||
| Set Mint Paused | 37832924 | 60 days ago | IN | 0 MON | 0.00749749 | ||||
| Set Mint Paused | 37832920 | 60 days ago | IN | 0 MON | 0.00749749 | ||||
| List Tokens | 37832915 | 60 days ago | IN | 0 MON | 0.08622059 | ||||
| Add Position Man... | 37832863 | 60 days ago | IN | 0 MON | 0.0113867 |
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:
MarketManagerIsolated
Compiler Version
v0.8.28+commit.7893614a
Contract Source Code (Solidity)
/**
*Submitted for verification at monadscan.com on 2025-11-25
*/
// SPDX-License-Identifier: BUSL-1.1
pragma solidity =0.8.28;
// 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/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/interfaces/IActionRegistry.sol
interface IActionRegistry {
/// @notice Checks whether `user` has transferability enabled or disabled
/// for their tokens.
/// @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);
/// @notice Checks whether `user` has disabled creating new delegations
/// for actions inside Curvance.
/// @param user The address to check whether delegation is enabled or
/// disabled 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);
/// @notice Returns `user`'s approval index.
/// @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);
}
// 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/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;
/// @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/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/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/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/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;
}
// 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/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.
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;
}
/// @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/isolated/LiquidityManagerIsolated.sol
/// @title Curvance Liquidity Manager.
/// @notice Calculates liquidity of an account in various positions.
/// @dev NOTE: Only use this as an abstract contract as no account
/// data is written here.
abstract contract LiquidityManagerIsolated {
/// TYPES ///
/// @notice Storage structure for Account data involving liquidity
/// positions, and pending redemption cooldown.
/// @param cooldownTimestamp Timestamp corresponding to when the last time
/// `account` performed a liquidity focused
/// action, which activates a cooldown period on
/// redemptions/repayment/collateral removal.
/// @param assets Array containing all Curvance tokens an account has
/// active liquidity positions in.
struct AccountData {
uint256 cooldownTimestamp;
address[] assets;
}
/// @notice Storage configuration for how a Curvance token should behave
/// in the liquidity manager.
/// @param isListed Whether or not this Curvance token is listed.
/// @dev false = unlisted; true = listed.
/// @param mintPaused Whether token minting is paused.
/// @dev Token Address => 0 or 1 = unpaused; 2 = paused.
/// @param collateralizationPaused Whether token collateralization is paused.
/// @dev Token Address => 0 or 1 = unpaused; 2 = paused.
/// @param borrowPaused Whether token borrowing is paused.
/// @dev Token Address => 0 or 1 = unpaused; 2 = paused.
/// @param collRatio The ratio at which this token can be borrowed against
/// when collateralized.
/// @dev In `BPS`, e.g. 0.8e18 = 80% collateral value borrowable.
/// @param collReqSoft The collateral requirement where dipping below this
/// will cause a soft liquidation.
/// @dev In `BPS`, e.g. 1.2e18 = 120% collateral vs debt value.
/// @param collReqHard The collateral requirement where dipping below
/// this will cause a hard liquidation.
/// @dev In `BPS`, e.g. 1.1e18 = 110% collateral vs debt value.
/// @param liqIncBase The base ratio at which this token will be
/// compensated on soft liquidation.
/// @dev In `BPS`, stored as Incentive + BPS e.g. 1.05e18 = 5% incentive.
/// @param liqIncCurve The liquidation incentive curve length between
/// soft liquidation to hard liquidation.
/// e.g. 5% base incentive with 8% curve length results
/// in 13% liquidation incentive on hard liquidation.
/// @dev In `BPS`, e.g. 0.05e18 = 5% maximum additional incentive.
/// @param liqIncMin The minimum possible liquidation incentive for
/// during an auction.
/// @dev In `BPS`, stored as Incentive + BPS e.g. 1.03e18 = 3% incentive.
/// @param liqIncMax The maximum possible liquidation incentive for
/// during an auction.
/// @dev In `BPS`, stored as Incentive + BPS e.g. 1.07e18 = 7% incentive.
/// @param closeFactorBase Maximum % that a liquidator can repay when soft
/// liquidating an account.
/// @dev In `BPS` format, e.g. 0.1e18 = 10% base close factor.
/// @param closeFactorCurve Curve length between soft liquidation and hard
/// liquidation, should be equal to
/// 100% - `closeFactorBase`.
/// @dev In `BPS` format, e.g. 0.9e18 = 90% distance between
/// `closeFactorBase`, and 100%.
/// @param closeFactorMin The minimum possible close factor for during an
/// auction.
/// @dev In `BPS` format, e.g. 0.2e18 = 20% minimum close factor.
/// @param closeFactorMax The maximum possible close factor for during an
/// auction.
/// @dev In `BPS` format, e.g. 0.4e18 = 40% maximum close factor.
struct CurvanceToken {
bool isListed;
uint8 mintPaused;
uint8 collateralizationPaused;
uint8 borrowPaused;
uint24 collRatio;
uint24 collReqSoft;
uint24 collReqHard;
uint16 liqIncBase;
uint16 liqIncCurve;
uint16 liqIncMin;
uint16 liqIncMax;
uint16 closeFactorBase;
uint16 closeFactorCurve;
uint16 closeFactorMin;
uint16 closeFactorMax;
}
/// @notice Data structure containing information on hypothetical action
/// to execute.
/// @param cTokenModified The cToken to hypothetically redeem/borrow.
/// @param redemptionShares The number of tokens to hypothetically redeem,
/// in `shares`.
/// @param borrowAssets The amount of underlying to hypothetically borrow,
/// in `assets`.
/// @param errorCodeBreakpoint The error code that will cause liquidity
/// operations to revert. We reuse
/// `errorCodeBreakpoint` as a return variable
/// as a garbage collection flag to minimize
/// local variables.
struct HypotheticalAction {
address cTokenModified;
uint256 redemptionShares;
uint256 borrowAssets;
uint256 errorCodeBreakpoint;
}
/// @notice Data structure returned on liquidation threshold calculation
/// containing an accounts collateral values under specific
/// (soft liquidation versus hard liquidation) methodology
/// that will lead to liquidations.
/// @param cSoft The account's soft collateral value (collateral adjusted
/// by soft requirements).
/// @param cHard The account's hard collateral value (collateral adjusted
/// by hard requirements).
/// @param debt The account's total outstanding debt.
struct AccountLiqResult {
uint256 cSoft;
uint256 cHard;
uint256 debt;
}
/// @notice Data structure returned on querying a liquidation's current
/// configuration based on the auction liquidation system.
/// @param lFactor The liquidation factor for an account, indicating the
/// severity of a liquidation, between 0 and WAD.
/// @param debtBalance An account's outstanding debt to a cToken.
/// @param liqInc The ratio at which debt repayment will be compensated on
/// liquidation.
/// @param liqIncBase The base ratio at which this token will be
/// compensated on soft liquidation.
/// @param liqIncCurve The liquidation incentive curve length between soft
/// liquidation to hard liquidation.
/// @param closeFactor Maximum debt % that a liquidator can repay
/// during a liquidation of an account.
/// @param closeFactorBase Maximum % that a liquidator can repay when soft
/// liquidating an account.
/// @param closeFactorCurve Curve length between soft liquidation and hard
/// liquidation, should be equal to
/// 100% - `closeFactorBase`.
struct AccountLiqData {
uint256 lFactor;
uint256 debtBalance;
uint256 liqInc;
uint256 liqIncBase;
uint256 liqIncCurve;
uint256 closeFactor;
uint256 closeFactorBase;
uint256 closeFactorCurve;
}
/// @notice Data structure returned on querying a liquidation's current
/// configuration based on the aggregate liquidation system.
/// @param collateralToken The address of the Curvance token to be seized
/// during in the liquidation.
/// @param collateralExchangeRate The exchange rate of `collateralToken`'s
/// underlying token to the cToken itself.
/// @param collateralReqSoft The collateral requirement where dipping
/// below this will cause a soft liquidation.
/// @param collateralReqHard The collateral requirement where dipping
/// below this will cause a hard liquidation.
/// @param collateralSharesPrice The current price of `collateralToken`,
/// in `shares`.
/// @param collateralDecimals The decimals that `collateralToken` is
/// measured in.
/// @param debtToken The address of the Curvance token to be repaid during
/// the liquidation.
/// @param debtDecimals The decimals that `debtToken` is measured in.
/// @param debtUnderlyingPrice The current price of the underlying token
/// of `debtToken`, in `assets`.
/// @param auctionBuffer The current buffer that `cSoft` and `cHard` are
/// multiplied against, 10 bps, or 0 if not an
/// auction-based liquidation.
struct TokenLiqData {
address collateralToken;
uint256 collateralReqSoft;
uint256 collateralReqHard;
uint256 collateralSharesPrice;
uint256 collateralDecimals;
address debtToken;
uint256 debtDecimals;
uint256 debtUnderlyingPrice;
uint256 auctionBuffer;
}
/// CONSTANTS ///
/// @notice Maximum collateralization ratio, in `BPS`.
/// @dev 9750 = 97.50%.
/// ~40x leverage calculated from: 1 / (1 - Collateralization Ratio).
uint256 public constant MAX_COLL_RATIO_CORRELATED = 9750;
/// @notice Maximum collateralization ratio, in `BPS`.
/// @dev 9696 = 96.96%.
/// ~33x leverage calculated from: 1 / (1 - Collateralization Ratio).
uint256 public constant MAX_COLL_RATIO_UNCORRELATED = 9696;
/// @notice Buffer to ensure orderflow auction-based liquidations have
/// priority versus basic liquidations, for correlated assets,
/// in `BPS`.
/// @dev 9990 = 99.9%. Multiplied then divided by `BPS` = 10 bps buffer
/// auction liquidation priority for correlated assets.
uint256 public constant AUCTION_BUFFER_CORRELATED = 9990;
/// @notice Buffer to ensure orderflow auction-based liquidations have
/// priority versus basic liquidations, for uncorrelated assets,
/// in `BPS`.
/// @dev 9950 = 99.5%. Multiplied then divided by `BPS` = 50 bps buffer
/// auction liquidation priority for uncorrelated assets.
uint256 public constant AUCTION_BUFFER_UNCORRELATED = 9950;
/// @notice Minimum Liquidity buffer provided to maximally leveraged users
/// before a liquidation can occur. This value is adjusted by
/// `AUCTION_BUFFER` to calculate `MIN_LIQUIDATION_BUFFER_REQUIRED`
/// inside a market, in `BPS`.
/// @dev 9960 = 0.4% buffer. An additional 40 basis points buffer before a
/// liquidation can trigger (Then modified by `AUCTION_BUFFER`).
uint256 public constant EXTRA_BUFFER_BEFORE_LIQUIDATION = 9960;
/// @notice Enforced buffer provided to maximally leveraged users before a
/// liquidation can occur, stored in `BPS`^2.
/// @dev 99,500,000 = ~99.5% bps^2 = 0.5% buffer. An additional 50 basis
/// points buffer before a liquidation can trigger.
uint256 public immutable MIN_LIQUIDATION_BUFFER;
/// @notice Whether this market is for correlated assets or not, this
/// impacts auction buffer and maximum theoretical
/// collateralization ratio allowed.
bool public immutable IS_CORRELATED_ASSET_MARKET;
/// @notice Maximum collateralization ratio ratio allowed for any asset
/// inside this market, in `BPS`, e.g. 9696 = 96.96%, or ~33x
/// leverage calculated from: 1 / (1 - Collateralization Ratio).
uint256 public immutable MAX_COLL_RATIO;
/// @notice Buffer to ensure auction-based liquidations have priority
/// versus basic liquidations by multiplying a user's active
/// collateral $ value by `AUCTION_BUFFER` then dividing by `BPS`.
/// Denominated in `BPS`, e.g. 9990 = 99.9% -> 10 bps priority.
uint256 public immutable AUCTION_BUFFER;
/// @notice Minimum excess collateral requirement before soft liquidation
/// can occur, in `BPS`, e.g. 9950 = 99.5% -> 50 bps drop before a
/// liquidation can step in, used during `updateTokenConfig`.
uint256 public immutable MIN_LIQUIDATION_BUFFER_REQUIRED;
/// @notice Minimum loan size allowed inside Curvance that can be created
/// from a new line of credit inside a market.
/// @dev This restriction is to minimize the potential of debt positions
/// being created that cannot not be profitably closed.
uint256 public immutable MIN_LOAN_SIZE;
/// @notice Curvance DAO hub.
ICentralRegistry public immutable centralRegistry;
/// STORAGE ///
/// @notice Curvance token data including listing status,
/// action enablement, collateralization configuration,
/// and liquidation configuration.
/// @dev Curvance Token Address => CurvanceToken struct.
mapping(address => CurvanceToken) internal _tokenConfig;
// ACCOUNT LIQUIDITY DATA //
/// @notice Value that indicates whether an account has an
/// active position in the token.
/// @dev Curvance Token address => Account address => Active position
/// status. 0 or 1 for no; 2 for yes.
mapping(address => mapping(address => uint256)) public accountPositions;
/// @notice Assets and redemption cooldown data for an account.
/// @dev Account => AccountData struct.
mapping(address => AccountData) public accountAssets;
/// ERRORS ///
error LiquidityManager__InsufficientLoanSize();
error LiquidityManager__PriceError();
/// @param cr The address of the Protocol Central Registry.
/// @param minLoanSize The minimum active loan size for this isolated
/// market, must be between $10 - $100 in `WAD`.
/// @param isCorrelatedMarket Whether this market is for correlated assets
/// or not, this impacts auction buffer and
/// maximum theoretical collateralization
/// ratio allowed.
constructor(
ICentralRegistry cr,
uint256 minLoanSize,
bool isCorrelatedMarket
) {
if (minLoanSize < 10e18 || minLoanSize > 100e18) {
revert LiquidityManager__InsufficientLoanSize();
}
CentralRegistryLib._isCentralRegistry(cr);
centralRegistry = cr;
MIN_LOAN_SIZE = minLoanSize;
IS_CORRELATED_ASSET_MARKET = isCorrelatedMarket;
MAX_COLL_RATIO = isCorrelatedMarket ?
MAX_COLL_RATIO_CORRELATED :
MAX_COLL_RATIO_UNCORRELATED;
AUCTION_BUFFER = isCorrelatedMarket ? AUCTION_BUFFER_CORRELATED :
AUCTION_BUFFER_UNCORRELATED;
// Calculates the minimum liquidation buffer the market needs to give
// users before liquidation. E.g. 9960 extra buffer * 10 bps auction
// buffer = 9960 * 9990 = 99.5 bps^2 or ~50 bps buffer from max
// leverage to liquidation.
MIN_LIQUIDATION_BUFFER =
EXTRA_BUFFER_BEFORE_LIQUIDATION * AUCTION_BUFFER;
}
/// @notice Determine `account`'s current status between collateral,
/// debt, and additional liquidity.
/// @param account The account to determine liquidity for.
/// @return collateral Total value of `account`'s collateral across
/// all positions.
/// @return maxDebt The maximum amount of debt `account`
/// could take on based on `collateral`.
/// @return debt Total value of `account`'s current outstanding
/// debt across all positions.
function _statusOf(address account) internal returns (
uint256 collateral,
uint256 maxDebt,
uint256 debt
) {
(
AccountSnapshot[] memory snapshots,
uint256[] memory prices,
uint256 numAssets
) = _assetDataOf(account, BAD_SOURCE);
AccountSnapshot memory snap;
for (uint256 i; i < numAssets; ++i) {
snap = snapshots[i];
if (snap.isCollateral) {
uint256 collateralValue = _assetValue(
snap.collateralPosted,
prices[i],
10 ** snap.decimals,
true
);
collateral += collateralValue;
maxDebt += _mulDiv(
collateralValue,
_tokenConfig[snap.asset].collRatio,
BPS
);
} else {
// If they have a debt balance, increment their debt.
if (snap.debtBalance > 0) {
debt += _assetValue(
snap.debtBalance,
prices[i],
10 ** snap.decimals,
false
);
}
}
}
}
/// @notice Calculates hypothetical liquidity for an account after a
/// potential action such as redemption and borrowing.
/// @param account The address of the account being evaluated for `action`
/// being done.
/// @param action Instructions for a hypothetical action containing:
/// cTokenModified The address of the token being modified
/// by the action.
/// redemptionShares The amount of tokens to hypothetically
/// redeem, in `shares`.
/// borrowAssets The amount of underlying to hypothetically
/// borrow, in `assets`.
/// errorCodeBreakpoint The error code that will cause
/// liquidity operations to revert.
/// @return uint256 Excess collateral capacity after the action.
/// uint256 Shortfall in collateral capacity after the action.
function _hypotheticalLiquidityOf(
address account,
HypotheticalAction memory action
) internal returns (uint256, uint256) {
(
AccountSnapshot[] memory snapshots,
uint256[] memory prices,
uint256 numAssets
) = _assetDataOf(account, action.errorCodeBreakpoint);
AccountSnapshot memory snap;
uint256 maxDebt;
uint256 newDebt;
for (uint256 i; i < numAssets; ++i) {
snap = snapshots[i];
// Generally `isCollateral` tells us if an entry is collateral or
// debt, but, on a fresh borrow position snapshot misreports
// `isCollateral` as true until its action is fully processed
// because debtBalance still equals 0 at getSnapshotUpdated level.
if (
action.cTokenModified == snap.asset && snap.isCollateral &&
action.borrowAssets > 0
) {
uint256 errorCode;
(prices[i], errorCode) =
CommonLib._oracleManager(centralRegistry).
getPrice(snap.underlying, true, false);
if (errorCode >= action.errorCodeBreakpoint) {
revert LiquidityManager__PriceError();
}
// Adjust `isCollateral` to be false since this is a debt
// entry not a collateral entry.
delete snap.isCollateral;
}
if (snap.isCollateral) {
// If the user is redeeming collateral, offset their
// collateral posted.
if (action.cTokenModified == snap.asset) {
snap.collateralPosted -= action.redemptionShares;
}
// CASE: There is no collateral posted. Either the position
// will be closed through a full redemption, or the user
// already had their position closed via liquidation.
if (snap.collateralPosted > 0) {
// CASE: There is collateral posted in this cToken,
// the user can take on more debt from lenders.
maxDebt += _mulDiv(
_assetValue(
snap.collateralPosted,
prices[i],
10 ** snap.decimals,
true
),
_tokenConfig[snap.asset].collRatio,
BPS
);
}
} else {
if (action.cTokenModified == snap.asset) {
snap.debtBalance += action.borrowAssets;
}
// CASE: There is no outstanding debt, clean up the position
// entry as the user was liquidated, otherwise add to the
// user's outstanding debt.
if (snap.debtBalance > 0) {
// CASE: There is outstanding debt to lenders, add it to
// `newDebt` to check against `maxDebt`.
newDebt += _assetValue(
snap.debtBalance,
prices[i],
10 ** snap.decimals,
false
);
// Check `newDebt` to make sure the loan size will not be
// too small for us to allow issuing the loan.
if (newDebt < MIN_LOAN_SIZE) {
revert LiquidityManager__InsufficientLoanSize();
}
}
}
}
// Returns excess liquidity on hypothetical positions.
if (maxDebt > newDebt) {
return (maxDebt - newDebt, 0);
}
// Returns shortfall on hypothetical positions.
return (0, newDebt - maxDebt);
}
/// @notice Evaluates an account's collateral and debt positions to
/// determine liquidation factor using cached data.
/// @param account The address of the account being evaluated for
/// liquidation.
/// @param tData A TokenLiqData struct containing:
/// collateralToken The token which is used as collateral
/// by `account` and may be seized.
/// collateralExchangeRate The exchange rate of
/// `collateralToken` underlying token
/// to `collateralToken`.
/// collateralReqSoft The collateral requirement where
/// dipping below this will cause a soft
/// liquidation.
/// collateralReqHard The collateral requirement where
/// dipping below this will cause a hard
/// liquidation.
/// collateralUnderlyingPrice The current price of the
/// underlying token of
/// `collateralToken`.
/// collateralDecimals The decimals that `collateralToken`
/// is measured in.
/// debtToken The token to potentially repay which has
/// outstanding debt by `account`.
/// debtDecimals The decimals that `debtToken` is measured
/// in.
/// debtUnderlyingPrice The current price of the underlying
/// token of `debtToken`.
/// auctionBuffer The current buffer that `cSoft` and `cHard`
/// are multiplied against, 10 bps, or 0 if not
/// an auction-based liquidation.
/// @return lFactor The liquidation factor where:
/// 0: No liquidation (account is healthy).
/// 1 to WAD - 1: Soft liquidation (partial liquidation
/// allowed).
/// WAD: Hard liquidation (full liquidation, possibly
/// including bad debt).
/// @return debt The current debt position in `liqData.debtToken` for
/// `account`.
function _liquidationValuesOf(
address account,
TokenLiqData memory tData
) internal view returns (uint256 lFactor, uint256 debt) {
AccountLiqResult memory r;
address[] memory assets = accountAssets[account].assets;
address asset;
uint256 numAssets = assets.length;
for (uint256 i; i < numAssets; ) {
asset = assets[i++];
if (asset == tData.collateralToken) {
(r.cSoft, r.cHard) = _addLiquidationValues(
tData.collateralDecimals,
tData.collateralReqSoft,
tData.collateralReqHard,
tData.collateralSharesPrice,
ICToken(tData.collateralToken).collateralPosted(account),
r.cSoft,
r.cHard
);
} else {
// If the asset is not `collateralToken`, the asset must
// be the `debtToken` debt position because this market
// only has two tokens.
debt =
IBorrowableCToken(tData.debtToken).debtBalance(account);
// If they have a debt balance, document additional
// collateral requirements.
if (debt > 0) {
r.debt += _assetValue(
debt,
tData.debtUnderlyingPrice,
tData.debtDecimals,
false
);
}
}
}
// If this is a potential liquidation from an auction, apply the
// auction buffer to collateral values, discounting collateral values.
if (tData.auctionBuffer != 0) {
r.cSoft = _mulDiv(r.cSoft, tData.auctionBuffer, BPS);
r.cHard = _mulDiv(r.cHard, tData.auctionBuffer, BPS);
}
// Get `account` lFactor.
if (r.cSoft >= r.debt) {
// Indicates no liquidation.
lFactor = 0;
} else {
lFactor = r.debt >= r.cHard ? WAD // Indicates hard liquidation.
// Indicates soft liquidation, we round up here in favor of the
// protocol, we know that we wont run into a value > WAD due to
// cHard being at least 1 higher than debt.
: FixedPointMathLib.mulDivUp(r.debt - r.cSoft, WAD, r.cHard - r.cSoft);
}
}
/// @notice Retrieves the prices and account data of multiple assets
/// inside this market.
/// @param account The account to retrieve data for.
/// @param errorCodeBreakpoint The error code that will cause liquidity
/// operations to revert.
/// @return Assets data for `account`.
/// @return Prices for `account` assets.
/// @return The number of assets `account` is in.
function _assetDataOf(address account, uint256 errorCodeBreakpoint)
internal
returns (AccountSnapshot[] memory, uint256[] memory, uint256) {
return CommonLib._oracleManager(centralRegistry).getPricesForMarket(
account,
accountAssets[account].assets,
errorCodeBreakpoint
);
}
/// @notice Calculates an assets value based on its `price`,
/// `amount`, and adjusts for decimals.
/// @param amount The asset amount to calculate asset value from.
/// @param price The asset price to calculate asset value from, in `WAD`.
/// @param decimals The asset decimals to adjust asset value
/// into proper form.
/// @param increasesCollateral Whether the asset adds positive value or
/// not to the liquidity check, we round down when increasing
/// collateral value and round up when increasing collateral
/// value/increasing debt.
/// @return The calculated asset value.
function _assetValue(
uint256 amount,
uint256 price,
uint256 decimals,
bool increasesCollateral
) internal pure returns (uint256) {
if (increasesCollateral) {
return _mulDiv(amount, price, decimals);
}
return FixedPointMathLib.mulDivUp(amount, price, decimals);
}
/// @notice Calculates and adds soft and hard collateral values for
/// liquidation assessment with cached data.
/// @param decimals The number of decimals for the collateral token.
/// @param collReqSoft The soft collateral requirement ratio, in WAD.
/// @param collReqHard The hard collateral requirement ratio, in WAD.
/// @param price The price of the underlying asset, in `WAD`.
/// @param collateralPosted The amount of collateral token posted as
/// collateral by the account.
/// @param softSumPrior The previous sum of soft collateral values.
/// @param hardSumPrior The previous sum of hard collateral values.
/// @return softSum The updated sum of soft collateral values.
/// @return hardSum The updated sum of hard collateral values.
function _addLiquidationValues(
uint256 decimals,
uint256 collReqSoft,
uint256 collReqHard,
uint256 price,
uint256 collateralPosted,
uint256 softSumPrior,
uint256 hardSumPrior
) internal pure returns (uint256 softSum, uint256 hardSum) {
uint256 assetValue = _assetValue(
collateralPosted,
price,
decimals,
true
) * BPS;
softSum = softSumPrior + (assetValue / collReqSoft);
hardSum = hardSumPrior + (assetValue / collReqHard);
}
/// @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);
}
/// @dev Internal helper for reverting efficiently.
function _revert(uint256 s) internal pure {
/// @solidity memory-safe-assembly
assembly {
mstore(0x00, s)
revert(0x1c, 0x04)
}
}
}
// contracts/market/isolated/MarketManagerIsolated.sol
/// @title Curvance DAO Market Manager.
/// @notice Manages risk within the Curvance DAO markets.
/// @dev Curvance Market Managers are built as "thesis driven" micro
/// ecosystems. This means that a market may be focused specifically
/// on interest-bearing stablecoins, or bluechip long market exposure,
/// volatile LP tokens for a particular dex or perpetual platform. This
/// minimizes systemic risk by having many market managers with unique
/// opportunities and risk profiles.
///
/// All management of token actions are managed by the Market Manager.
/// These tokens are collectively referred to as Curvance tokens,
/// or cTokens. Each market has a maximum number of supportable assets
/// this is to minimize systemic risk and gas costs on liquidity checks.
///
/// Curvance offers the ability to store unlimited tokens inside Curvance
/// token contracts while restricting the scale of exogenous risk.
/// Every collateral asset has a "Collateral Cap", measured in shares.
/// As collateral is posted, the `collateralPosted` invariant increases,
/// and is compared to `collateralCaps`. By measuring collateral posted
/// in shares, this allows collateral caps to grow proportionally with
/// any auto compounding mechanism strategy attached to the token.
///
/// It is important to note that, in theory, collateral caps can be
/// decreased below current market collateral posted levels. This would
/// restrict the addition of new exogenous risk being added to the
/// system, but will not result in forced unwinding of user positions.
///
/// Curvance also employs a 20-minute minimum duration of posting of
/// collateral and borrowing of tokens. This restriction improves
/// the security model of Curvance and allows for more advanced
/// interest rate methodology.
///
/// Additionally, a new "Dynamic Liquidation Engine" or DLE
/// allows for more nuanced position management inside the system.
/// The DLE facilitates aggressive asset support and elevated
/// collateralization ratios paired with reduced minimum liquidation
/// penalties. In periods of low volatility, users will experience soft
/// liquidations. But, when volatility is elevated, users may experience
/// more aggressive or complete liquidation of positions.
///
/// Bad debt is minimized via a "Bad Debt Socialization" system.
/// When a user's debt is greater than their collateral assets,
/// the entire user's account can be liquidated with lenders paying any
/// collateral shortfall.
///
contract MarketManagerIsolated is
LiquidityManagerIsolated,
IMarketManager,
ERC165,
Multicall
{
/// TYPES ///
struct TokenConfig {
address cToken;
uint256 collRatio;
uint256 collReqSoft;
uint256 collReqHard;
uint256 liqIncBase;
uint256 liqIncHard;
uint256 liqIncMin;
uint256 liqIncMax;
uint256 closeFactorBase;
uint256 closeFactorMin;
uint256 closeFactorMax;
uint256 collateralCap;
uint256 debtCap;
}
/// CONSTANTS ///
/// @notice Maximum collateral requirement to avoid liquidation, in `BPS`.
/// @dev 23400 = 234%. Resulting in 1 / (BPS + 2.34 BPS),
/// or ~30% maximum LTV soft liquidation level.
uint256 public constant MAX_COLLATERAL_REQUIREMENT = 23400;
/// @notice Minimum excess collateral requirement on top of liquidation
/// incentives, in `BPS`.
/// @dev 100 = 1.0%.
uint256 public constant MIN_EXCESS_COLL_REQUIRED = 100;
/// @notice Minimum excess collateral requirement before soft liquidation
/// can occur, in `BPS`.
/// @notice The maximum liquidation incentive, in `BPS`.
/// @dev 3000 = 30%.
uint256 public constant MAX_LIQUIDATION_INCENTIVE = 3000;
/// @notice The maximum base cFactor, in `BPS`.
/// @dev 5000 = 50%. NOTE: This can NEVER be changed to 100% or offchain
/// parameters can be unintentionally ignored.
uint256 public constant MAX_BASE_CFACTOR = 5000;
/// @notice The minimum base cFactor, in `BPS`.
/// @dev 1000 = 10%.
uint256 public constant MIN_BASE_CFACTOR = 1000;
/// @notice Minimum hold time to minimize external risks, in seconds.
/// @dev 20 minutes = 1,200 seconds.
/// The 20 minute holding period is intentionally set so that every
/// borrower experiences a minimum 2 interest rate adjustments from a
/// standard borrow action (10 minute interest rate adjustment rate).
uint256 public constant MIN_HOLD_PERIOD = 20 minutes;
/// @dev Limit for market debt cap to max sure outstanding user debt
/// never overflows `outstandingDebt` value inside _debtOf.
uint256 internal constant _MAX_DEBT_CAP = type(uint136).max;
/// @dev `bytes4(keccak256(bytes("MarketManager__InvalidParameter()")))`
uint256 internal constant _INVALID_PARAMETER_SELECTOR = 0x65513fc1;
/// @dev `bytes4(keccak256(bytes("MarketManager__Unauthorized()")))`
uint256 internal constant _UNAUTHORIZED_SELECTOR = 0x37cf6ad5;
/// @dev `bytes4(keccak256(bytes("MarketManager__InvariantError()")))`
uint256 internal constant _INVARIANT_ERROR_SELECTOR = 0x5518d5cb;
/// @dev A fixed key to use in transient storage for offchain liquidation
/// configuration.
/// Key value = `uint256(keccak256(_TRANSIENT_LIQUIDATION_CONFIG_KEY))`.
/// Bits Layout:
/// - [0..159] `COLLATERAL_UNLOCKED`.
/// - [160..175] `LIQ_INCENTIVE`.
/// - [176..191] `CLOSE_FACTOR`.
uint256 internal constant _TRANSIENT_LIQUIDATION_CONFIG_KEY
= 0x1966ec4daf81281b2aba49348128e9b155301b8486bde131e0db16a52b730b82;
uint256 internal constant _BITMASK_COLLATERAL_UNLOCKED = (1 << 160) - 1;
/// @dev The bit position of `LIQ_INCENTIVE` in
/// `_TRANSIENT_LIQUIDATION_CONFIG_KEY`.
uint256 internal constant _BITPOS_LIQ_INCENTIVE = 160;
/// @dev The bit position of `CLOSE_FACTOR` in
/// `_TRANSIENT_LIQUIDATION_CONFIG_KEY`.
uint256 internal constant _BITPOS_CLOSE_FACTOR = 176;
/// STORAGE ///
/// @notice A list of all tokens inside this market for
/// offchain querying.
address[] public tokensListed;
/// MARKET STATE
/// @notice Whether market-wide liquidations are paused.
/// @dev 1 = unpaused; 2 = paused.
uint8 public liquidationPaused = 1;
/// @notice Whether market-wide token redemptions are paused.
/// @dev 1 = unpaused; 2 = paused.
uint8 public redeemPaused = 1;
/// @notice Whether market-wide token transfers are paused.
/// @dev 1 = unpaused; 2 = paused.
uint8 public transferPaused = 1;
/// @notice The total amount of `cToken` that can be posted as collateral,
/// in shares.
/// @dev Token Address => Market-wide Collateral Cap, in shares.
mapping(address => uint256) public collateralCaps;
/// @notice The total amount of `cToken` underlying that can be borrowed,
/// in assets.
/// @dev Token Address => Market-wide Debt Cap, in assets.
mapping(address => uint256) public debtCaps;
/// @notice Whether an address is an authorized position manager or not.
/// @dev Address => Is an approved position management operator.
mapping(address => bool) public isPositionManager;
/// EVENTS ///
event PositionUpdated(address cToken, address account, bool open);
event TokenListed(address cToken);
event TokenConfigUpdated(TokenConfig config);
event PositionManagerUpdated(address positionManager, bool addPerms);
event ActionPaused(string action, bool pauseState);
event TokenActionPaused(address cToken, string action, bool pauseState);
/// ERRORS ///
error MarketManager__Unauthorized();
error MarketManager__UnauthorizedLiquidation();
error MarketManager__TokenNotListed();
error MarketManager__Paused();
error MarketManager__InsufficientCollateral();
error MarketManager__NoLiquidationAvailable();
error MarketManager__PriceError();
error MarketManager__CapReached();
error MarketManager__MarketManagerMismatch();
error MarketManager__InvalidParameter();
error MarketManager__MinimumHoldPeriod();
error MarketManager__InvariantError();
/// CONSTRUCTOR ///
/// @param cr The address of the Protocol Central Registry.
/// @param minLoanSize The minimum active loan size for this isolated
/// market (must be between $10-$100 in WAD).
/// @param isCorrelatedMarket Whether this market is for correlated assets
/// or not, this impacts auction buffer and
/// maximum theoretical collateralization
/// ratio allowed.
constructor(
ICentralRegistry cr,
uint256 minLoanSize,
bool isCorrelatedMarket
) LiquidityManagerIsolated(cr, minLoanSize, isCorrelatedMarket) {}
/// EXTERNAL FUNCTIONS ///
/// @notice Returns whether `cToken` is listed in the lending market.
/// @param cToken The address of a token to check for listing status.
/// @return result Whether `cToken` is listed inside this lending market
/// or not.
function isListed(address cToken) external view returns (bool result) {
result = _tokenConfig[cToken].isListed;
}
/// @notice Returns whether minting, collateralization, borrowing of
/// `cToken` is disabled.
/// @param cToken The address of the Curvance token to return
/// action statuses of.
/// @return mintPaused Whether minting `cToken` is paused or not.
/// @return collateralizationPaused Whether collateralization `cToken`
/// is paused or not.
/// @return borrowPaused Whether borrowing `cToken` is paused or not.
function actionsPaused(address cToken) external view returns (
bool mintPaused,
bool collateralizationPaused,
bool borrowPaused
) {
CurvanceToken storage c = _tokenConfig[cToken];
mintPaused = c.mintPaused == 2;
collateralizationPaused = c.collateralizationPaused == 2;
borrowPaused = c.borrowPaused == 2;
}
/// @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, in `BPS`.
/// @return The collateral requirement where dipping below this
/// will cause a soft liquidation, in `BPS`.
/// @return The collateral requirement where dipping below
/// this will cause a hard liquidation, in `BPS`.
function collConfig(address cToken) external view returns (
uint256, uint256, uint256
) {
CurvanceToken storage c = _tokenConfig[cToken];
return (c.collRatio, c.collReqSoft, c.collReqHard);
}
/// @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 `BPS`. 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 `BPS`.
/// @return The maximum possible liquidation incentive for during an
/// auction, in `BPS`.
/// @return Maximum % that a liquidator can repay when soft
/// liquidating an account, in `BPS`.
/// @return Curve length between soft liquidation and hard liquidation,
/// should be equal to 100% - `closeFactorBase`, in `BPS`.
/// @return The minimum possible close factor for during an auction,
/// in `BPS`.
/// @return The maximum possible close factor for during an auction,
/// in `BPS`.
function liquidationConfig(address cToken) external view returns (
uint256, uint256, uint256, uint256, uint256, uint256, uint256, uint256
) {
CurvanceToken storage c = _tokenConfig[cToken];
return (
c.liqIncBase,
c.liqIncCurve,
c.liqIncMin,
c.liqIncMax,
c.closeFactorBase,
c.closeFactorCurve,
c.closeFactorMin,
c.closeFactorMax
);
}
/// @notice Helper function for querying the current Curvance tokens listed
/// inside this market.
/// @return r Array containing list of all Curvance token addresses
/// listed in this market.
function queryTokensListed() external view returns (address[] memory r) {
r = tokensListed;
}
/// ACCOUNT SPECIFIC FUNCTIONS ///
/// @notice Returns the assets `account` has an open position in.
/// @param account The address of the account to pull assets for.
/// @return result An array containing the assets `account` has
/// positions in.
function assetsOf(
address account
) external view returns (address[] memory result) {
result = accountAssets[account].assets;
}
/// @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) {
return _statusOf(account);
}
/// @notice Checks if the account should be allowed to mint tokens
/// in the given market.
/// @param cToken The Curvance token to verify mintability of.
function canMint(address cToken) external view virtual {
if (_tokenConfig[cToken].mintPaused == 2) {
revert MarketManager__Paused();
}
_checkIsListedToken(cToken);
}
/// @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 collateralToken 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 collateralToken,
address account,
uint256 newNetCollateral
) external {
_checkIsToken(collateralToken);
// Can skip token listing check since collateralCaps[collateralToken]
// can only be set above 0 if `debtToken` is listed already, so we
// only need to check that `newNetCollateral` != 0 instead, which
// should be impossible but only costs 2 gas.
/// @solidity memory-safe-assembly
assembly {
if iszero(newNetCollateral) {
mstore(0x00, _INVARIANT_ERROR_SELECTOR)
// Return bytes 29-32 for the selector.
revert(0x1c, 0x04)
}
}
if (_tokenConfig[collateralToken].collateralizationPaused == 2) {
revert MarketManager__Paused();
}
// This also acts as a check that collateralization ratio is > 0,
// since collateralCaps can only be raised above zero if the
// its collateralization ratio is > 0.
if (newNetCollateral > collateralCaps[collateralToken]) {
revert MarketManager__CapReached();
}
// On collateral posting:
// We need to flip their cooldown flag to prevent flashloan attacks.
accountAssets[account].cooldownTimestamp = block.timestamp;
// If `account` does not have a position in `collateralToken`,
// open one.
if (accountPositions[collateralToken][account] != 2) {
accountPositions[collateralToken][account] = 2;
accountAssets[account].assets.push(collateralToken);
emit PositionUpdated(collateralToken, account, true);
}
}
/// @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.
/// @return collateralRedeemed The amount of collateral shares redeemed.
function canRedeemWithCollateralRemoval(
address cToken,
uint256 shares,
address account,
uint256 balanceOf,
uint256 collateralPosted,
bool forceRedeemCollateral
) external returns (uint256 collateralRedeemed) {
_checkIsToken(cToken);
if (redeemPaused == 2) {
revert MarketManager__Paused();
}
collateralRedeemed = _canRedeem(
cToken,
shares,
account,
balanceOf,
collateralPosted,
true,
forceRedeemCollateral
);
}
/// @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 the 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 {
_canBorrow(cToken, assets, account, newNetDebt);
}
/// @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 token to verify borrowability of.
/// @param assets The amount of underlying the 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 {
accountAssets[account].cooldownTimestamp = block.timestamp;
_canBorrow(cToken, assets, account, newNetDebt);
}
/// @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 cToken that the account is borrowing.
/// @param account The address of the account that has just borrowed.
function notifyBorrow(address cToken, address account) external {
_checkIsToken(cToken);
_checkIsListedToken(cToken);
accountAssets[account].cooldownTimestamp = block.timestamp;
}
/// @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 {
_checkIsToken(cToken);
_checkIsListedToken(cToken);
_checkHoldPeriod(account);
// Validate `account` actually has a debt position in `cToken`.
if (accountPositions[cToken][account] != 2) {
_revert(_INVALID_PARAMETER_SELECTOR);
}
// If `account` is fully repaying their debt, we can skip loan size
// check.
if (newNetDebt == 0) {
return;
}
// We round down to favor the protocol here even though typically
// we use !getLower for debt.
(uint256 price, uint256 errorCode) =
CommonLib._oracleManager(centralRegistry)
.getPrice(debtAsset, true, true);
// If there an issue pricing we should bubble up an error since we
// cannot validate the loan size.
if (errorCode != NO_ERROR) {
revert MarketManager__PriceError();
}
// Check `account`'s new debt position in $ and review if the loan
// size is too small for us to allow issuing the loan.
if (
_assetValue(newNetDebt, price, 10 ** decimals, true) <
MIN_LOAN_SIZE
) {
revert LiquidityManager__InsufficientLoanSize();
}
}
/// @notice Validates and processes batch liquidations for multiple
/// accounts, calculating collateral seizure amounts, debt
/// repayment, and bad debt based on account health and market
/// parameters.
/// @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 Instructions for a liquidation action 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.
/// liquidatedShares 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 Hypothetical results for an action 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 (
IMarketManager.LiqResult memory result,
uint256[] memory
) {
if (liquidationPaused == 2) {
revert MarketManager__Paused();
}
_checkIsToken(action.debtToken);
_checkIsListedToken(action.collateralToken);
_checkIsListedToken(action.debtToken);
(TokenLiqData memory tData, AccountLiqData memory aData) =
_getLiquidationConfig(action.collateralToken, action.debtToken);
// Amounts array is empty since the max amount possible
// will be liquidated.
result.liquidatedShares = new uint256[](action.numAccounts);
address cachedAccount;
address priorAccount;
for (uint256 i; i < action.numAccounts; ++i) {
cachedAccount = accounts[i];
// Do not let an account liquidate themselves.
if (liquidator == cachedAccount) {
_revert(_UNAUTHORIZED_SELECTOR);
}
// Liquidators MUST sort the token addresses offchain from
// smallest to largest to validate there are no duplicate
// liquidations.
if (priorAccount >= cachedAccount) {
_revert(_UNAUTHORIZED_SELECTOR);
}
(
action.liquidatedShares,
action.debtRepaid,
action.badDebt
) = _canLiquidate(
debtAmounts[i],
cachedAccount,
tData,
aData,
action.liquidateExact
);
// We optimistically update values even if they are setting from
// 0 -> 0 to act as an invariant check for the sum of all debt
// values in `debtAmounts` equal to `debtRepaid`.
result.debtRepaid += action.debtRepaid;
result.liquidatedShares[i] = action.liquidatedShares;
if (action.badDebt > 0) {
result.badDebtRealized += action.badDebt;
// Add the bad debt to debt to remove from the liquidated
// account.
action.debtRepaid += action.badDebt;
}
// If its an exact liquidation this will be a redundant setter
// but anticipation is majority of liquidators will use
// non-exact so checking for liquidateExact each time is a
// waste.
debtAmounts[i] = action.debtRepaid;
// Update prior account to current account.
priorAccount = cachedAccount;
}
// If theres no debt to repay then there were no liquidations.
if (result.debtRepaid == 0) {
revert MarketManager__NoLiquidationAvailable();
}
return (result, debtAmounts);
}
/// @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 view {
_checkIsListedToken(collateralToken);
_checkIsListedToken(debtToken);
if (
ICToken(collateralToken).marketManager() !=
ICToken(debtToken).marketManager()
) {
revert MarketManager__MarketManagerMismatch();
}
}
/// @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.
/// @return collateralRedeemed The amount of collateral shares redeemed
/// on transfer.
function canTransfer(
address cToken,
uint256 shares,
address account,
uint256 balanceOf,
uint256 collateralPosted,
bool isCollateral
) external returns (uint256 collateralRedeemed) {
_checkIsToken(cToken);
if (transferPaused == 2) {
revert MarketManager__Paused();
}
collateralRedeemed = _canRedeem(
cToken,
shares,
account,
balanceOf,
collateralPosted,
isCollateral,
false
);
}
/// PERMISSIONED EXTERNAL FUNCTIONS ///
/// @notice List isolated Curvance token pair to the market and enable
/// deposits.
/// @dev Admin function to set isListed for token pair and add support
/// for the market. Only callable once due to isolated market design.
/// Emits {TokenListed} event twice.
/// @param token0 The address of the first Curvance token to list in this
/// isolated market.
/// @param token1 The address of the second Curvance token to list in this
/// isolated market.
function listTokens(address token0, address token1) external {
_checkMarketPermissions();
// The same token cannot be listed twice in a market.
if (token0 == token1) {
_revert(_INVALID_PARAMETER_SELECTOR);
}
// The same underlying asset cannot be listed twice in a market.
if (ICToken(token0).asset() == ICToken(token1).asset()) {
_revert(_INVALID_PARAMETER_SELECTOR);
}
// Validate that tokens are not already listed inside this market.
if (tokensListed.length != 0) {
_revert(_INVALID_PARAMETER_SELECTOR);
}
// At least one of the two tokens has to be borrowable or the
// market does not make any sense to create.
if (!ICToken(token0).isBorrowable() && !ICToken(token1).isBorrowable()) {
_revert(_INVALID_PARAMETER_SELECTOR);
}
// List the tokens, we do this prior since some _afterDeposit
// hooks could require listing.
_tokenConfig[token0].isListed = true;
_tokenConfig[token1].isListed = true;
// Immediately deposits into the cToken before anyone else can,
// preventing any rounding attack vectors.
if (!ICToken(token0).initializeDeposits(msg.sender)) {
_revert(_INVARIANT_ERROR_SELECTOR);
}
if (!ICToken(token1).initializeDeposits(msg.sender)) {
_revert(_INVARIANT_ERROR_SELECTOR);
}
// Update `tokenListed` array and emit events for any frontends that
// need this information.
tokensListed.push(token0);
tokensListed.push(token1);
emit TokenListed(token0);
emit TokenListed(token1);
}
/// @notice Sets token liquidity configuration values for
/// `newConfig.cToken` a listed cToken inside this market.
/// @dev Emits a {TokenConfigUpdated} event.
/// @param newConfig A TokenConfig struct containing:
/// cToken The Curvance token to update liquidity
/// configuration values of.
/// collRatio The ratio at which $1 of collateral can be
/// borrowed against, for `newConfig.cToken`,
/// in `BPS`.
/// collReqSoft The premium of excess collateral required
/// to avoid soft liquidation, in `BPS`.
/// collReqHard The premium of excess collateral required
/// to avoid hard liquidation, in `BPS`.
/// liqIncBase The default liquidation incentive for
/// `newConfig.cToken`, in `BPS`.
/// liqIncHard The hard liquidation incentive for
/// `newConfig.cToken`, in `BPS`.
/// liqIncMin The minimum possible liquidation incentive
/// for `newConfig.cToken` during an auction,
/// in `BPS`.
/// liqIncMax The maximum possible liquidation incentive
/// for `newConfig.cToken` during an auction,
/// in `BPS`.
/// closeFactorBase Maximum % that a liquidator can repay
/// when soft liquidating
/// `newConfig.cToken` for an account.
/// closeFactorMin The minimum possible close factor for
/// `newConfig.cToken` during an auction,
/// in `BPS`.
/// closeFactorMax The maximum possible close factor for
/// `newConfig.cToken` during an auction,
/// in `BPS`.
/// collateralCap The maximum amount of shares that can
/// be collateralized of `newConfig.cToken`
/// inside this market.
/// debtCap The maximum amount of assets that can be
/// borrowed of `newConfig.cToken` inside this
/// market.
function updateTokenConfig(TokenConfig memory newConfig) external {
_checkIsListedToken(newConfig.cToken);
_checkMarketPermissions();
// Validate collateralization ratio is not above the maximum allowed,
// and that hard liquidation collateral requirement is not above
// the soft liquidation requirement. Liquidations occur when
// collateral dries up so hard liquidation should be less collateral
// than soft liquidation.
if (
newConfig.collRatio > MAX_COLL_RATIO ||
newConfig.collReqSoft > MAX_COLLATERAL_REQUIREMENT ||
newConfig.collReqHard >= newConfig.collReqSoft
) {
_revert(_INVALID_PARAMETER_SELECTOR);
}
// Validate hard liquidation incentive is higher than the soft
// liquidation incentive. We should give heavier incentives when
// collateral is running out to reduce lender delta exposure.
// The maximum dynamic penalty is not greater than the base
// liquidation incentive and that the minimum dynamic penalty is not
// less than the base liquidation incentive.
// Validate maximum liquidation incentive and default is
// equal or higher than the minimum liquidation incentive.
// Validate minimum liquidation incentive is non-zero to ensure
// liquidators have economic incentive to perform liquidations.
// Validate both hard and max liquidation incentives do not exceed
// the protocol maximum.
if (
newConfig.liqIncBase >= newConfig.liqIncHard ||
newConfig.liqIncBase > newConfig.liqIncMax ||
newConfig.liqIncBase < newConfig.liqIncMin ||
newConfig.liqIncMin >= newConfig.liqIncMax ||
newConfig.liqIncMax > MAX_LIQUIDATION_INCENTIVE ||
newConfig.liqIncMin == 0 ||
newConfig.liqIncHard > MAX_LIQUIDATION_INCENTIVE
) {
_revert(_INVALID_PARAMETER_SELECTOR);
}
// Validate hard and max liquidation collateral requirements are larger
// than the hard liquidation incentive. We cannot give more incentives
// than are available. We do not need to check soft liquidation as the
// restrictions are thinner than this case.
if (
newConfig.liqIncHard + MIN_EXCESS_COLL_REQUIRED > newConfig.collReqHard ||
newConfig.liqIncMax + MIN_EXCESS_COLL_REQUIRED > newConfig.collReqHard
) {
_revert(_INVALID_PARAMETER_SELECTOR);
}
// Validate that soft liquidation is within acceptable bounds.
if (
newConfig.closeFactorBase > MAX_BASE_CFACTOR ||
newConfig.closeFactorBase < MIN_BASE_CFACTOR
) {
_revert(_INVALID_PARAMETER_SELECTOR);
}
// Validate closeFactorMin and closeFactorMax are properly configured.
// closeFactorBase should be between min and max, min should be less
// than max, but greater than 0, and max cannot exceed BPS.
if (
newConfig.closeFactorBase > newConfig.closeFactorMax ||
newConfig.closeFactorBase < newConfig.closeFactorMin ||
newConfig.closeFactorMin >= newConfig.closeFactorMax ||
newConfig.closeFactorMin == 0 ||
newConfig.closeFactorMax > BPS
) {
_revert(_INVALID_PARAMETER_SELECTOR);
}
// Validate the soft liquidation collateral premium is not stricter
// than its `collRatio` and has a sufficient buffer against
// soft liquidation.
if (
newConfig.collRatio >
(MIN_LIQUIDATION_BUFFER / (BPS + newConfig.collReqSoft))
) {
_revert(_INVALID_PARAMETER_SELECTOR);
}
// Validate that collateral is not trying to be turned on without
// setting a collateralization ratio.
if (newConfig.collRatio == 0 && newConfig.collateralCap > 0) {
_revert(_INVALID_PARAMETER_SELECTOR);
}
// Do not let people borrow assets if they are not intended to be.
if (newConfig.debtCap > 0) {
if (
newConfig.debtCap > _MAX_DEBT_CAP ||
!ICToken(newConfig.cToken).isBorrowable()
) {
_revert(_INVALID_PARAMETER_SELECTOR);
}
}
CurvanceToken storage storedConfig = _tokenConfig[newConfig.cToken];
// If this token already has collateralization enabled,
// we cannot turn collateralization off completely as this
// would cause downstream effects to the DLE.
if (storedConfig.collRatio != 0 && newConfig.collRatio == 0) {
_revert(_INVALID_PARAMETER_SELECTOR);
}
// Validate we get a safe price when pricing both as a debt or
// collateral asset, even if the asset cannot be collateralized.
(, uint256 errorCode) = CommonLib._oracleManager(centralRegistry)
.getPrice(newConfig.cToken, true, true);
// Validate a safe price for our more important action, liquidations.
if (errorCode == BAD_SOURCE) {
revert MarketManager__PriceError();
}
(, errorCode) = CommonLib._oracleManager(centralRegistry)
.getPrice(newConfig.cToken, true, false);
// Validate a safe price for our more important action, liquidations.
if (errorCode == BAD_SOURCE) {
revert MarketManager__PriceError();
}
// Set new collateralization ratio.
// Note that a collateralization ratio of 0 corresponds to
// no collateralization of `cToken`.
storedConfig.collRatio = uint24(newConfig.collRatio);
// Store the collateral requirement as a premium above `BPS`,
// that way we can calculate solvency via division
// efficiently in _liquidationStatusOf.
storedConfig.collReqSoft = uint24(newConfig.collReqSoft + BPS);
storedConfig.collReqHard = uint24(newConfig.collReqHard + BPS);
// We use the liquidation incentive values as a premium in
// `_canLiquidate`, so it needs to be 1 + incentive.
storedConfig.liqIncBase = uint16(BPS + newConfig.liqIncBase);
storedConfig.liqIncMin = uint16(BPS + newConfig.liqIncMin);
storedConfig.liqIncMax = uint16(BPS + newConfig.liqIncMax);
// Store the distance between liquidation incentive A & B,
// so we can quickly scale between [base, 100%] based on lFactor.
storedConfig.liqIncCurve = uint16(newConfig.liqIncHard - newConfig.liqIncBase);
// Assign the base cFactor.
storedConfig.closeFactorBase = uint16(newConfig.closeFactorBase);
// Store the distance between base cFactor and 100%,
// that way we can quickly scale between [base, 100%] based on lFactor.
storedConfig.closeFactorCurve = uint16(BPS - newConfig.closeFactorBase);
// Assign the min and max effective closeFactor.
storedConfig.closeFactorMin = uint16(newConfig.closeFactorMin);
storedConfig.closeFactorMax = uint16(newConfig.closeFactorMax);
// Assign the collateral posted cap of `newConfig.cToken`.
collateralCaps[newConfig.cToken] = newConfig.collateralCap;
// Assign the outstanding debt cap of `newConfig.cToken`.
debtCaps[newConfig.cToken] = newConfig.debtCap;
emit TokenConfigUpdated(newConfig);
}
/// @notice Admin function to set market-wide liquidation status.
/// @dev Requires market permissions, corresponding contracts may restrict
/// `state` input. Emits an {ActionPaused} event.
/// @param state Whether the desired action is pausing or unpausing.
function setLiquidationPaused(bool state) external {
_checkMarketPermissions();
liquidationPaused = state ? 2 : 1;
emit ActionPaused("Liquidation Paused", state);
}
/// @notice Admin function to set market-wide redemption status.
/// @dev Requires market permissions, corresponding contracts may restrict
/// `state` input. Emits an {ActionPaused} event.
/// @param state Whether redemptions should be paused or unpaused.
function setRedeemPaused(bool state) external {
_checkMarketPermissions();
redeemPaused = state ? 2 : 1;
emit ActionPaused("Redeem Paused", state);
}
/// @notice Admin function to set market-wide transfer status.
/// @dev Requires market permissions, corresponding contracts may restrict
/// `state` input. Emits an {ActionPaused} event.
/// @param state Whether transfers should be paused or unpaused.
function setTransferPaused(bool state) external {
_checkMarketPermissions();
transferPaused = state ? 2 : 1;
emit ActionPaused("Transfer Paused", state);
}
/// @notice Admin function to set token-specific Curvance token
/// minting status.
/// @dev Requires market permissions, corresponding contracts may restrict
/// `state` input. Emits a {TokenActionPaused} event.
/// @param cToken The Curvance token to set minting status for.
/// @param state Whether minting should be paused or unpaused.
function setMintPaused(address cToken, bool state) external {
_checkMarketPermissions();
_checkIsListedToken(cToken);
_tokenConfig[cToken].mintPaused = state ? 2 : 1;
emit TokenActionPaused(cToken, "Mint Paused", state);
}
/// @notice Admin function to set token-specific Curvance token
/// collateralization status.
/// @dev Requires market permissions, corresponding contracts may restrict
/// `state` input. Emits a {TokenActionPaused} event.
/// @param cToken The Curvance token to set collateralization status for.
/// @param state Whether collateralization should be paused or unpaused.
function setCollateralizationPaused(address cToken, bool state) external {
_checkMarketPermissions();
_checkIsListedToken(cToken);
_tokenConfig[cToken].collateralizationPaused = state ? 2 : 1;
emit TokenActionPaused(cToken, "Collateralization Paused", state);
}
/// @notice Admin function to set token-specific Curvance token
/// borrowing status.
/// @dev Requires market permissions, corresponding contracts may restrict
/// `state` input. Emits a {TokenActionPaused} event.
/// @param cToken The Curvance token to set borrowing status for.
/// @param state Whether borrowing should be paused or unpaused.
function setBorrowPaused(address cToken, bool state) external {
_checkMarketPermissions();
_checkIsListedToken(cToken);
_tokenConfig[cToken].borrowPaused = state ? 2 : 1;
emit TokenActionPaused(cToken, "Borrow Paused", state);
}
/// @notice Adds a new position manager address for complex
/// position actions.
/// @dev Requires timelock authority.
/// Emits a {PositionManagerUpdated} event.
/// @param newPM The address to add position manager permissions for.
function addPositionManager(address newPM) external {
_checkMarketPermissions();
if (
!ERC165Checker
.supportsInterface(newPM, type(IPositionManager).interfaceId)
) {
_revert(_INVALID_PARAMETER_SELECTOR);
}
// Validate `newPM` does not have permissions.
if (isPositionManager[newPM]) {
_revert(_INVALID_PARAMETER_SELECTOR);
}
// Add `isPositionManager` permissions to `newPM`.
isPositionManager[newPM] = true;
emit PositionManagerUpdated(newPM, true);
}
/// @notice Removes a current position manager address from complex
/// position actions.
/// @dev Requires timelock authority.
/// Emits a {PositionManagerUpdated} event.
/// @param oldPM The address to remove position manager permissions for.
function removePositionManager(address oldPM) external {
_checkMarketPermissions();
// Validate `oldPM` already has permissions.
if (!isPositionManager[oldPM]) {
_revert(_INVALID_PARAMETER_SELECTOR);
}
// Remove `isPositionManager` permissions.
delete isPositionManager[oldPM];
emit PositionManagerUpdated(oldPM, false);
}
/// @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 {
_checkAuctionPermissions();
_checkIsListedToken(cToken);
CurvanceToken memory c = _tokenConfig[cToken];
// Make sure this token actually can be liquidated, by being
// collateralizable in the first place.
if (c.collRatio == 0) {
revert MarketManager__UnauthorizedLiquidation();
}
// Validate `incentive` is within configured incentive bounds, unless
// zero is passed to signal protocol-derived values should be used.
// This also validates `incentive` is not > the 16 bits we have allocated.
if (
incentive != 0 &&
(incentive < c.liqIncMin || incentive > c.liqIncMax)
) {
_revert(_INVALID_PARAMETER_SELECTOR);
}
// Validate `closeFactor` is within configured allowed close factor
// range, unless zero is passed to signal protocol-derived values
// should be used. This also validates `closeFactor` is not > the 16
// bits we have allocated.
if (
closeFactor != 0 &&
(closeFactor < c.closeFactorMin || closeFactor > c.closeFactorMax)
) {
_revert(_INVALID_PARAMETER_SELECTOR);
}
uint256 liqConfig = uint256(uint160(cToken));
assembly {
// Mask `liqConfig` to the lower 160 bits, in case the upper bits
// somehow are not clean.
liqConfig := and(liqConfig, _BITMASK_COLLATERAL_UNLOCKED)
// Equals: liqConfig | (incentive << _BITPOS_LIQ_INCENTIVE) |
// closeFactor << _BITPOS_CLOSE_FACTOR.
liqConfig := or(
liqConfig,
or(
shl(_BITPOS_LIQ_INCENTIVE, incentive),
shl(_BITPOS_CLOSE_FACTOR, closeFactor)
)
)
tstore(_TRANSIENT_LIQUIDATION_CONFIG_KEY, liqConfig)
}
}
/// @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 {
_checkAuctionPermissions();
/// @solidity memory-safe-assembly
assembly {
tstore(_TRANSIENT_LIQUIDATION_CONFIG_KEY, 0)
}
}
/// PUBLIC FUNCTIONS ///
/// @notice Returns the current liquidation configuration in an active
/// transaction.
/// @dev If a liquidation configuration value is set in transient storage,
/// that value is returned, 0 is returned if no set value.
/// @return cTokenUnlocked The Curvance token unlocked for auction-based
/// liquidations.
/// @return incentive The liquidation incentive value, in `BPS`.
/// @return closeFactor The close factor value, in `BPS`.
function getTransientLiquidationConfig() public view returns (
address cTokenUnlocked,
uint256 incentive,
uint256 closeFactor
) {
uint256 liqConfig;
/// @solidity memory-safe-assembly
assembly {
liqConfig := tload(_TRANSIENT_LIQUIDATION_CONFIG_KEY)
}
cTokenUnlocked = address(uint160(liqConfig));
incentive = uint16(liqConfig >> _BITPOS_LIQ_INCENTIVE);
closeFactor = uint16(liqConfig >> _BITPOS_CLOSE_FACTOR);
}
/// @dev Returns true that this contract implements both IMarketManager
/// and ERC165 interfaces.
/// @param interfaceId The interface ID to check.
/// @return result Whether the contract implements the interface.
function supportsInterface(
bytes4 interfaceId
) public view override returns (bool result) {
result = interfaceId == type(IMarketManager).interfaceId ||
super.supportsInterface(interfaceId);
}
/// INTERNAL FUNCTIONS ///
/// @notice Checks if the account should be allowed to borrow
/// the underlying asset of the given market.
/// @dev Will natively revert if a hypothetical new borrow will result in
/// a loan less than `MIN_LOAN_SIZE`,
/// set in `LiquidityManager`. May emit a {PositionUpdated} event.
/// @param debtToken The token to borrow from.
/// @param assets The amount of underlying the 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 debtToken,
uint256 assets,
address account,
uint256 newNetDebt
) internal {
_checkIsToken(debtToken);
// Can skip token listing check since debtCaps[debtToken] can only
// be set above 0 if `debtToken` is listed already, so we only need
// to check that `newNetDebt` != 0 instead, which should be impossible
// but only costs 2 gas.
/// @solidity memory-safe-assembly
assembly {
if iszero(newNetDebt) {
mstore(0x00, _INVARIANT_ERROR_SELECTOR)
// Return bytes 29-32 for the selector.
revert(0x1c, 0x04)
}
}
if (_tokenConfig[debtToken].borrowPaused == 2) {
revert MarketManager__Paused();
}
// Validates that newNetDebt is not an empty value and this borrow
// action will not push net debt above the debt limit.
// DEV: By rounding up the debt of each user, up to 1 wei for each
// time a user has their interest accrued, the actual sum of user
// debts may exceed marketOutstandingDebt and thus debtCap.
if (newNetDebt > debtCaps[debtToken]) {
revert MarketManager__CapReached();
}
// Check if the user already has an outstanding debt position in
// `debtToken`.
if (accountPositions[debtToken][account] != 2) {
// The account does not have outstanding debt position in
// `debtToken`, so add `debtToken` as an active position for
// `account`.
accountPositions[debtToken][account] = 2;
accountAssets[account].assets.push(debtToken);
emit PositionUpdated(debtToken, account, true);
}
// Check if the user has sufficient liquidity to borrow,
// with heavier error code scrutiny.
(, uint256 liquidityDeficit) = _hypotheticalLiquidityOf(
account,
HypotheticalAction({
cTokenModified: debtToken,
redemptionShares: 0,
borrowAssets: assets,
errorCodeBreakpoint: CAUTION
})
);
// Validate that `account` will not run out of collateral based
// on their collateralization ratio(s).
if (liquidityDeficit > 0) {
revert MarketManager__InsufficientCollateral();
}
}
/// @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 balance The current cToken share balance of `account`.
/// @param collateralPosted The current cToken shares posted as
/// collateral by `account`.
/// @param isCollateral Boolean indicating whether the token is currently
/// being used as collateral.
/// @param forceRedeemCollateral Whether the collateral should be force
/// reduced, used if isCollateral is true.
/// @return collateralRedeemed The amount of collateral shares redeemed.
function _canRedeem(
address cToken,
uint256 shares,
address account,
uint256 balance,
uint256 collateralPosted,
bool isCollateral,
bool forceRedeemCollateral
) internal returns (uint256 collateralRedeemed) {
_checkIsListedToken(cToken);
_checkTransfersAllowed(account);
if (isCollateral) {
// If collateral is being directly removed by user intention,
// or liquidation we can skip balance checks.
if (forceRedeemCollateral) {
// Explicitly revert here if trying to redeem too much
// collateral rather than panic revert.
if (shares > collateralPosted) {
revert MarketManager__InsufficientCollateral();
}
collateralRedeemed = shares;
} else {
// We know that shares <= balance because of
// `_checkRedemption` check inside cToken contracts prior so
// no need for overflow check here. If they want to redeem
// more `cToken` shares than they have idle, calculate how
// much posted collateral will be redeemed from the delta.
// Otherwise `collateralRedeemed` = 0 is correct.
if (collateralPosted + shares >= balance) {
collateralRedeemed = collateralPosted + shares - balance;
}
}
}
// If `collateralRedeemed` is 0 or the account does not have an
// active position in `cToken`, we can bypass the liquidity check.
if (collateralRedeemed == 0 || accountPositions[cToken][account] != 2) {
return collateralRedeemed;
}
// Check account liquidity with hypothetical cToken redemption.
(, uint256 liquidityDeficit) = _hypotheticalLiquidityOf(
account,
HypotheticalAction({
cTokenModified: cToken,
redemptionShares: collateralRedeemed,
borrowAssets: 0,
errorCodeBreakpoint: CAUTION
})
);
// Validate that `account` will not run out of collateral based
// on their collateralization ratio(s).
if (liquidityDeficit > 0) {
revert MarketManager__InsufficientCollateral();
}
}
/// @notice Determines if an account can be liquidated and calculates
/// liquidation parameters. Computes liquidation amounts,
/// collateral seizure, and potential bad debt based on `account`
/// health.
/// @param debtAmount The amount of debt to repay, used only if
/// `liquidateExact` is true, in assets.
/// @param account The address of the account being evaluated for
/// liquidation.
/// @param tData A TokenLiqData struct containing:
/// collateralToken The token which is used as collateral
/// by `account` and may be seized.
/// collateralExchangeRate The exchange rate of
/// `collateralToken` underlying token
/// to `collateralToken`.
/// collateralReqSoft The collateral requirement where
/// dipping below this will cause a soft
/// liquidation.
/// collateralReqHard The collateral requirement where
/// dipping below this will cause a hard
/// liquidation.
/// collateralUnderlyingPrice The current price of the
/// underlying token of
/// `collateralToken`.
/// collateralDecimals The decimals that `collateralToken`
/// is measured in.
/// debtToken The token to potentially repay which has
/// outstanding debt by `account`.
/// debtDecimals The decimals that `debtToken` is measured
/// in.
/// debtUnderlyingPrice The current price of the underlying
/// token of `debtToken`.
/// auctionBuffer The current buffer that `cSoft` and `cHard` are
/// multiplied against, 10 bps, or 0 if not an
/// auction-based liquidation.
/// @param aData An AccountLiqData struct containing:
/// lFactor Empty variable to hold an account's liquidation
/// factor later.
/// debtBalance Empty variable to hold an account's debt's
/// active debt to `tData.debtToken` later.
/// liqInc The ratio at which debt repayment will be
/// compensated on liquidation.
/// liqIncBase The base ratio at which debt repayment will be
/// compensated on soft liquidation.
/// liqIncCurve The liquidation incentive curve length
/// between soft liquidation to hard liquidation.
/// closeFactor Maximum debt % that a liquidator can repay
/// during a liquidation of an account.
/// closeFactorBase Maximum debt % that a liquidator can
/// repay when soft liquidating an account.
/// closeFactorCurve Curve length between soft liquidation
/// and hard liquidation, should be equal
/// to 100% - `closeFactorBase`.
/// @param liquidateExact If true, liquidate exactly `debtAmount`; if
/// false, liquidate maximum possible.
/// @return liquidatedShares The amount of `tData.collateralToken`
/// that will be seized as collateral.
/// @return uint256 The amount of `debtToken` outstanding debt that will be
/// repaid.
/// @return badDebt The amount of bad debt to recognize as part of the
/// liquidation (if any).
function _canLiquidate(
uint256 debtAmount,
address account,
TokenLiqData memory tData,
AccountLiqData memory aData,
bool liquidateExact
) internal view returns (
uint256 liquidatedShares,
uint256,
uint256 badDebt
) {
// Calculate the users lFactor and bubble up their active debt.
(aData.lFactor, aData.debtBalance) =
_liquidationValuesOf(account, tData);
if (aData.lFactor == 0) {
return (0, 0, 0);
}
// If this liquidation does not have offchain submitted parameters
// then closeFactorCurve and liqIncCurve will not be 0. Because
// closeFactorCurve is BPS - closeFactorBase and closeFactorBase is
// limited to MAX_BASE_CFACTOR meaning closeFactorCurve cannot ever be
// 0. liqIncCurve cannot be zero due to the `updateTokenConfig`
// c.liqIncBase >= c.liqIncHard inline check.
if (aData.closeFactorCurve != 0) {
aData.closeFactor = aData.closeFactorBase +
_mulDiv(aData.closeFactorCurve, aData.lFactor, WAD);
}
if (aData.liqIncCurve != 0) {
aData.liqInc = aData.liqIncBase +
_mulDiv(aData.liqIncCurve, aData.lFactor, WAD);
}
// Get the exchange rate, and calculate the number of collateralized
// shares to seize.
// Convert liqInc to WAD via `WAD_SQUARED_BPS_OFFSET` so we dont run
// into precision loss from only multiplying into WAD_SQUARED form.
uint256 debtToCollateral = FixedPointMathLib.fullMulDiv(
FixedPointMathLib.fullMulDiv(
aData.liqInc * tData.debtUnderlyingPrice,
WAD_SQUARED_BPS_OFFSET,
tData.collateralSharesPrice
),
tData.collateralDecimals,
tData.debtDecimals
);
uint256 maxDebt = (aData.closeFactor * aData.debtBalance) / BPS;
// If they want to liquidate an exact amount, liquidate `debtAmount`,
// otherwise liquidate the maximum amount possible.
if (!liquidateExact) {
debtAmount = maxDebt;
}
// Calculate how many shares should be liquidated.
liquidatedShares = FixedPointMathLib.fullMulDiv(
debtAmount,
debtToCollateral,
WAD_SQUARED
);
// Cache `account`'s collateral posted of
// `tData.collateralToken`.
uint256 sharesPosted =
ICToken(tData.collateralToken).collateralPosted(account);
// If the user wants to liquidate an exact amount, make sure theres
// enough collateral available to liquidate, otherwise
// liquidate as much as possible.
if (liquidateExact) {
if (debtAmount > maxDebt || liquidatedShares > sharesPosted) {
// Make sure that the liquidation limit,
// and collateral posted >= amount.
_revert(_INVALID_PARAMETER_SELECTOR);
}
} else {
// If there is not enough shares available for liquidation,
// liquidate what is available.
if (liquidatedShares > sharesPosted) {
debtAmount = FixedPointMathLib.fullMulDivUp(
debtAmount,
sharesPosted,
liquidatedShares
);
liquidatedShares = sharesPosted;
}
}
// If the necessary collateral shares to liquidate `account`'s debt is
// more than their shares posted, there is bad debt that should be
// socialized among lenders, calculate using the same formula we used
// for `liquidatedShares`.
uint256 sharesNeeded = FixedPointMathLib.fullMulDivUp(
aData.debtBalance,
debtToCollateral,
WAD_SQUARED
);
if (sharesNeeded > sharesPosted) {
// Calculate total debt necessary to compensate liquidators
// in full based on `sharesNeeded` vs `sharesPosted`.
// `sharesPosted` = `sharesNeeded` / 2 means 50%
// of debt should be recognized as bad debt, so this
// intermediary step for `badDebt` would be 2x `debtAmount`.
badDebt = FixedPointMathLib
.fullMulDivUp(debtAmount, sharesNeeded, sharesPosted);
// Calculate if compensation calculation will overflow, this can
// happen in scenarios where collateral goes to near 0.
// If it would cause an underflow -> clamp the bad debt down,
// siding with lenders over liquidators.
if (badDebt > aData.debtBalance) {
// CASE: Unhappy path, collateral went to near zero, reduce
// bad debt and keep liquidator's `debtAmount` consistent.
badDebt = aData.debtBalance - debtAmount;
} else {
// CASE: Happy path, normal calculation of recognizing bad
// debt pro-rata based on shortfall of `sharesNeeded` versus
// sharesPosted.
badDebt = badDebt - debtAmount;
}
}
// Calculate the maximum amount of debt that can be liquidated
// and what collateral will be received. As well as any bad debt
// to recognize.
return (liquidatedShares, debtAmount, badDebt);
}
/// @notice Retrieves and caches liquidation configuration data for a
/// given token pair.
/// @param collateralToken The address of the Curvance token to be seized
/// during in the liquidation.
/// @param debtToken The address of the Curvance token to be repaid during
/// the liquidation.
/// @return tData A TokenLiqData struct containing:
/// collateralToken The token which is used as collateral
/// by `account` and may be seized.
/// collateralExchangeRate The exchange rate of
/// `collateralToken` underlying
/// token to `collateralToken`.
/// collateralReqSoft The collateral requirement where
/// dipping below this will cause a soft
/// liquidation.
/// collateralReqHard The collateral requirement where
/// dipping below this will cause a hard
/// liquidation.
/// collateralUnderlyingPrice The current price of the
/// underlying token of
/// `collateralToken`.
/// collateralDecimals The decimals that `collateralToken`
/// is measured in.
/// debtToken The token to potentially repay which has
/// outstanding debt by `account`.
/// debtDecimals The decimals that `debtToken` is measured
/// in.
/// debtUnderlyingPrice The current price of the underlying
/// token of `debtToken`.
/// auctionBuffer The current buffer that `cSoft` and `cHard` are
/// multiplied against, 10 bps, or 0 if not an
/// an auction-based liquidation.
/// @return aData An AccountLiqData struct containing:
/// lFactor Empty variable to hold an account's liquidation
/// factor later.
/// debtBalance Empty variable to hold an account's debt's
/// active debt to `tData.debtToken` later.
/// liqInc The ratio at which debt repayment will be
/// compensated on liquidation.
/// liqIncBase The base ratio at which debt repayment will
/// be compensated on soft liquidation.
/// liqIncCurve The liquidation incentive curve length
/// between soft liquidation to hard
/// liquidation.
/// closeFactor Maximum debt % that a liquidator can repay
/// during a liquidation of an account.
/// closeFactorBase Maximum debt % that a liquidator can
/// repay when soft liquidating an account.
/// closeFactorCurve Curve length between soft liquidation
/// and hard liquidation, should be equal
/// to 100% - `closeFactorBase`.
function _getLiquidationConfig(
address collateralToken,
address debtToken
) internal returns (
TokenLiqData memory tData,
AccountLiqData memory aData
) {
CurvanceToken memory c = _tokenConfig[collateralToken];
// Do not let people liquidate 0% collateralization ratio assets.
if (c.collRatio == 0) {
_revert(_INVALID_PARAMETER_SELECTOR);
}
// Will revert if this liquidation is an attempted auction liquidator
// and liquidator has chosen incorrect collateral or market.
// Pulls any relevant offchain liquidation configuration.
(tData.auctionBuffer, aData.liqInc, aData.closeFactor) =
_checkLiquidationConfig(collateralToken);
// Liquidations are only blocked if an error code of 2 (NO_SOURCE)
// is calculated.
(tData.collateralSharesPrice, tData.debtUnderlyingPrice) =
CommonLib._oracleManager(centralRegistry)
.getPriceIsolatedPair(collateralToken, debtToken, BAD_SOURCE);
// Cache all variables needed for computing liquidation levels.
tData.collateralToken = collateralToken;
tData.collateralReqSoft = c.collReqSoft;
tData.collateralReqHard = c.collReqHard;
tData.collateralDecimals = 10 ** IERC20(collateralToken).decimals();
tData.debtToken = debtToken;
tData.debtDecimals = 10 ** IERC20(debtToken).decimals();
// We only need to cache these variables if we did not receive close
// factor/liquidation incentive from `getLiquidationConfig`.
if (aData.closeFactor == 0) {
aData.closeFactorBase = c.closeFactorBase;
aData.closeFactorCurve = c.closeFactorCurve;
}
if (aData.liqInc == 0) {
aData.liqIncBase = c.liqIncBase;
aData.liqIncCurve = c.liqIncCurve;
}
}
/// @notice Check whether the hold period is met.
/// @param account The account to check the hold period for.
function _checkHoldPeriod(address account) internal view {
// We require a `minimumHoldPeriod` to break flashloan
// and multi-block price manipulations if the dynamic dual oracle
// fails to protect the market somehow.
if (
accountAssets[account].cooldownTimestamp + MIN_HOLD_PERIOD >
block.timestamp
) {
revert MarketManager__MinimumHoldPeriod();
}
}
/// @notice Checks whether `token` is listed in this Market Manager.
/// @param token The token to check whether it's listed or not.
function _checkIsListedToken(address token) internal view {
if (!_tokenConfig[token].isListed) {
revert MarketManager__TokenNotListed();
}
}
/// @dev Checks whether the caller is `token`.
function _checkIsToken(address token) internal view {
/// @solidity memory-safe-assembly
assembly {
// Equal to if (msg.sender != token)
if iszero(eq(caller(), token)) {
mstore(0x00, _UNAUTHORIZED_SELECTOR)
// Return bytes 29-32 for the selector.
revert(0x1c, 0x04)
}
}
}
/// @dev Checks whether `account` has token transfers enabled.
function _checkTransfersAllowed(address account) internal view {
if (centralRegistry.checkTransfersDisabled(account)) {
_revert(_UNAUTHORIZED_SELECTOR);
}
_checkHoldPeriod(account);
}
/// @notice Will revert and block liquidations of collateral that are not
/// currently allowed by Auction, only if this is an Auction tx.
/// @param cToken The address of the collateral token to liquidate.
/// @return The buffer priority value to apply as a discount to collateral
/// during auctioned liquidations.
function _checkLiquidationConfig(
address cToken
) internal view returns (uint256, uint256, uint256) {
(address unlockedCToken, uint256 liqIncentive, uint256 closeFactor) =
getTransientLiquidationConfig();
bool unlockedMarket = centralRegistry.isMarketUnlocked();
bool unlockedCollateral = unlockedCToken == cToken;
if (unlockedMarket || unlockedCollateral) {
// This is an attempted auction liquidation, and is configured
// correctly so give them the auction priority buffer.
if (unlockedMarket && unlockedCollateral) {
return (AUCTION_BUFFER, liqIncentive, closeFactor);
}
// This is an attempted auction liquidation, but its misconfigured
// and unauthorized because of this.
revert MarketManager__UnauthorizedLiquidation();
}
// This is not an attempted auction liquidation, so approve the
// liquidation, but without any offchain liquidation config values.
return (0, 0, 0);
}
/// @dev Checks whether the caller has sufficient permissioning.
/// NOTE: Market Permissioned contracts should have corresponding
/// restrictions handled within the contract itself such as
/// enforcing a specific party to pause but not unpause
/// markets.
function _checkMarketPermissions() internal view virtual {
if (!centralRegistry.hasMarketPermissions(msg.sender)) {
_revert(_UNAUTHORIZED_SELECTOR);
}
}
/// @dev Checks whether the caller has sufficient permissioning.
function _checkAuctionPermissions() internal view {
if (!centralRegistry.hasAuctionPermissions(msg.sender)) {
_revert(_UNAUTHORIZED_SELECTOR);
}
}
/// @dev Returns the Protocol Central Registry contract in interface
/// form.
function _getCentralRegistry()
internal
view
override
returns (ICentralRegistry)
{
return centralRegistry;
}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"contract ICentralRegistry","name":"cr","type":"address"},{"internalType":"uint256","name":"minLoanSize","type":"uint256"},{"internalType":"bool","name":"isCorrelatedMarket","type":"bool"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"CentralRegistryLib__InvalidCentralRegistry","type":"error"},{"inputs":[],"name":"LiquidityManager__InsufficientLoanSize","type":"error"},{"inputs":[],"name":"LiquidityManager__PriceError","type":"error"},{"inputs":[],"name":"LowLevelCallsHelper__CallFailed","type":"error"},{"inputs":[],"name":"MarketManager__CapReached","type":"error"},{"inputs":[],"name":"MarketManager__InsufficientCollateral","type":"error"},{"inputs":[],"name":"MarketManager__InvalidParameter","type":"error"},{"inputs":[],"name":"MarketManager__InvariantError","type":"error"},{"inputs":[],"name":"MarketManager__MarketManagerMismatch","type":"error"},{"inputs":[],"name":"MarketManager__MinimumHoldPeriod","type":"error"},{"inputs":[],"name":"MarketManager__NoLiquidationAvailable","type":"error"},{"inputs":[],"name":"MarketManager__Paused","type":"error"},{"inputs":[],"name":"MarketManager__PriceError","type":"error"},{"inputs":[],"name":"MarketManager__TokenNotListed","type":"error"},{"inputs":[],"name":"MarketManager__Unauthorized","type":"error"},{"inputs":[],"name":"MarketManager__UnauthorizedLiquidation","type":"error"},{"inputs":[],"name":"Multicall__InvalidTarget","type":"error"},{"inputs":[],"name":"Multicall__UnknownCalldata","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"action","type":"string"},{"indexed":false,"internalType":"bool","name":"pauseState","type":"bool"}],"name":"ActionPaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"positionManager","type":"address"},{"indexed":false,"internalType":"bool","name":"addPerms","type":"bool"}],"name":"PositionManagerUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"cToken","type":"address"},{"indexed":false,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"bool","name":"open","type":"bool"}],"name":"PositionUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"cToken","type":"address"},{"indexed":false,"internalType":"string","name":"action","type":"string"},{"indexed":false,"internalType":"bool","name":"pauseState","type":"bool"}],"name":"TokenActionPaused","type":"event"},{"anonymous":false,"inputs":[{"components":[{"internalType":"address","name":"cToken","type":"address"},{"internalType":"uint256","name":"collRatio","type":"uint256"},{"internalType":"uint256","name":"collReqSoft","type":"uint256"},{"internalType":"uint256","name":"collReqHard","type":"uint256"},{"internalType":"uint256","name":"liqIncBase","type":"uint256"},{"internalType":"uint256","name":"liqIncHard","type":"uint256"},{"internalType":"uint256","name":"liqIncMin","type":"uint256"},{"internalType":"uint256","name":"liqIncMax","type":"uint256"},{"internalType":"uint256","name":"closeFactorBase","type":"uint256"},{"internalType":"uint256","name":"closeFactorMin","type":"uint256"},{"internalType":"uint256","name":"closeFactorMax","type":"uint256"},{"internalType":"uint256","name":"collateralCap","type":"uint256"},{"internalType":"uint256","name":"debtCap","type":"uint256"}],"indexed":false,"internalType":"struct MarketManagerIsolated.TokenConfig","name":"config","type":"tuple"}],"name":"TokenConfigUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"cToken","type":"address"}],"name":"TokenListed","type":"event"},{"inputs":[],"name":"AUCTION_BUFFER","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"AUCTION_BUFFER_CORRELATED","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"AUCTION_BUFFER_UNCORRELATED","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"EXTRA_BUFFER_BEFORE_LIQUIDATION","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"IS_CORRELATED_ASSET_MARKET","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_BASE_CFACTOR","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_COLLATERAL_REQUIREMENT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_COLL_RATIO","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_COLL_RATIO_CORRELATED","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_COLL_RATIO_UNCORRELATED","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_LIQUIDATION_INCENTIVE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_BASE_CFACTOR","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_EXCESS_COLL_REQUIRED","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_HOLD_PERIOD","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_LIQUIDATION_BUFFER","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_LIQUIDATION_BUFFER_REQUIRED","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_LOAN_SIZE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"accountAssets","outputs":[{"internalType":"uint256","name":"cooldownTimestamp","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"accountPositions","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"cToken","type":"address"}],"name":"actionsPaused","outputs":[{"internalType":"bool","name":"mintPaused","type":"bool"},{"internalType":"bool","name":"collateralizationPaused","type":"bool"},{"internalType":"bool","name":"borrowPaused","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newPM","type":"address"}],"name":"addPositionManager","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"assetsOf","outputs":[{"internalType":"address[]","name":"result","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"cToken","type":"address"},{"internalType":"uint256","name":"assets","type":"uint256"},{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"newNetDebt","type":"uint256"}],"name":"canBorrow","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"cToken","type":"address"},{"internalType":"uint256","name":"assets","type":"uint256"},{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"newNetDebt","type":"uint256"}],"name":"canBorrowWithNotify","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"collateralToken","type":"address"},{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"newNetCollateral","type":"uint256"}],"name":"canCollateralize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"debtAmounts","type":"uint256[]"},{"internalType":"address","name":"liquidator","type":"address"},{"internalType":"address[]","name":"accounts","type":"address[]"},{"components":[{"internalType":"address","name":"collateralToken","type":"address"},{"internalType":"address","name":"debtToken","type":"address"},{"internalType":"uint256","name":"numAccounts","type":"uint256"},{"internalType":"bool","name":"liquidateExact","type":"bool"},{"internalType":"uint256","name":"liquidatedShares","type":"uint256"},{"internalType":"uint256","name":"debtRepaid","type":"uint256"},{"internalType":"uint256","name":"badDebt","type":"uint256"}],"internalType":"struct IMarketManager.LiqAction","name":"action","type":"tuple"}],"name":"canLiquidate","outputs":[{"components":[{"internalType":"uint256[]","name":"liquidatedShares","type":"uint256[]"},{"internalType":"uint256","name":"debtRepaid","type":"uint256"},{"internalType":"uint256","name":"badDebtRealized","type":"uint256"}],"internalType":"struct IMarketManager.LiqResult","name":"result","type":"tuple"},{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"cToken","type":"address"}],"name":"canMint","outputs":[],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"cToken","type":"address"},{"internalType":"uint256","name":"shares","type":"uint256"},{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"balanceOf","type":"uint256"},{"internalType":"uint256","name":"collateralPosted","type":"uint256"},{"internalType":"bool","name":"forceRedeemCollateral","type":"bool"}],"name":"canRedeemWithCollateralRemoval","outputs":[{"internalType":"uint256","name":"collateralRedeemed","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"cToken","type":"address"},{"internalType":"uint256","name":"newNetDebt","type":"uint256"},{"internalType":"address","name":"debtAsset","type":"address"},{"internalType":"uint256","name":"decimals","type":"uint256"},{"internalType":"address","name":"account","type":"address"}],"name":"canRepayWithReview","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"collateralToken","type":"address"},{"internalType":"address","name":"debtToken","type":"address"}],"name":"canSeize","outputs":[],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"cToken","type":"address"},{"internalType":"uint256","name":"shares","type":"uint256"},{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"balanceOf","type":"uint256"},{"internalType":"uint256","name":"collateralPosted","type":"uint256"},{"internalType":"bool","name":"isCollateral","type":"bool"}],"name":"canTransfer","outputs":[{"internalType":"uint256","name":"collateralRedeemed","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"centralRegistry","outputs":[{"internalType":"contract ICentralRegistry","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"cToken","type":"address"}],"name":"collConfig","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"collateralCaps","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"debtCaps","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTransientLiquidationConfig","outputs":[{"internalType":"address","name":"cTokenUnlocked","type":"address"},{"internalType":"uint256","name":"incentive","type":"uint256"},{"internalType":"uint256","name":"closeFactor","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"cToken","type":"address"}],"name":"isListed","outputs":[{"internalType":"bool","name":"result","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"isPositionManager","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"cToken","type":"address"}],"name":"liquidationConfig","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"liquidationPaused","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token0","type":"address"},{"internalType":"address","name":"token1","type":"address"}],"name":"listTokens","outputs":[],"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":[{"internalType":"address","name":"cToken","type":"address"},{"internalType":"address","name":"account","type":"address"}],"name":"notifyBorrow","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"queryTokensListed","outputs":[{"internalType":"address[]","name":"r","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"redeemPaused","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"oldPM","type":"address"}],"name":"removePositionManager","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"resetTransientLiquidationConfig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"cToken","type":"address"},{"internalType":"bool","name":"state","type":"bool"}],"name":"setBorrowPaused","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"cToken","type":"address"},{"internalType":"bool","name":"state","type":"bool"}],"name":"setCollateralizationPaused","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"state","type":"bool"}],"name":"setLiquidationPaused","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"cToken","type":"address"},{"internalType":"bool","name":"state","type":"bool"}],"name":"setMintPaused","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"state","type":"bool"}],"name":"setRedeemPaused","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"state","type":"bool"}],"name":"setTransferPaused","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"cToken","type":"address"},{"internalType":"uint256","name":"incentive","type":"uint256"},{"internalType":"uint256","name":"closeFactor","type":"uint256"}],"name":"setTransientLiquidationConfig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"statusOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"result","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"tokensListed","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"transferPaused","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"cToken","type":"address"},{"internalType":"uint256","name":"collRatio","type":"uint256"},{"internalType":"uint256","name":"collReqSoft","type":"uint256"},{"internalType":"uint256","name":"collReqHard","type":"uint256"},{"internalType":"uint256","name":"liqIncBase","type":"uint256"},{"internalType":"uint256","name":"liqIncHard","type":"uint256"},{"internalType":"uint256","name":"liqIncMin","type":"uint256"},{"internalType":"uint256","name":"liqIncMax","type":"uint256"},{"internalType":"uint256","name":"closeFactorBase","type":"uint256"},{"internalType":"uint256","name":"closeFactorMin","type":"uint256"},{"internalType":"uint256","name":"closeFactorMax","type":"uint256"},{"internalType":"uint256","name":"collateralCap","type":"uint256"},{"internalType":"uint256","name":"debtCap","type":"uint256"}],"internalType":"struct MarketManagerIsolated.TokenConfig","name":"newConfig","type":"tuple"}],"name":"updateTokenConfig","outputs":[],"stateMutability":"nonpayable","type":"function"}]Contract Creation Code
6101606040526004805462ffffff191662010101179055348015610021575f5ffd5b50604051615115380380615115833981016040819052610040916101f4565b828282678ac7230489e80000821080610061575068056bc75e2d6310000082115b1561007f57604051632e7cf4cd60e11b815260040160405180910390fd5b610088836100e7565b6001600160a01b0383166101405261012082905280151560a052806100af576125e06100b3565b6126165b60c052806100c3576126de6100c7565b6127065b60e08190526100d8906126e8610243565b60805250610266945050505050565b6100f8816399011ef160e01b610118565b610115576040516369b5e45b60e11b815260040160405180910390fd5b50565b5f6101228361013c565b80156101335750610133838361016e565b90505b92915050565b5f61014e826301ffc9a760e01b61016e565b80156101365750610167826001600160e01b031961016e565b1592915050565b6040516001600160e01b0319821660248201525f90819060440160408051601f19818403018152919052602080820180516001600160e01b03166301ffc9a760e01b17815282519293505f9283928392909183918a617530fa92503d91505f5190508280156101de575060208210155b80156101e957505f81115b979650505050505050565b5f5f5f60608486031215610206575f5ffd5b83516001600160a01b038116811461021c575f5ffd5b6020850151604086015191945092508015158114610238575f5ffd5b809150509250925092565b808202811582820484141761013657634e487b7160e01b5f52601160045260245ffd5b60805160a05160c05160e051610100516101205161014051614dee6103275f395f81816106bb01528181610f1a01528181610fd801528181611532015281816125790152818161285e01528181612c8b01528181612ffd01528181613574015281816136b2015281816139920152613a7701525f8181610737015281816115ea01526138ca01525f61066e01525f81816106e20152613b2601525f81816104b90152610bf901525f6108c901525f81816104e00152610dc70152614dee5ff3fe608060405234801561000f575f5ffd5b5060043610610387575f3560e01c80638a05a2e6116101df578063c03c24bb11610109578063d99f05e1116100a9578063ecdb97a011610079578063ecdb97a01461093f578063f794062e146109f4578063f96492c914610a1f578063fb2cb34e14610a32575f5ffd5b8063d99f05e1146108c4578063da11ee23146108eb578063e2f0ab011461090c578063e8bbf5d71461091f575f5ffd5b8063c8b5277e116100e4578063c8b5277e14610889578063ccb99c261461089c578063d53dc739146108af578063d78db3f1146108bc575f5ffd5b8063c03c24bb14610844578063c2ba474414610863578063c80fa87214610876575f5ffd5b8063a2675bcd1161017f578063afbe407a1161014f578063afbe407a146107f2578063b235d468146107fa578063b6606d1c1461081e578063b7b7f26014610831575f5ffd5b8063a2675bcd1461076c578063a2f88e49146107b6578063abf883cb146107bf578063af79b3ca146107e9575f5ffd5b8063901941f9116101ba578063901941f9146106dd57806397a5d5b5146107045780639b4e3822146107325780639d488a0c14610759575f5ffd5b80638a05a2e6146106905780638c75d4fe146106a35780638f73dcfa146106b6575f5ffd5b80633fd596ce116102c0578063699ba8b3116102605780637551cd48116102305780637551cd4814610644578063757942ea146106575780637beec6af1461066057806380a00b7414610669575f5ffd5b8063699ba8b31461059c5780636c3b426f146106095780636dac9023146106125780637148fa5414610631575f5ffd5b80634b3d3b581161029b5780634b3d3b58146105435780634b7e1ff114610556578063504d6b181461056957806363e12aa314610571575f5ffd5b80633fd596ce1461051e57806345a9bbde146105275780634b03195214610530575f5ffd5b80631e9fb63a1161032b5780632f7a4c65116103065780632f7a4c65146104b457806337142666146104db57806339a8bf38146105025780633e0cdfd31461050b575f5ffd5b80631e9fb63a146104785780632076d8e7146104815780632c62fa1014610494575f5ffd5b80630358e376116103665780630358e376146103e957806308799c63146103fe5780630a73e3911461041157806317c221c614610433575f5ffd5b80623c8bd41461038b57806301ffc9a7146103a7578063032886d9146103ca575b5f5ffd5b6103946104b081565b6040519081526020015b60405180910390f35b6103ba6103b53660046140c9565b610a45565b604051901515815260200161039e565b6103946103d8366004614114565b60056020525f908152604090205481565b6103fc6103f736600461412f565b610a7b565b005b6103fc61040c366004614240565b610be4565b6103ba61041f366004614114565b60076020525f908152604090205460ff1681565b5f516020614d995f395f51905f525c61ffff60a082901c81169060b083901c16604080516001600160a01b03909416845260208401929092529082015260600161039e565b6103946126de81565b61039461048f3660046142f9565b611352565b6104a76104a2366004614114565b6113a2565b60405161039e919061435c565b6103947f000000000000000000000000000000000000000000000000000000000000000081565b6103947f000000000000000000000000000000000000000000000000000000000000000081565b61039461270681565b6103fc6105193660046143a7565b611418565b6103946126e881565b6103946125e081565b6103fc61053e3660046143de565b6114d1565b6103fc610551366004614439565b611649565b6103fc61056436600461447e565b61165b565b6103fc611836565b61058461057f3660046144b0565b611850565b6040516001600160a01b03909116815260200161039e565b6105ea6105aa366004614114565b6001600160a01b03165f90815260208190526040902054600260ff6101008304811682149362010000840482168314936301000000900490911690911490565b604080519315158452911515602084015215159082015260600161039e565b61039461261681565b610394610620366004614114565b60026020525f908152604090205481565b6103fc61063f3660046144c7565b611878565b6103fc6106523660046144c7565b611c73565b61039461138881565b6103946103e881565b6103947f000000000000000000000000000000000000000000000000000000000000000081565b6103fc61069e366004614114565b611d79565b6103fc6106b13660046144c7565b611e0a565b6105847f000000000000000000000000000000000000000000000000000000000000000081565b6103947f000000000000000000000000000000000000000000000000000000000000000081565b610717610712366004614114565b611e38565b6040805193845260208401929092529082015260600161039e565b6103947f000000000000000000000000000000000000000000000000000000000000000081565b6103fc6107673660046144f3565b611e52565b61071761077a366004614114565b6001600160a01b03165f9081526020819052604090205462ffffff600160201b8204811692600160381b8304821692600160501b900490911690565b610394615b6881565b6103946107cd3660046144c7565b600160209081525f928352604080842090915290825290205481565b610394610bb881565b6104a7611ede565b60045461080c90610100900460ff1681565b60405160ff909116815260200161039e565b6103fc61082c3660046143a7565b611f3e565b61039461083f3660046142f9565b611ff5565b610394610852366004614114565b60066020525f908152604090205481565b6103fc610871366004614114565b61203a565b6103fc6108843660046143a7565b612086565b6103fc6108973660046144f3565b61214b565b6103fc6108aa3660046144f3565b6121d3565b60045461080c9060ff1681565b610394606481565b6103ba7f000000000000000000000000000000000000000000000000000000000000000081565b6108fe6108f93660046145ed565b61225d565b60405161039e92919061470f565b6103fc61091a366004614114565b6124c4565b61093261092d366004614752565b612575565b60405161039e91906147be565b6109b961094d366004614114565b6001600160a01b03165f9081526020819052604090205461ffff600160681b8204811692600160781b8304821692600160881b8104831692600160981b8204811692600160a81b8304821692600160b81b8104831692600160c81b8204811692600160d81b9092041690565b604080519889526020890197909752958701949094526060860192909252608085015260a084015260c083015260e08201526101000161039e565b6103ba610a02366004614114565b6001600160a01b03165f9081526020819052604090205460ff1690565b6103fc610a2d366004614439565b6127d7565b60045461080c9062010000900460ff1681565b5f6001600160e01b03198216634d6978eb60e11b1480610a7557506301ffc9a760e01b6001600160e01b03198316145b92915050565b610a84836127fd565b80610a9657635518d5cb5f526004601cfd5b6001600160a01b0383165f9081526020819052604090205462010000900460ff16600203610ad757604051633d1cc8fd60e21b815260040160405180910390fd5b6001600160a01b0383165f90815260056020526040902054811115610b0f57604051633448aa9d60e01b815260040160405180910390fd5b6001600160a01b038083165f81815260026020818152604080842042905594881683526001815284832093835292909252919091205414610bdf576001600160a01b038381165f81815260016020818152604080842095881680855295825280842060029081905582528084208301805480850182559085529382902090930180546001600160a01b0319168517905582519384528301939093528101919091527f5cbb919307f3804aff990e94bdc923c0878589779d539552a35353302b8ed8e5906060015b60405180910390a15b505050565b8051610bef90612811565b610bf7612849565b7f000000000000000000000000000000000000000000000000000000000000000081602001511180610c2e5750615b688160400151115b80610c4157508060400151816060015110155b15610c5357610c536365513fc16128e3565b8060a001518160800151101580610c7157508060e001518160800151115b80610c8357508060c001518160800151105b80610c9657508060e001518160c0015110155b80610ca65750610bb88160e00151115b80610cb3575060c0810151155b80610cc35750610bb88160a00151115b15610cd557610cd56365513fc16128e3565b806060015160648260a00151610ceb9190614835565b1180610d0a5750806060015160648260e00151610d089190614835565b115b15610d1c57610d1c6365513fc16128e3565b6113888161010001511180610d3757506103e8816101000151105b15610d4957610d496365513fc16128e3565b8061014001518161010001511180610d6a5750806101200151816101000151105b80610d7f575080610140015181610120015110155b80610d8d5750610120810151155b80610d9e5750612710816101400151115b15610db057610db06365513fc16128e3565b6040810151610dc190612710614835565b610deb907f0000000000000000000000000000000000000000000000000000000000000000614848565b81602001511115610e0357610e036365513fc16128e3565b6020810151158015610e1957505f816101600151115b15610e2b57610e2b6365513fc16128e3565b61018081015115610ecc5761018081015170ffffffffffffffffffffffffffffffffff1080610eba5750805f01516001600160a01b03166345d7b97a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610e94573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610eb89190614867565b155b15610ecc57610ecc6365513fc16128e3565b80516001600160a01b03165f9081526020819052604090208054600160201b900462ffffff1615801590610f0257506020820151155b15610f1457610f146365513fc16128e3565b5f610f3e7f00000000000000000000000000000000000000000000000000000000000000006128ec565b8351604051635ae6916360e01b81526001600160a01b039290921691635ae6916391610f71916001908190600401614882565b6040805180830381865afa158015610f8b573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610faf91906148a5565b91505060028103610fd35760405163583c953760e01b815260040160405180910390fd5b610ffc7f00000000000000000000000000000000000000000000000000000000000000006128ec565b8351604051635ae6916360e01b81526001600160a01b039290921691635ae691639161102f916001905f90600401614882565b6040805180830381865afa158015611049573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061106d91906148a5565b91505060011981016110925760405163583c953760e01b815260040160405180910390fd5b6020830151825462ffffff909116600160201b0266ffffff000000001990911617825560408301516110c79061271090614835565b825462ffffff91909116600160381b0269ffffff000000000000001990911617825560608301516110fb9061271090614835565b825462ffffff91909116600160501b0262ffffff60501b19909116178255608083015161112a90612710614835565b825461ffff91909116600160681b0261ffff60681b1990911617825560c083015161115790612710614835565b825461ffff91909116600160881b0261ffff60881b1990911617825560e083015161118490612710614835565b825461ffff91909116600160981b0261ffff60981b19909116178255608083015160a08401516111b491906148c7565b825461010085015167ffff00000000ffff60781b19909116600160781b61ffff9384160261ffff60a81b191617600160a81b928216929092029190911783556111ff906127106148c7565b825461012085015161014086015163ffffffff60b81b19909216600160b81b61ffff9485160261ffff60c81b191617600160c81b918416919091021761ffff60d81b1916600160d81b929091169190910217825561016083015183516001600160a01b039081165f90815260056020908152604080832094909455610180870151875190931682526006905282902055517f7118653a594971f43f27090077f0b05efeaf77dd61915894fa826f79ca0ab5b890610bd690859081516001600160a01b031681526101a081016020830151602083015260408301516040830152606083015160608301526080830151608083015260a083015160a083015260c083015160c083015260e083015160e083015261010083015161010083015261012083015161012083015261014083015161014083015261016083015161016083015261018083015161018083015292915050565b5f61135c876127fd565b600454610100900460ff1660020361138757604051633d1cc8fd60e21b815260040160405180910390fd5b611397878787878760018861294d565b979650505050505050565b6001600160a01b0381165f9081526002602090815260409182902060010180548351818402810184019094528084526060939283018282801561140c57602002820191905f5260205f20905b81546001600160a01b031681526001909101906020018083116113ee575b50505050509050919050565b611420612849565b61142982612811565b80611435576001611438565b60025b6001600160a01b0383165f8181526020818152604091829020805460ff959095166101000261ff00199095169490941790935580519182526060928201839052600b928201929092526a135a5b9d0814185d5cd95960aa1b6080820152821515918101919091527f359e41b7f6189b08ab0ad7b56dfc630860095deba215f7d1e24f126d048ac6219060a0015b60405180910390a15050565b6114da856127fd565b6114e385612811565b6114ec81612a55565b6001600160a01b038086165f90815260016020908152604080832093851683529290522054600214611525576115256365513fc16128e3565b8315611642575f5f6115567f00000000000000000000000000000000000000000000000000000000000000006128ec565b6001600160a01b0316635ae69163866001806040518463ffffffff1660e01b815260040161158693929190614882565b6040805180830381865afa1580156115a0573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906115c491906148a5565b915091505f81146115e85760405163583c953760e01b815260040160405180910390fd5b7f0000000000000000000000000000000000000000000000000000000000000000611620878461161988600a6149bd565b6001612a9b565b101561163f57604051632e7cf4cd60e11b815260040160405180910390fd5b50505b5050505050565b61165584848484612aca565b50505050565b611663612c76565b61166c83612811565b6001600160a01b0383165f9081526020818152604080832081516101e081018352905460ff8082161515835261010080830482169584019590955262010000820481169383019390935263010000008104909216606082015262ffffff600160201b8304811660808301819052600160381b8404821660a0840152600160501b840490911660c083015261ffff600160681b8404811660e0840152600160781b8404811694830194909452600160881b83048416610120830152600160981b83048416610140830152600160a81b83048416610160830152600160b81b83048416610180830152600160c81b830484166101a0830152600160d81b9092049092166101c08301529091036117935760405163fac97a2b60e01b815260040160405180910390fd5b82158015906117bc575080610120015161ffff168310806117bc575080610140015161ffff1683115b156117ce576117ce6365513fc16128e3565b81158015906117f75750806101a0015161ffff168210806117f75750806101c0015161ffff1682115b15611809576118096365513fc16128e3565b60a083901b60b083901b176001600160a01b03851617805f516020614d995f395f51905f525d5050505050565b61183e612c76565b5f5f516020614d995f395f51905f525d565b6003818154811061185f575f80fd5b5f918252602090912001546001600160a01b0316905081565b611880612849565b806001600160a01b0316826001600160a01b0316036118a6576118a66365513fc16128e3565b806001600160a01b03166338d52e0f6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156118e2573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061190691906149c8565b6001600160a01b0316826001600160a01b03166338d52e0f6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561194b573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061196f91906149c8565b6001600160a01b03160361198a5761198a6365513fc16128e3565b6003541561199f5761199f6365513fc16128e3565b816001600160a01b03166345d7b97a6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156119db573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906119ff9190614867565b158015611a695750806001600160a01b03166345d7b97a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611a43573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611a679190614867565b155b15611a7b57611a7b6365513fc16128e3565b6001600160a01b038281165f818152602081905260408082208054600160ff19918216811790925594861683529181902080549094169091179092559051637ada7a0960e01b8152336004820152637ada7a09906024016020604051808303815f875af1158015611aee573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611b129190614867565b611b2357611b23635518d5cb6128e3565b604051637ada7a0960e01b81523360048201526001600160a01b03821690637ada7a09906024016020604051808303815f875af1158015611b66573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611b8a9190614867565b611b9b57611b9b635518d5cb6128e3565b60038054600180820183555f8390527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b91820180546001600160a01b03199081166001600160a01b0388811691821790935585549384019095559190920180549091169184169190911790556040519081527f017664858438d89f547fee46da0bcfc5396ea13a9fb1490b8fdd76cfa979f1a99060200160405180910390a16040516001600160a01b03821681527f017664858438d89f547fee46da0bcfc5396ea13a9fb1490b8fdd76cfa979f1a9906020016114c5565b611c7c82612811565b611c8581612811565b806001600160a01b03166341ed2c126040518163ffffffff1660e01b8152600401602060405180830381865afa158015611cc1573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611ce591906149c8565b6001600160a01b0316826001600160a01b03166341ed2c126040518163ffffffff1660e01b8152600401602060405180830381865afa158015611d2a573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611d4e91906149c8565b6001600160a01b031614611d7557604051631284375160e11b815260040160405180910390fd5b5050565b611d81612849565b6001600160a01b0381165f9081526007602052604090205460ff16611dad57611dad6365513fc16128e3565b6001600160a01b0381165f818152600760209081526040808320805460ff191690558051938452908301919091527f95f28d5f3b25ba2ec0ace967a30ee05f0ff47e77f8c63e8fe5fc009f95894a1691015b60405180910390a150565b611e13826127fd565b611e1c82612811565b6001600160a01b03165f90815260026020526040902042905550565b5f5f5f611e4484612cc2565b9250925092505b9193909250565b611e5a612849565b80611e66576001611e69565b60025b600460026101000a81548160ff021916908360ff1602179055507fef159d9a32b2472e32b098f954f3ce62d232939f1c207070b584df1814de2de081604051611dff91906040808252600f908201526e151c985b9cd9995c8814185d5cd959608a1b6060820152901515602082015260800190565b60606003805480602002602001604051908101604052809291908181526020018280548015611f3457602002820191905f5260205f20905b81546001600160a01b03168152600190910190602001808311611f16575b5050505050905090565b611f46612849565b611f4f82612811565b80611f5b576001611f5e565b60025b6001600160a01b0383165f8181526020818152604091829020805460ff9590951663010000000263ff000000199095169490941790935580519182526060928201839052600d928201929092526c109bdc9c9bddc814185d5cd959609a1b6080820152821515918101919091527f359e41b7f6189b08ab0ad7b56dfc630860095deba215f7d1e24f126d048ac6219060a0016114c5565b5f611fff876127fd565b60045462010000900460ff1660020361202b57604051633d1cc8fd60e21b815260040160405180910390fd5b6113978787878787875f61294d565b6001600160a01b0381165f90815260208190526040902054610100900460ff1660020361207a57604051633d1cc8fd60e21b815260040160405180910390fd5b61208381612811565b50565b61208e612849565b61209782612811565b806120a35760016120a6565b60025b6001600160a01b0383165f8181526020818152604091829020805460ff95909516620100000262ff00001990951694909417909355805191825260609282018390526018928201929092527f436f6c6c61746572616c697a6174696f6e2050617573656400000000000000006080820152821515918101919091527f359e41b7f6189b08ab0ad7b56dfc630860095deba215f7d1e24f126d048ac6219060a0016114c5565b612153612849565b8061215f576001612162565b60025b6004805460ff191660ff929092169190911790556040805181815260129181019190915271131a5c5d5a59185d1a5bdb8814185d5cd95960721b606082015281151560208201527fef159d9a32b2472e32b098f954f3ce62d232939f1c207070b584df1814de2de090608001611dff565b6121db612849565b806121e75760016121ea565b60025b600460016101000a81548160ff021916908360ff1602179055507fef159d9a32b2472e32b098f954f3ce62d232939f1c207070b584df1814de2de081604051611dff91906040808252600d908201526c14995919595b4814185d5cd959609a1b6060820152901515602082015260800190565b61227f6040518060600160405280606081526020015f81526020015f81525090565b60045460609060ff166002036122a857604051633d1cc8fd60e21b815260040160405180910390fd5b6122b583602001516127fd565b82516122c090612811565b6122cd8360200151612811565b5f5f6122e0855f01518660200151612e2c565b9150915084604001516001600160401b038111156123005761230061416d565b604051908082528060200260200182016040528015612329578160200160208202803683370190505b5084525f80805b87604001518110156124915789898281811061234e5761234e6149e3565b90506020020160208101906123639190614114565b9250826001600160a01b03168b6001600160a01b03160361238b5761238b6337cf6ad56128e3565b826001600160a01b0316826001600160a01b0316106123b1576123b16337cf6ad56128e3565b6123db8c82815181106123c6576123c66149e3565b60200260200101518487878c60600151613216565b60c08b015260a08a0181905260808a0191909152602088018051612400908390614835565b9052506080880151875180518390811061241c5761241c6149e3565b602090810291909101015260c088015115612464578760c00151876040018181516124479190614835565b90525060c088015160a089018051612460908390614835565b9052505b8760a001518c828151811061247b5761247b6149e3565b6020908102919091010152829150600101612330565b5085602001515f036124b6576040516311d1870d60e11b815260040160405180910390fd5b509399975050505050505050565b6124cc612849565b6124dd816316bb16f160e11b61346a565b6124ee576124ee6365513fc16128e3565b6001600160a01b0381165f9081526007602052604090205460ff161561251b5761251b6365513fc16128e3565b6001600160a01b0381165f81815260076020908152604091829020805460ff191660019081179091558251938452908301527f95f28d5f3b25ba2ec0ace967a30ee05f0ff47e77f8c63e8fe5fc009f95894a169101611dff565b60607f000000000000000000000000000000000000000000000000000000000000000082806001600160401b038111156125b1576125b161416d565b6040519080825280602002602001820160405280156125e457816020015b60608152602001906001900390816125cf5790505b5060408051606080820183525f80835260208301819052928201529194505b828110156127cd5786868281811061261d5761261d6149e3565b905060200281019061262f91906149f7565b61263890614a15565b915081602001511561276f57815160405163191d0cc560e11b81526001600160a01b0391821660048201525f9186169063323a198a90602401602060405180830381865afa15801561268c573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906126b091906149c8565b90506001600160a01b0381166126d957604051632f3285fb60e21b815260040160405180910390fd5b8251604080850151905163bd0226d760e01b81526001600160a01b0384169263bd0226d79261270e9233929190600401614ad6565b5f604051808303815f87803b158015612725575f5ffd5b505af1158015612737573d5f5f3e3d5ffd5b5050505061274c835f0151846040015161348c565b86838151811061275e5761275e6149e3565b6020026020010181905250506127c5565b81516001600160a01b0316301461279957604051637720ccd960e01b815260040160405180910390fd5b6127a7308360400151613501565b8582815181106127b9576127b96149e3565b60200260200101819052505b600101612603565b5050505092915050565b6001600160a01b0382165f90815260026020526040902042905561165584848484612aca565b803314612083576337cf6ad55f526004601cfd5b6001600160a01b0381165f9081526020819052604090205460ff1661208357604051634f3013c560e01b815260040160405180910390fd5b604051630225e24360e01b81523360048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690630225e243906024015b602060405180830381865afa1580156128ac573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906128d09190614867565b6128e1576128e16337cf6ad56128e3565b565b805f526004601cfd5b5f816001600160a01b031663565d878c6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612929573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610a7591906149c8565b5f61295788612811565b61296086613555565b82156129bc578115612994578387111561298d576040516378a198b960e11b815260040160405180910390fd5b50856129bc565b8461299f8886614835565b106129bc57846129af8886614835565b6129b991906148c7565b90505b8015806129ee57506001600160a01b038089165f908152600160209081526040808320938a1683529290522054600214155b611397575f612a278760405180608001604052808c6001600160a01b031681526020018581526020015f815260200160018152506135f8565b9150508015612a49576040516378a198b960e11b815260040160405180910390fd5b50979650505050505050565b6001600160a01b0381165f908152600260205260409020544290612a7c906104b090614835565b11156120835760405163792f8c5960e11b815260040160405180910390fd5b5f8115612ab457612aad858585613951565b9050612ac2565b612abf85858561395d565b90505b949350505050565b612ad3846127fd565b80612ae557635518d5cb5f526004601cfd5b6001600160a01b0384165f908152602081905260409020546301000000900460ff16600203612b2757604051633d1cc8fd60e21b815260040160405180910390fd5b6001600160a01b0384165f90815260066020526040902054811115612b5f57604051633448aa9d60e01b815260040160405180910390fd5b6001600160a01b038085165f90815260016020908152604080832093861683529290522054600214612c1f576001600160a01b038481165f81815260016020818152604080842095881680855295825280842060029081905582528084208301805480850182559085529382902090930180546001600160a01b0319168517905582519384528301939093528101919091527f5cbb919307f3804aff990e94bdc923c0878589779d539552a35353302b8ed8e59060600160405180910390a15b5f612c54836040518060800160405280886001600160a01b031681526020015f815260200187815260200160018152506135f8565b9150508015611642576040516378a198b960e11b815260040160405180910390fd5b60405163287530f760e01b81523360048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063287530f790602401612891565b5f5f5f5f5f5f612cd3876002613989565b925092509250612d106040805160c0810182525f80825260208201819052918101829052606081018290526080810182905260a081019190915290565b5f5b82811015612e2057848181518110612d2c57612d2c6149e3565b60200260200101519150816060015115612dc8575f612d748360800151868481518110612d5b57612d5b6149e3565b60200260200101518560400151600a6116199190614b01565b9050612d80818a614835565b83516001600160a01b03165f90815260208190526040902054909950612db6908290600160201b900462ffffff16612710613951565b612dc09089614835565b975050612e18565b60a082015115612e1857612e0b8260a00151858381518110612dec57612dec6149e3565b60200260200101518460400151600a612e059190614b01565b5f612a9b565b612e159087614835565b95505b600101612d12565b50505050509193909250565b612e846040518061012001604052805f6001600160a01b031681526020015f81526020015f81526020015f81526020015f81526020015f6001600160a01b031681526020015f81526020015f81526020015f81525090565b612ec46040518061010001604052805f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81525090565b6001600160a01b0384165f9081526020818152604080832081516101e081018352905460ff8082161515835261010080830482169584019590955262010000820481169383019390935263010000008104909216606082015262ffffff600160201b8304811660808301819052600160381b8404821660a0840152600160501b840490911660c083015261ffff600160681b8404811660e0840152600160781b8404811694830194909452600160881b83048416610120830152600160981b83048416610140830152600160a81b83048416610160830152600160b81b83048416610180830152600160c81b830484166101a0830152600160d81b9092049092166101c0830152909103612fdf57612fdf6365513fc16128e3565b612fe885613a48565b60a085015260408401526101008401526130217f00000000000000000000000000000000000000000000000000000000000000006128ec565b60405163035e6c1960e01b81526001600160a01b038781166004830152868116602483015260026044830152919091169063035e6c199060640160408051808303815f875af1158015613076573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061309a91906148a5565b60e085015260608401526001600160a01b03851680845260a082015162ffffff90811660208087019190915260c0840151909116604080870191909152805163313ce56760e01b8152905163313ce567926004808401939192918290030181865afa15801561310b573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061312f9190614b1f565b61313a90600a614b01565b60808401526001600160a01b03841660a084018190526040805163313ce56760e01b8152905163313ce567916004808201926020929091908290030181865afa158015613189573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906131ad9190614b1f565b6131b890600a614b01565b60c084015260a08201515f036131e65761016081015161ffff90811660c08401526101808201511660e08301525b81604001515f0361320e5760e081015161ffff90811660608401526101008201511660808301525b509250929050565b5f5f5f6132238787613b7f565b60208701528086525f0361323e57505f91508190508061345f565b60e085015115613277576132628560e00151865f0151670de0b6b3a7640000613951565b8560c001516132719190614835565b60a08601525b6080850151156132b05761329b8560800151865f0151670de0b6b3a7640000613951565b85606001516132aa9190614835565b60408601525b5f6132f36132e48860e0015188604001516132cb9190614b38565b6d04ee2d6d415b85acef81000000008a60600151613e5a565b88608001518960c00151613e5a565b90505f61271087602001518860a0015161330d9190614b38565b6133179190614848565b905085613322578099505b61333c8a836ec097ce7bc90715b34b9f1000000000613e5a565b885160405163e28d591d60e01b81526001600160a01b038c811660048301529297505f929091169063e28d591d90602401602060405180830381865afa158015613388573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906133ac9190614b4f565b905086156133d857818b11806133c157508086115b156133d3576133d36365513fc16128e3565b6133f1565b808611156133f1576133eb8b8288613ef6565b9a508095505b5f6134108960200151856ec097ce7bc90715b34b9f1000000000613ef6565b905081811115613457576134258c8284613ef6565b9450886020015185111561344a578b896020015161344391906148c7565b9450613457565b6134548c866148c7565b94505b508a94505050505b955095509592505050565b5f61347483613f22565b801561348557506134858383613f54565b9392505050565b60605f5f846001600160a01b03165f856040516134a99190614b66565b5f6040518083038185875af1925050503d805f81146134e3576040519150601f19603f3d011682016040523d82523d5f602084013e6134e8565b606091505b50915091506134f8858383613fd7565b95945050505050565b60605f5f846001600160a01b03168460405161351d9190614b66565b5f60405180830381855af49150503d805f81146134e3576040519150601f19603f3d011682016040523d82523d5f602084013e6134e8565b6040516373578c6760e01b81526001600160a01b0382811660048301527f000000000000000000000000000000000000000000000000000000000000000016906373578c6790602401602060405180830381865afa1580156135b9573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906135dd9190614867565b156135ef576135ef6337cf6ad56128e3565b61208381612a55565b5f5f5f5f5f61360b878760600151613989565b9250925092506136486040805160c0810182525f80825260208201819052918101829052606081018290526080810182905260a081019190915290565b5f5f5f5b8481101561391157868181518110613666576136666149e3565b60200260200101519350835f01516001600160a01b03168a5f01516001600160a01b0316148015613698575083606001515b80156136a757505f8a60400151115b15613796575f6136d67f00000000000000000000000000000000000000000000000000000000000000006128ec565b6001600160a01b0316635ae69163866020015160015f6040518463ffffffff1660e01b815260040161370a93929190614882565b6040805180830381865afa158015613724573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061374891906148a5565b88848151811061375a5761375a6149e3565b602002602001018193508281525050508a60600151811061378e57604051631db384db60e11b815260040160405180910390fd5b505f60608501525b83606001511561384f5783518a516001600160a01b039182169116036137d0578960200151846080018181516137cc91906148c7565b9052505b60808401511561384a5761383d61381085608001518884815181106137f7576137f76149e3565b60200260200101518760400151600a6116199190614b01565b85516001600160a01b03165f90815260208190526040902054600160201b900462ffffff16612710613951565b6138479084614835565b92505b613909565b83518a516001600160a01b0391821691160361387f5789604001518460a00181815161387b9190614835565b9052505b60a084015115613909576138bc8460a001518783815181106138a3576138a36149e3565b60200260200101518660400151600a612e059190614b01565b6138c69083614835565b91507f000000000000000000000000000000000000000000000000000000000000000082101561390957604051632e7cf4cd60e11b815260040160405180910390fd5b60010161364c565b50808211156139345761392481836148c7565b5f9750975050505050505061394a565b5f61393f83836148c7565b975097505050505050505b9250929050565b5f612ac284848461401f565b5f825f19048411830215820261397a5763ad251c275f526004601cfd5b50910281810615159190040190565b6060805f6139b67f00000000000000000000000000000000000000000000000000000000000000006128ec565b6001600160a01b038681165f9081526002602052604090819020905162020bc560e21b8152929091169162082f14916139f9918991600101908990600401614b7c565b5f604051808303815f875af1158015613a14573d5f5f3e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052613a3b9190810190614c4a565b9250925092509250925092565b5f80808080805f516020614d995f395f51905f525c61ffff60a082901c81169060b083901c169250925092505f7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663572e2fa26040518163ffffffff1660e01b8152600401602060405180830381865afa158015613ad1573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613af59190614867565b90506001600160a01b03848116908916148180613b0f5750805b15613b6d57818015613b1e5750805b15613b5457507f000000000000000000000000000000000000000000000000000000000000000096509194509250611e4b915050565b60405163fac97a2b60e01b815260040160405180910390fd5b505f9889985088975095505050505050565b5f5f613ba260405180606001604052805f81526020015f81526020015f81525090565b6001600160a01b0385165f90815260026020908152604080832060010180548251818502810185019093528083529192909190830182828015613c0c57602002820191905f5260205f20905b81546001600160a01b03168152600190910190602001808311613bee575b505050505090505f5f825190505f5b81811015613da5578381613c2e81614d80565b925081518110613c4057613c406149e3565b60200260200101519250875f01516001600160a01b0316836001600160a01b031603613d0157608088015160208901516040808b015160608c01518c51925163e28d591d60e01b81526001600160a01b038f81166004830152613cf5969594169063e28d591d90602401602060405180830381865afa158015613cc5573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613ce99190614b4f565b8a5160208c0151614043565b60208701528552613c1b565b60a08801516040516311005b0760e01b81526001600160a01b038b81166004830152909116906311005b0790602401602060405180830381865afa158015613d4b573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613d6f9190614b4f565b95508515613da057613d8b868960e001518a60c001515f612a9b565b85604001818151613d9c9190614835565b9052505b613c1b565b5061010087015115613de657613dc6845f0151886101000151612710613951565b84526020840151610100880151613de09190612710613951565b60208501525b6040840151845110613dfa575f9550613e4f565b836020015184604001511015613e425783516040850151613e3d91613e1e916148c7565b85516020870151670de0b6b3a764000091613e38916148c7565b61395d565b613e4c565b670de0b6b3a76400005b95505b505050509250929050565b8282025f198385098181108201900380613e895782613e805763ae47f7025f526004601cfd5b50819004613485565b808311613e9d5763ae47f7025f526004601cfd5b828486095f84810385169485900494848311909303908390038390046001010292030417600260038302811880840282030280840282030280840282030280840282030280840282030280840290910302029392505050565b5f613f02848484613e5a565b9050818385091561348557600101806134855763ae47f7025f526004601cfd5b5f613f34826301ffc9a760e01b613f54565b8015610a755750613f4d826001600160e01b0319613f54565b1592915050565b6040516001600160e01b0319821660248201525f90819060440160408051601f19818403018152919052602080820180516001600160e01b03166301ffc9a760e01b17815282519293505f9283928392909183918a617530fa92503d91505f519050828015613fc4575060208210155b8015611397575015159695505050505050565b6060613fe3838361409b565b8151158015613ffa57506001600160a01b0384163b155b15614018576040516314859aeb60e21b815260040160405180910390fd5b5092915050565b5f825f19048411830215820261403c5763ad251c275f526004601cfd5b5091020490565b5f5f5f61271061405687898d6001612a9b565b6140609190614b38565b905061406c8982614848565b6140769086614835565b92506140828882614848565b61408c9085614835565b91505097509795505050505050565b81611d755780515f036140c1576040516314859aeb60e21b815260040160405180910390fd5b805181602001fd5b5f602082840312156140d9575f5ffd5b81356001600160e01b031981168114613485575f5ffd5b6001600160a01b0381168114612083575f5ffd5b803561410f816140f0565b919050565b5f60208284031215614124575f5ffd5b8135613485816140f0565b5f5f5f60608486031215614141575f5ffd5b833561414c816140f0565b9250602084013561415c816140f0565b929592945050506040919091013590565b634e487b7160e01b5f52604160045260245ffd5b6040516101a081016001600160401b03811182821017156141a4576141a461416d565b60405290565b60405160e081016001600160401b03811182821017156141a4576141a461416d565b604051606081016001600160401b03811182821017156141a4576141a461416d565b60405160c081016001600160401b03811182821017156141a4576141a461416d565b604051601f8201601f191681016001600160401b03811182821017156142385761423861416d565b604052919050565b5f6101a0828403128015614252575f5ffd5b5061425b614181565b61426483614104565b81526020838101359082015260408084013590820152606080840135908201526080808401359082015260a0808401359082015260c0808401359082015260e080840135908201526101008084013590820152610120808401359082015261014080840135908201526101608084013590820152610180928301359281019290925250919050565b8015158114612083575f5ffd5b5f5f5f5f5f5f60c0878903121561430e575f5ffd5b8635614319816140f0565b9550602087013594506040870135614330816140f0565b9350606087013592506080870135915060a087013561434e816142ec565b809150509295509295509295565b602080825282518282018190525f918401906040840190835b8181101561439c5783516001600160a01b0316835260209384019390920191600101614375565b509095945050505050565b5f5f604083850312156143b8575f5ffd5b82356143c3816140f0565b915060208301356143d3816142ec565b809150509250929050565b5f5f5f5f5f60a086880312156143f2575f5ffd5b85356143fd816140f0565b9450602086013593506040860135614414816140f0565b925060608601359150608086013561442b816140f0565b809150509295509295909350565b5f5f5f5f6080858703121561444c575f5ffd5b8435614457816140f0565b935060208501359250604085013561446e816140f0565b9396929550929360600135925050565b5f5f5f60608486031215614490575f5ffd5b833561449b816140f0565b95602085013595506040909401359392505050565b5f602082840312156144c0575f5ffd5b5035919050565b5f5f604083850312156144d8575f5ffd5b82356144e3816140f0565b915060208301356143d3816140f0565b5f60208284031215614503575f5ffd5b8135613485816142ec565b5f6001600160401b038211156145265761452661416d565b5060051b60200190565b5f5f83601f840112614540575f5ffd5b5081356001600160401b03811115614556575f5ffd5b6020830191508360208260051b850101111561394a575f5ffd5b5f60e08284031215614580575f5ffd5b6145886141aa565b90508135614595816140f0565b815260208201356145a5816140f0565b60208201526040828101359082015260608201356145c2816142ec565b60608201526080828101359082015260a0808301359082015260c09182013591810191909152919050565b5f5f5f5f5f6101408688031215614602575f5ffd5b85356001600160401b03811115614617575f5ffd5b8601601f81018813614627575f5ffd5b803561463a6146358261450e565b614210565b8082825260208201915060208360051b85010192508a83111561465b575f5ffd5b6020840193505b8284101561467d578335825260209384019390910190614662565b975061468f9250505060208701614104565b935060408601356001600160401b038111156146a9575f5ffd5b6146b588828901614530565b90945092506146c990508760608801614570565b90509295509295909350565b5f8151808452602084019350602083015f5b828110156147055781518652602095860195909101906001016146e7565b5093949350505050565b604081525f83516060604084015261472a60a08401826146d5565b9050602085015160608401526040850151608084015282810360208401526134f881856146d5565b5f5f60208385031215614763575f5ffd5b82356001600160401b03811115614778575f5ffd5b61478485828601614530565b90969095509350505050565b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b5f602082016020835280845180835260408501915060408160051b8601019250602086015f5b8281101561481557603f19878603018452614800858351614790565b945060209384019391909101906001016147e4565b50929695505050505050565b634e487b7160e01b5f52601160045260245ffd5b80820180821115610a7557610a75614821565b5f8261486257634e487b7160e01b5f52601260045260245ffd5b500490565b5f60208284031215614877575f5ffd5b8151613485816142ec565b6001600160a01b0393909316835290151560208301521515604082015260600190565b5f5f604083850312156148b6575f5ffd5b505080516020909101519092909150565b81810381811115610a7557610a75614821565b6001815b6001841115614915578085048111156148f9576148f9614821565b600184161561490757908102905b60019390931c9280026148de565b935093915050565b5f8261492b57506001610a75565b8161493757505f610a75565b816001811461494d576002811461495757614973565b6001915050610a75565b60ff84111561496857614968614821565b50506001821b610a75565b5060208310610133831016604e8410600b8410161715614996575081810a610a75565b6149a25f1984846148da565b805f19048211156149b5576149b5614821565b029392505050565b5f613485838361491d565b5f602082840312156149d8575f5ffd5b8151613485816140f0565b634e487b7160e01b5f52603260045260245ffd5b5f8235605e19833603018112614a0b575f5ffd5b9190910192915050565b5f60608236031215614a25575f5ffd5b614a2d6141cc565b8235614a38816140f0565b81526020830135614a48816142ec565b602082015260408301356001600160401b03811115614a65575f5ffd5b830136601f820112614a75575f5ffd5b80356001600160401b03811115614a8e57614a8e61416d565b614aa1601f8201601f1916602001614210565b818152366020838501011115614ab5575f5ffd5b816020840160208301375f9181016020019190915260408301525092915050565b6001600160a01b038481168252831660208201526060604082018190525f90612abf90830184614790565b5f61348560ff84168361491d565b805160ff8116811461410f575f5ffd5b5f60208284031215614b2f575f5ffd5b61348582614b0f565b8082028115828204841417610a7557610a75614821565b5f60208284031215614b5f575f5ffd5b5051919050565b5f82518060208501845e5f920191825250919050565b6001600160a01b03841681526060602080830182905284549183018290525f85815290812090916080840190835b81811015614bd15783546001600160a01b0316835260019384019360209093019201614baa565b505060409390930193909352509392505050565b5f82601f830112614bf4575f5ffd5b8151614c026146358261450e565b8082825260208201915060208360051b860101925085831115614c23575f5ffd5b602085015b83811015614c40578051835260209283019201614c28565b5095945050505050565b5f5f5f60608486031215614c5c575f5ffd5b83516001600160401b03811115614c71575f5ffd5b8401601f81018613614c81575f5ffd5b8051614c8f6146358261450e565b80828252602082019150602060c08402850101925088831115614cb0575f5ffd5b6020840193505b82841015614d415760c0848a031215614cce575f5ffd5b614cd66141ee565b8451614ce1816140f0565b81526020850151614cf1816140f0565b6020820152614d0260408601614b0f565b60408201526060850151614d15816142ec565b60608201526080858101519082015260a08086015190820152825260c090930192602090910190614cb7565b8096505050505060208401516001600160401b03811115614d60575f5ffd5b614d6c86828701614be5565b604095909501519396949550929392505050565b5f60018201614d9157614d91614821565b506001019056fe1966ec4daf81281b2aba49348128e9b155301b8486bde131e0db16a52b730b82a26469706673582212203480a9d34d0738f022270141175efb5c96b0766841cbae8de67341217ab4a49d64736f6c634300081c00330000000000000000000000001310f352f1389969ece6741671c4b919523912ff0000000000000000000000000000000000000000000000008ac7230489e800000000000000000000000000000000000000000000000000000000000000000001
Deployed Bytecode
0x608060405234801561000f575f5ffd5b5060043610610387575f3560e01c80638a05a2e6116101df578063c03c24bb11610109578063d99f05e1116100a9578063ecdb97a011610079578063ecdb97a01461093f578063f794062e146109f4578063f96492c914610a1f578063fb2cb34e14610a32575f5ffd5b8063d99f05e1146108c4578063da11ee23146108eb578063e2f0ab011461090c578063e8bbf5d71461091f575f5ffd5b8063c8b5277e116100e4578063c8b5277e14610889578063ccb99c261461089c578063d53dc739146108af578063d78db3f1146108bc575f5ffd5b8063c03c24bb14610844578063c2ba474414610863578063c80fa87214610876575f5ffd5b8063a2675bcd1161017f578063afbe407a1161014f578063afbe407a146107f2578063b235d468146107fa578063b6606d1c1461081e578063b7b7f26014610831575f5ffd5b8063a2675bcd1461076c578063a2f88e49146107b6578063abf883cb146107bf578063af79b3ca146107e9575f5ffd5b8063901941f9116101ba578063901941f9146106dd57806397a5d5b5146107045780639b4e3822146107325780639d488a0c14610759575f5ffd5b80638a05a2e6146106905780638c75d4fe146106a35780638f73dcfa146106b6575f5ffd5b80633fd596ce116102c0578063699ba8b3116102605780637551cd48116102305780637551cd4814610644578063757942ea146106575780637beec6af1461066057806380a00b7414610669575f5ffd5b8063699ba8b31461059c5780636c3b426f146106095780636dac9023146106125780637148fa5414610631575f5ffd5b80634b3d3b581161029b5780634b3d3b58146105435780634b7e1ff114610556578063504d6b181461056957806363e12aa314610571575f5ffd5b80633fd596ce1461051e57806345a9bbde146105275780634b03195214610530575f5ffd5b80631e9fb63a1161032b5780632f7a4c65116103065780632f7a4c65146104b457806337142666146104db57806339a8bf38146105025780633e0cdfd31461050b575f5ffd5b80631e9fb63a146104785780632076d8e7146104815780632c62fa1014610494575f5ffd5b80630358e376116103665780630358e376146103e957806308799c63146103fe5780630a73e3911461041157806317c221c614610433575f5ffd5b80623c8bd41461038b57806301ffc9a7146103a7578063032886d9146103ca575b5f5ffd5b6103946104b081565b6040519081526020015b60405180910390f35b6103ba6103b53660046140c9565b610a45565b604051901515815260200161039e565b6103946103d8366004614114565b60056020525f908152604090205481565b6103fc6103f736600461412f565b610a7b565b005b6103fc61040c366004614240565b610be4565b6103ba61041f366004614114565b60076020525f908152604090205460ff1681565b5f516020614d995f395f51905f525c61ffff60a082901c81169060b083901c16604080516001600160a01b03909416845260208401929092529082015260600161039e565b6103946126de81565b61039461048f3660046142f9565b611352565b6104a76104a2366004614114565b6113a2565b60405161039e919061435c565b6103947f000000000000000000000000000000000000000000000000000000000000261681565b6103947f0000000000000000000000000000000000000000000000000000000005ee417081565b61039461270681565b6103fc6105193660046143a7565b611418565b6103946126e881565b6103946125e081565b6103fc61053e3660046143de565b6114d1565b6103fc610551366004614439565b611649565b6103fc61056436600461447e565b61165b565b6103fc611836565b61058461057f3660046144b0565b611850565b6040516001600160a01b03909116815260200161039e565b6105ea6105aa366004614114565b6001600160a01b03165f90815260208190526040902054600260ff6101008304811682149362010000840482168314936301000000900490911690911490565b604080519315158452911515602084015215159082015260600161039e565b61039461261681565b610394610620366004614114565b60026020525f908152604090205481565b6103fc61063f3660046144c7565b611878565b6103fc6106523660046144c7565b611c73565b61039461138881565b6103946103e881565b6103947f000000000000000000000000000000000000000000000000000000000000000081565b6103fc61069e366004614114565b611d79565b6103fc6106b13660046144c7565b611e0a565b6105847f0000000000000000000000001310f352f1389969ece6741671c4b919523912ff81565b6103947f000000000000000000000000000000000000000000000000000000000000270681565b610717610712366004614114565b611e38565b6040805193845260208401929092529082015260600161039e565b6103947f0000000000000000000000000000000000000000000000008ac7230489e8000081565b6103fc6107673660046144f3565b611e52565b61071761077a366004614114565b6001600160a01b03165f9081526020819052604090205462ffffff600160201b8204811692600160381b8304821692600160501b900490911690565b610394615b6881565b6103946107cd3660046144c7565b600160209081525f928352604080842090915290825290205481565b610394610bb881565b6104a7611ede565b60045461080c90610100900460ff1681565b60405160ff909116815260200161039e565b6103fc61082c3660046143a7565b611f3e565b61039461083f3660046142f9565b611ff5565b610394610852366004614114565b60066020525f908152604090205481565b6103fc610871366004614114565b61203a565b6103fc6108843660046143a7565b612086565b6103fc6108973660046144f3565b61214b565b6103fc6108aa3660046144f3565b6121d3565b60045461080c9060ff1681565b610394606481565b6103ba7f000000000000000000000000000000000000000000000000000000000000000181565b6108fe6108f93660046145ed565b61225d565b60405161039e92919061470f565b6103fc61091a366004614114565b6124c4565b61093261092d366004614752565b612575565b60405161039e91906147be565b6109b961094d366004614114565b6001600160a01b03165f9081526020819052604090205461ffff600160681b8204811692600160781b8304821692600160881b8104831692600160981b8204811692600160a81b8304821692600160b81b8104831692600160c81b8204811692600160d81b9092041690565b604080519889526020890197909752958701949094526060860192909252608085015260a084015260c083015260e08201526101000161039e565b6103ba610a02366004614114565b6001600160a01b03165f9081526020819052604090205460ff1690565b6103fc610a2d366004614439565b6127d7565b60045461080c9062010000900460ff1681565b5f6001600160e01b03198216634d6978eb60e11b1480610a7557506301ffc9a760e01b6001600160e01b03198316145b92915050565b610a84836127fd565b80610a9657635518d5cb5f526004601cfd5b6001600160a01b0383165f9081526020819052604090205462010000900460ff16600203610ad757604051633d1cc8fd60e21b815260040160405180910390fd5b6001600160a01b0383165f90815260056020526040902054811115610b0f57604051633448aa9d60e01b815260040160405180910390fd5b6001600160a01b038083165f81815260026020818152604080842042905594881683526001815284832093835292909252919091205414610bdf576001600160a01b038381165f81815260016020818152604080842095881680855295825280842060029081905582528084208301805480850182559085529382902090930180546001600160a01b0319168517905582519384528301939093528101919091527f5cbb919307f3804aff990e94bdc923c0878589779d539552a35353302b8ed8e5906060015b60405180910390a15b505050565b8051610bef90612811565b610bf7612849565b7f000000000000000000000000000000000000000000000000000000000000261681602001511180610c2e5750615b688160400151115b80610c4157508060400151816060015110155b15610c5357610c536365513fc16128e3565b8060a001518160800151101580610c7157508060e001518160800151115b80610c8357508060c001518160800151105b80610c9657508060e001518160c0015110155b80610ca65750610bb88160e00151115b80610cb3575060c0810151155b80610cc35750610bb88160a00151115b15610cd557610cd56365513fc16128e3565b806060015160648260a00151610ceb9190614835565b1180610d0a5750806060015160648260e00151610d089190614835565b115b15610d1c57610d1c6365513fc16128e3565b6113888161010001511180610d3757506103e8816101000151105b15610d4957610d496365513fc16128e3565b8061014001518161010001511180610d6a5750806101200151816101000151105b80610d7f575080610140015181610120015110155b80610d8d5750610120810151155b80610d9e5750612710816101400151115b15610db057610db06365513fc16128e3565b6040810151610dc190612710614835565b610deb907f0000000000000000000000000000000000000000000000000000000005ee4170614848565b81602001511115610e0357610e036365513fc16128e3565b6020810151158015610e1957505f816101600151115b15610e2b57610e2b6365513fc16128e3565b61018081015115610ecc5761018081015170ffffffffffffffffffffffffffffffffff1080610eba5750805f01516001600160a01b03166345d7b97a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610e94573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610eb89190614867565b155b15610ecc57610ecc6365513fc16128e3565b80516001600160a01b03165f9081526020819052604090208054600160201b900462ffffff1615801590610f0257506020820151155b15610f1457610f146365513fc16128e3565b5f610f3e7f0000000000000000000000001310f352f1389969ece6741671c4b919523912ff6128ec565b8351604051635ae6916360e01b81526001600160a01b039290921691635ae6916391610f71916001908190600401614882565b6040805180830381865afa158015610f8b573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610faf91906148a5565b91505060028103610fd35760405163583c953760e01b815260040160405180910390fd5b610ffc7f0000000000000000000000001310f352f1389969ece6741671c4b919523912ff6128ec565b8351604051635ae6916360e01b81526001600160a01b039290921691635ae691639161102f916001905f90600401614882565b6040805180830381865afa158015611049573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061106d91906148a5565b91505060011981016110925760405163583c953760e01b815260040160405180910390fd5b6020830151825462ffffff909116600160201b0266ffffff000000001990911617825560408301516110c79061271090614835565b825462ffffff91909116600160381b0269ffffff000000000000001990911617825560608301516110fb9061271090614835565b825462ffffff91909116600160501b0262ffffff60501b19909116178255608083015161112a90612710614835565b825461ffff91909116600160681b0261ffff60681b1990911617825560c083015161115790612710614835565b825461ffff91909116600160881b0261ffff60881b1990911617825560e083015161118490612710614835565b825461ffff91909116600160981b0261ffff60981b19909116178255608083015160a08401516111b491906148c7565b825461010085015167ffff00000000ffff60781b19909116600160781b61ffff9384160261ffff60a81b191617600160a81b928216929092029190911783556111ff906127106148c7565b825461012085015161014086015163ffffffff60b81b19909216600160b81b61ffff9485160261ffff60c81b191617600160c81b918416919091021761ffff60d81b1916600160d81b929091169190910217825561016083015183516001600160a01b039081165f90815260056020908152604080832094909455610180870151875190931682526006905282902055517f7118653a594971f43f27090077f0b05efeaf77dd61915894fa826f79ca0ab5b890610bd690859081516001600160a01b031681526101a081016020830151602083015260408301516040830152606083015160608301526080830151608083015260a083015160a083015260c083015160c083015260e083015160e083015261010083015161010083015261012083015161012083015261014083015161014083015261016083015161016083015261018083015161018083015292915050565b5f61135c876127fd565b600454610100900460ff1660020361138757604051633d1cc8fd60e21b815260040160405180910390fd5b611397878787878760018861294d565b979650505050505050565b6001600160a01b0381165f9081526002602090815260409182902060010180548351818402810184019094528084526060939283018282801561140c57602002820191905f5260205f20905b81546001600160a01b031681526001909101906020018083116113ee575b50505050509050919050565b611420612849565b61142982612811565b80611435576001611438565b60025b6001600160a01b0383165f8181526020818152604091829020805460ff959095166101000261ff00199095169490941790935580519182526060928201839052600b928201929092526a135a5b9d0814185d5cd95960aa1b6080820152821515918101919091527f359e41b7f6189b08ab0ad7b56dfc630860095deba215f7d1e24f126d048ac6219060a0015b60405180910390a15050565b6114da856127fd565b6114e385612811565b6114ec81612a55565b6001600160a01b038086165f90815260016020908152604080832093851683529290522054600214611525576115256365513fc16128e3565b8315611642575f5f6115567f0000000000000000000000001310f352f1389969ece6741671c4b919523912ff6128ec565b6001600160a01b0316635ae69163866001806040518463ffffffff1660e01b815260040161158693929190614882565b6040805180830381865afa1580156115a0573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906115c491906148a5565b915091505f81146115e85760405163583c953760e01b815260040160405180910390fd5b7f0000000000000000000000000000000000000000000000008ac7230489e80000611620878461161988600a6149bd565b6001612a9b565b101561163f57604051632e7cf4cd60e11b815260040160405180910390fd5b50505b5050505050565b61165584848484612aca565b50505050565b611663612c76565b61166c83612811565b6001600160a01b0383165f9081526020818152604080832081516101e081018352905460ff8082161515835261010080830482169584019590955262010000820481169383019390935263010000008104909216606082015262ffffff600160201b8304811660808301819052600160381b8404821660a0840152600160501b840490911660c083015261ffff600160681b8404811660e0840152600160781b8404811694830194909452600160881b83048416610120830152600160981b83048416610140830152600160a81b83048416610160830152600160b81b83048416610180830152600160c81b830484166101a0830152600160d81b9092049092166101c08301529091036117935760405163fac97a2b60e01b815260040160405180910390fd5b82158015906117bc575080610120015161ffff168310806117bc575080610140015161ffff1683115b156117ce576117ce6365513fc16128e3565b81158015906117f75750806101a0015161ffff168210806117f75750806101c0015161ffff1682115b15611809576118096365513fc16128e3565b60a083901b60b083901b176001600160a01b03851617805f516020614d995f395f51905f525d5050505050565b61183e612c76565b5f5f516020614d995f395f51905f525d565b6003818154811061185f575f80fd5b5f918252602090912001546001600160a01b0316905081565b611880612849565b806001600160a01b0316826001600160a01b0316036118a6576118a66365513fc16128e3565b806001600160a01b03166338d52e0f6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156118e2573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061190691906149c8565b6001600160a01b0316826001600160a01b03166338d52e0f6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561194b573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061196f91906149c8565b6001600160a01b03160361198a5761198a6365513fc16128e3565b6003541561199f5761199f6365513fc16128e3565b816001600160a01b03166345d7b97a6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156119db573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906119ff9190614867565b158015611a695750806001600160a01b03166345d7b97a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611a43573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611a679190614867565b155b15611a7b57611a7b6365513fc16128e3565b6001600160a01b038281165f818152602081905260408082208054600160ff19918216811790925594861683529181902080549094169091179092559051637ada7a0960e01b8152336004820152637ada7a09906024016020604051808303815f875af1158015611aee573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611b129190614867565b611b2357611b23635518d5cb6128e3565b604051637ada7a0960e01b81523360048201526001600160a01b03821690637ada7a09906024016020604051808303815f875af1158015611b66573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611b8a9190614867565b611b9b57611b9b635518d5cb6128e3565b60038054600180820183555f8390527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b91820180546001600160a01b03199081166001600160a01b0388811691821790935585549384019095559190920180549091169184169190911790556040519081527f017664858438d89f547fee46da0bcfc5396ea13a9fb1490b8fdd76cfa979f1a99060200160405180910390a16040516001600160a01b03821681527f017664858438d89f547fee46da0bcfc5396ea13a9fb1490b8fdd76cfa979f1a9906020016114c5565b611c7c82612811565b611c8581612811565b806001600160a01b03166341ed2c126040518163ffffffff1660e01b8152600401602060405180830381865afa158015611cc1573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611ce591906149c8565b6001600160a01b0316826001600160a01b03166341ed2c126040518163ffffffff1660e01b8152600401602060405180830381865afa158015611d2a573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611d4e91906149c8565b6001600160a01b031614611d7557604051631284375160e11b815260040160405180910390fd5b5050565b611d81612849565b6001600160a01b0381165f9081526007602052604090205460ff16611dad57611dad6365513fc16128e3565b6001600160a01b0381165f818152600760209081526040808320805460ff191690558051938452908301919091527f95f28d5f3b25ba2ec0ace967a30ee05f0ff47e77f8c63e8fe5fc009f95894a1691015b60405180910390a150565b611e13826127fd565b611e1c82612811565b6001600160a01b03165f90815260026020526040902042905550565b5f5f5f611e4484612cc2565b9250925092505b9193909250565b611e5a612849565b80611e66576001611e69565b60025b600460026101000a81548160ff021916908360ff1602179055507fef159d9a32b2472e32b098f954f3ce62d232939f1c207070b584df1814de2de081604051611dff91906040808252600f908201526e151c985b9cd9995c8814185d5cd959608a1b6060820152901515602082015260800190565b60606003805480602002602001604051908101604052809291908181526020018280548015611f3457602002820191905f5260205f20905b81546001600160a01b03168152600190910190602001808311611f16575b5050505050905090565b611f46612849565b611f4f82612811565b80611f5b576001611f5e565b60025b6001600160a01b0383165f8181526020818152604091829020805460ff9590951663010000000263ff000000199095169490941790935580519182526060928201839052600d928201929092526c109bdc9c9bddc814185d5cd959609a1b6080820152821515918101919091527f359e41b7f6189b08ab0ad7b56dfc630860095deba215f7d1e24f126d048ac6219060a0016114c5565b5f611fff876127fd565b60045462010000900460ff1660020361202b57604051633d1cc8fd60e21b815260040160405180910390fd5b6113978787878787875f61294d565b6001600160a01b0381165f90815260208190526040902054610100900460ff1660020361207a57604051633d1cc8fd60e21b815260040160405180910390fd5b61208381612811565b50565b61208e612849565b61209782612811565b806120a35760016120a6565b60025b6001600160a01b0383165f8181526020818152604091829020805460ff95909516620100000262ff00001990951694909417909355805191825260609282018390526018928201929092527f436f6c6c61746572616c697a6174696f6e2050617573656400000000000000006080820152821515918101919091527f359e41b7f6189b08ab0ad7b56dfc630860095deba215f7d1e24f126d048ac6219060a0016114c5565b612153612849565b8061215f576001612162565b60025b6004805460ff191660ff929092169190911790556040805181815260129181019190915271131a5c5d5a59185d1a5bdb8814185d5cd95960721b606082015281151560208201527fef159d9a32b2472e32b098f954f3ce62d232939f1c207070b584df1814de2de090608001611dff565b6121db612849565b806121e75760016121ea565b60025b600460016101000a81548160ff021916908360ff1602179055507fef159d9a32b2472e32b098f954f3ce62d232939f1c207070b584df1814de2de081604051611dff91906040808252600d908201526c14995919595b4814185d5cd959609a1b6060820152901515602082015260800190565b61227f6040518060600160405280606081526020015f81526020015f81525090565b60045460609060ff166002036122a857604051633d1cc8fd60e21b815260040160405180910390fd5b6122b583602001516127fd565b82516122c090612811565b6122cd8360200151612811565b5f5f6122e0855f01518660200151612e2c565b9150915084604001516001600160401b038111156123005761230061416d565b604051908082528060200260200182016040528015612329578160200160208202803683370190505b5084525f80805b87604001518110156124915789898281811061234e5761234e6149e3565b90506020020160208101906123639190614114565b9250826001600160a01b03168b6001600160a01b03160361238b5761238b6337cf6ad56128e3565b826001600160a01b0316826001600160a01b0316106123b1576123b16337cf6ad56128e3565b6123db8c82815181106123c6576123c66149e3565b60200260200101518487878c60600151613216565b60c08b015260a08a0181905260808a0191909152602088018051612400908390614835565b9052506080880151875180518390811061241c5761241c6149e3565b602090810291909101015260c088015115612464578760c00151876040018181516124479190614835565b90525060c088015160a089018051612460908390614835565b9052505b8760a001518c828151811061247b5761247b6149e3565b6020908102919091010152829150600101612330565b5085602001515f036124b6576040516311d1870d60e11b815260040160405180910390fd5b509399975050505050505050565b6124cc612849565b6124dd816316bb16f160e11b61346a565b6124ee576124ee6365513fc16128e3565b6001600160a01b0381165f9081526007602052604090205460ff161561251b5761251b6365513fc16128e3565b6001600160a01b0381165f81815260076020908152604091829020805460ff191660019081179091558251938452908301527f95f28d5f3b25ba2ec0ace967a30ee05f0ff47e77f8c63e8fe5fc009f95894a169101611dff565b60607f0000000000000000000000001310f352f1389969ece6741671c4b919523912ff82806001600160401b038111156125b1576125b161416d565b6040519080825280602002602001820160405280156125e457816020015b60608152602001906001900390816125cf5790505b5060408051606080820183525f80835260208301819052928201529194505b828110156127cd5786868281811061261d5761261d6149e3565b905060200281019061262f91906149f7565b61263890614a15565b915081602001511561276f57815160405163191d0cc560e11b81526001600160a01b0391821660048201525f9186169063323a198a90602401602060405180830381865afa15801561268c573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906126b091906149c8565b90506001600160a01b0381166126d957604051632f3285fb60e21b815260040160405180910390fd5b8251604080850151905163bd0226d760e01b81526001600160a01b0384169263bd0226d79261270e9233929190600401614ad6565b5f604051808303815f87803b158015612725575f5ffd5b505af1158015612737573d5f5f3e3d5ffd5b5050505061274c835f0151846040015161348c565b86838151811061275e5761275e6149e3565b6020026020010181905250506127c5565b81516001600160a01b0316301461279957604051637720ccd960e01b815260040160405180910390fd5b6127a7308360400151613501565b8582815181106127b9576127b96149e3565b60200260200101819052505b600101612603565b5050505092915050565b6001600160a01b0382165f90815260026020526040902042905561165584848484612aca565b803314612083576337cf6ad55f526004601cfd5b6001600160a01b0381165f9081526020819052604090205460ff1661208357604051634f3013c560e01b815260040160405180910390fd5b604051630225e24360e01b81523360048201527f0000000000000000000000001310f352f1389969ece6741671c4b919523912ff6001600160a01b031690630225e243906024015b602060405180830381865afa1580156128ac573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906128d09190614867565b6128e1576128e16337cf6ad56128e3565b565b805f526004601cfd5b5f816001600160a01b031663565d878c6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612929573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610a7591906149c8565b5f61295788612811565b61296086613555565b82156129bc578115612994578387111561298d576040516378a198b960e11b815260040160405180910390fd5b50856129bc565b8461299f8886614835565b106129bc57846129af8886614835565b6129b991906148c7565b90505b8015806129ee57506001600160a01b038089165f908152600160209081526040808320938a1683529290522054600214155b611397575f612a278760405180608001604052808c6001600160a01b031681526020018581526020015f815260200160018152506135f8565b9150508015612a49576040516378a198b960e11b815260040160405180910390fd5b50979650505050505050565b6001600160a01b0381165f908152600260205260409020544290612a7c906104b090614835565b11156120835760405163792f8c5960e11b815260040160405180910390fd5b5f8115612ab457612aad858585613951565b9050612ac2565b612abf85858561395d565b90505b949350505050565b612ad3846127fd565b80612ae557635518d5cb5f526004601cfd5b6001600160a01b0384165f908152602081905260409020546301000000900460ff16600203612b2757604051633d1cc8fd60e21b815260040160405180910390fd5b6001600160a01b0384165f90815260066020526040902054811115612b5f57604051633448aa9d60e01b815260040160405180910390fd5b6001600160a01b038085165f90815260016020908152604080832093861683529290522054600214612c1f576001600160a01b038481165f81815260016020818152604080842095881680855295825280842060029081905582528084208301805480850182559085529382902090930180546001600160a01b0319168517905582519384528301939093528101919091527f5cbb919307f3804aff990e94bdc923c0878589779d539552a35353302b8ed8e59060600160405180910390a15b5f612c54836040518060800160405280886001600160a01b031681526020015f815260200187815260200160018152506135f8565b9150508015611642576040516378a198b960e11b815260040160405180910390fd5b60405163287530f760e01b81523360048201527f0000000000000000000000001310f352f1389969ece6741671c4b919523912ff6001600160a01b03169063287530f790602401612891565b5f5f5f5f5f5f612cd3876002613989565b925092509250612d106040805160c0810182525f80825260208201819052918101829052606081018290526080810182905260a081019190915290565b5f5b82811015612e2057848181518110612d2c57612d2c6149e3565b60200260200101519150816060015115612dc8575f612d748360800151868481518110612d5b57612d5b6149e3565b60200260200101518560400151600a6116199190614b01565b9050612d80818a614835565b83516001600160a01b03165f90815260208190526040902054909950612db6908290600160201b900462ffffff16612710613951565b612dc09089614835565b975050612e18565b60a082015115612e1857612e0b8260a00151858381518110612dec57612dec6149e3565b60200260200101518460400151600a612e059190614b01565b5f612a9b565b612e159087614835565b95505b600101612d12565b50505050509193909250565b612e846040518061012001604052805f6001600160a01b031681526020015f81526020015f81526020015f81526020015f81526020015f6001600160a01b031681526020015f81526020015f81526020015f81525090565b612ec46040518061010001604052805f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81525090565b6001600160a01b0384165f9081526020818152604080832081516101e081018352905460ff8082161515835261010080830482169584019590955262010000820481169383019390935263010000008104909216606082015262ffffff600160201b8304811660808301819052600160381b8404821660a0840152600160501b840490911660c083015261ffff600160681b8404811660e0840152600160781b8404811694830194909452600160881b83048416610120830152600160981b83048416610140830152600160a81b83048416610160830152600160b81b83048416610180830152600160c81b830484166101a0830152600160d81b9092049092166101c0830152909103612fdf57612fdf6365513fc16128e3565b612fe885613a48565b60a085015260408401526101008401526130217f0000000000000000000000001310f352f1389969ece6741671c4b919523912ff6128ec565b60405163035e6c1960e01b81526001600160a01b038781166004830152868116602483015260026044830152919091169063035e6c199060640160408051808303815f875af1158015613076573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061309a91906148a5565b60e085015260608401526001600160a01b03851680845260a082015162ffffff90811660208087019190915260c0840151909116604080870191909152805163313ce56760e01b8152905163313ce567926004808401939192918290030181865afa15801561310b573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061312f9190614b1f565b61313a90600a614b01565b60808401526001600160a01b03841660a084018190526040805163313ce56760e01b8152905163313ce567916004808201926020929091908290030181865afa158015613189573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906131ad9190614b1f565b6131b890600a614b01565b60c084015260a08201515f036131e65761016081015161ffff90811660c08401526101808201511660e08301525b81604001515f0361320e5760e081015161ffff90811660608401526101008201511660808301525b509250929050565b5f5f5f6132238787613b7f565b60208701528086525f0361323e57505f91508190508061345f565b60e085015115613277576132628560e00151865f0151670de0b6b3a7640000613951565b8560c001516132719190614835565b60a08601525b6080850151156132b05761329b8560800151865f0151670de0b6b3a7640000613951565b85606001516132aa9190614835565b60408601525b5f6132f36132e48860e0015188604001516132cb9190614b38565b6d04ee2d6d415b85acef81000000008a60600151613e5a565b88608001518960c00151613e5a565b90505f61271087602001518860a0015161330d9190614b38565b6133179190614848565b905085613322578099505b61333c8a836ec097ce7bc90715b34b9f1000000000613e5a565b885160405163e28d591d60e01b81526001600160a01b038c811660048301529297505f929091169063e28d591d90602401602060405180830381865afa158015613388573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906133ac9190614b4f565b905086156133d857818b11806133c157508086115b156133d3576133d36365513fc16128e3565b6133f1565b808611156133f1576133eb8b8288613ef6565b9a508095505b5f6134108960200151856ec097ce7bc90715b34b9f1000000000613ef6565b905081811115613457576134258c8284613ef6565b9450886020015185111561344a578b896020015161344391906148c7565b9450613457565b6134548c866148c7565b94505b508a94505050505b955095509592505050565b5f61347483613f22565b801561348557506134858383613f54565b9392505050565b60605f5f846001600160a01b03165f856040516134a99190614b66565b5f6040518083038185875af1925050503d805f81146134e3576040519150601f19603f3d011682016040523d82523d5f602084013e6134e8565b606091505b50915091506134f8858383613fd7565b95945050505050565b60605f5f846001600160a01b03168460405161351d9190614b66565b5f60405180830381855af49150503d805f81146134e3576040519150601f19603f3d011682016040523d82523d5f602084013e6134e8565b6040516373578c6760e01b81526001600160a01b0382811660048301527f0000000000000000000000001310f352f1389969ece6741671c4b919523912ff16906373578c6790602401602060405180830381865afa1580156135b9573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906135dd9190614867565b156135ef576135ef6337cf6ad56128e3565b61208381612a55565b5f5f5f5f5f61360b878760600151613989565b9250925092506136486040805160c0810182525f80825260208201819052918101829052606081018290526080810182905260a081019190915290565b5f5f5f5b8481101561391157868181518110613666576136666149e3565b60200260200101519350835f01516001600160a01b03168a5f01516001600160a01b0316148015613698575083606001515b80156136a757505f8a60400151115b15613796575f6136d67f0000000000000000000000001310f352f1389969ece6741671c4b919523912ff6128ec565b6001600160a01b0316635ae69163866020015160015f6040518463ffffffff1660e01b815260040161370a93929190614882565b6040805180830381865afa158015613724573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061374891906148a5565b88848151811061375a5761375a6149e3565b602002602001018193508281525050508a60600151811061378e57604051631db384db60e11b815260040160405180910390fd5b505f60608501525b83606001511561384f5783518a516001600160a01b039182169116036137d0578960200151846080018181516137cc91906148c7565b9052505b60808401511561384a5761383d61381085608001518884815181106137f7576137f76149e3565b60200260200101518760400151600a6116199190614b01565b85516001600160a01b03165f90815260208190526040902054600160201b900462ffffff16612710613951565b6138479084614835565b92505b613909565b83518a516001600160a01b0391821691160361387f5789604001518460a00181815161387b9190614835565b9052505b60a084015115613909576138bc8460a001518783815181106138a3576138a36149e3565b60200260200101518660400151600a612e059190614b01565b6138c69083614835565b91507f0000000000000000000000000000000000000000000000008ac7230489e8000082101561390957604051632e7cf4cd60e11b815260040160405180910390fd5b60010161364c565b50808211156139345761392481836148c7565b5f9750975050505050505061394a565b5f61393f83836148c7565b975097505050505050505b9250929050565b5f612ac284848461401f565b5f825f19048411830215820261397a5763ad251c275f526004601cfd5b50910281810615159190040190565b6060805f6139b67f0000000000000000000000001310f352f1389969ece6741671c4b919523912ff6128ec565b6001600160a01b038681165f9081526002602052604090819020905162020bc560e21b8152929091169162082f14916139f9918991600101908990600401614b7c565b5f604051808303815f875af1158015613a14573d5f5f3e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052613a3b9190810190614c4a565b9250925092509250925092565b5f80808080805f516020614d995f395f51905f525c61ffff60a082901c81169060b083901c169250925092505f7f0000000000000000000000001310f352f1389969ece6741671c4b919523912ff6001600160a01b031663572e2fa26040518163ffffffff1660e01b8152600401602060405180830381865afa158015613ad1573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613af59190614867565b90506001600160a01b03848116908916148180613b0f5750805b15613b6d57818015613b1e5750805b15613b5457507f000000000000000000000000000000000000000000000000000000000000270696509194509250611e4b915050565b60405163fac97a2b60e01b815260040160405180910390fd5b505f9889985088975095505050505050565b5f5f613ba260405180606001604052805f81526020015f81526020015f81525090565b6001600160a01b0385165f90815260026020908152604080832060010180548251818502810185019093528083529192909190830182828015613c0c57602002820191905f5260205f20905b81546001600160a01b03168152600190910190602001808311613bee575b505050505090505f5f825190505f5b81811015613da5578381613c2e81614d80565b925081518110613c4057613c406149e3565b60200260200101519250875f01516001600160a01b0316836001600160a01b031603613d0157608088015160208901516040808b015160608c01518c51925163e28d591d60e01b81526001600160a01b038f81166004830152613cf5969594169063e28d591d90602401602060405180830381865afa158015613cc5573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613ce99190614b4f565b8a5160208c0151614043565b60208701528552613c1b565b60a08801516040516311005b0760e01b81526001600160a01b038b81166004830152909116906311005b0790602401602060405180830381865afa158015613d4b573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613d6f9190614b4f565b95508515613da057613d8b868960e001518a60c001515f612a9b565b85604001818151613d9c9190614835565b9052505b613c1b565b5061010087015115613de657613dc6845f0151886101000151612710613951565b84526020840151610100880151613de09190612710613951565b60208501525b6040840151845110613dfa575f9550613e4f565b836020015184604001511015613e425783516040850151613e3d91613e1e916148c7565b85516020870151670de0b6b3a764000091613e38916148c7565b61395d565b613e4c565b670de0b6b3a76400005b95505b505050509250929050565b8282025f198385098181108201900380613e895782613e805763ae47f7025f526004601cfd5b50819004613485565b808311613e9d5763ae47f7025f526004601cfd5b828486095f84810385169485900494848311909303908390038390046001010292030417600260038302811880840282030280840282030280840282030280840282030280840282030280840290910302029392505050565b5f613f02848484613e5a565b9050818385091561348557600101806134855763ae47f7025f526004601cfd5b5f613f34826301ffc9a760e01b613f54565b8015610a755750613f4d826001600160e01b0319613f54565b1592915050565b6040516001600160e01b0319821660248201525f90819060440160408051601f19818403018152919052602080820180516001600160e01b03166301ffc9a760e01b17815282519293505f9283928392909183918a617530fa92503d91505f519050828015613fc4575060208210155b8015611397575015159695505050505050565b6060613fe3838361409b565b8151158015613ffa57506001600160a01b0384163b155b15614018576040516314859aeb60e21b815260040160405180910390fd5b5092915050565b5f825f19048411830215820261403c5763ad251c275f526004601cfd5b5091020490565b5f5f5f61271061405687898d6001612a9b565b6140609190614b38565b905061406c8982614848565b6140769086614835565b92506140828882614848565b61408c9085614835565b91505097509795505050505050565b81611d755780515f036140c1576040516314859aeb60e21b815260040160405180910390fd5b805181602001fd5b5f602082840312156140d9575f5ffd5b81356001600160e01b031981168114613485575f5ffd5b6001600160a01b0381168114612083575f5ffd5b803561410f816140f0565b919050565b5f60208284031215614124575f5ffd5b8135613485816140f0565b5f5f5f60608486031215614141575f5ffd5b833561414c816140f0565b9250602084013561415c816140f0565b929592945050506040919091013590565b634e487b7160e01b5f52604160045260245ffd5b6040516101a081016001600160401b03811182821017156141a4576141a461416d565b60405290565b60405160e081016001600160401b03811182821017156141a4576141a461416d565b604051606081016001600160401b03811182821017156141a4576141a461416d565b60405160c081016001600160401b03811182821017156141a4576141a461416d565b604051601f8201601f191681016001600160401b03811182821017156142385761423861416d565b604052919050565b5f6101a0828403128015614252575f5ffd5b5061425b614181565b61426483614104565b81526020838101359082015260408084013590820152606080840135908201526080808401359082015260a0808401359082015260c0808401359082015260e080840135908201526101008084013590820152610120808401359082015261014080840135908201526101608084013590820152610180928301359281019290925250919050565b8015158114612083575f5ffd5b5f5f5f5f5f5f60c0878903121561430e575f5ffd5b8635614319816140f0565b9550602087013594506040870135614330816140f0565b9350606087013592506080870135915060a087013561434e816142ec565b809150509295509295509295565b602080825282518282018190525f918401906040840190835b8181101561439c5783516001600160a01b0316835260209384019390920191600101614375565b509095945050505050565b5f5f604083850312156143b8575f5ffd5b82356143c3816140f0565b915060208301356143d3816142ec565b809150509250929050565b5f5f5f5f5f60a086880312156143f2575f5ffd5b85356143fd816140f0565b9450602086013593506040860135614414816140f0565b925060608601359150608086013561442b816140f0565b809150509295509295909350565b5f5f5f5f6080858703121561444c575f5ffd5b8435614457816140f0565b935060208501359250604085013561446e816140f0565b9396929550929360600135925050565b5f5f5f60608486031215614490575f5ffd5b833561449b816140f0565b95602085013595506040909401359392505050565b5f602082840312156144c0575f5ffd5b5035919050565b5f5f604083850312156144d8575f5ffd5b82356144e3816140f0565b915060208301356143d3816140f0565b5f60208284031215614503575f5ffd5b8135613485816142ec565b5f6001600160401b038211156145265761452661416d565b5060051b60200190565b5f5f83601f840112614540575f5ffd5b5081356001600160401b03811115614556575f5ffd5b6020830191508360208260051b850101111561394a575f5ffd5b5f60e08284031215614580575f5ffd5b6145886141aa565b90508135614595816140f0565b815260208201356145a5816140f0565b60208201526040828101359082015260608201356145c2816142ec565b60608201526080828101359082015260a0808301359082015260c09182013591810191909152919050565b5f5f5f5f5f6101408688031215614602575f5ffd5b85356001600160401b03811115614617575f5ffd5b8601601f81018813614627575f5ffd5b803561463a6146358261450e565b614210565b8082825260208201915060208360051b85010192508a83111561465b575f5ffd5b6020840193505b8284101561467d578335825260209384019390910190614662565b975061468f9250505060208701614104565b935060408601356001600160401b038111156146a9575f5ffd5b6146b588828901614530565b90945092506146c990508760608801614570565b90509295509295909350565b5f8151808452602084019350602083015f5b828110156147055781518652602095860195909101906001016146e7565b5093949350505050565b604081525f83516060604084015261472a60a08401826146d5565b9050602085015160608401526040850151608084015282810360208401526134f881856146d5565b5f5f60208385031215614763575f5ffd5b82356001600160401b03811115614778575f5ffd5b61478485828601614530565b90969095509350505050565b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b5f602082016020835280845180835260408501915060408160051b8601019250602086015f5b8281101561481557603f19878603018452614800858351614790565b945060209384019391909101906001016147e4565b50929695505050505050565b634e487b7160e01b5f52601160045260245ffd5b80820180821115610a7557610a75614821565b5f8261486257634e487b7160e01b5f52601260045260245ffd5b500490565b5f60208284031215614877575f5ffd5b8151613485816142ec565b6001600160a01b0393909316835290151560208301521515604082015260600190565b5f5f604083850312156148b6575f5ffd5b505080516020909101519092909150565b81810381811115610a7557610a75614821565b6001815b6001841115614915578085048111156148f9576148f9614821565b600184161561490757908102905b60019390931c9280026148de565b935093915050565b5f8261492b57506001610a75565b8161493757505f610a75565b816001811461494d576002811461495757614973565b6001915050610a75565b60ff84111561496857614968614821565b50506001821b610a75565b5060208310610133831016604e8410600b8410161715614996575081810a610a75565b6149a25f1984846148da565b805f19048211156149b5576149b5614821565b029392505050565b5f613485838361491d565b5f602082840312156149d8575f5ffd5b8151613485816140f0565b634e487b7160e01b5f52603260045260245ffd5b5f8235605e19833603018112614a0b575f5ffd5b9190910192915050565b5f60608236031215614a25575f5ffd5b614a2d6141cc565b8235614a38816140f0565b81526020830135614a48816142ec565b602082015260408301356001600160401b03811115614a65575f5ffd5b830136601f820112614a75575f5ffd5b80356001600160401b03811115614a8e57614a8e61416d565b614aa1601f8201601f1916602001614210565b818152366020838501011115614ab5575f5ffd5b816020840160208301375f9181016020019190915260408301525092915050565b6001600160a01b038481168252831660208201526060604082018190525f90612abf90830184614790565b5f61348560ff84168361491d565b805160ff8116811461410f575f5ffd5b5f60208284031215614b2f575f5ffd5b61348582614b0f565b8082028115828204841417610a7557610a75614821565b5f60208284031215614b5f575f5ffd5b5051919050565b5f82518060208501845e5f920191825250919050565b6001600160a01b03841681526060602080830182905284549183018290525f85815290812090916080840190835b81811015614bd15783546001600160a01b0316835260019384019360209093019201614baa565b505060409390930193909352509392505050565b5f82601f830112614bf4575f5ffd5b8151614c026146358261450e565b8082825260208201915060208360051b860101925085831115614c23575f5ffd5b602085015b83811015614c40578051835260209283019201614c28565b5095945050505050565b5f5f5f60608486031215614c5c575f5ffd5b83516001600160401b03811115614c71575f5ffd5b8401601f81018613614c81575f5ffd5b8051614c8f6146358261450e565b80828252602082019150602060c08402850101925088831115614cb0575f5ffd5b6020840193505b82841015614d415760c0848a031215614cce575f5ffd5b614cd66141ee565b8451614ce1816140f0565b81526020850151614cf1816140f0565b6020820152614d0260408601614b0f565b60408201526060850151614d15816142ec565b60608201526080858101519082015260a08086015190820152825260c090930192602090910190614cb7565b8096505050505060208401516001600160401b03811115614d60575f5ffd5b614d6c86828701614be5565b604095909501519396949550929392505050565b5f60018201614d9157614d91614821565b506001019056fe1966ec4daf81281b2aba49348128e9b155301b8486bde131e0db16a52b730b82a26469706673582212203480a9d34d0738f022270141175efb5c96b0766841cbae8de67341217ab4a49d64736f6c634300081c0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000001310f352f1389969ece6741671c4b919523912ff0000000000000000000000000000000000000000000000008ac7230489e800000000000000000000000000000000000000000000000000000000000000000001
-----Decoded View---------------
Arg [0] : cr (address): 0x1310f352f1389969Ece6741671c4B919523912fF
Arg [1] : minLoanSize (uint256): 10000000000000000000
Arg [2] : isCorrelatedMarket (bool): True
-----Encoded View---------------
3 Constructor Arguments found :
Arg [0] : 0000000000000000000000001310f352f1389969ece6741671c4b919523912ff
Arg [1] : 0000000000000000000000000000000000000000000000008ac7230489e80000
Arg [2] : 0000000000000000000000000000000000000000000000000000000000000001
Deployed Bytecode Sourcemap
162397:77036:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;164452:52;;164494:10;164452:52;;;;;160:25:1;;;148:2;133:18;164452:52:0;;;;;;;;213149:234;;;;;;:::i;:::-;;:::i;:::-;;;652:14:1;;645:22;627:41;;615:2;600:18;213149:234:0;487:187:1;166863:49:0;;;;;;:::i;:::-;;;;;;;;;;;;;;175241:1760;;;;;;:::i;:::-;;:::i;:::-;;195619:7649;;;;;;:::i;:::-;;:::i;167290:49::-;;;;;;:::i;:::-;;;;;;;;;;;;;;;;212375:526;-1:-1:-1;;;;;;;;;;;212655:40:0;212773:54;165894:3;212792:34;;;212773:54;;;166056:3;212859:33;;;212838:55;212375:526;;;-1:-1:-1;;;;;5253:32:1;;;5235:51;;5317:2;5302:18;;5295:34;;;;5345:18;;;5338:34;5223:2;5208:18;212375:526:0;5033:345:1;138808:58:0;;138862:4;138808:58;;177858:628;;;;;;:::i;:::-;;:::i;173580:156::-;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;140186:39::-;;;;;139658:47;;;;;138405:56;;138457:4;138405:56;;205098:265;;;;;;:::i;:::-;;:::i;139308:62::-;;139366:4;139308:62;;138004:58;;138058:4;138004:58;;181211:1469;;;;;;:::i;:::-;;:::i;179058:206::-;;;;;;:::i;:::-;;:::i;208939:2121::-;;;;;;:::i;:::-;;:::i;211591:232::-;;;:::i;166192:29::-;;;;;;:::i;:::-;;:::i;:::-;;;-1:-1:-1;;;;;9723:32:1;;;9705:51;;9693:2;9678:18;166192:29:0;9559:203:1;169953:380:0;;;;;;:::i;:::-;-1:-1:-1;;;;;170152:20:0;170025:15;170152:20;;;;;;;;;;170196:12;170212:1;170196:12;;;;;;:17;;;170250:25;;;;;:30;;;170306:14;;;;;;:19;;;;169953:380;;;;;9976:14:1;;9969:22;9951:41;;10035:14;;10028:22;10023:2;10008:18;;10001:50;10094:14;10087:22;10067:18;;;10060:50;9939:2;9924:18;169953:380:0;9767:349:1;137772:56:0;;137824:4;137772:56;;142093:52;;;;;;:::i;:::-;;;;;;;;;;;;;;191203:1783;;;;;;:::i;:::-;;:::i;188778:402::-;;;;;;:::i;:::-;;:::i;163910:47::-;;163953:4;163910:47;;164043;;164086:4;164043:47;;140818:56;;;;;207939:409;;;;;;:::i;:::-;;:::i;180467:213::-;;;;;;:::i;:::-;;:::i;141244:49::-;;;;;140538:39;;;;;174176:140;;;;;;:::i;:::-;;:::i;:::-;;;;10948:25:1;;;11004:2;10989:18;;10982:34;;;;11032:18;;;11025:34;10936:2;10921:18;174176:140:0;10746:319:1;141164:38:0;;;;;204518:189;;;;;;:::i;:::-;;:::i;170939:229::-;;;;;;:::i;:::-;-1:-1:-1;;;;;171079:20:0;171009:7;171079:20;;;;;;;;;;171118:11;;-1:-1:-1;;;171118:11:0;;;;;-1:-1:-1;;;171131:13:0;;;;;-1:-1:-1;;;171146:13:0;;;;;;170939:229;163186:58;;163239:5;163186:58;;141901:71;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;163659:56;;163711:4;163659:56;;173174:107;;;:::i;166504:29::-;;;;;;;;;;;;;;;11488:4:1;11476:17;;;11458:36;;11446:2;11431:18;166504:29:0;11316:184:1;206485:271:0;;;;;;:::i;:::-;;:::i;190009:594::-;;;;;;:::i;:::-;;:::i;167090:43::-;;;;;;:::i;:::-;;;;;;;;;;;;;;174502:212;;;;;;:::i;:::-;;:::i;205784:304::-;;;;;;:::i;:::-;;:::i;203561:198::-;;;;;;:::i;:::-;;:::i;204049:183::-;;;;;;:::i;:::-;;:::i;166356:34::-;;;;;;;;;163393:54;;163444:3;163393:54;;139901:48;;;;;185301:3058;;;;;;:::i;:::-;;:::i;:::-;;;;;;;;:::i;207036:612::-;;;;;;:::i;:::-;;:::i;77742:1590::-;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;172451:482::-;;;;;;:::i;:::-;-1:-1:-1;;;;;172642:20:0;172527:7;172642:20;;;;;;;;;;172695:12;;-1:-1:-1;;;172695:12:0;;;;;-1:-1:-1;;;172722:13:0;;;;;-1:-1:-1;;;172750:11:0;;;;;-1:-1:-1;;;172776:11:0;;;;;-1:-1:-1;;;172802:17:0;;;;;-1:-1:-1;;;172834:18:0;;;;;-1:-1:-1;;;172867:16:0;;;;;-1:-1:-1;;;172898:16:0;;;;;172451:482;;;;;17599:25:1;;;17655:2;17640:18;;17633:34;;;;17683:18;;;17676:34;;;;17741:2;17726:18;;17719:34;;;;17784:3;17769:19;;17762:35;17828:3;17813:19;;17806:35;17872:3;17857:19;;17850:35;17916:3;17901:19;;17894:35;17586:3;17571:19;172451:482:0;17256:679:1;169314:127:0;;;;;;:::i;:::-;-1:-1:-1;;;;;169404:20:0;169371:11;169404:20;;;;;;;;;;:29;;;;169314:127;179842:285;;;;;;:::i;:::-;;:::i;166645:31::-;;;;;;;;;;;;213149:234;213242:11;-1:-1:-1;;;;;;213275:47:0;;-1:-1:-1;;;213275:47:0;;:100;;-1:-1:-1;;;;;;;;;;72453:40:0;;;213339:36;213266:109;213149:234;-1:-1:-1;;213149:234:0:o;175241:1760::-;175389:30;175403:15;175389:13;:30::i;:::-;175795:16;175785:194;;175845:25;175839:4;175832:39;175959:4;175953;175946:18;175785:194;-1:-1:-1;;;;;176006:29:0;;:12;:29;;;;;;;;;;:53;;;;;;;:58;176002:121;;176088:23;;-1:-1:-1;;;176088:23:0;;;;;;;;;;;176002:121;-1:-1:-1;;;;;176351:31:0;;;;;;:14;:31;;;;;;176332:50;;176328:117;;;176406:27;;-1:-1:-1;;;176406:27:0;;;;;;;;;;;176328:117;-1:-1:-1;;;;;176570:22:0;;;;;;;:13;:22;;;;;;;;176613:15;176570:58;;176737:33;;;;;:16;:33;;;;;:42;;;;;;;;;;;;:47;176733:261;;-1:-1:-1;;;;;176801:33:0;;;;;;;:16;:33;;;;;;;;:42;;;;;;;;;;;;176846:1;176801:46;;;;176862:22;;;;;:29;;:51;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;;176862:51:0;;;;;176935:47;;18136:51:1;;;18203:18;;18196:60;;;;18272:18;;18265:50;;;;176935:47:0;;18124:2:1;18109:18;176935:47:0;;;;;;;;176733:261;175241:1760;;;:::o;195619:7649::-;195716:16;;195696:37;;:19;:37::i;:::-;195744:25;:23;:25::i;:::-;196158:14;196136:9;:19;;;:36;:103;;;;163239:5;196189:9;:21;;;:50;196136:103;:166;;;;196281:9;:21;;;196256:9;:21;;;:46;;196136:166;196118:259;;;196329:36;164857:10;196329:7;:36::i;:::-;197239:9;:20;;;197215:9;:20;;;:44;;:103;;;;197299:9;:19;;;197276:9;:20;;;:42;197215:103;:162;;;;197358:9;:19;;;197335:9;:20;;;:42;197215:162;:221;;;;197417:9;:19;;;197394:9;:19;;;:42;;197215:221;:285;;;;163711:4;197453:9;:19;;;:47;197215:285;:326;;;-1:-1:-1;197517:19:0;;;;:24;197215:326;:391;;;;163711:4;197558:9;:20;;;:48;197215:391;197197:484;;;197633:36;164857:10;197633:7;:36::i;:::-;198055:9;:21;;;163444:3;198005:9;:20;;;:47;;;;:::i;:::-;:71;:158;;;;198142:9;:21;;;163444:3;198093:9;:19;;;:46;;;;:::i;:::-;:70;198005:158;197987:251;;;198190:36;164857:10;198190:7;:36::i;:::-;163953:4;198340:9;:25;;;:44;:105;;;;164086:4;198401:9;:25;;;:44;198340:105;198322:198;;;198472:36;164857:10;198472:7;:36::i;:::-;198805:9;:24;;;198777:9;:25;;;:52;:121;;;;198874:9;:24;;;198846:9;:25;;;:52;198777:121;:190;;;;198943:9;:24;;;198915:9;:24;;;:52;;198777:190;:236;;;-1:-1:-1;198984:24:0;;;;:29;198777:236;:283;;;;745:3;199030:9;:24;;;:30;198777:283;198759:376;;;199087:36;164857:10;199087:7;:36::i;:::-;199409:21;;;;199403:27;;745:3;199403:27;:::i;:::-;199377:54;;:22;:54;:::i;:::-;199341:9;:19;;;:91;199323:184;;;199459:36;164857:10;199459:7;:36::i;:::-;199645:19;;;;:24;:55;;;;;199699:1;199673:9;:23;;;:27;199645:55;199641:124;;;199717:36;164857:10;199717:7;:36::i;:::-;199857:17;;;;:21;199853:257;;199917:17;;;;164699;-1:-1:-1;199917:33:0;:95;;;199980:9;:16;;;-1:-1:-1;;;;;199972:38:0;;:40;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;199971:41;199917:95;199895:204;;;200047:36;164857:10;200047:7;:36::i;:::-;200172:16;;-1:-1:-1;;;;;200159:30:0;200122:34;200159:30;;;;;;;;;;200394:22;;-1:-1:-1;;;200394:22:0;;;;:27;;;;:55;;-1:-1:-1;200425:19:0;;;;:24;200394:55;200390:124;;;200466:36;164857:10;200466:7;:36::i;:::-;200675:17;200696:41;200721:15;200696:24;:41::i;:::-;200761:16;;200696:94;;-1:-1:-1;;;200696:94:0;;-1:-1:-1;;;;;200696:64:0;;;;;;;:94;;200779:4;;;;200696:94;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;200672:118;;;843:1;200886:9;:23;200882:90;;200933:27;;-1:-1:-1;;;200933:27:0;;;;;;;;;;;200882:90;201000:41;201025:15;201000:24;:41::i;:::-;201065:16;;201000:95;;-1:-1:-1;;;201000:95:0;;-1:-1:-1;;;;;201000:64:0;;;;;;;:95;;201083:4;;201065:16;;201000:95;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;200984:111;-1:-1:-1;;;;201191:23:0;;201187:90;;201238:27;;-1:-1:-1;;;201238:27:0;;;;;;;;;;;201187:90;201480:19;;;;201448:52;;;;;;-1:-1:-1;;;201448:52:0;-1:-1:-1;;201448:52:0;;;;;;201727:21;;;;:27;;745:3;;201727:27;:::i;:::-;201693:62;;;;;;;-1:-1:-1;;;201693:62:0;-1:-1:-1;;201693:62:0;;;;;;201800:21;;;;:27;;745:3;;201800:27;:::i;:::-;201766:62;;;;;;;-1:-1:-1;;;201766:62:0;-1:-1:-1;;;;201766:62:0;;;;;;202010:20;;;;202004:26;;745:3;202004:26;:::i;:::-;201971:60;;;;;;;-1:-1:-1;;;201971:60:0;-1:-1:-1;;;;201971:60:0;;;;;;202080:19;;;;202074:25;;745:3;202074:25;:::i;:::-;202042:58;;;;;;;-1:-1:-1;;;202042:58:0;-1:-1:-1;;;;202042:58:0;;;;;;202149:19;;;;202143:25;;745:3;202143:25;:::i;:::-;202111:58;;;;;;;-1:-1:-1;;;202111:58:0;-1:-1:-1;;;;202111:58:0;;;;;;202382:20;;;;202359;;;;:43;;202382:20;202359:43;:::i;:::-;202325:78;;;202491:25;;;-1:-1:-1;;;;202453:64:0;;;-1:-1:-1;;;202325:78:0;;;;;-1:-1:-1;;;;202453:64:0;;-1:-1:-1;;;202453:64:0;;;;;;;;;;;;;202710:31;;745:3;202710:31;:::i;:::-;202671:71;;202850:24;;;;202923;;;;-1:-1:-1;;;;202813:62:0;;;-1:-1:-1;;;202671:71:0;;;;;-1:-1:-1;;;;202813:62:0;;-1:-1:-1;;;202813:62:0;;;;;;;;-1:-1:-1;;;;202886:62:0;-1:-1:-1;;;202886:62:0;;;;;;;;;;;203064:23;;;;203044:16;;-1:-1:-1;;;;;203029:32:0;;;-1:-1:-1;203029:32:0;;;:14;:32;;;;;;;;:58;;;;203196:17;;;;203176:16;;203167:26;;;;;:8;:26;;;;;:46;203231:29;;;;;202850:24;;20135:13:1;;-1:-1:-1;;;;;4990:31:1;4978:44;;20103:3;20088:19;;20216:4;20208:6;20204:17;20198:24;20191:4;20180:9;20176:20;20169:54;20279:4;20271:6;20267:17;20261:24;20254:4;20243:9;20239:20;20232:54;20342:4;20334:6;20330:17;20324:24;20317:4;20306:9;20302:20;20295:54;20405:4;20397:6;20393:17;20387:24;20380:4;20369:9;20365:20;20358:54;20468:4;20460:6;20456:17;20450:24;20443:4;20432:9;20428:20;20421:54;20531:4;20523:6;20519:17;20513:24;20506:4;20495:9;20491:20;20484:54;20594:4;20586:6;20582:17;20576:24;20569:4;20558:9;20554:20;20547:54;20659:6;20651;20647:19;20641:26;20632:6;20621:9;20617:22;20610:58;20726:6;20718;20714:19;20708:26;20699:6;20688:9;20684:22;20677:58;20793:6;20785;20781:19;20775:26;20766:6;20755:9;20751:22;20744:58;20860:6;20852;20848:19;20842:26;20833:6;20822:9;20818:22;20811:58;20927:6;20919;20915:19;20909:26;20900:6;20889:9;20885:22;20878:58;19911:1031;;;;;177858:628:0;178099:26;178138:21;178152:6;178138:13;:21::i;:::-;178174:12;;;;;;;178190:1;178174:17;178170:80;;178215:23;;-1:-1:-1;;;178215:23:0;;;;;;;;;;;178170:80;178283:195;178308:6;178329;178350:7;178372:9;178396:16;178427:4;178446:21;178283:10;:195::i;:::-;178262:216;177858:628;-1:-1:-1;;;;;;;177858:628:0:o;173580:156::-;-1:-1:-1;;;;;173699:22:0;;;;;;:13;:22;;;;;;;;;:29;;173690:38;;;;;;;;;;;;;;;;;173654:23;;173690:38;;;173699:29;173690:38;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;173690:38:0;;;;;;;;;;;;;;;;;;;;;;;173580:156;;;:::o;205098:265::-;205169:25;:23;:25::i;:::-;205205:27;205225:6;205205:19;:27::i;:::-;205279:5;:13;;205291:1;205279:13;;;205287:1;205279:13;-1:-1:-1;;;;;205245:20:0;;:12;:20;;;;;;;;;;;;:47;;;;;;;;;-1:-1:-1;;205245:47:0;;;;;;;;;;205308;;21181:51:1;;;21268:2;21248:18;;;21241:30;;;21307:2;21287:18;;;21280:30;;;;-1:-1:-1;;;21341:3:1;21326:19;;21319:42;21440:14;;21433:22;21413:18;;;21406:50;;;;205308:47:0;;21219:3:1;21378:19;205308:47:0;;;;;;;;205098:265;;:::o;181211:1469::-;181401:21;181415:6;181401:13;:21::i;:::-;181433:27;181453:6;181433:19;:27::i;:::-;181471:25;181488:7;181471:16;:25::i;:::-;-1:-1:-1;;;;;181586:24:0;;;;;;;:16;:24;;;;;;;;:33;;;;;;;;;;181623:1;181586:38;181582:107;;181641:36;164857:10;181641:7;:36::i;:::-;181797:54;;181833:7;181797:54;181976:13;181991:17;182025:41;182050:15;182025:24;:41::i;:::-;-1:-1:-1;;;;;182025:68:0;;182094:9;182105:4;182111;182025:91;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;181975:141;;;;1036:1;182252:9;:21;182248:88;;182297:27;;-1:-1:-1;;;182297:27:0;;;;;;;;;;;182248:88;182574:13;182506:52;182518:10;182530:5;182537:14;182543:8;182537:2;:14;:::i;:::-;182553:4;182506:11;:52::i;:::-;:81;182488:185;;;182621:40;;-1:-1:-1;;;182621:40:0;;;;;;;;;;;182488:185;181390:1290;;181211:1469;;;;;;:::o;179058:206::-;179209:47;179220:6;179228;179236:7;179245:10;179209;:47::i;:::-;179058:206;;;;:::o;208939:2121::-;209088:26;:24;:26::i;:::-;209125:27;209145:6;209125:19;:27::i;:::-;-1:-1:-1;;;;;209191:20:0;;209166:22;209191:20;;;;;;;;;;;209166:45;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;209166:45:0;;;;;;;;;;-1:-1:-1;;;209166:45:0;;;;;;;;-1:-1:-1;;;209166:45:0;;;;;;;;;;-1:-1:-1;;;209166:45:0;;;;;;;;-1:-1:-1;;;209166:45:0;;;;;;;;;;;-1:-1:-1;;;209166:45:0;;;;;;;;-1:-1:-1;;;209166:45:0;;;;;;;;-1:-1:-1;;;209166:45:0;;;;;;;;-1:-1:-1;;;209166:45:0;;;;;;;;-1:-1:-1;;;209166:45:0;;;;;;;;-1:-1:-1;;;209166:45:0;;;;;;;;;;;;209347:16;209343:96;;209387:40;;-1:-1:-1;;;209387:40:0;;;;;;;;;;;209343:96;209709:14;;;;;:83;;;209753:1;:11;;;209741:23;;:9;:23;:50;;;;209780:1;:11;;;209768:23;;:9;:23;209741:50;209691:176;;;209819:36;164857:10;209819:7;:36::i;:::-;210163:16;;;;;:99;;;210211:1;:16;;;210197:30;;:11;:30;:64;;;;210245:1;:16;;;210231:30;;:11;:30;210197:64;210145:192;;;210289:36;164857:10;210289:7;:36::i;:::-;210844:21;210840:37;;;210904:20;210900:38;;;210815:142;-1:-1:-1;;;;;210369:24:0;;210766:208;;-1:-1:-1;;;;;;;;;;;210990:52:0;210413:640;;208939:2121;;;:::o;211591:232::-;211654:26;:24;:26::i;:::-;211803:1;-1:-1:-1;;;;;;;;;;;211761:44:0;211591:232::o;166192:29::-;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;166192:29:0;;-1:-1:-1;166192:29:0;:::o;191203:1783::-;191275:25;:23;:25::i;:::-;191390:6;-1:-1:-1;;;;;191380:16:0;:6;-1:-1:-1;;;;;191380:16:0;;191376:85;;191413:36;164857:10;191413:7;:36::i;:::-;191586:6;-1:-1:-1;;;;;191578:21:0;;:23;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;191551:50:0;191559:6;-1:-1:-1;;;;;191551:21:0;;:23;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;191551:50:0;;191547:119;;191618:36;164857:10;191618:7;:36::i;:::-;191758:12;:19;:24;191754:93;;191799:36;164857:10;191799:7;:36::i;:::-;191997:6;-1:-1:-1;;;;;191989:28:0;;:30;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;191988:31;:66;;;;;192032:6;-1:-1:-1;;;;;192024:28:0;;:30;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;192023:31;191988:66;191984:135;;;192071:36;164857:10;192071:7;:36::i;:::-;-1:-1:-1;;;;;192243:20:0;;;:12;:20;;;;;;;;;;;:36;;192275:4;-1:-1:-1;;192243:36:0;;;;;;;;192290:20;;;;;;;;;:36;;;;;;;;;;;192469:46;;-1:-1:-1;;;192469:46:0;;192504:10;192469:46;;;9705:51:1;192469:34:0;;9678:18:1;;192469:46:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;192464:114;;192532:34;165146:10;192532:7;:34::i;:::-;192603:46;;-1:-1:-1;;;192603:46:0;;192638:10;192603:46;;;9705:51:1;-1:-1:-1;;;;;192603:34:0;;;;;9678:18:1;;192603:46:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;192598:114;;192666:34;165146:10;192666:7;:34::i;:::-;192837:12;:25;;;;;;;;-1:-1:-1;192837:25:0;;;;;;;;;-1:-1:-1;;;;;;192837:25:0;;;-1:-1:-1;;;;;192837:25:0;;;;;;;;;192873;;;;;;;;;;;;;;;;;;;;;;;;;;192924:19;;9705:51:1;;;192924:19:0;;9693:2:1;9678:18;192924:19:0;;;;;;;192959;;-1:-1:-1;;;;;9723:32:1;;9705:51;;192959:19:0;;9693:2:1;9678:18;192959:19:0;9559:203:1;188778:402:0;188890:36;188910:15;188890:19;:36::i;:::-;188937:30;188957:9;188937:19;:30::i;:::-;189063:9;-1:-1:-1;;;;;189055:32:0;;:34;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;188998:91:0;189006:15;-1:-1:-1;;;;;188998:38:0;;:40;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;188998:91:0;;188980:193;;189123:38;;-1:-1:-1;;;189123:38:0;;;;;;;;;;;188980:193;188778:402;;:::o;207939:409::-;208005:25;:23;:25::i;:::-;-1:-1:-1;;;;;208102:24:0;;;;;;:17;:24;;;;;;;;208097:94;;208143:36;164857:10;208143:7;:36::i;:::-;-1:-1:-1;;;;;208262:24:0;;;;;;:17;:24;;;;;;;;208255:31;;-1:-1:-1;;208255:31:0;;;208304:36;;23592:51:1;;;23659:18;;;23652:50;;;;208304:36:0;;23565:18:1;208304:36:0;;;;;;;;207939:409;:::o;180467:213::-;180542:21;180556:6;180542:13;:21::i;:::-;180574:27;180594:6;180574:19;:27::i;:::-;-1:-1:-1;;;;;180614:22:0;;;;;:13;:22;;;;;180657:15;180614:58;;-1:-1:-1;180467:213:0:o;174176:140::-;174245:7;174254;174263;174290:18;174300:7;174290:9;:18::i;:::-;174283:25;;;;;;174176:140;;;;;;:::o;204518:189::-;204577:25;:23;:25::i;:::-;204632:5;:13;;204644:1;204632:13;;;204640:1;204632:13;204615:14;;:30;;;;;;;;;;;;;;;;;;204661:38;204693:5;204661:38;;;;;23937:2:1;23919:21;;;23976:2;23956:18;;;23949:30;-1:-1:-1;;;24010:2:1;23995:18;;23988:45;24114:14;;24107:22;24100:4;24085:20;;24078:52;24065:3;24050:19;;23713:423;173174:107:0;173226:18;173261:12;173257:16;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;173257:16:0;;;;;;;;;;;;;;;;;;;;;;;173174:107;:::o;206485:271::-;206558:25;:23;:25::i;:::-;206594:27;206614:6;206594:19;:27::i;:::-;206670:5;:13;;206682:1;206670:13;;;206678:1;206670:13;-1:-1:-1;;;;;206634:20:0;;:12;:20;;;;;;;;;;;;:49;;;;;;;;;-1:-1:-1;;206634:49:0;;;;;;;;;;206699;;24375:51:1;;;24462:2;24442:18;;;24435:30;;;24501:2;24481:18;;;24474:30;;;;-1:-1:-1;;;24535:3:1;24520:19;;24513:44;24636:14;;24629:22;24609:18;;;24602:50;;;;206699:49:0;;24413:3:1;24574:19;206699:49:0;24141:517:1;190009:594:0;190222:26;190261:21;190275:6;190261:13;:21::i;:::-;190297:14;;;;;;;;:19;190293:82;;190340:23;;-1:-1:-1;;;190340:23:0;;;;;;;;;;;190293:82;190408:187;190433:6;190454;190475:7;190497:9;190521:16;190552:12;190579:5;190408:10;:187::i;174502:212::-;-1:-1:-1;;;;;174572:20:0;;:12;:20;;;;;;;;;;:31;;;;;;174607:1;174572:36;174568:99;;174632:23;;-1:-1:-1;;;174632:23:0;;;;;;;;;;;174568:99;174679:27;174699:6;174679:19;:27::i;:::-;174502:212;:::o;205784:304::-;205868:25;:23;:25::i;:::-;205904:27;205924:6;205904:19;:27::i;:::-;205991:5;:13;;206003:1;205991:13;;;205999:1;205991:13;-1:-1:-1;;;;;205944:20:0;;:12;:20;;;;;;;;;;;;:60;;;;;;;;;-1:-1:-1;;205944:60:0;;;;;;;;;;206020;;24897:51:1;;;24984:2;24964:18;;;24957:30;;;25023:2;25003:18;;;24996:30;;;;25063:26;25057:3;25042:19;;25035:55;25169:14;;25162:22;25142:18;;;25135:50;;;;206020:60:0;;24935:3:1;25107:19;206020:60:0;24663:528:1;203561:198:0;203623:25;:23;:25::i;:::-;203681:5;:13;;203693:1;203681:13;;;203689:1;203681:13;203661:17;:33;;-1:-1:-1;;203661:33:0;;;;;;;;;;;;203710:41;;;25402:21:1;;;25459:2;25439:18;;;25432:30;;;;-1:-1:-1;;;25493:2:1;25478:18;;25471:48;25600:14;;25593:22;25586:4;25571:20;;25564:52;203710:41:0;;25551:3:1;25536:19;203710:41:0;25196:426:1;204049:183:0;204106:25;:23;:25::i;:::-;204159:5;:13;;204171:1;204159:13;;;204167:1;204159:13;204144:12;;:28;;;;;;;;;;;;;;;;;;204188:36;204218:5;204188:36;;;;;25851:2:1;25833:21;;;25890:2;25870:18;;;25863:30;-1:-1:-1;;;25924:2:1;25909:18;;25902:43;26026:14;;26019:22;26012:4;25997:20;;25990:52;25977:3;25962:19;;25627:421;185301:3058:0;185513:38;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;185513:38:0;185601:17;;185562:16;;185601:17;;185622:1;185601:22;185597:85;;185647:23;;-1:-1:-1;;;185647:23:0;;;;;;;;;;;185597:85;185694:31;185708:6;:16;;;185694:13;:31::i;:::-;185756:22;;185736:43;;:19;:43::i;:::-;185790:37;185810:6;:16;;;185790:19;:37::i;:::-;185841:25;185868:27;185912:63;185934:6;:22;;;185958:6;:16;;;185912:21;:63::i;:::-;185840:135;;;;186125:6;:18;;;-1:-1:-1;;;;;186111:33:0;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;186111:33:0;-1:-1:-1;186085:59:0;;:23;;;186218:1908;186238:6;:18;;;186234:1;:22;186218:1908;;;186294:8;;186303:1;186294:11;;;;;;;:::i;:::-;;;;;;;;;;;;;;:::i;:::-;186278:27;;186412:13;-1:-1:-1;;;;;186398:27:0;:10;-1:-1:-1;;;;;186398:27:0;;186394:99;;186446:31;164999:10;186446:7;:31::i;:::-;186702:13;-1:-1:-1;;;;;186686:29:0;:12;-1:-1:-1;;;;;186686:29:0;;186682:101;;186736:31;164999:10;186736:7;:31::i;:::-;186928:181;186960:11;186972:1;186960:14;;;;;;;;:::i;:::-;;;;;;;186993:13;187025:5;187049;187073:6;:21;;;186928:13;:181::i;:::-;186896:14;;;186799:310;186860:17;;;186799:310;;;186818:23;;;186799:310;;;;-1:-1:-1;187343:17:0;;:38;;;;186799:310;;187343:38;:::i;:::-;;;-1:-1:-1;187425:23:0;;;;187396;;:26;;187420:1;;187396:26;;;;;;:::i;:::-;;;;;;;;;;:52;187469:14;;;;:18;187465:257;;187534:6;:14;;;187508:6;:22;;:40;;;;;;;:::i;:::-;;;-1:-1:-1;187692:14:0;;;;187671:17;;;:35;;;;187692:14;;187671:35;:::i;:::-;;;-1:-1:-1;187465:257:0;187995:6;:17;;;187978:11;187990:1;187978:14;;;;;;;;:::i;:::-;;;;;;;;;;:34;188101:13;;-1:-1:-1;186258:3:0;;186218:1908;;;;188214:6;:17;;;188235:1;188214:22;188210:101;;188260:39;;-1:-1:-1;;;188260:39:0;;;;;;;;;;;188210:101;-1:-1:-1;185301:3058:0;;;-1:-1:-1;;;;;;;;185301:3058:0:o;207036:612::-;207099:25;:23;:25::i;:::-;207156:92;207206:5;-1:-1:-1;;;207156:49:0;:92::i;:::-;207137:186;;207275:36;164857:10;207275:7;:36::i;:::-;-1:-1:-1;;;;;207395:24:0;;;;;;:17;:24;;;;;;;;207391:93;;;207436:36;164857:10;207436:7;:36::i;:::-;-1:-1:-1;;;;;207556:24:0;;;;;;:17;:24;;;;;;;;;:31;;-1:-1:-1;;207556:31:0;207583:4;207556:31;;;;;;207605:35;;23592:51:1;;;23659:18;;;23652:50;207605:35:0;;23565:18:1;207605:35:0;23424:284:1;77742:1590:0;77829:22;239407:15;77937:5;;-1:-1:-1;;;;;77970:21:0;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;77960:31:0;;-1:-1:-1;78048:1277:0;78068:8;78064:1;:12;78048:1277;;;78111:5;;78117:1;78111:8;;;;;;;:::i;:::-;;;;;;;;;;;;:::i;:::-;78098:21;;;:::i;:::-;;;78152:10;:24;;;78148:810;;;78380:17;;78360:38;;-1:-1:-1;;;78360:38:0;;-1:-1:-1;;;;;9723:32:1;;;78360:38:0;;;9705:51:1;78342:15:0;;78360:19;;;;;9678:18:1;;78360:38:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;78342:56;-1:-1:-1;;;;;;78489:21:0;;78485:105;;78542:28;;-1:-1:-1;;;78542:28:0;;;;;;;;;;;78485:105;78706:17;;78746:15;;;;;78610:170;;-1:-1:-1;;;78610:170:0;;-1:-1:-1;;;;;78610:40:0;;;;;:170;;78673:10;;78706:17;78746:15;78610:170;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;78814:83;78862:10;:17;;;78881:10;:15;;;78814:47;:83::i;:::-;78801:7;78809:1;78801:10;;;;;;;;:::i;:::-;;;;;;:96;;;;78934:8;;;78148:810;79114:17;;-1:-1:-1;;;;;79097:34:0;79105:4;79097:34;79093:108;;79159:26;;-1:-1:-1;;;79159:26:0;;;;;;;;;;;79093:108;79230:83;79290:4;79297:10;:15;;;79230:51;:83::i;:::-;79217:7;79225:1;79217:10;;;;;;;;:::i;:::-;;;;;;:96;;;;78048:1277;78078:3;;78048:1277;;;;77853:1479;;;77742:1590;;;;:::o;179842:285::-;-1:-1:-1;;;;;180003:22:0;;;;;;:13;:22;;;;;180046:15;180003:58;;180072:47;180083:6;180091;180017:7;180108:10;180072;:47::i;236219:393::-;236423:5;236413:8;236410:19;236400:194;;236463:22;236457:4;236450:36;236574:4;236568;236561:18;235983:176;-1:-1:-1;;;;;236057:19:0;;:12;:19;;;;;;;;;;:28;;;236052:100;;236109:31;;-1:-1:-1;;;236109:31:0;;;;;;;;;;;238717:188;238790:48;;-1:-1:-1;;;238790:48:0;;238827:10;238790:48;;;9705:51:1;238790:15:0;-1:-1:-1;;;;;238790:36:0;;;;9678:18:1;;238790:48:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;238785:113;;238855:31;164999:10;238855:7;:31::i;:::-;238717:188::o;159439:186::-;159573:1;159567:4;159560:15;159602:4;159596;159589:18;81461:183;81545:28;81617:2;-1:-1:-1;;;;;81617:16:0;;:18;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;217629:2478::-;217876:26;217915:27;217935:6;217915:19;:27::i;:::-;217953:31;217976:7;217953:22;:31::i;:::-;218001:12;217997:1153;;;218168:21;218164:975;;;218352:16;218343:6;:25;218339:120;;;218400:39;;-1:-1:-1;;;218400:39:0;;;;;;;;;;;218339:120;-1:-1:-1;218500:6:0;218164:975;;;219016:7;218987:25;219006:6;218987:16;:25;:::i;:::-;:36;218983:141;;219097:7;219069:25;219088:6;219069:16;:25;:::i;:::-;:35;;;;:::i;:::-;219048:56;;218983:141;219315:23;;;:65;;-1:-1:-1;;;;;;219342:24:0;;;;;;;:16;:24;;;;;;;;:33;;;;;;;;;;219379:1;219342:38;;219315:65;219397:25;219311:123;219522:24;219550:316;219593:7;219619:232;;;;;;;;219677:6;-1:-1:-1;;;;;219619:232:0;;;;;219724:18;219619:232;;;;219779:1;219619:232;;;;952:1;219619:232;;;219550:24;:316::i;:::-;219519:347;-1:-1:-1;;220005:20:0;;220001:99;;220049:39;;-1:-1:-1;;;220049:39:0;;;;;;;;;;;220001:99;217904:2203;217629:2478;;;;;;;;;:::o;235382:450::-;-1:-1:-1;;;;;235656:22:0;;;;;;:13;:22;;;;;:40;235730:15;;235656:58;;164494:10;;235656:58;:::i;:::-;:89;235638:187;;;235779:34;;-1:-1:-1;;;235779:34:0;;;;;;;;;;;157308:351;157470:7;157494:19;157490:91;;;157537:32;157545:6;157553:5;157560:8;157537:7;:32::i;:::-;157530:39;;;;157490:91;157600:51;157627:6;157635:5;157642:8;157600:26;:51::i;:::-;157593:58;;157308:351;;;;;;;:::o;214075:2536::-;214230:24;214244:9;214230:13;:24::i;:::-;214612:10;214602:188;;214656:25;214650:4;214643:39;214770:4;214764;214757:18;214602:188;-1:-1:-1;;;;;214817:23:0;;:12;:23;;;;;;;;;;:36;;;;;;214857:1;214817:41;214813:104;;214882:23;;-1:-1:-1;;;214882:23:0;;;;;;;;;;;214813:104;-1:-1:-1;;;;;215306:19:0;;;;;;:8;:19;;;;;;215293:32;;215289:99;;;215349:27;;-1:-1:-1;;;215349:27:0;;;;;;;;;;;215289:99;-1:-1:-1;;;;;215503:27:0;;;;;;;:16;:27;;;;;;;;:36;;;;;;;;;;215543:1;215503:41;215499:409;;-1:-1:-1;;;;;215733:27:0;;;;;;;:16;:27;;;;;;;;:36;;;;;;;;;;;;215772:1;215733:40;;;;215788:22;;;;;:29;;:45;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;;215788:45:0;;;;;215855:41;;18136:51:1;;;18203:18;;18196:60;;;;18272:18;;18265:50;;;;215855:41:0;;18124:2:1;18109:18;215855:41:0;;;;;;;215499:409;216035:24;216063:307;216106:7;216132:223;;;;;;;;216190:9;-1:-1:-1;;;;;216132:223:0;;;;;216240:1;216132:223;;;;216278:6;216132:223;;;;952:1;216132:223;;;216063:24;:307::i;:::-;216032:338;-1:-1:-1;;216509:20:0;;216505:99;;216553:39;;-1:-1:-1;;;216553:39:0;;;;;;;;;;;238983:182;239049:49;;-1:-1:-1;;;239049:49:0;;239087:10;239049:49;;;9705:51:1;239049:15:0;-1:-1:-1;;;;;239049:37:0;;;;9678:18:1;;239049:49:0;9559:203:1;144374:1335:0;144438:18;144467:15;144493:12;144539:34;144588:23;144626:17;144657:33;144670:7;843:1;144657:12;:33::i;:::-;144524:166;;;;;;144701:27;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;144701:27:0;144746:9;144741:961;144761:9;144757:1;:13;144741:961;;;144799:9;144809:1;144799:12;;;;;;;;:::i;:::-;;;;;;;144792:19;;144832:4;:17;;;144828:863;;;144870:23;144896:175;144930:4;:21;;;144974:6;144981:1;144974:9;;;;;;;;:::i;:::-;;;;;;;145012:4;:13;;;145006:2;:19;;;;:::i;144896:175::-;144870:201;-1:-1:-1;145090:29:0;144870:201;145090:29;;:::i;:::-;145230:10;;-1:-1:-1;;;;;145217:24:0;:12;:24;;;;;;;;;;:34;145090:29;;-1:-1:-1;145149:147:0;;145179:15;;-1:-1:-1;;;145217:34:0;;;;745:3;145149:7;:147::i;:::-;145138:158;;;;:::i;:::-;;;144851:461;144828:863;;;145412:16;;;;:20;145408:268;;145465:191;145503:4;:16;;;145546:6;145553:1;145546:9;;;;;;;;:::i;:::-;;;;;;;145588:4;:13;;;145582:2;:19;;;;:::i;:::-;145628:5;145465:11;:191::i;:::-;145457:199;;;;:::i;:::-;;;145408:268;144772:3;;144741:961;;;;144513:1196;;;;144374:1335;;;;;:::o;233302:1951::-;233430:25;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;233430:25:0;233466:27;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;233466:27:0;-1:-1:-1;;;;;233537:29:0;;233512:22;233537:29;;;;;;;;;;;233512:54;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;233512:54:0;;;;;;;;;;-1:-1:-1;;;233512:54:0;;;;;;;;-1:-1:-1;;;233512:54:0;;;;;;;;;;-1:-1:-1;;;233512:54:0;;;;;;;;-1:-1:-1;;;233512:54:0;;;;;;;;;;;-1:-1:-1;;;233512:54:0;;;;;;;;-1:-1:-1;;;233512:54:0;;;;;;;;-1:-1:-1;;;233512:54:0;;;;;;;;-1:-1:-1;;;233512:54:0;;;;;;;;-1:-1:-1;;;233512:54:0;;;;;;;;-1:-1:-1;;;233512:54:0;;;;;;;;;;;;233656:16;233652:85;;233689:36;164857:10;233689:7;:36::i;:::-;234035:40;234059:15;234035:23;:40::i;:::-;234001:17;;;233965:110;233987:12;;;233965:110;233966:19;;;233965:110;234263:41;234288:15;234263:24;:41::i;:::-;:120;;-1:-1:-1;;;234263:120:0;;-1:-1:-1;;;;;28488:32:1;;;234263:120:0;;;28470:51:1;28557:32;;;28537:18;;;28530:60;843:1:0;28606:18:1;;;28599:34;234263:80:0;;;;;;;28443:18:1;;234263:120:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;234221:25;;;234191:192;234192:27;;;234191:192;-1:-1:-1;;;;;234469:39:0;;;;;234545:13;;;;234519:39;;;;:23;;;;:39;;;;-1:-1:-1;234595:13:0;;;234569:39;;;-1:-1:-1;234569:23:0;;;:39;;;;234652:34;;-1:-1:-1;;;234652:34:0;;;;:32;;:34;;;;;234519:23;;234652:34;;;;;;234469:39;234652:34;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;234646:40;;:2;:40;:::i;:::-;234619:24;;;:67;-1:-1:-1;;;;;234697:27:0;;:15;;;:27;;;234762:28;;;-1:-1:-1;;;234762:28:0;;;;:26;;:28;;;;;;;;;;;;;;;234697:27;234762:28;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;234756:34;;:2;:34;:::i;:::-;234735:18;;;:55;234955:17;;;;234976:1;234955:22;234951:154;;235018:17;;;;234994:41;;;;:21;;;:41;235075:18;;;;235050:43;:22;;;:43;234951:154;235121:5;:12;;;235137:1;235121:17;235117:129;;235174:12;;;;235155:31;;;;:16;;;:31;235221:13;;;;235201:33;-1:-1:-1;235201:17:0;;:33;235117:129;233501:1752;233302:1951;;;;;:::o;224191:5585::-;224413:24;224448:7;224466:15;224623:36;224644:7;224653:5;224623:20;:36::i;:::-;224589:17;;;224573:86;;;;224574:13;224676:18;224672:67;;-1:-1:-1;224719:1:0;;-1:-1:-1;224719:1:0;;-1:-1:-1;224719:1:0;224711:16;;224672:67;225189:22;;;;:27;225185:172;;225294:51;225302:5;:22;;;225326:5;:13;;;636:4;225294:7;:51::i;:::-;225253:5;:21;;;:92;;;;:::i;:::-;225233:17;;;:112;225185:172;225373:17;;;;:22;225369:152;;225463:46;225471:5;:17;;;225490:5;:13;;;636:4;225463:7;:46::i;:::-;225427:5;:16;;;:82;;;;:::i;:::-;225412:12;;;:97;225369:152;225803:24;225830:315;225873:189;225935:5;:25;;;225920:5;:12;;;:40;;;;:::i;:::-;311:4;226020:5;:27;;;225873:28;:189::i;:::-;226077:5;:24;;;226116:5;:18;;;225830:28;:315::i;:::-;225803:342;;226156:15;745:3;226195:5;:17;;;226175:5;:17;;;:37;;;;:::i;:::-;226174:45;;;;:::i;:::-;226156:63;;226375:14;226370:68;;226419:7;226406:20;;226370:68;226537:121;226580:10;226605:16;182:4;226537:28;:121::i;:::-;226803:21;;226795:56;;-1:-1:-1;;;226795:56:0;;-1:-1:-1;;;;;9723:32:1;;;226795:56:0;;;9705:51:1;226518:140:0;;-1:-1:-1;226759:20:0;;226795:47;;;;;;9678:18:1;;226795:56:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;226759:92;;227052:14;227048:730;;;227100:7;227087:10;:20;:55;;;;227130:12;227111:16;:31;227087:55;227083:243;;;227274:36;164857:10;227274:7;:36::i;:::-;227048:730;;;227499:12;227480:16;:31;227476:291;;;227545:156;227598:10;227631:12;227666:16;227545:30;:156::i;:::-;227532:169;;227739:12;227720:31;;227476:291;228061:20;228084:130;228129:5;:17;;;228161:16;182:4;228084:30;:130::i;:::-;228061:153;;228244:12;228229;:27;228225:1313;;;228626:88;228675:10;228687:12;228701;228626:48;:88::i;:::-;228616:98;;229021:5;:17;;;229011:7;:27;229007:520;;;229242:10;229222:5;:17;;;:30;;;;:::i;:::-;229212:40;;229007:520;;;229491:20;229501:10;229491:7;:20;:::i;:::-;229481:30;;229007:520;-1:-1:-1;229748:10:0;;-1:-1:-1;;;;224191:5585:0;;;;;;;;;;:::o;73907:336::-;74019:4;74141:23;74156:7;74141:14;:23::i;:::-;:94;;;;;74181:54;74214:7;74223:11;74181:32;:54::i;:::-;74121:114;73907:336;-1:-1:-1;;;73907:336:0:o;49056:265::-;49149:12;49175;49189:23;49216:6;-1:-1:-1;;;;;49216:11:0;49235:1;49238:4;49216:27;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;49174:69;;;;49271:42;49285:6;49293:7;49302:10;49271:13;:42::i;:::-;49264:49;49056:265;-1:-1:-1;;;;;49056:265:0:o;50936:263::-;51037:12;51063;51077:23;51104:6;-1:-1:-1;;;;;51104:19:0;51124:4;51104:25;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;236688:230;236766:47;;-1:-1:-1;;;236766:47:0;;-1:-1:-1;;;;;9723:32:1;;;236766:47:0;;;9705:51:1;236766:15:0;:38;;;;9678:18:1;;236766:47:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;236762:111;;;236830:31;164999:10;236830:7;:31::i;:::-;236885:25;236902:7;236885:16;:25::i;146751:4029::-;146879:7;146888;146923:34;146972:23;147010:17;147041:49;147054:7;147063:6;:26;;;147041:12;:49::i;:::-;146908:182;;;;;;147101:27;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;147101:27:0;147139:15;147165;147206:9;147201:3318;147221:9;147217:1;:13;147201:3318;;;147259:9;147269:1;147259:12;;;;;;;;:::i;:::-;;;;;;;147252:19;;147643:4;:10;;;-1:-1:-1;;;;;147618:35:0;:6;:21;;;-1:-1:-1;;;;;147618:35:0;;:56;;;;;147657:4;:17;;;147618:56;:100;;;;;147717:1;147695:6;:19;;;:23;147618:100;147596:676;;;147753:17;147835:41;147860:15;147835:24;:41::i;:::-;-1:-1:-1;;;;;147835:76:0;;147912:4;:15;;;147929:4;147935:5;147835:106;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;147790:6;147797:1;147790:9;;;;;;;;:::i;:::-;;;;;;147789:152;;;;;;;;;147979:6;:26;;;147966:9;:39;147962:125;;148037:30;;-1:-1:-1;;;148037:30:0;;;;;;;;;;;147962:125;-1:-1:-1;148232:24:0;148239:17;;;148232:24;147596:676;148292:4;:17;;;148288:2220;;;148468:10;;148443:21;;-1:-1:-1;;;;;148443:35:0;;;;;;148439:132;;148528:6;:23;;;148503:4;:21;;:48;;;;;;;:::i;:::-;;;-1:-1:-1;148439:132:0;148817:21;;;;:25;148813:590;;149020:363;149054:215;149096:4;:21;;;149148:6;149155:1;149148:9;;;;;;;;:::i;:::-;;;;;;;149194:4;:13;;;149188:2;:19;;;;:::i;149054:215::-;149309:10;;-1:-1:-1;;;;;149296:24:0;:12;:24;;;;;;;;;;:34;-1:-1:-1;;;149296:34:0;;;;745:3;149020:7;:363::i;:::-;149009:374;;;;:::i;:::-;;;148813:590;148288:2220;;;149472:10;;149447:21;;-1:-1:-1;;;;;149447:35:0;;;;;;149443:123;;149527:6;:19;;;149507:4;:16;;:39;;;;;;;:::i;:::-;;;-1:-1:-1;149443:123:0;149788:16;;;;:20;149784:709;;149984:191;150022:4;:16;;;150065:6;150072:1;150065:9;;;;;;;;:::i;:::-;;;;;;;150107:4;:13;;;150101:2;:19;;;;:::i;149984:191::-;149973:202;;;;:::i;:::-;;;150361:13;150351:7;:23;150347:127;;;150410:40;;-1:-1:-1;;;150410:40:0;;;;;;;;;;;150347:127;147232:3;;147201:3318;;;;150609:7;150599;:17;150595:79;;;150641:17;150651:7;150641;:17;:::i;:::-;150660:1;150633:29;;;;;;;;;;;;150595:79;150751:1;150754:17;150764:7;150754;:17;:::i;:::-;150743:29;;;;;;;;;;146751:4029;;;;;;:::o;159200:174::-;159307:9;159333:33;159358:1;159361;159364;159333:24;:33::i;8475:518::-;8549:9;8776:1;8772;8768:6;8764:14;8761:1;8758:21;8755:1;8751:29;8744:37;8741:1;8737:45;8727:172;;8816:10;8810:4;8803:24;8879:4;8873;8866:18;8727:172;-1:-1:-1;8961:9:0;;8936:17;;;8929:25;8922:33;8957:17;;;8918:57;;8475:518::o;156260:354::-;156364:24;156390:16;156408:7;156435:41;156460:15;156435:24;:41::i;:::-;-1:-1:-1;;;;;156532:22:0;;;;;;;:13;:22;;;;;;;156435:171;;-1:-1:-1;;;156435:171:0;;:60;;;;;;;:171;;156510:7;;156532:29;;;156576:19;;156435:171;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;156435:171:0;;;;;;;;;;;;:::i;:::-;156428:178;;;;;;156260:354;;;;;:::o;237284:1102::-;237372:7;;;;;;-1:-1:-1;;;;;;;;;;;212655:40:0;212773:54;165894:3;212792:34;;;212773:54;;;166056:3;212859:33;;;212838:55;237410:114;;;;;;237537:19;237559:15;-1:-1:-1;;;;;237559:32:0;;:34;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;237537:56;-1:-1:-1;;;;;;237630:24:0;;;;;;;237537:56;;237671:36;;;237689:18;237671:36;237667:533;;;237872:14;:36;;;;;237890:18;237872:36;237868:127;;;-1:-1:-1;237937:14:0;;-1:-1:-1;237953:12:0;;-1:-1:-1;237967:11:0;-1:-1:-1;237929:50:0;;-1:-1:-1;;237929:50:0;237868:127;238148:40;;-1:-1:-1;;;238148:40:0;;;;;;;;;;;237667:533;-1:-1:-1;238370:1:0;;;;-1:-1:-1;238370:1:0;;-1:-1:-1;237284:1102:0;-1:-1:-1;;;;;;237284:1102:0:o;153308:2495::-;153430:15;153447:12;153472:25;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;153472:25:0;-1:-1:-1;;;;;153534:22:0;;153508:23;153534:22;;;:13;:22;;;;;;;;:29;;153508:55;;;;;;;;;;;;;;;;;;;153534:29;;153508:55;;;153534:29;153508:55;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;153508:55:0;;;;;;;;;;;;;;;;;;;;;;;153576:13;153600:17;153620:6;:13;153600:33;;153649:9;153644:1260;153664:9;153660:1;:13;153644:1260;;;153700:6;153707:3;;;;:::i;:::-;;;153700:11;;;;;;;;:::i;:::-;;;;;;;153692:19;;153739:5;:21;;;-1:-1:-1;;;;;153730:30:0;:5;-1:-1:-1;;;;;153730:30:0;;153726:1167;;153846:24;;;;153893:23;;;;153939;;;;;153985:27;;;;154043:21;;154035:56;;-1:-1:-1;;;154035:56:0;;-1:-1:-1;;;;;9723:32:1;;;154035:56:0;;;9705:51:1;153802:368:0;;153846:24;153893:23;154035:47;;;;9678:18:1;;154035:56:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;154114:7;;154144;;;;153802:21;:368::i;:::-;153791:7;;;153781:389;;;153644:1260;;153726:1167;154445:15;;;;154427:55;;-1:-1:-1;;;154427:55:0;;-1:-1:-1;;;;;9723:32:1;;;154427:55:0;;;9705:51:1;154427:46:0;;;;;;9678:18:1;;154427:55:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;154399:83;-1:-1:-1;154621:8:0;;154617:261;;154664:194;154702:4;154733:5;:25;;;154785:5;:18;;;154830:5;154664:11;:194::i;:::-;154654:1;:6;;:204;;;;;;;:::i;:::-;;;-1:-1:-1;154617:261:0;153644:1260;;;-1:-1:-1;155082:19:0;;;;:24;155078:176;;155133:42;155141:1;:7;;;155150:5;:19;;;745:3;155133:7;:42::i;:::-;155123:52;;155208:7;;;;155217:19;;;;155200:42;;155208:7;745:3;155200:7;:42::i;:::-;155190:7;;;:52;155078:176;155316:6;;;;155305:7;;:17;155301:495;;155391:1;155381:11;;155301:495;;;155445:1;:7;;;155435:1;:6;;;:17;;:349;;155752:7;;155743:6;;;;155716:68;;155743:16;;;:::i;:::-;155776:7;;155766;;;;636:4;;155766:17;;;:::i;:::-;155716:26;:68::i;:::-;155435:349;;;636:4;155435:349;155425:359;;155301:495;153461:2342;;;;153308:2495;;;;;:::o;3388:3640::-;4011:9;;;-1:-1:-1;;4018:1:0;4015;4097:20;4227:14;;;4215:27;;4207:36;;;4331:285;;4378:1;4368:156;;4421:10;4415:4;4408:24;4496:4;4490;4483:18;4368:156;-1:-1:-1;4556:14:0;;;4592:5;;4331:285;4740:2;4737:1;4734:9;4724:152;;4781:10;4775:4;4768:24;4852:4;4846;4839:18;4724:152;5139:1;5136;5133;5126:15;5290:1;5286:9;;;5279:17;;5383:9;;;;;6724:13;;;6716:22;;;6748:9;;;;6744:17;;;6763:1;6740:25;6712:54;6801:14;;6797:22;6679:167;5764:1;5771;5767:9;;5760:17;;6050:11;;;6043:19;;6034:29;6124:11;;;6117:19;;6108:29;6199:11;;;6192:19;;6183:29;6274:11;;;6267:19;;6258:29;6349:11;;;6342:19;;6333:29;6936:11;;;6929:19;;;6920:29;6433:539;3388:3640;;;;;:::o;7316:474::-;7394:14;7430:19;7441:1;7444;7447;7430:10;:19::i;:::-;7421:28;;7544:1;7541;7538;7531:15;7528:244;;;7588:1;7576:14;;7608:149;;7662:10;7656:4;7649:24;7733:4;7727;7720:18;73199:482;73263:4;73474:117;73525:7;-1:-1:-1;;;73474:32:0;:117::i;:::-;:199;;;;-1:-1:-1;73609:64:0;73642:7;-1:-1:-1;;;;;;73609:32:0;:64::i;:::-;73608:65;73454:219;73199:482;-1:-1:-1;;73199:482:0:o;75088:826::-;75286:93;;-1:-1:-1;;;;;;33693:33:1;;75286:93:0;;;33675:52:1;75215:4:0;;;;33648:18:1;;75286:93:0;;;-1:-1:-1;;75286:93:0;;;;;;;;;;;;;;;-1:-1:-1;;;;;75286:93:0;-1:-1:-1;;;75286:93:0;;;75663:20;;75286:93;;-1:-1:-1;;;;;;;75286:93:0;;-1:-1:-1;;75594:7:0;75570:5;75541:203;75530:214;;75772:16;75758:30;;75823:4;75817:11;75802:26;;75858:7;:29;;;;;75883:4;75869:10;:18;;75858:29;:48;;;;-1:-1:-1;75891:15:0;;;75851:55;-1:-1:-1;;;;;;75088:826:0:o;51413:513::-;51548:12;51573:36;51589:7;51598:10;51573:15;:36::i;:::-;51771:17;;:22;:49;;;;-1:-1:-1;;;;;;51797:18:0;;;:23;51771:49;51767:122;;;51844:33;;-1:-1:-1;;;51844:33:0;;;;;;;;;;;51767:122;-1:-1:-1;51908:10:0;51413:513;-1:-1:-1;;51413:513:0:o;7895:476::-;7967:9;8194:1;8190;8186:6;8182:14;8179:1;8176:21;8173:1;8169:29;8162:37;8159:1;8155:45;8145:172;;8234:10;8228:4;8221:24;8297:4;8291;8284:18;8145:172;-1:-1:-1;8340:9:0;;8336:17;;7895:476::o;158505:590::-;158774:15;158791;158819:18;745:3;158840:115;158866:16;158897:5;158917:8;158940:4;158840:11;:115::i;:::-;:121;;;;:::i;:::-;158819:142;-1:-1:-1;159000:24:0;159013:11;158819:142;159000:24;:::i;:::-;158984:41;;:12;:41;:::i;:::-;158974:51;-1:-1:-1;159062:24:0;159075:11;159062:10;:24;:::i;:::-;159046:41;;:12;:41;:::i;:::-;159036:51;;158808:287;158505:590;;;;;;;;;;:::o;52102:425::-;52221:7;52216:304;;52249:10;:17;52270:1;52249:22;52245:103;;52299:33;;-1:-1:-1;;;52299:33:0;;;;;;;;;;;52245:103;52482:10;52476:17;52463:10;52459:2;52455:19;52448:46;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:131;-1:-1:-1;;;;;754:31:1;;744:42;;734:70;;800:1;797;790:12;815:134;883:20;;912:31;883:20;912:31;:::i;:::-;815:134;;;:::o;954:247::-;1013:6;1066:2;1054:9;1045:7;1041:23;1037:32;1034:52;;;1082:1;1079;1072:12;1034:52;1121:9;1108:23;1140:31;1165:5;1140:31;:::i;1206:508::-;1283:6;1291;1299;1352:2;1340:9;1331:7;1327:23;1323:32;1320:52;;;1368:1;1365;1358:12;1320:52;1407:9;1394:23;1426:31;1451:5;1426:31;:::i;:::-;1476:5;-1:-1:-1;1533:2:1;1518:18;;1505:32;1546:33;1505:32;1546:33;:::i;:::-;1206:508;;1598:7;;-1:-1:-1;;;1678:2:1;1663:18;;;;1650:32;;1206:508::o;1719:127::-;1780:10;1775:3;1771:20;1768:1;1761:31;1811:4;1808:1;1801:15;1835:4;1832:1;1825:15;1851:252;1923:2;1917:9;1965:3;1953:16;;-1:-1:-1;;;;;1984:34:1;;2020:22;;;1981:62;1978:88;;;2046:18;;:::i;:::-;2082:2;2075:22;1851:252;:::o;2108:253::-;2180:2;2174:9;2222:4;2210:17;;-1:-1:-1;;;;;2242:34:1;;2278:22;;;2239:62;2236:88;;;2304:18;;:::i;2366:253::-;2438:2;2432:9;2480:4;2468:17;;-1:-1:-1;;;;;2500:34:1;;2536:22;;;2497:62;2494:88;;;2562:18;;:::i;2624:253::-;2696:2;2690:9;2738:4;2726:17;;-1:-1:-1;;;;;2758:34:1;;2794:22;;;2755:62;2752:88;;;2820:18;;:::i;2882:275::-;2953:2;2947:9;3018:2;2999:13;;-1:-1:-1;;2995:27:1;2983:40;;-1:-1:-1;;;;;3038:34:1;;3074:22;;;3035:62;3032:88;;;3100:18;;:::i;:::-;3136:2;3129:22;2882:275;;-1:-1:-1;2882:275:1:o;3162:1757::-;3250:6;3310:3;3298:9;3289:7;3285:23;3281:33;3326:2;3323:22;;;3341:1;3338;3331:12;3323:22;-1:-1:-1;3383:22:1;;:::i;:::-;3428:29;3447:9;3428:29;:::i;:::-;3414:44;;3531:2;3516:18;;;3503:32;3551:14;;;3544:31;3648:2;3633:18;;;3620:32;3668:14;;;3661:31;3765:2;3750:18;;;3737:32;3785:14;;;3778:31;3882:3;3867:19;;;3854:33;3903:15;;;3896:32;4001:3;3986:19;;;3973:33;4022:15;;;4015:32;4120:3;4105:19;;;4092:33;4141:15;;;4134:32;4239:3;4224:19;;;4211:33;4260:15;;;4253:32;4358:3;4343:19;;;4330:33;4379:15;;;4372:32;4477:3;4462:19;;;4449:33;4498:15;;;4491:32;4598:3;4583:19;;;4570:33;4619:15;;;4612:33;4720:3;4705:19;;;4692:33;4741:15;;;4734:33;4842:3;4827:19;;;4814:33;4863:15;;;4856:33;;;;-1:-1:-1;3421:5:1;3162:1757;-1:-1:-1;3162:1757:1:o;5383:118::-;5469:5;5462:13;5455:21;5448:5;5445:32;5435:60;;5491:1;5488;5481:12;5506:886;5607:6;5615;5623;5631;5639;5647;5700:3;5688:9;5679:7;5675:23;5671:33;5668:53;;;5717:1;5714;5707:12;5668:53;5756:9;5743:23;5775:31;5800:5;5775:31;:::i;:::-;5825:5;-1:-1:-1;5903:2:1;5888:18;;5875:32;;-1:-1:-1;5985:2:1;5970:18;;5957:32;5998:33;5957:32;5998:33;:::i;:::-;6050:7;-1:-1:-1;6130:2:1;6115:18;;6102:32;;-1:-1:-1;6233:3:1;6218:19;;6205:33;;-1:-1:-1;6316:3:1;6301:19;;6288:33;6330:30;6288:33;6330:30;:::i;:::-;6379:7;6369:17;;;5506:886;;;;;;;;:::o;6397:637::-;6587:2;6599:21;;;6669:13;;6572:18;;;6691:22;;;6539:4;;6770:15;;;6744:2;6729:18;;;6539:4;6813:195;6827:6;6824:1;6821:13;6813:195;;;6892:13;;-1:-1:-1;;;;;6888:39:1;6876:52;;6957:2;6983:15;;;;6948:12;;;;6924:1;6842:9;6813:195;;;-1:-1:-1;7025:3:1;;6397:637;-1:-1:-1;;;;;6397:637:1:o;7039:382::-;7104:6;7112;7165:2;7153:9;7144:7;7140:23;7136:32;7133:52;;;7181:1;7178;7171:12;7133:52;7220:9;7207:23;7239:31;7264:5;7239:31;:::i;:::-;7289:5;-1:-1:-1;7346:2:1;7331:18;;7318:32;7359:30;7318:32;7359:30;:::i;:::-;7408:7;7398:17;;;7039:382;;;;;:::o;7426:771::-;7521:6;7529;7537;7545;7553;7606:3;7594:9;7585:7;7581:23;7577:33;7574:53;;;7623:1;7620;7613:12;7574:53;7662:9;7649:23;7681:31;7706:5;7681:31;:::i;:::-;7731:5;-1:-1:-1;7809:2:1;7794:18;;7781:32;;-1:-1:-1;7891:2:1;7876:18;;7863:32;7904:33;7863:32;7904:33;:::i;:::-;7956:7;-1:-1:-1;8036:2:1;8021:18;;8008:32;;-1:-1:-1;8118:3:1;8103:19;;8090:33;8132;8090;8132;:::i;:::-;8184:7;8174:17;;;7426:771;;;;;;;;:::o;8202:629::-;8288:6;8296;8304;8312;8365:3;8353:9;8344:7;8340:23;8336:33;8333:53;;;8382:1;8379;8372:12;8333:53;8421:9;8408:23;8440:31;8465:5;8440:31;:::i;:::-;8490:5;-1:-1:-1;8568:2:1;8553:18;;8540:32;;-1:-1:-1;8650:2:1;8635:18;;8622:32;8663:33;8622:32;8663:33;:::i;:::-;8202:629;;;;-1:-1:-1;8715:7:1;;8795:2;8780:18;8767:32;;-1:-1:-1;;8202:629:1:o;8836:487::-;8913:6;8921;8929;8982:2;8970:9;8961:7;8957:23;8953:32;8950:52;;;8998:1;8995;8988:12;8950:52;9037:9;9024:23;9056:31;9081:5;9056:31;:::i;:::-;9106:5;9184:2;9169:18;;9156:32;;-1:-1:-1;9287:2:1;9272:18;;;9259:32;;8836:487;-1:-1:-1;;;8836:487:1:o;9328:226::-;9387:6;9440:2;9428:9;9419:7;9415:23;9411:32;9408:52;;;9456:1;9453;9446:12;9408:52;-1:-1:-1;9501:23:1;;9328:226;-1:-1:-1;9328:226:1:o;10121:388::-;10189:6;10197;10250:2;10238:9;10229:7;10225:23;10221:32;10218:52;;;10266:1;10263;10256:12;10218:52;10305:9;10292:23;10324:31;10349:5;10324:31;:::i;:::-;10374:5;-1:-1:-1;10431:2:1;10416:18;;10403:32;10444:33;10403:32;10444:33;:::i;11070:241::-;11126:6;11179:2;11167:9;11158:7;11154:23;11150:32;11147:52;;;11195:1;11192;11185:12;11147:52;11234:9;11221:23;11253:28;11275:5;11253:28;:::i;11505:183::-;11565:4;-1:-1:-1;;;;;11590:6:1;11587:30;11584:56;;;11620:18;;:::i;:::-;-1:-1:-1;11665:1:1;11661:14;11677:4;11657:25;;11505:183::o;11693:367::-;11756:8;11766:6;11820:3;11813:4;11805:6;11801:17;11797:27;11787:55;;11838:1;11835;11828:12;11787:55;-1:-1:-1;11861:20:1;;-1:-1:-1;;;;;11893:30:1;;11890:50;;;11936:1;11933;11926:12;11890:50;11973:4;11965:6;11961:17;11949:29;;12033:3;12026:4;12016:6;12013:1;12009:14;12001:6;11997:27;11993:38;11990:47;11987:67;;;12050:1;12047;12040:12;12065:1039;12121:5;12169:4;12157:9;12152:3;12148:19;12144:30;12141:50;;;12187:1;12184;12177:12;12141:50;12209:22;;:::i;:::-;12200:31;;12268:9;12255:23;12287:33;12312:7;12287:33;:::i;:::-;12329:22;;12403:2;12388:18;;12375:32;12416:33;12375:32;12416:33;:::i;:::-;12476:2;12465:14;;12458:31;12562:2;12547:18;;;12534:32;12582:14;;;12575:31;12658:2;12643:18;;12630:32;12671:30;12630:32;12671:30;:::i;:::-;12728:2;12717:14;;12710:31;12814:3;12799:19;;;12786:33;12835:15;;;12828:32;12933:3;12918:19;;;12905:33;12954:15;;;12947:32;13052:3;13037:19;;;13024:33;13073:15;;;13066:32;;;;12721:5;12065:1039;-1:-1:-1;12065:1039:1:o;13109:1476::-;13273:6;13281;13289;13297;13305;13358:3;13346:9;13337:7;13333:23;13329:33;13326:53;;;13375:1;13372;13365:12;13326:53;13415:9;13402:23;-1:-1:-1;;;;;13440:6:1;13437:30;13434:50;;;13480:1;13477;13470:12;13434:50;13503:22;;13556:4;13548:13;;13544:27;-1:-1:-1;13534:55:1;;13585:1;13582;13575:12;13534:55;13625:2;13612:16;13648:64;13664:47;13704:6;13664:47;:::i;:::-;13648:64;:::i;:::-;13734:3;13758:6;13753:3;13746:19;13790:4;13785:3;13781:14;13774:21;;13847:4;13837:6;13834:1;13830:14;13826:2;13822:23;13818:34;13804:48;;13875:7;13867:6;13864:19;13861:39;;;13896:1;13893;13886:12;13861:39;13928:4;13924:2;13920:13;13909:24;;13942:200;13958:6;13953:3;13950:15;13942:200;;;14050:17;;14080:18;;14127:4;13975:14;;;;14118;;;;13942:200;;;14161:5;-1:-1:-1;14185:40:1;;-1:-1:-1;;;14219:4:1;14204:20;;14185:40;:::i;:::-;14175:50;;14278:2;14267:9;14263:18;14250:32;-1:-1:-1;;;;;14297:8:1;14294:32;14291:52;;;14339:1;14336;14329:12;14291:52;14378:72;14442:7;14431:8;14420:9;14416:24;14378:72;:::i;:::-;14469:8;;-1:-1:-1;14352:98:1;-1:-1:-1;14523:56:1;;-1:-1:-1;14571:7:1;14566:2;14551:18;;14523:56;:::i;:::-;14513:66;;13109:1476;;;;;;;;:::o;14590:420::-;14643:3;14681:5;14675:12;14708:6;14703:3;14696:19;14740:4;14735:3;14731:14;14724:21;;14779:4;14772:5;14768:16;14802:1;14812:173;14826:6;14823:1;14820:13;14812:173;;;14887:13;;14875:26;;14930:4;14921:14;;;;14958:17;;;;14848:1;14841:9;14812:173;;;-1:-1:-1;15001:3:1;;14590:420;-1:-1:-1;;;;14590:420:1:o;15015:682::-;15274:2;15263:9;15256:21;15237:4;15312:6;15306:13;15355:4;15350:2;15339:9;15335:18;15328:32;15383:63;15441:3;15430:9;15426:19;15412:12;15383:63;:::i;:::-;15369:77;;15502:4;15494:6;15490:17;15484:24;15477:4;15466:9;15462:20;15455:54;15564:2;15556:6;15552:15;15546:22;15540:3;15529:9;15525:19;15518:51;15619:9;15611:6;15607:22;15600:4;15589:9;15585:20;15578:52;15647:44;15684:6;15676;15647:44;:::i;15702:472::-;15823:6;15831;15884:2;15872:9;15863:7;15859:23;15855:32;15852:52;;;15900:1;15897;15890:12;15852:52;15940:9;15927:23;-1:-1:-1;;;;;15965:6:1;15962:30;15959:50;;;16005:1;16002;15995:12;15959:50;16044:70;16106:7;16097:6;16086:9;16082:22;16044:70;:::i;:::-;16133:8;;16018:96;;-1:-1:-1;15702:472:1;-1:-1:-1;;;;15702:472:1:o;16179:288::-;16220:3;16258:5;16252:12;16285:6;16280:3;16273:19;16341:6;16334:4;16327:5;16323:16;16316:4;16311:3;16307:14;16301:47;16393:1;16386:4;16377:6;16372:3;16368:16;16364:27;16357:38;16456:4;16449:2;16445:7;16440:2;16432:6;16428:15;16424:29;16419:3;16415:39;16411:50;16404:57;;;16179:288;;;;:::o;16472:779::-;16632:4;16680:2;16669:9;16665:18;16710:2;16699:9;16692:21;16733:6;16768;16762:13;16799:6;16791;16784:22;16837:2;16826:9;16822:18;16815:25;;16899:2;16889:6;16886:1;16882:14;16871:9;16867:30;16863:39;16849:53;;16937:2;16929:6;16925:15;16958:1;16968:254;16982:6;16979:1;16976:13;16968:254;;;17075:2;17071:7;17059:9;17051:6;17047:22;17043:36;17038:3;17031:49;17103:39;17135:6;17126;17120:13;17103:39;:::i;:::-;17093:49;-1:-1:-1;17177:2:1;17200:12;;;;17165:15;;;;;17004:1;16997:9;16968:254;;;-1:-1:-1;17239:6:1;;16472:779;-1:-1:-1;;;;;;16472:779:1:o;18326:127::-;18387:10;18382:3;18378:20;18375:1;18368:31;18418:4;18415:1;18408:15;18442:4;18439:1;18432:15;18458:125;18523:9;;;18544:10;;;18541:36;;;18557:18;;:::i;18588:217::-;18628:1;18654;18644:132;;18698:10;18693:3;18689:20;18686:1;18679:31;18733:4;18730:1;18723:15;18761:4;18758:1;18751:15;18644:132;-1:-1:-1;18790:9:1;;18588:217::o;18810:245::-;18877:6;18930:2;18918:9;18909:7;18905:23;18901:32;18898:52;;;18946:1;18943;18936:12;18898:52;18978:9;18972:16;18997:28;19019:5;18997:28;:::i;19060:365::-;-1:-1:-1;;;;;19268:32:1;;;;19250:51;;19344:14;;19337:22;19332:2;19317:18;;19310:50;19403:14;19396:22;19391:2;19376:18;;19369:50;19238:2;19223:18;;19060:365::o;19430:343::-;19509:6;19517;19570:2;19558:9;19549:7;19545:23;19541:32;19538:52;;;19586:1;19583;19576:12;19538:52;-1:-1:-1;;19631:16:1;;19737:2;19722:18;;;19716:25;19631:16;;19716:25;;-1:-1:-1;19430:343:1:o;19778:128::-;19845:9;;;19866:11;;;19863:37;;;19880:18;;:::i;21467:375::-;21555:1;21573:5;21587:249;21608:1;21598:8;21595:15;21587:249;;;21658:4;21653:3;21649:14;21643:4;21640:24;21637:50;;;21667:18;;:::i;:::-;21717:1;21707:8;21703:16;21700:49;;;21731:16;;;;21700:49;21814:1;21810:16;;;;;21770:15;;21587:249;;;21467:375;;;;;;:::o;21847:902::-;21896:5;21926:8;21916:80;;-1:-1:-1;21967:1:1;21981:5;;21916:80;22015:4;22005:76;;-1:-1:-1;22052:1:1;22066:5;;22005:76;22097:4;22115:1;22110:59;;;;22183:1;22178:174;;;;22090:262;;22110:59;22140:1;22131:10;;22154:5;;;22178:174;22215:3;22205:8;22202:17;22199:43;;;22222:18;;:::i;:::-;-1:-1:-1;;22278:1:1;22264:16;;22337:5;;22090:262;;22436:2;22426:8;22423:16;22417:3;22411:4;22408:13;22404:36;22398:2;22388:8;22385:16;22380:2;22374:4;22371:12;22367:35;22364:77;22361:203;;;-1:-1:-1;22473:19:1;;;22549:5;;22361:203;22596:42;-1:-1:-1;;22621:8:1;22615:4;22596:42;:::i;:::-;22674:6;22670:1;22666:6;22662:19;22653:7;22650:32;22647:58;;;22685:18;;:::i;:::-;22723:20;;21847:902;-1:-1:-1;;;21847:902:1:o;22754:131::-;22814:5;22843:36;22870:8;22864:4;22843:36;:::i;22890:251::-;22960:6;23013:2;23001:9;22992:7;22988:23;22984:32;22981:52;;;23029:1;23026;23019:12;22981:52;23061:9;23055:16;23080:31;23105:5;23080:31;:::i;26053:127::-;26114:10;26109:3;26105:20;26102:1;26095:31;26145:4;26142:1;26135:15;26169:4;26166:1;26159:15;26185:332;26286:4;26344:11;26331:25;26438:2;26434:7;26423:8;26407:14;26403:29;26399:43;26379:18;26375:68;26365:96;;26457:1;26454;26447:12;26365:96;26478:33;;;;;26185:332;-1:-1:-1;;26185:332:1:o;26522:1180::-;26640:9;26699:4;26691:5;26675:14;26671:26;26667:37;26664:57;;;26717:1;26714;26707:12;26664:57;26745:22;;:::i;:::-;26804:5;26791:19;26819:33;26844:7;26819:33;:::i;:::-;26861:24;;26933:2;26922:14;;26909:28;26946:30;26909:28;26946:30;:::i;:::-;27005:2;26992:16;;26985:33;27065:2;27054:14;;27041:28;-1:-1:-1;;;;;27081:30:1;;27078:50;;;27124:1;27121;27114:12;27078:50;27147:18;;27203:14;27196:4;27188:13;;27184:34;27174:62;;27232:1;27229;27222:12;27174:62;27272:2;27259:16;-1:-1:-1;;;;;27290:6:1;27287:30;27284:56;;;27320:18;;:::i;:::-;27362:57;27409:2;27386:17;;-1:-1:-1;;27382:31:1;27415:2;27378:40;27362:57;:::i;:::-;27442:6;27435:5;27428:21;27490:14;27485:2;27476:6;27472:2;27468:15;27464:24;27461:44;27458:64;;;27518:1;27515;27508:12;27458:64;27573:6;27568:2;27564;27560:11;27555:2;27548:5;27544:14;27531:49;27625:1;27600:18;;;27620:2;27596:27;27589:38;;;;27656:2;27643:16;;27636:31;-1:-1:-1;27647:7:1;26522:1180;-1:-1:-1;;26522:1180:1:o;27707:411::-;-1:-1:-1;;;;;27910:32:1;;;27892:51;;27979:32;;27974:2;27959:18;;27952:60;28048:2;28043;28028:18;;28021:30;;;-1:-1:-1;;28068:44:1;;28093:18;;28085:6;28068:44;:::i;28123:140::-;28181:5;28210:47;28251:4;28241:8;28237:19;28231:4;28210:47;:::i;28644:160::-;28721:13;;28774:4;28763:16;;28753:27;;28743:55;;28794:1;28791;28784:12;28809:204;28877:6;28930:2;28918:9;28909:7;28905:23;28901:32;28898:52;;;28946:1;28943;28936:12;28898:52;28969:38;28997:9;28969:38;:::i;29018:168::-;29091:9;;;29122;;29139:15;;;29133:22;;29119:37;29109:71;;29160:18;;:::i;29191:230::-;29261:6;29314:2;29302:9;29293:7;29289:23;29285:32;29282:52;;;29330:1;29327;29320:12;29282:52;-1:-1:-1;29375:16:1;;29191:230;-1:-1:-1;29191:230:1:o;29426:301::-;29555:3;29593:6;29587:13;29639:6;29632:4;29624:6;29620:17;29615:3;29609:37;29701:1;29665:16;;29690:13;;;-1:-1:-1;29665:16:1;29426:301;-1:-1:-1;29426:301:1:o;29732:829::-;-1:-1:-1;;;;;30005:32:1;;29987:51;;29975:2;30069;30054:18;;;30047:30;;;30126:13;;29960:18;;;30148:22;;;29927:4;30214:17;;;30254:16;;;29927:4;;30201:3;30186:19;;;29927:4;30298:194;30312:6;30309:1;30306:13;30298:194;;;30377:13;;-1:-1:-1;;;;;30373:39:1;30361:52;;30409:1;30468:14;;;;30442:2;30433:12;;;;30327:9;30298:194;;;-1:-1:-1;;30543:2:1;30528:18;;;;30521:34;;;;-1:-1:-1;30509:3:1;29732:829;-1:-1:-1;;;29732:829:1:o;30566:720::-;30631:5;30684:3;30677:4;30669:6;30665:17;30661:27;30651:55;;30702:1;30699;30692:12;30651:55;30735:6;30729:13;30762:64;30778:47;30818:6;30778:47;:::i;30762:64::-;30850:3;30874:6;30869:3;30862:19;30906:4;30901:3;30897:14;30890:21;;30967:4;30957:6;30954:1;30950:14;30942:6;30938:27;30934:38;30920:52;;30995:3;30987:6;30984:15;30981:35;;;31012:1;31009;31002:12;30981:35;31048:4;31040:6;31036:17;31062:193;31078:6;31073:3;31070:15;31062:193;;;31170:10;;31193:18;;31240:4;31231:14;;;;31095;31062:193;;;-1:-1:-1;31273:7:1;30566:720;-1:-1:-1;;;;;30566:720:1:o;31291:2095::-;31462:6;31470;31478;31531:2;31519:9;31510:7;31506:23;31502:32;31499:52;;;31547:1;31544;31537:12;31499:52;31580:9;31574:16;-1:-1:-1;;;;;31605:6:1;31602:30;31599:50;;;31645:1;31642;31635:12;31599:50;31668:22;;31721:4;31713:13;;31709:27;-1:-1:-1;31699:55:1;;31750:1;31747;31740:12;31699:55;31783:2;31777:9;31806:64;31822:47;31862:6;31822:47;:::i;31806:64::-;31892:3;31916:6;31911:3;31904:19;31948:4;31943:3;31939:14;31932:21;;32008:4;32000;31992:6;31988:17;31984:2;31980:26;31976:37;31962:51;;32036:7;32028:6;32025:19;32022:39;;;32057:1;32054;32047:12;32022:39;32089:4;32085:2;32081:13;32070:24;;32103:951;32119:6;32114:3;32111:15;32103:951;;;32201:4;32195:3;32186:7;32182:17;32178:28;32175:48;;;32219:1;32216;32209:12;32175:48;32249:22;;:::i;:::-;32305:3;32299:10;32322:33;32347:7;32322:33;:::i;:::-;32368:22;;32433:4;32424:14;;32418:21;32452:33;32418:21;32452:33;:::i;:::-;32516:4;32505:16;;32498:33;32567:41;32604:2;32595:12;;32567:41;:::i;:::-;32562:2;32555:5;32551:14;32544:65;32652:2;32647:3;32643:12;32637:19;32669:30;32691:7;32669:30;:::i;:::-;32730:2;32719:14;;32712:31;32811:3;32802:13;;;32796:20;32836:15;;;32829:32;32929:3;32920:13;;;32914:20;32954:15;;;32947:32;32992:18;;32145:4;32136:14;;;;33039:4;33030:14;;;;32103:951;;;33073:5;33063:15;;;;;;33124:4;33113:9;33109:20;33103:27;-1:-1:-1;;;;;33145:8:1;33142:32;33139:52;;;33187:1;33184;33177:12;33139:52;33210:74;33276:7;33265:8;33254:9;33250:24;33210:74;:::i;:::-;33350:2;33335:18;;;;33329:25;31291:2095;;33200:84;;-1:-1:-1;33329:25:1;;31291:2095;-1:-1:-1;;;31291:2095:1:o;33391:135::-;33430:3;33451:17;;;33448:43;;33471:18;;:::i;:::-;-1:-1:-1;33518:1:1;33507:13;;33391:135::o
Swarm Source
ipfs://3480a9d34d0738f022270141175efb5c96b0766841cbae8de67341217ab4a49d
Loading...
Loading
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in MON
Multichain Portfolio | 35 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.