Source Code
Overview
MON Balance
MON Value
$0.00Latest 25 from a total of 54 transactions
| Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
| Add C Token Supp... | 48577105 | 10 days ago | IN | 0 MON | 0.01082077 | ||||
| Add C Token Supp... | 48577081 | 10 days ago | IN | 0 MON | 0.01082077 | ||||
| Add Asset Pricin... | 48577005 | 10 days ago | IN | 0 MON | 0.04838461 | ||||
| Add Asset Pricin... | 40850025 | 46 days ago | IN | 0 MON | 0.04539989 | ||||
| Add C Token Supp... | 38696339 | 56 days ago | IN | 0 MON | 0.0108475 | ||||
| Add C Token Supp... | 38696312 | 56 days ago | IN | 0 MON | 0.0108475 | ||||
| Add Asset Pricin... | 37936998 | 60 days ago | IN | 0 MON | 0.06095496 | ||||
| Remove Asset Pri... | 37936969 | 60 days ago | IN | 0 MON | 0.0089674 | ||||
| Add Asset Pricin... | 37936198 | 60 days ago | IN | 0 MON | 0.05425969 | ||||
| Remove Asset Pri... | 37936167 | 60 days ago | IN | 0 MON | 0.01098795 | ||||
| Remove Asset Pri... | 37936162 | 60 days ago | IN | 0 MON | 0.01243023 | ||||
| Add C Token Supp... | 37834123 | 60 days ago | IN | 0 MON | 0.01379118 | ||||
| Add C Token Supp... | 37834099 | 60 days ago | IN | 0 MON | 0.01379118 | ||||
| Add C Token Supp... | 37834022 | 60 days ago | IN | 0 MON | 0.01379118 | ||||
| Add C Token Supp... | 37833993 | 60 days ago | IN | 0 MON | 0.01379118 | ||||
| Add C Token Supp... | 37833903 | 60 days ago | IN | 0 MON | 0.01379118 | ||||
| Add C Token Supp... | 37833873 | 60 days ago | IN | 0 MON | 0.01379118 | ||||
| Add C Token Supp... | 37833787 | 60 days ago | IN | 0 MON | 0.01379118 | ||||
| Add C Token Supp... | 37833760 | 60 days ago | IN | 0 MON | 0.01379118 | ||||
| Add C Token Supp... | 37833678 | 60 days ago | IN | 0 MON | 0.01379118 | ||||
| Add C Token Supp... | 37833654 | 60 days ago | IN | 0 MON | 0.01379118 | ||||
| Add C Token Supp... | 37833582 | 60 days ago | IN | 0 MON | 0.01379118 | ||||
| Add C Token Supp... | 37833559 | 60 days ago | IN | 0 MON | 0.01379118 | ||||
| Add C Token Supp... | 37833398 | 60 days ago | IN | 0 MON | 0.01100536 | ||||
| Add C Token Supp... | 37833373 | 60 days ago | IN | 0 MON | 0.01100536 |
Advanced mode: Intended for advanced users or developers and will display all Internal Transactions including zero value transfers.
Latest 25 internal transactions (View All)
Advanced mode:
| Parent Transaction Hash | Block | From | To | ||||
|---|---|---|---|---|---|---|---|
| 50896219 | 4 mins ago | 0 MON | |||||
| 50896219 | 4 mins ago | 0 MON | |||||
| 50896219 | 4 mins ago | 0 MON | |||||
| 50896219 | 4 mins ago | 0 MON | |||||
| 50896219 | 4 mins ago | 0 MON | |||||
| 50896219 | 4 mins ago | 0 MON | |||||
| 50889376 | 49 mins ago | 0 MON | |||||
| 50889376 | 49 mins ago | 0 MON | |||||
| 50889376 | 49 mins ago | 0 MON | |||||
| 50889376 | 49 mins ago | 0 MON | |||||
| 50889376 | 49 mins ago | 0 MON | |||||
| 50888062 | 58 mins ago | 0 MON | |||||
| 50888062 | 58 mins ago | 0 MON | |||||
| 50888062 | 58 mins ago | 0 MON | |||||
| 50887829 | 1 hr ago | 0 MON | |||||
| 50887829 | 1 hr ago | 0 MON | |||||
| 50887829 | 1 hr ago | 0 MON | |||||
| 50887829 | 1 hr ago | 0 MON | |||||
| 50887829 | 1 hr ago | 0 MON | |||||
| 50886058 | 1 hr ago | 0 MON | |||||
| 50886058 | 1 hr ago | 0 MON | |||||
| 50886058 | 1 hr ago | 0 MON | |||||
| 50886058 | 1 hr ago | 0 MON | |||||
| 50886058 | 1 hr ago | 0 MON | |||||
| 50886058 | 1 hr ago | 0 MON |
Loading...
Loading
Contract Name:
OracleManager
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/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/external/chainlink/IChainlink.sol
interface IChainlink {
/// @notice Returns the number of decimals the aggregator responds with.
function decimals() external view returns (uint8);
/// @notice Returns the latest oracle data from the aggregator.
/// @return roundId The round ID from the aggregator for which the data
/// was retrieved.
/// answer The price returned by the aggregator.
/// startedAt The timestamp the current round was started.
/// updatedAt The timestamp the current round last was updated.
/// answeredInRound The round ID of the round in which `answer`
/// was computed.
function latestRoundData() external view returns (
uint80 roundId,
int256 answer,
uint256 startedAt,
uint256 updatedAt,
uint80 answeredInRound
);
/// @notice Returns the latest roundID the aggregator responds with.
function latestRound() external view returns (uint256);
function getRoundData(uint80 _roundId) external view returns (
uint80 roundId,
int256 answer,
uint256 startedAt,
uint256 updatedAt,
uint80 answeredInRound
);
}
// 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/interfaces/IOracleAdaptor.sol
interface IOracleAdaptor {
/// TYPES ///
/// @notice Return data from pricing an asset.
/// @param price The price of the asset.
/// @param inUsd Boolean indicating whether `price` is denominated
/// in USD (true) or native token (false).
/// @param hadError Boolean indicating whether the asset was priced
/// without running into any issues or not.
struct PricingResult {
uint256 price;
bool inUSD;
bool hadError;
}
/// @notice Guard logic when pricing `asset` configured to prevent oracle
/// mispricing either by mistake or malicious PriceGuard when
/// pricing `asset` denominated either USD or native tokens.
/// @param timestampStart When `increasePerYear` should start increasing
/// `basePrice` raising the maximum price returned
/// when pricing `asset`.
/// @param ips The magnitude that `basePrice` should increase overtime
/// from `timestampStart`, in `WAD`, per second.
/// @param basePrice The base price that should be the maximum price
/// returned when pricing `asset`.
/// @param minPrice The minimum price that should be allowed to be
/// returned when pricing `asset`.
struct PriceGuard {
uint40 timestampStart;
uint40 ips;
uint88 basePrice;
uint88 minPrice;
}
/// @notice Called by OracleManager to price an asset.
/// @param asset The address of the asset for which the price is needed.
/// @param inUSD A boolean to determine if the price should be returned in
/// USD or not.
/// @param getLower A boolean to determine if lower of two oracle prices
/// should be retrieved.
/// @return result Return data for a priced asset containing:
/// price The price of the asset.
/// inUSD Boolean indicating whether `price` is denominated
/// in USD (true) or native token (false).
/// hadError Boolean indicating whether the asset was priced
/// without running into any issues or not.
function getPrice(
address asset,
bool inUSD,
bool getLower
) external view returns (PricingResult memory);
/// @notice Whether an asset is supported by the Oracle Adaptor or not.
/// @dev Asset => Supported by adaptor.
function isSupportedAsset(address asset) external view returns (bool);
/// @notice Token price guard configuration for pricing an asset.
/// @dev Token address => inUSD => Price Guard configuration.
function getPriceGuard(
address asset,
bool inUSD
) external view returns (PriceGuard memory);
/// @notice Returns the adaptor's type.
/// @dev Used by frontends to determine how to properly interact
/// with a supported asset.
function adaptorType() external view returns (uint256);
}
// 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/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/oracles/OracleManager.sol
/// @title Curvance Dynamic Pessimistic Dual Oracle Manager.
/// @notice Provides a universal interface allowing contracts
/// to retrieve secure pricing data based on various price feeds.
/// @dev The Curvance Oracle Manager acts as a unified hub for pricing anything.
/// The Oracle Manager can support up to two oracle adaptors, returning
/// a maximum of two prices for any asset.
///
/// Prices can be returned in USD or a chain's native gas token.
/// Either the higher or lower of the two prices can returned, based on
/// what is desired. For Curvance protocol, the more advantageous of both
/// prices is used. For user collateralized assets, the lower of the two
/// prices is used. For user debt positions, the higher of the two prices
/// is used.
///
/// Curvance specific voucher tokens can also be priced by the Oracle
/// Router, based on the exchange rate between the voucher token, and
/// its underlying token.
///
/// The Oracle Manager also relays feedback based on any issues that
/// occurred during pricing an asset. This takes the form of three error
/// codes that are returned on querying a price or prices:
/// - An error code of 0 (NO_ERROR) corresponds to no error occurred
/// during pricing.
/// - An error code of 1 (CAUTION) corresponds to moderate issues
/// occurring during pricing, inside Curvance this results in new
/// borrowing, repayment, and redemption actions being blocked.
/// - An error code of 2 (BAD_SOURCE) corresponds to large issues
/// occurring during pricing, inside Curvance this results in new
/// borrowing, repayment, redemptions, and liquidation actions being
/// blocked.
///
/// "Circuit Breakers" have been introduced, that can be triggered based
/// on the prices returned to the Oracle Manager by adaptors. If prices
/// deviate heavily, error codes can be returned.
/// - An error code of 1 will be triggered by a deviation between pricing
/// adaptors of >= `cautionBound` for the corresponding asset.
/// - An error code of 2 will be triggered by a deviation between pricing
/// adaptors of >= `badSourceBound` for the corresponding asset.
///
/// Oracle Adaptors can be added or removed by the DAO which can change
/// how an asset is priced. This allows for continually improving the
/// data quality returned within the system. Oracle Adaptors handle
/// checks such as price staleness, decimal offsetting, and ecosystem
/// specific logic. All this is abstracted away from the Oracle Manager,
/// all data is returned in a standardized format of 18 decimals. Prices
/// must be positive (> 0). When PriceGuards are configured on an adaptor,
/// minimum and maximum prices are enforced via the guard's `minPrice`
/// (uint88) and `basePrice` (uint88) parameters respectively. When no
/// PriceGuard is configured, prices can range up to uint256.max with no
/// upper constraint beyond what the underlying oracle feed supports.
/// When using the Oracle Manager, verify what PriceGuard configurations
/// are active for the oracle adaptors to understand the effective
/// minimum/maximum price constraints.
///
/// Oracle Adaptors also can be used to introduce realtime information
/// based on offchain logic such as dynamic liquidation penalties.
///
/// The Oracle Manager was built to minimize Oracle trust by introducing
/// a decentralized model, many oracle providers all verified against
/// each other. "Don't trust, verify."
///
contract OracleManager is IOracleManager {
/// TYPES ///
/// @notice Storage structure for asset pricing configuration from various
/// oracle pricing adaptors.
/// @param badSourceBoundUSD The bound value allowed between adaptor
/// prices before `BAD_SOURCE` error code is
/// returned, in `BPS`. An additional `BPS` is
/// added to the value to save runtime gas costs
/// during `_checkBounds` call. Used when pricing
/// in USD denomination.
/// @param cautionBoundUSD The bound value allowed between adaptor prices
/// before `CAUTION` error code is returned, in
/// `BPS`. An additional `BPS` is added to the
/// value to save runtime gas costs during
/// `_checkBounds` call. Used when pricing in USD
/// denomination.
/// @param badSourceBoundNative The bound value allowed between adaptor
/// prices before `BAD_SOURCE` error code is
/// returned, in `BPS`. An additional `BPS` is
/// added to the value to save runtime gas
/// costs during `_checkBounds` call. Used
/// when pricing in native chain token
/// denomination.
/// @param cautionBoundNative The bound value allowed between adaptor
/// prices before `CAUTION` error code is
/// returned, in `BPS`. An additional `BPS`
/// is added to the value to save runtime gas
/// costs during `_checkBounds` call. Used when
/// pricing in native chain token denomination.
/// @dev 10050 = 0.5% = 50 basis point price feed deviation allowed.
/// @param adaptors Array containing all pricing adaptors an asset is
/// dependent on, maximum 2, 0 dependencies means the
/// asset is not.
struct PricingConfig {
uint16 badSourceBoundUSD;
uint16 cautionBoundUSD;
uint16 badSourceBoundNative;
uint16 cautionBoundNative;
address[] adaptors;
}
/// CONSTANTS ///
/// @notice Address identifying a chain's native token.
address public constant native =
0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
/// @notice Time to pass before accepting answers when sequencer
/// comes back up, in seconds.
uint256 public constant GRACE_PERIOD_TIME = 300;
/// @notice Maximum value that a price deviation bound can be set as
/// inside the protocol, in `BPS`.
/// @dev 300 = 3.0%, in `BPS`.
uint256 public constant MAX_DEVIATION_BOUND = 350;
/// @notice Minimum value that a price deviation bound can be set as
/// inside the protocol.
/// @dev 20 = 0.2%.
uint256 public constant MIN_DEVIATION_BOUND = 20;
/// @notice The minimum buffer between `CAUTION` bound and `BAD_SOURCE`
/// bound when configuring bound values, in `BPS`.
/// @dev 20 = 0.2% minimum buffer before `BAD_SOURCE` value can
/// be triggered.
uint256 public constant MIN_CAUTION_TO_BAD_SOURCE_DELTA = 20;
/// @notice Curvance DAO hub.
ICentralRegistry public immutable centralRegistry;
/// STORAGE ///
/// @notice Whether an address is an approved Curvance price feed adaptor.
/// @dev Adaptor address => Approved for usage.
// Address => Adaptor approval status.
mapping(address => bool) public isApprovedAdaptor;
/// @notice Pricing configuration data for an asset.
/// @dev Token address => Pricing configuration for `asset`.
mapping(address => PricingConfig) public assetPricingConfig;
// Address => Curvance token underlying asset address.
mapping(address => address) public cTokens;
/// EVENTS ///
event AdaptorDependencyAdded(address asset, address adaptor);
event AdaptorDependencyRemoved(address asset, address adaptor);
event AssetDeviationBoundsSet(
address asset,
uint256 badSourceBoundUSD,
uint256 cautionBoundUSD,
uint256 badSourceBoundNative,
uint256 cautionBoundNative
);
/// ERRORS ///
error OracleManager__Unauthorized();
error OracleManager__NotSupported();
error OracleManager__InvalidParameter();
error OracleManager__ErrorCodeFlagged();
error OracleManager__AdaptorIsNotApproved();
/// CONSTRUCTOR ///
/// @param cr The address of the Protocol Central Registry.
constructor(ICentralRegistry cr) {
CentralRegistryLib._isCentralRegistry(cr);
centralRegistry = cr;
}
/// EXTERNAL FUNCTIONS ///
/// @notice Adds a new dependency for pricing `asset` on `adaptor`. If
/// this is the second adaptor dependency, set deviation values
/// too, validating they are safe based on price feed deviation.
/// @dev Requires that `adaptor` is an approved adaptor, and that `asset`
/// does not already have two adaptor dependencies.
/// May emit an {AssetDeviationBoundsSet} event.
/// @param asset The address of the asset to add a new pricing adaptor
/// dependency for.
/// @param adaptor The address of the new adaptor to add dependency to.
/// @param badSourceBoundUSD The new maximum price deviation before a
/// `BAD_SOURCE` error code is returned for USD
/// pricing, only used when adding a second
/// adaptor dependency.
/// @param cautionBoundUSD The new maximum price deviation before a
/// `CAUTION` error code is returned for USD
/// pricing, only used when adding a second
/// adaptor dependency.
/// @param badSourceBoundNative The new maximum price deviation before a
/// `BAD_SOURCE` error code is returned for
/// native pricing, only used when adding a
/// second adaptor dependency.
/// @param cautionBoundNative The new maximum price deviation before a
/// `CAUTION` error code is returned for native
/// pricing, only used when adding a second
/// adaptor dependency.
function addAssetPricingAdaptor(
address asset,
address adaptor,
uint256 badSourceBoundUSD,
uint256 cautionBoundUSD,
uint256 badSourceBoundNative,
uint256 cautionBoundNative
) external {
_checkElevatedPermissions();
_addAssetPricingAdaptor(asset, adaptor);
// Pull `asset` pricing config data after the new adaptor has been
// added.
PricingConfig storage config = assetPricingConfig[asset];
// If there are not two adaptor dependencies we can skip this logic.
if (config.adaptors.length > 1) {
_setDeviationBounds(
asset,
config,
badSourceBoundUSD,
cautionBoundUSD,
badSourceBoundNative,
cautionBoundNative
);
}
}
/// @notice Replaces the dependency on pricing from `adaptorToRemove` for
/// `asset` in favor of adding dependency on pricing to
/// `adaptorToAdd`.
/// @dev Requires that `adaptorToAdd` is an approved adaptor, and that
/// `asset` currently has at least one adaptor configured. Which
/// should include `adaptorToRemove`.
/// May emit an {AssetDeviationBoundsSet} event.
/// @param asset The address of the asset to adjust pricing adaptors for.
/// @param adaptorToRemove The address of the adaptor to remove dependency
/// from.
/// @param adaptorToAdd The address of the new adaptor to add dependency
/// to.
/// @param badSourceBoundUSD The new maximum price deviation before a
/// `BAD_SOURCE` error code is returned for USD
/// pricing, only used when replacing a second
/// adaptor dependency.
/// @param cautionBoundUSD The new maximum price deviation before a
/// `CAUTION` error code is returned for USD
/// pricing, only used when replacing a second
/// adaptor dependency.
/// @param badSourceBoundNative The new maximum price deviation before a
/// `BAD_SOURCE` error code is returned for
/// native pricing, only used when replacing a
/// second adaptor dependency.
/// @param cautionBoundNative The new maximum price deviation before a
/// `CAUTION` error code is returned for native
/// pricing, only used when replacing a second
/// adaptor dependency.
function replaceAssetPricingAdaptor(
address asset,
address adaptorToRemove,
address adaptorToAdd,
uint256 badSourceBoundUSD,
uint256 cautionBoundUSD,
uint256 badSourceBoundNative,
uint256 cautionBoundNative
) external {
_checkElevatedPermissions();
// Validate that the feeds are not identical as there would be no
// point to replace a feed with itself.
if (adaptorToRemove == adaptorToAdd) {
revert OracleManager__InvalidParameter();
}
_removeAssetPricingAdaptor(asset, adaptorToRemove);
_addAssetPricingAdaptor(asset, adaptorToAdd);
// Pull `asset` pricing config data after the new adaptor has been
// added.
PricingConfig storage config = assetPricingConfig[asset];
// If there are not two adaptor dependencies we can skip this logic.
if (config.adaptors.length > 1) {
_setDeviationBounds(
asset,
config,
badSourceBoundUSD,
cautionBoundUSD,
badSourceBoundNative,
cautionBoundNative
);
}
}
/// @notice Removes the dependency on pricing from `adaptor` for `asset`.
/// @dev Requires that `adaptor` is currently being used for pricing
/// `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 remove pricing adaptor
/// dependency from.
/// @param adaptor The address of the adaptor to remove dependency from.
function removeAssetPricingAdaptor(address asset, address adaptor) external {
_checkElevatedPermissions();
_removeAssetPricingAdaptor(asset, adaptor);
}
/// @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 deviation bound 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 {
if (!isApprovedAdaptor[msg.sender]) {
return;
}
address[] memory adaptors = assetPricingConfig[asset].adaptors;
uint256 numAdaptors = adaptors.length;
// Validate calling adaptor is a currently supported used for `asset`.
// If unused can return immediately.
if (numAdaptors > 1) {
if (adaptors[0] != msg.sender && adaptors[1] != msg.sender) {
return;
}
} else {
if (numAdaptors == 0) {
return;
}
if (adaptors[0] != msg.sender) {
return;
}
}
_removeAssetPricingAdaptor(asset, msg.sender);
}
/// @notice Returns the adaptors used for pricing `asset`.
/// @param asset The address of the asset to get pricing adaptors for.
/// @return result The current adaptor(s) used for pricing `asset`.
function getPricingAdaptors(
address asset
) external view returns(address[] memory result) {
result = assetPricingConfig[asset].adaptors;
}
/// @notice Adds a new Curvance token to the Oracle Manager.
/// @dev Requires that `newCToken` is not already supported.
/// The cToken's underlying CANNOT be equal to address(0).
/// @param newCToken The address of the Curvance token to support.
function addCTokenSupport(address newCToken) external {
_checkElevatedPermissions();
// We call a Curvance-specific token function as a sanity check.
ICToken(newCToken).isBorrowable();
// Validate `newCToken` has not already been registered as a cToken,
// and that `newUnderlying` is not address(0) as that is how we check
// whether a token is a cToken or not.
address newUnderlying = ICToken(newCToken).asset();
if (cTokens[newCToken] != address(0) || newUnderlying == address(0)) {
revert OracleManager__InvalidParameter();
}
cTokens[newCToken]= newUnderlying;
}
/// @notice Removes a Curvance token's support in the Oracle Manager.
/// @dev Requires that the Curvance token is supported.
/// @param cTokenToRemove The address of the Curvance token to remove
/// support for.
function removeCTokenSupport(address cTokenToRemove) external {
_checkElevatedPermissions();
// Validate `newCToken` has already been registered as a cToken.
if (cTokens[cTokenToRemove] == address(0)) {
revert OracleManager__InvalidParameter();
}
delete cTokens[cTokenToRemove];
}
/// @notice Removes adaptor approval for `adaptorToRemove`, then,
/// adds adaptor approval for `adaptorToAdd`.
/// @dev Requires that the adaptor isn't already approved.
/// @param adaptorToRemove The address of the adaptor to remove approval.
/// @param adaptorToAdd The address of the adaptor to approve.
function replaceApprovedAdaptor(
address adaptorToRemove,
address adaptorToAdd
) external {
_checkElevatedPermissions();
// Validate `adaptorToAdd` is not already supported.
if (isApprovedAdaptor[adaptorToAdd]) {
revert OracleManager__InvalidParameter();
}
// Validate `adaptorToRemove` is currently supported.
_checkIsApprovedAdaptor(adaptorToRemove);
delete isApprovedAdaptor[adaptorToRemove];
isApprovedAdaptor[adaptorToAdd] = true;
}
/// @notice Adds `newAdaptor` as an approved adaptor.
/// @dev Requires that the adaptor isn't already approved.
/// @param adaptorToAdd The address of the adaptor to approve.
function addApprovedAdaptor(address adaptorToAdd) external {
_checkElevatedPermissions();
// Validate `adaptorToAdd` is not already supported.
if (isApprovedAdaptor[adaptorToAdd]) {
revert OracleManager__InvalidParameter();
}
isApprovedAdaptor[adaptorToAdd] = true;
}
/// @notice Removes `adaptorToRemove` as an approved adaptor.
/// @dev Requires that the adaptor is currently approved.
/// @param adaptorToRemove The address of the adaptor to remove.
function removeApprovedAdaptor(address adaptorToRemove) external {
_checkElevatedPermissions();
// Validate `adaptorToRemove` is currently supported.
_checkIsApprovedAdaptor(adaptorToRemove);
delete isApprovedAdaptor[adaptorToRemove];
}
/// @notice Sets new maximum deviation bound values for pricing adaptors
/// before `CAUTION` or `BAD_SOURCE` error codes are activated
/// for `asset`.
/// @dev Only allowed if there are two adaptor dependencies configured
/// already. Emits an {AssetDeviationBoundsSet} event.
/// @param asset The address of the asset to set pricing deviation bound
/// values for.
/// @param badSourceBoundUSD The new maximum price deviation before a
/// `BAD_SOURCE` error code is returned for USD
/// pricing.
/// @param cautionBoundUSD The new maximum price deviation before a
/// `CAUTION` error code is returned for USD
/// pricing.
/// @param badSourceBoundNative The new maximum price deviation before a
/// `BAD_SOURCE` error code is returned for
/// native pricing.
/// @param cautionBoundNative The new maximum price deviation before a
/// `CAUTION` error code is returned for native
/// pricing.
function setDeviationBounds(
address asset,
uint256 badSourceBoundUSD,
uint256 cautionBoundUSD,
uint256 badSourceBoundNative,
uint256 cautionBoundNative
) external {
_checkElevatedPermissions();
PricingConfig storage config = assetPricingConfig[asset];
// If there are not two adaptor dependencies we can skip this logic.
if (config.adaptors.length < 2) {
revert OracleManager__InvalidParameter();
}
_setDeviationBounds(
asset,
config,
badSourceBoundUSD,
cautionBoundUSD,
badSourceBoundNative,
cautionBoundNative
);
}
/// @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) {
address cTokenUnderlying = cTokens[asset];
if (cTokenUnderlying != address(0)) {
return assetPricingConfig[cTokenUnderlying].adaptors.length > 0;
}
return assetPricingConfig[asset].adaptors.length > 0;
}
/// @notice Check whether L2 sequencer is valid or down.
/// @dev Uses Chainlink sequencer check if available, regardless of
/// linked oracle adaptor.
/// @return True if sequencer is valid.
function isSequencerValid() external view returns (bool) {
return _isSequencerValid();
}
/// PUBLIC FUNCTIONS ///
/// @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. Additionally, also checks Chainlink L2 sequencer via
/// `_isSequencerValid()`
/// and returns `(0, BAD_SOURCE)` if down, even for non-Chainlink
/// adaptors. This is by design.
/// @param asset The address of the asset to retrieve the price for.
/// @param inUSD Specifies whether the price format should be in
/// USD (true) or a chain's native token (false).
/// @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
) public view returns (uint256 price, uint256 errorCode) {
if (!_isSequencerValid()) {
return (0, BAD_SOURCE);
}
address cToken;
address cTokenUnderlying = cTokens[asset];
// Check whether `asset` is Curvance token.
if (cTokenUnderlying != address(0)) {
cToken = asset;
asset = cTokenUnderlying;
}
(price, errorCode) = _getPrice(asset, inUSD, getLower);
// Query the exchange rate between a Curvance token and its underlying
// token and convert the price into WAD form.
if (cToken != address(0)) {
if (getLower) {
price = FixedPointMathLib.mulDiv(
price,
ICToken(cToken).exchangeRate(),
WAD
);
} else {
price = FixedPointMathLib.mulDivUp(
price,
ICToken(cToken).exchangeRate(),
WAD
);
}
}
// If somehow an adaptor returns a price of 0, make sure a BAD_SOURCE
// flag is bubbled up.
if (price == 0 && errorCode < BAD_SOURCE) {
errorCode = BAD_SOURCE;
}
}
/// @notice Retrieves the prices of a collateral token, and debt token
/// underlying.
/// @param collateralToken The cToken currently collateralized to price.
/// @param debtToken The borrowableCToken borrowed from to price
/// underlying of.
/// @param errorCodeBreakpoint The error code that will cause liquidity
/// operations to revert.
/// @return collateralSharesPrice The current price of `collateralToken`.
/// @return debtUnderlyingPrice The current price of `debtToken`
/// underlying.
function getPriceIsolatedPair(
address collateralToken,
address debtToken,
uint256 errorCodeBreakpoint
) external returns (
uint256 collateralSharesPrice,
uint256 debtUnderlyingPrice
) {
if (!_isSequencerValid()) {
revert OracleManager__ErrorCodeFlagged();
}
uint256 errorCode;
address underlying = cTokens[collateralToken];
if (underlying == address(0)) {
revert OracleManager__NotSupported();
}
(collateralSharesPrice, errorCode) = _getPrice(
underlying,
true,
true
);
collateralSharesPrice = FixedPointMathLib.mulDiv(
collateralSharesPrice,
ICToken(collateralToken).exchangeRateUpdated(),
WAD
);
// If somehow an adaptor returns a price of 0, make sure a BAD_SOURCE
// flag is bubbled up.
if (collateralSharesPrice == 0 && errorCode < BAD_SOURCE) {
errorCode = BAD_SOURCE;
}
if (errorCode >= errorCodeBreakpoint) {
revert OracleManager__ErrorCodeFlagged();
}
underlying = cTokens[debtToken];
if (underlying == address(0)) {
revert OracleManager__NotSupported();
}
(debtUnderlyingPrice, errorCode) = _getPrice(
underlying,
true,
false
);
// If somehow an adaptor returns a price of 0, make sure a BAD_SOURCE
// flag is bubbled up.
if (debtUnderlyingPrice == 0 && errorCode < BAD_SOURCE) {
errorCode = BAD_SOURCE;
}
if (errorCode >= errorCodeBreakpoint) {
revert OracleManager__ErrorCodeFlagged();
}
}
/// @notice Retrieves the prices and account data of multiple assets
/// inside a Curvance Market.
/// @dev If the asset is being used as collateral the users liquidity is
/// priced in shares, if theyre borrowing the outstanding debt is
/// measured in assets (underlying).
/// @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
) {
if (!_isSequencerValid()) {
revert OracleManager__ErrorCodeFlagged();
}
uint256 numAssets = assets.length;
AccountSnapshot[] memory snapshots = new AccountSnapshot[](numAssets);
uint256[] memory prices = new uint256[](numAssets);
uint256 errorCode;
address asset;
for (uint256 i; i < numAssets; ++i) {
asset = assets[i];
snapshots[i] = ICToken(asset).getSnapshotUpdated(account);
if (snapshots[i].isCollateral) {
// If the asset is being used as collateral the users liquidity is
// priced in shares using _getPrice multiplied by exchange rate.
(prices[i], errorCode) = _getPrice(
snapshots[i].underlying,
true,
true
);
// `getSnapshotUpdated` already accrues any pending assets so
// we can call `exchangeRate` directly.
prices[i] = FixedPointMathLib.mulDiv(
prices[i],
ICToken(asset).exchangeRate(),
WAD
);
} else {
// If the asset is being borrowed the outstanding debt is
// measured in assets (underlying) using _getPrice.
(prices[i], errorCode) = _getPrice(
snapshots[i].underlying,
true,
false
);
}
// If somehow an adaptor returns a price of 0, make sure a BAD_SOURCE
// flag is bubbled up.
if (prices[i] == 0 && errorCode < BAD_SOURCE) {
errorCode = BAD_SOURCE;
}
if (errorCode >= errorCodeBreakpoint) {
revert OracleManager__ErrorCodeFlagged();
}
}
return (snapshots, prices, numAssets);
}
/// INTERNAL FUNCTIONS ///
/// @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 Specifies whether the price format should be in
/// USD (true) or a chain's native token (false).
/// @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
) internal view returns (uint256 price, uint256 errorCode) {
if (asset == address(0)) {
revert OracleManager__NotSupported();
}
PricingConfig memory config = assetPricingConfig[asset];
uint256 numAdaptors = config.adaptors.length;
if (numAdaptors == 0) {
revert OracleManager__NotSupported();
}
// Get price from a single adaptor source or dual adaptor source.
if (numAdaptors > 1) {
(price, errorCode) =
_getPriceDualAdaptor(asset, config, inUSD, getLower);
} else {
bool hadError;
(price, hadError) =
_getPriceFromAdaptor(asset, config.adaptors[0], inUSD, getLower);
if (hadError) {
errorCode = BAD_SOURCE;
}
}
}
/// @notice Adds a new dependency for pricing `asset` on `adaptor`. If
/// this is the second adaptor dependency, set deviation values
/// too, validating they are safe based on adaptor's price feed
/// deviation threshold.
/// @dev Requires that `adaptor` is an approved adaptor, and that `asset`
/// does not already have two adaptor dependencies.
/// @param asset The address of the asset to add a new pricing adaptor
/// dependency for.
/// @param adaptor The address of the new adaptor to add dependency to.
function _addAssetPricingAdaptor(address asset, address adaptor) internal {
// Validate that `adaptor` is approved for pricing usage.
_checkIsApprovedAdaptor(adaptor);
// Validate that the adaptor supports pricing `asset`.
if (!IOracleAdaptor(adaptor).isSupportedAsset(asset)) {
revert OracleManager__InvalidParameter();
}
address[] storage adaptors = assetPricingConfig[asset].adaptors;
uint256 numAdaptors = adaptors.length;
// Validate that we do not already have 2 pricing adaptors configured
// for `asset`.
if (numAdaptors > 1) {
revert OracleManager__InvalidParameter();
}
// If there is already an adaptor dependency for `asset` make sure
// that it is not `adaptor`, which would duplicate the dependency.
// Validate that the adaptor proposed is not a duplicate of the
// current adaptor of a supported feed for `asset`.
if (numAdaptors != 0 && adaptors[0] == adaptor) {
revert OracleManager__InvalidParameter();
}
// Validate that the adaptor returns an acceptable price for `asset`
// by sampling a price call with `getLower` = true.
IOracleAdaptor.PricingResult memory result = IOracleAdaptor(adaptor)
.getPrice(asset, true, true);
if (result.price == 0 || result.hadError) {
revert OracleManager__InvalidParameter();
}
// Validate that the adaptor returns an acceptable price for `asset`
// by sampling a price call with `getLower` = false.
result = IOracleAdaptor(adaptor).getPrice(asset, true, false);
if (result.price == 0 || result.hadError) {
revert OracleManager__InvalidParameter();
}
adaptors.push(adaptor);
emit AdaptorDependencyAdded(asset, adaptor);
}
/// @notice Removes the dependency on pricing from `adaptor` for `asset`.
/// @dev Requires that `adaptor` is currently being used for pricing
/// `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 remove pricing adaptor
/// dependency from.
/// @param adaptor The address of the adaptor to remove dependency from.
function _removeAssetPricingAdaptor(
address asset,
address adaptor
) internal {
// If theres two adaptor dependencies, figure out which to remove,
// otherwise we know the adaptor to remove is the first entry.
address[] storage adaptors = assetPricingConfig[asset].adaptors;
uint256 numAdaptors = adaptors.length;
if (numAdaptors == 0) {
revert OracleManager__NotSupported();
}
if (numAdaptors > 1) {
// Check whether `adaptor` is a currently dependency for pricing
// `asset`.
if (adaptors[0] != adaptor && adaptors[1] != adaptor) {
revert OracleManager__NotSupported();
}
// We want to remove the first adaptor dependency of the two,
// so move the second adaptor dependency to slot one.
if (adaptors[0] == adaptor) {
adaptors[0] = adaptors[1];
}
} else {
if (adaptors[0] != adaptor) {
revert OracleManager__NotSupported();
}
}
// We know the adaptor exists, but we cannot use `isApprovedAdaptor`
// as we could have removed it as an approved adaptor prior to this
// function call.
adaptors.pop();
emit AdaptorDependencyRemoved(asset, adaptor);
}
/// @notice Retrieves the price of a specified asset from two specific
/// price feeds.
/// @dev If both price feeds return an error, it returns (0, BAD_SOURCE).
/// If one of the price feeds return an error, it returns the
/// price from the working feed along with a CAUTION flag.
/// Otherwise, it returns (price, NO_ERROR).
/// @param asset The address of the asset to retrieve the price for.
/// @param config The current pricing configuration of `asset`.
/// @param inUSD Specifies whether the price format should be in
/// USD (true) or a chain's native token (false).
/// @param getLower Whether the lower or higher price should be returned
/// if two feeds are available.
/// @return uint256 The current price of `asset`.
/// @return bool An error flag (if any).
function _getPriceDualAdaptor(
address asset,
PricingConfig memory config,
bool inUSD,
bool getLower
) internal view returns (uint256, uint256) {
(uint256 price0, bool error0) = _getPriceFromAdaptor(
asset, config.adaptors[0], inUSD, getLower
);
(uint256 price1, bool error1)= _getPriceFromAdaptor(
asset, config.adaptors[1], inUSD, getLower
);
// Check if we had any working price feeds,
// if not we need to block any market operations.
if (error0 && error1){
return (0, BAD_SOURCE);
}
// Check if we had an error in either price that should block
// borrowing/redemption.
if (error0 || error1) {
// We know based on context of when this if statement block is
// called that one but not both adaptors have an error. So, if
// adaptor0 had the error, adaptor1 is usable, and vice versa.
if (error0) {
return (price1, CAUTION);
}
return (price0, CAUTION);
}
uint256 badSourceBound = inUSD ?
config.badSourceBoundUSD : config.badSourceBoundNative;
uint256 cautionBound = inUSD ?
config.cautionBoundUSD : config.cautionBoundNative;
uint256 errorCode =
_checkBounds(price0, price1, badSourceBound, cautionBound);
if (getLower) {
return (price1 < price0 ? price1 : price0, errorCode);
}
return (price1 > price0 ? price1 : price0, errorCode);
}
/// @notice Retrieves the price of `asset` from `adaptor`.
/// @dev Converts the price received to `inUSD` if necessary.
/// @param asset The address of the asset to retrieve the price for.
/// @param adaptor The address of the pricing adaptor to use for pricing
/// `asset`.
/// @param inUSD Specifies whether the price format should be in
/// USD (true) or a chain's native token (false).
/// @param getLower Whether the lower or higher price should be returned
/// if there are two adaptor dependencies.
/// @return uint256 The current price of `asset`.
/// @return bool Whether the adaptor ran into an error when pricing.
function _getPriceFromAdaptor(
address asset,
address adaptor,
bool inUSD,
bool getLower
) internal view returns (uint256, bool) {
_checkIsApprovedAdaptor(adaptor);
IOracleAdaptor.PricingResult memory result = IOracleAdaptor(adaptor)
.getPrice(asset, inUSD, getLower);
// If we had an error pricing the asset, bubble up we had a error.
if (result.hadError) {
return (0, true);
}
// If the adaptor's price denomination is not in the proper form,
// modify it.
if (result.inUSD != inUSD) {
uint256 newPrice;
(newPrice, result.hadError) =
_getNativeUSD(inUSD ? getLower : !getLower);
if (result.hadError) {
return (0, true);
}
return (
_convertNativeUSD(result.price, newPrice, result.inUSD, getLower),
result.hadError
);
}
return (result.price, result.hadError);
}
/// @notice Queries the current price of a chain's native token in USD
/// using the Oracle Manager.
/// @dev The price is deemed valid if the data from the Oracle Manager
/// is fresh and a positive value.
/// @param getLower Whether the lower or higher price should be returned
/// if there are two adaptor dependencies.
/// @return price The current price of `native`.
/// @return hadError Whether the adaptor ran into an error when pricing
/// `native`.
function _getNativeUSD(
bool getLower
) internal view returns (uint256 price, bool hadError) {
uint256 errorCode;
(price, errorCode) = _getPrice(native, true, getLower);
// If somehow an adaptor returns a price of 0, make sure a BAD_SOURCE
// flag is bubbled up.
if (price == 0 && errorCode < BAD_SOURCE) {
errorCode = BAD_SOURCE;
}
// If there was any error while querying native token price,
// bubble up an error.
hadError = errorCode != NO_ERROR;
}
/// @notice Check whether a sequencer is valid or down.
/// @return True if sequencer is valid.
function _isSequencerValid() internal view returns (bool) {
address sequencerUptimeFeed = centralRegistry.SEQUENCER_ORACLE();
if (sequencerUptimeFeed != address(0)) {
(, int256 answer, uint256 startedAt, , ) =
IChainlink(sequencerUptimeFeed).latestRoundData();
// Answer == 0: Sequencer is up.
// Check that the sequencer is up or the grace period has passed
// after the sequencer is back up.
if (startedAt == 0) {
return false;
}
uint256 timeSinceUp = block.timestamp - startedAt;
if (answer != 0 || timeSinceUp <= GRACE_PERIOD_TIME) {
return false;
}
}
return true;
}
/// @notice Converts a given price between a chain's native token
/// and USD.
/// @dev Depending on the currentFormatInUSD parameter,
/// this function either converts the price from native token
/// to USD (if true) or from USD to native (if false) using the
/// provided conversion rate.
/// @param currentPrice The price to convert.
/// @param conversionRate The rate to use for the conversion.
/// @param currentlyInUSD Specifies whether the current format of the
/// price is in USD.
/// If true -> Convert the price from USD to
/// native token.
/// If false -> Convert the price from native token
/// to USD.
/// @param getLower Whether the lower or higher price should be returned.
/// @return The converted price.
function _convertNativeUSD(
uint256 currentPrice,
uint256 conversionRate,
bool currentlyInUSD,
bool getLower
) internal pure returns (uint256) {
if (!currentlyInUSD) {
// The price denomination is in native token and we want USD.
if (getLower) {
return FixedPointMathLib.mulDiv(currentPrice, conversionRate, WAD);
}
return FixedPointMathLib.mulDivUp(currentPrice, conversionRate, WAD);
}
// The price denomination is in USD and we want native token.
if (getLower) {
return FixedPointMathLib.mulDiv(currentPrice, WAD, conversionRate);
}
return FixedPointMathLib.mulDivUp(currentPrice, WAD, conversionRate);
}
/// @notice Sets a new maximum deviation for pricing adaptors before
/// CAUTION or BAD_SOURCE error codes are activated for `asset`.
/// @dev Only allowed if there are two adaptor dependencies configured
/// already.
/// @param asset The address of the asset to set pricing deviation values
/// for.
/// @param badSourceBoundUSD The new maximum price deviation before a
/// `BAD_SOURCE` error code is returned for USD
/// pricing.
/// @param cautionBoundUSD The new maximum price deviation before a
/// `CAUTION` error code is returned for USD
/// pricing.
/// @param badSourceBoundNative The new maximum price deviation before a
/// `BAD_SOURCE` error code is returned for
/// native pricing.
/// @param cautionBoundNative The new maximum price deviation before a
/// `CAUTION` error code is returned for native
/// pricing.
function _setDeviationBounds(
address asset,
PricingConfig storage config,
uint256 badSourceBoundUSD,
uint256 cautionBoundUSD,
uint256 badSourceBoundNative,
uint256 cautionBoundNative
) internal {
// Validate that the `CAUTION` error code will not trigger too
// closely to `BAD_SOURCE` error code for USD bounds.
if (badSourceBoundUSD < cautionBoundUSD + MIN_CAUTION_TO_BAD_SOURCE_DELTA) {
revert OracleManager__InvalidParameter();
}
// Validate that the `CAUTION` error code will not trigger too
// closely to `BAD_SOURCE` error code for native bounds.
if (badSourceBoundNative < cautionBoundNative + MIN_CAUTION_TO_BAD_SOURCE_DELTA) {
revert OracleManager__InvalidParameter();
}
// Validate USD bound values are within acceptable value range.
if (
cautionBoundUSD < MIN_DEVIATION_BOUND ||
badSourceBoundUSD > MAX_DEVIATION_BOUND
) {
revert OracleManager__InvalidParameter();
}
// Validate native bound values are within acceptable value range.
if (
cautionBoundNative < MIN_DEVIATION_BOUND ||
badSourceBoundNative > MAX_DEVIATION_BOUND
) {
revert OracleManager__InvalidParameter();
}
// Add `BPS` to the value to save converting to a BPS premium
// e.g. 10200 for 2% at runtime.
config.badSourceBoundUSD = uint16(badSourceBoundUSD + BPS);
config.cautionBoundUSD = uint16(cautionBoundUSD + BPS);
config.badSourceBoundNative = uint16(badSourceBoundNative + BPS);
config.cautionBoundNative = uint16(cautionBoundNative + BPS);
emit AssetDeviationBoundsSet(asset, badSourceBoundUSD, cautionBoundUSD, badSourceBoundNative, cautionBoundNative);
}
/// @notice Reviews the report prices from both pricing adaptors,
/// returning an appropriate error code if the deviation between
/// prices is significant enough.
/// @dev If the deviation is less than `cautionBound`, returns `NO_ERROR`.
/// If the deviation is more than `cautionBound` but less than
/// `badSourceBound`, returns `CAUTION`.
/// If the deviation is more than `badSourceBound`, returns
/// `BAD_SOURCE`.
/// @param a The price reported by the first adaptor.
/// @param b The price reported by the second adaptor.
/// @param badSourceBound The bound value where deviation in price
/// between `a` and `b` should return the
/// `BAD_SOURCE` error code.
/// @param cautionBound The bound value where deviation in price between
/// `a` and `b` should return the `CAUTION` error
/// code.
/// @return Returns the appropriate error code depending on deviation
/// between adaptor's reported prices.
function _checkBounds(
uint256 a,
uint256 b,
uint256 badSourceBound,
uint256 cautionBound
) internal pure returns (uint256) {
if (a <= b) {
// Check if both adaptor are within `cautionBound` of each other.
if (((a * cautionBound) / BPS) < b) {
// Notify that the price is dangerous and to treat data as
// invalid because we are outside the accepted range of
// deviation.
if (((a * badSourceBound) / BPS) < b) {
return BAD_SOURCE;
}
// Notify that the price should be taken with caution because
// we are outside the accepted range of deviation.
return CAUTION;
}
return NO_ERROR;
}
// Check if both feeds are within `cautionBound` of each other.
if (((b * cautionBound) / BPS) < a) {
// Notify that the price is dangerous and to treat data as invalid
// because we are outside the accepted range of deviation.
if (((b * badSourceBound) / BPS) < a) {
return BAD_SOURCE;
}
// Notify that the price should be taken with caution because
// we are outside the accepted range of deviation.
return CAUTION;
}
return NO_ERROR;
}
/// @notice Checks whether `adaptor` is an approved adaptor or not.
/// Reverts if `adaptor` is not approved.
/// @param adaptor The address of the adaptor to check.
function _checkIsApprovedAdaptor(address adaptor) internal view {
if (!isApprovedAdaptor[adaptor]) {
revert OracleManager__AdaptorIsNotApproved();
}
}
/// @dev Checks whether the caller has sufficient permissioning.
function _checkElevatedPermissions() internal view {
if (!centralRegistry.hasElevatedPermissions(msg.sender)) {
revert OracleManager__Unauthorized();
}
}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"contract ICentralRegistry","name":"cr","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"CentralRegistryLib__InvalidCentralRegistry","type":"error"},{"inputs":[],"name":"OracleManager__AdaptorIsNotApproved","type":"error"},{"inputs":[],"name":"OracleManager__ErrorCodeFlagged","type":"error"},{"inputs":[],"name":"OracleManager__InvalidParameter","type":"error"},{"inputs":[],"name":"OracleManager__NotSupported","type":"error"},{"inputs":[],"name":"OracleManager__Unauthorized","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"asset","type":"address"},{"indexed":false,"internalType":"address","name":"adaptor","type":"address"}],"name":"AdaptorDependencyAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"asset","type":"address"},{"indexed":false,"internalType":"address","name":"adaptor","type":"address"}],"name":"AdaptorDependencyRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"asset","type":"address"},{"indexed":false,"internalType":"uint256","name":"badSourceBoundUSD","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"cautionBoundUSD","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"badSourceBoundNative","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"cautionBoundNative","type":"uint256"}],"name":"AssetDeviationBoundsSet","type":"event"},{"inputs":[],"name":"GRACE_PERIOD_TIME","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_DEVIATION_BOUND","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_CAUTION_TO_BAD_SOURCE_DELTA","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_DEVIATION_BOUND","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"adaptorToAdd","type":"address"}],"name":"addApprovedAdaptor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"asset","type":"address"},{"internalType":"address","name":"adaptor","type":"address"},{"internalType":"uint256","name":"badSourceBoundUSD","type":"uint256"},{"internalType":"uint256","name":"cautionBoundUSD","type":"uint256"},{"internalType":"uint256","name":"badSourceBoundNative","type":"uint256"},{"internalType":"uint256","name":"cautionBoundNative","type":"uint256"}],"name":"addAssetPricingAdaptor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newCToken","type":"address"}],"name":"addCTokenSupport","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"assetPricingConfig","outputs":[{"internalType":"uint16","name":"badSourceBoundUSD","type":"uint16"},{"internalType":"uint16","name":"cautionBoundUSD","type":"uint16"},{"internalType":"uint16","name":"badSourceBoundNative","type":"uint16"},{"internalType":"uint16","name":"cautionBoundNative","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"cTokens","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"centralRegistry","outputs":[{"internalType":"contract ICentralRegistry","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"asset","type":"address"},{"internalType":"bool","name":"inUSD","type":"bool"},{"internalType":"bool","name":"getLower","type":"bool"}],"name":"getPrice","outputs":[{"internalType":"uint256","name":"price","type":"uint256"},{"internalType":"uint256","name":"errorCode","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"collateralToken","type":"address"},{"internalType":"address","name":"debtToken","type":"address"},{"internalType":"uint256","name":"errorCodeBreakpoint","type":"uint256"}],"name":"getPriceIsolatedPair","outputs":[{"internalType":"uint256","name":"collateralSharesPrice","type":"uint256"},{"internalType":"uint256","name":"debtUnderlyingPrice","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"address[]","name":"assets","type":"address[]"},{"internalType":"uint256","name":"errorCodeBreakpoint","type":"uint256"}],"name":"getPricesForMarket","outputs":[{"components":[{"internalType":"address","name":"asset","type":"address"},{"internalType":"address","name":"underlying","type":"address"},{"internalType":"uint8","name":"decimals","type":"uint8"},{"internalType":"bool","name":"isCollateral","type":"bool"},{"internalType":"uint256","name":"collateralPosted","type":"uint256"},{"internalType":"uint256","name":"debtBalance","type":"uint256"}],"internalType":"struct AccountSnapshot[]","name":"","type":"tuple[]"},{"internalType":"uint256[]","name":"","type":"uint256[]"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"asset","type":"address"}],"name":"getPricingAdaptors","outputs":[{"internalType":"address[]","name":"result","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"isApprovedAdaptor","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isSequencerValid","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"asset","type":"address"}],"name":"isSupportedAsset","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"native","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"asset","type":"address"}],"name":"notifyFeedRemoval","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"adaptorToRemove","type":"address"}],"name":"removeApprovedAdaptor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"asset","type":"address"},{"internalType":"address","name":"adaptor","type":"address"}],"name":"removeAssetPricingAdaptor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"cTokenToRemove","type":"address"}],"name":"removeCTokenSupport","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"adaptorToRemove","type":"address"},{"internalType":"address","name":"adaptorToAdd","type":"address"}],"name":"replaceApprovedAdaptor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"asset","type":"address"},{"internalType":"address","name":"adaptorToRemove","type":"address"},{"internalType":"address","name":"adaptorToAdd","type":"address"},{"internalType":"uint256","name":"badSourceBoundUSD","type":"uint256"},{"internalType":"uint256","name":"cautionBoundUSD","type":"uint256"},{"internalType":"uint256","name":"badSourceBoundNative","type":"uint256"},{"internalType":"uint256","name":"cautionBoundNative","type":"uint256"}],"name":"replaceAssetPricingAdaptor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"asset","type":"address"},{"internalType":"uint256","name":"badSourceBoundUSD","type":"uint256"},{"internalType":"uint256","name":"cautionBoundUSD","type":"uint256"},{"internalType":"uint256","name":"badSourceBoundNative","type":"uint256"},{"internalType":"uint256","name":"cautionBoundNative","type":"uint256"}],"name":"setDeviationBounds","outputs":[],"stateMutability":"nonpayable","type":"function"}]Contract Creation Code
60a060405234801561000f575f5ffd5b5060405161273138038061273183398101604081905261002e91610154565b61003781610048565b6001600160a01b031660805261017a565b610059816399011ef160e01b610079565b610076576040516369b5e45b60e11b815260040160405180910390fd5b50565b5f6100838361009b565b8015610094575061009483836100ce565b9392505050565b5f6100ad826301ffc9a760e01b6100ce565b80156100c857506100c6826001600160e01b03196100ce565b155b92915050565b6040516001600160e01b0319821660248201525f90819060440160408051601f19818403018152919052602080820180516001600160e01b03166301ffc9a760e01b17815282519293505f9283928392909183918a617530fa92503d91505f51905082801561013e575060208210155b801561014957505f81115b979650505050505050565b5f60208284031215610164575f5ffd5b81516001600160a01b0381168114610094575f5ffd5b6080516125916101a05f395f818161038a015281816110b6015261139801526125915ff3fe608060405234801561000f575f5ffd5b506004361061016c575f3560e01c806371e41254116100d95780639ae37a2811610093578063e04e7d701161006e578063e04e7d70146103ee578063e73af84614610401578063ed2f860314610414578063ff133d6d1461021e575f5ffd5b80639ae37a28146103b55780639be918e6146103c8578063ce16237c146103db575f5ffd5b806371e41254146103085780637f0ecd3c1461031b5780638c0b09d01461033d5780638d6fbb9e146103655780638f73dcfa146103855780639407d08f146103ac575f5ffd5b80632b12aaa91161012a5780632b12aaa91461023457806334abc11d146102475780635ae69163146102b7578063663158f5146102ca5780636b61db18146102dd5780637194ed42146102f0575f5ffd5b8062082f1414610170578063013ed4cd1461019b578063035e6c19146101b057806311b0b42d146101d85780631b4f30e51461020b5780631f42a45f1461021e575b5f5ffd5b61018361017e366004611f19565b61041d565b60405161019293929190611fdd565b60405180910390f35b6101ae6101a9366004612086565b61079a565b005b6101c36101be3660046120bd565b6107b0565b60408051928352602083019190915201610192565b6101f373eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee81565b6040516001600160a01b039091168152602001610192565b6101ae610219366004612086565b61092c565b610226601481565b604051908152602001610192565b6101ae6102423660046120fb565b6109b0565b6102896102553660046120fb565b60016020525f908152604090205461ffff808216916201000081048216916401000000008204811691600160301b90041684565b6040805161ffff95861681529385166020850152918416918301919091529091166060820152608001610192565b6101c36102c536600461212a565b610af6565b6101ae6102d83660046120fb565b610c39565b6101ae6102eb366004612172565b610c9d565b6102f8610cfa565b6040519015158152602001610192565b6101ae6103163660046120fb565b610d08565b6102f86103293660046120fb565b5f6020819052908152604090205460ff1681565b6101f361034b3660046120fb565b60026020525f90815260409020546001600160a01b031681565b6103786103733660046120fb565b610e64565b60405161019291906121b2565b6101f37f000000000000000000000000000000000000000000000000000000000000000081565b61022661015e81565b6101ae6103c33660046121fd565b610eda565b6102f86103d63660046120fb565b610f29565b6101ae6103e93660046120fb565b610f90565b6101ae6103fc366004612252565b610fc1565b6101ae61040f3660046120fb565b61104d565b61022661012c81565b6060805f6104296110b2565b61044657604051637c70f82f60e01b815260040160405180910390fd5b845f8167ffffffffffffffff811115610461576104616122bb565b6040519080825280602002602001820160405280156104bf57816020015b6040805160c0810182525f8082526020808301829052928201819052606082018190526080820181905260a082015282525f1990920191018161047f5790505b5090505f8267ffffffffffffffff8111156104dc576104dc6122bb565b604051908082528060200260200182016040528015610505578160200160208202803683370190505b5090505f5f5f5b85811015610787578b8b82818110610526576105266122cf565b905060200201602081019061053b91906120fb565b60405163cf6af22d60e01b81526001600160a01b038f811660048301529193509083169063cf6af22d9060240160c0604051808303815f875af1158015610584573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906105a89190612328565b8582815181106105ba576105ba6122cf565b60200260200101819052508481815181106105d7576105d76122cf565b602002602001015160600151156106e1576106118582815181106105fd576105fd6122cf565b6020026020010151602001516001806111f6565b858381518110610623576106236122cf565b602002602001018195508281525050506106be848281518110610648576106486122cf565b6020026020010151836001600160a01b0316633ba0b9a96040518163ffffffff1660e01b8152600401602060405180830381865afa15801561068c573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906106b091906123a8565b670de0b6b3a764000061135f565b8482815181106106d0576106d06122cf565b60200260200101818152505061072d565b61070a8582815181106106f6576106f66122cf565b60200260200101516020015160015f6111f6565b85838151811061071c5761071c6122cf565b602002602001018195508281525050505b83818151811061073f5761073f6122cf565b60200260200101515f1480156107555750600283105b1561075f57600292505b89831061077f57604051637c70f82f60e01b815260040160405180910390fd5b60010161050c565b50929b919a509298509650505050505050565b6107a2611383565b6107ac8282611428565b5050565b5f5f6107ba6110b2565b6107d757604051637c70f82f60e01b815260040160405180910390fd5b6001600160a01b038086165f9081526002602052604081205490911680610811576040516337ccbfb560e01b815260040160405180910390fd5b61081d816001806111f6565b809350819550505061086684886001600160a01b031663f41102916040518163ffffffff1660e01b81526004016020604051808303815f875af115801561068c573d5f5f3e3d5ffd5b9350831580156108765750600282105b1561088057600291505b8482106108a057604051637c70f82f60e01b815260040160405180910390fd5b506001600160a01b038086165f9081526002602052604090205416806108d9576040516337ccbfb560e01b815260040160405180910390fd5b6108e58160015f6111f6565b9093509150821580156108f85750600282105b1561090257600291505b84821061092257604051637c70f82f60e01b815260040160405180910390fd5b5050935093915050565b610934611383565b6001600160a01b0381165f9081526020819052604090205460ff161561096d57604051631f0d085960e11b815260040160405180910390fd5b6109768261166c565b6001600160a01b039182165f90815260208190526040808220805460ff199081169091559290931681529190912080549091166001179055565b6109b8611383565b806001600160a01b03166345d7b97a6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156109f4573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610a1891906123bf565b505f816001600160a01b03166338d52e0f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a56573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610a7a91906123da565b6001600160a01b038381165f9081526002602052604090205491925016151580610aab57506001600160a01b038116155b15610ac957604051631f0d085960e11b815260040160405180910390fd5b6001600160a01b039182165f90815260026020526040902080546001600160a01b03191691909216179055565b5f5f610b006110b2565b610b0f57505f90506002610c31565b6001600160a01b038086165f908152600260205260408120549091168015610b3657959050855b610b418787876111f6565b90945092506001600160a01b03821615610c17578415610ba257610b9b84836001600160a01b0316633ba0b9a96040518163ffffffff1660e01b8152600401602060405180830381865afa15801561068c573d5f5f3e3d5ffd5b9350610c17565b610c1484836001600160a01b0316633ba0b9a96040518163ffffffff1660e01b8152600401602060405180830381865afa158015610be2573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610c0691906123a8565b670de0b6b3a76400006116a7565b93505b83158015610c255750600283105b15610922576002925050505b935093915050565b610c41611383565b6001600160a01b0381165f9081526020819052604090205460ff1615610c7a57604051631f0d085960e11b815260040160405180910390fd5b6001600160a01b03165f908152602081905260409020805460ff19166001179055565b610ca5611383565b6001600160a01b0385165f9081526001602081905260409091209081015460021115610ce457604051631f0d085960e11b815260040160405180910390fd5b610cf28682878787876116d3565b505050505050565b5f610d036110b2565b905090565b335f9081526020819052604090205460ff16610d215750565b6001600160a01b0381165f90815260016020818152604080842090920180548351818402810184019094528084529091830182828015610d8857602002820191905f5260205f20905b81546001600160a01b03168152600190910190602001808311610d6a575b50508351939450505060018211159050610e1257336001600160a01b0316825f81518110610db857610db86122cf565b60200260200101516001600160a01b031614158015610e035750336001600160a01b031682600181518110610def57610def6122cf565b60200260200101516001600160a01b031614155b15610e0d57505050565b610e55565b805f03610e1e57505050565b336001600160a01b0316825f81518110610e3a57610e3a6122cf565b60200260200101516001600160a01b031614610e5557505050565b610e5f8333611428565b505050565b6001600160a01b0381165f90815260016020818152604092839020909101805483518184028101840190945280845260609392830182828015610ece57602002820191905f5260205f20905b81546001600160a01b03168152600190910190602001808311610eb0575b50505050509050919050565b610ee2611383565b610eec868661187d565b6001600160a01b0386165f9081526001602081905260409091208082015490911015610f2057610f208782878787876116d3565b50505050505050565b6001600160a01b038082165f908152600260205260408120549091168015610f6e576001600160a01b03165f9081526001602081905260409091200154151592915050565b50506001600160a01b03165f9081526001602081905260409091200154151590565b610f98611383565b610fa18161166c565b6001600160a01b03165f908152602081905260409020805460ff19169055565b610fc9611383565b846001600160a01b0316866001600160a01b031603610ffb57604051631f0d085960e11b815260040160405180910390fd5b6110058787611428565b61100f878661187d565b6001600160a01b0387165f9081526001602081905260409091208082015490911015611043576110438882878787876116d3565b5050505050505050565b611055611383565b6001600160a01b038181165f908152600260205260409020541661108c57604051631f0d085960e11b815260040160405180910390fd5b6001600160a01b03165f90815260026020526040902080546001600160a01b0319169055565b5f5f7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663b0ff43f56040518163ffffffff1660e01b8152600401602060405180830381865afa158015611110573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061113491906123da565b90506001600160a01b038116156111ee575f5f826001600160a01b031663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa158015611183573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906111a7919061240e565b50509250925050805f036111be575f935050505090565b5f6111c98242612470565b9050821515806111db575061012c8111155b156111ea575f94505050505090565b5050505b600191505090565b5f806001600160a01b03851661121f576040516337ccbfb560e01b815260040160405180910390fd5b6001600160a01b0385165f908152600160208181526040808420815160a081018352815461ffff80821683526201000082048116838701526401000000008204811683860152600160301b90910416606082015293810180548351818602810186019094528084529193608086019392908301828280156112c757602002820191905f5260205f20905b81546001600160a01b031681526001909101906020018083116112a9575b50505050508152505090505f8160800151519050805f036112fb576040516337ccbfb560e01b815260040160405180910390fd5b600181111561131a5761131087838888611b64565b9094509250610922565b5f6113448884608001515f81518110611335576113356122cf565b60200260200101518989611ca3565b9095509050801561135457600293505b505050935093915050565b5f825f19048411830215820261137c5763ad251c275f526004601cfd5b5091020490565b60405163de0c7a7160e01b81523360048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063de0c7a7190602401602060405180830381865afa1580156113e5573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061140991906123bf565b611426576040516317a1ac7960e01b815260040160405180910390fd5b565b6001600160a01b0382165f90815260016020819052604082200180549091819003611466576040516337ccbfb560e01b815260040160405180910390fd5b600181111561159957826001600160a01b0316825f8154811061148b5761148b6122cf565b5f918252602090912001546001600160a01b0316148015906114dc5750826001600160a01b0316826001815481106114c5576114c56122cf565b5f918252602090912001546001600160a01b031614155b156114fa576040516337ccbfb560e01b815260040160405180910390fd5b826001600160a01b0316825f81548110611516576115166122cf565b5f918252602090912001546001600160a01b0316036115945781600181548110611542576115426122cf565b5f91825260208220015483546001600160a01b03909116918491611568576115686122cf565b905f5260205f20015f6101000a8154816001600160a01b0302191690836001600160a01b031602179055505b6115e7565b826001600160a01b0316825f815481106115b5576115b56122cf565b5f918252602090912001546001600160a01b0316146115e7576040516337ccbfb560e01b815260040160405180910390fd5b818054806115f7576115f7612489565b5f8281526020902081015f1990810180546001600160a01b03191690550190556040517f125899ecb1260d173333573459b1a7a9cfb3817b130b413b4aa06a9ff31e4e809061165e90869086906001600160a01b0392831681529116602082015260400190565b60405180910390a150505050565b6001600160a01b0381165f9081526020819052604090205460ff166116a457604051633927310f60e11b815260040160405180910390fd5b50565b5f825f1904841183021582026116c45763ad251c275f526004601cfd5b50910281810615159190040190565b6116de60148461249d565b8410156116fe57604051631f0d085960e11b815260040160405180910390fd5b61170960148261249d565b82101561172957604051631f0d085960e11b815260040160405180910390fd5b6014831080611739575061015e84115b1561175757604051631f0d085960e11b815260040160405180910390fd5b6014811080611767575061015e82115b1561178557604051631f0d085960e11b815260040160405180910390fd5b6117916127108561249d565b855461ffff191661ffff919091161785556117ae6127108461249d565b855461ffff91909116620100000263ffff0000199091161785556117d46127108361249d565b855461ffff919091166401000000000265ffff00000000199091161785556117fe6127108261249d565b855461ffff91909116600160301b0267ffff00000000000019909116178555604080516001600160a01b03881681526020810186905290810184905260608101839052608081018290527ff9a7f594d37202867f28057760f73a7685c973a02d6ad8a27906d7a8331f13059060a00160405180910390a1505050505050565b6118868161166c565b604051634df48c7360e11b81526001600160a01b038381166004830152821690639be918e690602401602060405180830381865afa1580156118ca573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906118ee91906123bf565b61190b57604051631f0d085960e11b815260040160405180910390fd5b6001600160a01b0382165f90815260016020819052604090912081018054909181111561194b57604051631f0d085960e11b815260040160405180910390fd5b80158015906119875750826001600160a01b0316825f81548110611971576119716122cf565b5f918252602090912001546001600160a01b0316145b156119a557604051631f0d085960e11b815260040160405180910390fd5b604051635ae6916360e01b81526001600160a01b03858116600483015260016024830181905260448301525f9190851690635ae6916390606401606060405180830381865afa1580156119fa573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611a1e91906124b0565b80519091501580611a30575080604001515b15611a4e57604051631f0d085960e11b815260040160405180910390fd5b604051635ae6916360e01b81526001600160a01b038681166004830152600160248301525f6044830152851690635ae6916390606401606060405180830381865afa158015611a9f573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611ac391906124b0565b80519091501580611ad5575080604001515b15611af357604051631f0d085960e11b815260040160405180910390fd5b82546001810184555f84815260209081902090910180546001600160a01b0319166001600160a01b03878116918217909255604080519289168352928201527fd0fbbdc73d37c26b71504158457880a132e10105178f9286bbff8eea82a3f670910160405180910390a15050505050565b5f5f5f5f611b918888608001515f81518110611b8257611b826122cf565b60200260200101518888611ca3565b915091505f5f611bc18a8a60800151600181518110611bb257611bb26122cf565b60200260200101518a8a611ca3565b91509150828015611bcf5750805b15611be4575f60029550955050505050611c9a565b8280611bed5750805b15611c17578215611c075750935060019250611c9a915050565b8360019550955050505050611c9a565b5f88611c27578960400151611c2a565b89515b61ffff1690505f89611c40578a60600151611c46565b8a602001515b61ffff1690505f611c5987868585611dbc565b90508915611c8057868510611c6e5786611c70565b845b98509650611c9a95505050505050565b868511611c8d5786611c8f565b845b985096505050505050505b94509492505050565b5f5f611cae8561166c565b604051635ae6916360e01b81526001600160a01b038781166004830152851515602483015284151560448301525f9190871690635ae6916390606401606060405180830381865afa158015611d05573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611d2991906124b0565b9050806040015115611d42575f60019250925050611c9a565b8415158160200151151514611da7575f611d6786611d61578515611e4e565b85611e4e565b1580156040850152909150611d84575f6001935093505050611c9a565b611d97825f015182846020015188611e97565b8260400151935093505050611c9a565b80516040909101519097909650945050505050565b5f838511611e175783612710611dd28488612525565b611ddc919061253c565b1015611e105783612710611df08588612525565b611dfa919061253c565b1015611e0857506002611e46565b506001611e46565b505f611e46565b84612710611e258487612525565b611e2f919061253c565b1015611e435784612710611df08587612525565b505f5b949350505050565b5f5f5f611e7173eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee6001866111f6565b909350905082158015611e845750600281105b15611e8d575060025b9193911515925050565b5f82611ed0578115611ebd57611eb68585670de0b6b3a764000061135f565b9050611e46565b611eb68585670de0b6b3a76400006116a7565b8115611ee957611eb685670de0b6b3a76400008661135f565b611efc85670de0b6b3a7640000866116a7565b95945050505050565b6001600160a01b03811681146116a4575f5ffd5b5f5f5f5f60608587031215611f2c575f5ffd5b8435611f3781611f05565b9350602085013567ffffffffffffffff811115611f52575f5ffd5b8501601f81018713611f62575f5ffd5b803567ffffffffffffffff811115611f78575f5ffd5b8760208260051b8401011115611f8c575f5ffd5b949760209190910196509394604001359392505050565b5f8151808452602084019350602083015f5b82811015611fd3578151865260209586019590910190600101611fb5565b5093949350505050565b606080825284519082018190525f9060208601906080840190835b8181101561206057835180516001600160a01b0390811685526020808301519091168186015260408083015160ff16908601526060808301511515908601526080808301519086015260a091820151918501919091529093019260c090920191600101611ff8565b505083810360208501526120748187611fa3565b92505050826040830152949350505050565b5f5f60408385031215612097575f5ffd5b82356120a281611f05565b915060208301356120b281611f05565b809150509250929050565b5f5f5f606084860312156120cf575f5ffd5b83356120da81611f05565b925060208401356120ea81611f05565b929592945050506040919091013590565b5f6020828403121561210b575f5ffd5b813561211681611f05565b9392505050565b80151581146116a4575f5ffd5b5f5f5f6060848603121561213c575f5ffd5b833561214781611f05565b925060208401356121578161211d565b915060408401356121678161211d565b809150509250925092565b5f5f5f5f5f60a08688031215612186575f5ffd5b853561219181611f05565b97602087013597506040870135966060810135965060800135945092505050565b602080825282518282018190525f918401906040840190835b818110156121f25783516001600160a01b03168352602093840193909201916001016121cb565b509095945050505050565b5f5f5f5f5f5f60c08789031215612212575f5ffd5b863561221d81611f05565b9550602087013561222d81611f05565b95989597505050506040840135936060810135936080820135935060a0909101359150565b5f5f5f5f5f5f5f60e0888a031215612268575f5ffd5b873561227381611f05565b9650602088013561228381611f05565b9550604088013561229381611f05565b969995985095966060810135965060808101359560a0820135955060c0909101359350915050565b634e487b7160e01b5f52604160045260245ffd5b634e487b7160e01b5f52603260045260245ffd5b60405160c0810167ffffffffffffffff8111828210171561231257634e487b7160e01b5f52604160045260245ffd5b60405290565b80516123238161211d565b919050565b5f60c0828403128015612339575f5ffd5b506123426122e3565b825161234d81611f05565b8152602083015161235d81611f05565b6020820152604083015160ff81168114612375575f5ffd5b604082015261238660608401612318565b60608201526080838101519082015260a0928301519281019290925250919050565b5f602082840312156123b8575f5ffd5b5051919050565b5f602082840312156123cf575f5ffd5b81516121168161211d565b5f602082840312156123ea575f5ffd5b815161211681611f05565b805169ffffffffffffffffffff81168114612323575f5ffd5b5f5f5f5f5f60a08688031215612422575f5ffd5b61242b866123f5565b60208701516040880151606089015192975090955093509150612450608087016123f5565b90509295509295909350565b634e487b7160e01b5f52601160045260245ffd5b818103818111156124835761248361245c565b92915050565b634e487b7160e01b5f52603160045260245ffd5b808201808211156124835761248361245c565b5f60608284031280156124c1575f5ffd5b506040516060810167ffffffffffffffff811182821017156124f157634e487b7160e01b5f52604160045260245ffd5b6040528251815260208301516125068161211d565b602082015260408301516125198161211d565b60408201529392505050565b80820281158282048414176124835761248361245c565b5f8261255657634e487b7160e01b5f52601260045260245ffd5b50049056fea2646970667358221220290a04e776ce97ada5d767820102edf4b9dfa7dbece0ac19525ff6987afd934464736f6c634300081c00330000000000000000000000001310f352f1389969ece6741671c4b919523912ff
Deployed Bytecode
0x608060405234801561000f575f5ffd5b506004361061016c575f3560e01c806371e41254116100d95780639ae37a2811610093578063e04e7d701161006e578063e04e7d70146103ee578063e73af84614610401578063ed2f860314610414578063ff133d6d1461021e575f5ffd5b80639ae37a28146103b55780639be918e6146103c8578063ce16237c146103db575f5ffd5b806371e41254146103085780637f0ecd3c1461031b5780638c0b09d01461033d5780638d6fbb9e146103655780638f73dcfa146103855780639407d08f146103ac575f5ffd5b80632b12aaa91161012a5780632b12aaa91461023457806334abc11d146102475780635ae69163146102b7578063663158f5146102ca5780636b61db18146102dd5780637194ed42146102f0575f5ffd5b8062082f1414610170578063013ed4cd1461019b578063035e6c19146101b057806311b0b42d146101d85780631b4f30e51461020b5780631f42a45f1461021e575b5f5ffd5b61018361017e366004611f19565b61041d565b60405161019293929190611fdd565b60405180910390f35b6101ae6101a9366004612086565b61079a565b005b6101c36101be3660046120bd565b6107b0565b60408051928352602083019190915201610192565b6101f373eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee81565b6040516001600160a01b039091168152602001610192565b6101ae610219366004612086565b61092c565b610226601481565b604051908152602001610192565b6101ae6102423660046120fb565b6109b0565b6102896102553660046120fb565b60016020525f908152604090205461ffff808216916201000081048216916401000000008204811691600160301b90041684565b6040805161ffff95861681529385166020850152918416918301919091529091166060820152608001610192565b6101c36102c536600461212a565b610af6565b6101ae6102d83660046120fb565b610c39565b6101ae6102eb366004612172565b610c9d565b6102f8610cfa565b6040519015158152602001610192565b6101ae6103163660046120fb565b610d08565b6102f86103293660046120fb565b5f6020819052908152604090205460ff1681565b6101f361034b3660046120fb565b60026020525f90815260409020546001600160a01b031681565b6103786103733660046120fb565b610e64565b60405161019291906121b2565b6101f37f0000000000000000000000001310f352f1389969ece6741671c4b919523912ff81565b61022661015e81565b6101ae6103c33660046121fd565b610eda565b6102f86103d63660046120fb565b610f29565b6101ae6103e93660046120fb565b610f90565b6101ae6103fc366004612252565b610fc1565b6101ae61040f3660046120fb565b61104d565b61022661012c81565b6060805f6104296110b2565b61044657604051637c70f82f60e01b815260040160405180910390fd5b845f8167ffffffffffffffff811115610461576104616122bb565b6040519080825280602002602001820160405280156104bf57816020015b6040805160c0810182525f8082526020808301829052928201819052606082018190526080820181905260a082015282525f1990920191018161047f5790505b5090505f8267ffffffffffffffff8111156104dc576104dc6122bb565b604051908082528060200260200182016040528015610505578160200160208202803683370190505b5090505f5f5f5b85811015610787578b8b82818110610526576105266122cf565b905060200201602081019061053b91906120fb565b60405163cf6af22d60e01b81526001600160a01b038f811660048301529193509083169063cf6af22d9060240160c0604051808303815f875af1158015610584573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906105a89190612328565b8582815181106105ba576105ba6122cf565b60200260200101819052508481815181106105d7576105d76122cf565b602002602001015160600151156106e1576106118582815181106105fd576105fd6122cf565b6020026020010151602001516001806111f6565b858381518110610623576106236122cf565b602002602001018195508281525050506106be848281518110610648576106486122cf565b6020026020010151836001600160a01b0316633ba0b9a96040518163ffffffff1660e01b8152600401602060405180830381865afa15801561068c573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906106b091906123a8565b670de0b6b3a764000061135f565b8482815181106106d0576106d06122cf565b60200260200101818152505061072d565b61070a8582815181106106f6576106f66122cf565b60200260200101516020015160015f6111f6565b85838151811061071c5761071c6122cf565b602002602001018195508281525050505b83818151811061073f5761073f6122cf565b60200260200101515f1480156107555750600283105b1561075f57600292505b89831061077f57604051637c70f82f60e01b815260040160405180910390fd5b60010161050c565b50929b919a509298509650505050505050565b6107a2611383565b6107ac8282611428565b5050565b5f5f6107ba6110b2565b6107d757604051637c70f82f60e01b815260040160405180910390fd5b6001600160a01b038086165f9081526002602052604081205490911680610811576040516337ccbfb560e01b815260040160405180910390fd5b61081d816001806111f6565b809350819550505061086684886001600160a01b031663f41102916040518163ffffffff1660e01b81526004016020604051808303815f875af115801561068c573d5f5f3e3d5ffd5b9350831580156108765750600282105b1561088057600291505b8482106108a057604051637c70f82f60e01b815260040160405180910390fd5b506001600160a01b038086165f9081526002602052604090205416806108d9576040516337ccbfb560e01b815260040160405180910390fd5b6108e58160015f6111f6565b9093509150821580156108f85750600282105b1561090257600291505b84821061092257604051637c70f82f60e01b815260040160405180910390fd5b5050935093915050565b610934611383565b6001600160a01b0381165f9081526020819052604090205460ff161561096d57604051631f0d085960e11b815260040160405180910390fd5b6109768261166c565b6001600160a01b039182165f90815260208190526040808220805460ff199081169091559290931681529190912080549091166001179055565b6109b8611383565b806001600160a01b03166345d7b97a6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156109f4573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610a1891906123bf565b505f816001600160a01b03166338d52e0f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a56573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610a7a91906123da565b6001600160a01b038381165f9081526002602052604090205491925016151580610aab57506001600160a01b038116155b15610ac957604051631f0d085960e11b815260040160405180910390fd5b6001600160a01b039182165f90815260026020526040902080546001600160a01b03191691909216179055565b5f5f610b006110b2565b610b0f57505f90506002610c31565b6001600160a01b038086165f908152600260205260408120549091168015610b3657959050855b610b418787876111f6565b90945092506001600160a01b03821615610c17578415610ba257610b9b84836001600160a01b0316633ba0b9a96040518163ffffffff1660e01b8152600401602060405180830381865afa15801561068c573d5f5f3e3d5ffd5b9350610c17565b610c1484836001600160a01b0316633ba0b9a96040518163ffffffff1660e01b8152600401602060405180830381865afa158015610be2573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610c0691906123a8565b670de0b6b3a76400006116a7565b93505b83158015610c255750600283105b15610922576002925050505b935093915050565b610c41611383565b6001600160a01b0381165f9081526020819052604090205460ff1615610c7a57604051631f0d085960e11b815260040160405180910390fd5b6001600160a01b03165f908152602081905260409020805460ff19166001179055565b610ca5611383565b6001600160a01b0385165f9081526001602081905260409091209081015460021115610ce457604051631f0d085960e11b815260040160405180910390fd5b610cf28682878787876116d3565b505050505050565b5f610d036110b2565b905090565b335f9081526020819052604090205460ff16610d215750565b6001600160a01b0381165f90815260016020818152604080842090920180548351818402810184019094528084529091830182828015610d8857602002820191905f5260205f20905b81546001600160a01b03168152600190910190602001808311610d6a575b50508351939450505060018211159050610e1257336001600160a01b0316825f81518110610db857610db86122cf565b60200260200101516001600160a01b031614158015610e035750336001600160a01b031682600181518110610def57610def6122cf565b60200260200101516001600160a01b031614155b15610e0d57505050565b610e55565b805f03610e1e57505050565b336001600160a01b0316825f81518110610e3a57610e3a6122cf565b60200260200101516001600160a01b031614610e5557505050565b610e5f8333611428565b505050565b6001600160a01b0381165f90815260016020818152604092839020909101805483518184028101840190945280845260609392830182828015610ece57602002820191905f5260205f20905b81546001600160a01b03168152600190910190602001808311610eb0575b50505050509050919050565b610ee2611383565b610eec868661187d565b6001600160a01b0386165f9081526001602081905260409091208082015490911015610f2057610f208782878787876116d3565b50505050505050565b6001600160a01b038082165f908152600260205260408120549091168015610f6e576001600160a01b03165f9081526001602081905260409091200154151592915050565b50506001600160a01b03165f9081526001602081905260409091200154151590565b610f98611383565b610fa18161166c565b6001600160a01b03165f908152602081905260409020805460ff19169055565b610fc9611383565b846001600160a01b0316866001600160a01b031603610ffb57604051631f0d085960e11b815260040160405180910390fd5b6110058787611428565b61100f878661187d565b6001600160a01b0387165f9081526001602081905260409091208082015490911015611043576110438882878787876116d3565b5050505050505050565b611055611383565b6001600160a01b038181165f908152600260205260409020541661108c57604051631f0d085960e11b815260040160405180910390fd5b6001600160a01b03165f90815260026020526040902080546001600160a01b0319169055565b5f5f7f0000000000000000000000001310f352f1389969ece6741671c4b919523912ff6001600160a01b031663b0ff43f56040518163ffffffff1660e01b8152600401602060405180830381865afa158015611110573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061113491906123da565b90506001600160a01b038116156111ee575f5f826001600160a01b031663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa158015611183573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906111a7919061240e565b50509250925050805f036111be575f935050505090565b5f6111c98242612470565b9050821515806111db575061012c8111155b156111ea575f94505050505090565b5050505b600191505090565b5f806001600160a01b03851661121f576040516337ccbfb560e01b815260040160405180910390fd5b6001600160a01b0385165f908152600160208181526040808420815160a081018352815461ffff80821683526201000082048116838701526401000000008204811683860152600160301b90910416606082015293810180548351818602810186019094528084529193608086019392908301828280156112c757602002820191905f5260205f20905b81546001600160a01b031681526001909101906020018083116112a9575b50505050508152505090505f8160800151519050805f036112fb576040516337ccbfb560e01b815260040160405180910390fd5b600181111561131a5761131087838888611b64565b9094509250610922565b5f6113448884608001515f81518110611335576113356122cf565b60200260200101518989611ca3565b9095509050801561135457600293505b505050935093915050565b5f825f19048411830215820261137c5763ad251c275f526004601cfd5b5091020490565b60405163de0c7a7160e01b81523360048201527f0000000000000000000000001310f352f1389969ece6741671c4b919523912ff6001600160a01b03169063de0c7a7190602401602060405180830381865afa1580156113e5573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061140991906123bf565b611426576040516317a1ac7960e01b815260040160405180910390fd5b565b6001600160a01b0382165f90815260016020819052604082200180549091819003611466576040516337ccbfb560e01b815260040160405180910390fd5b600181111561159957826001600160a01b0316825f8154811061148b5761148b6122cf565b5f918252602090912001546001600160a01b0316148015906114dc5750826001600160a01b0316826001815481106114c5576114c56122cf565b5f918252602090912001546001600160a01b031614155b156114fa576040516337ccbfb560e01b815260040160405180910390fd5b826001600160a01b0316825f81548110611516576115166122cf565b5f918252602090912001546001600160a01b0316036115945781600181548110611542576115426122cf565b5f91825260208220015483546001600160a01b03909116918491611568576115686122cf565b905f5260205f20015f6101000a8154816001600160a01b0302191690836001600160a01b031602179055505b6115e7565b826001600160a01b0316825f815481106115b5576115b56122cf565b5f918252602090912001546001600160a01b0316146115e7576040516337ccbfb560e01b815260040160405180910390fd5b818054806115f7576115f7612489565b5f8281526020902081015f1990810180546001600160a01b03191690550190556040517f125899ecb1260d173333573459b1a7a9cfb3817b130b413b4aa06a9ff31e4e809061165e90869086906001600160a01b0392831681529116602082015260400190565b60405180910390a150505050565b6001600160a01b0381165f9081526020819052604090205460ff166116a457604051633927310f60e11b815260040160405180910390fd5b50565b5f825f1904841183021582026116c45763ad251c275f526004601cfd5b50910281810615159190040190565b6116de60148461249d565b8410156116fe57604051631f0d085960e11b815260040160405180910390fd5b61170960148261249d565b82101561172957604051631f0d085960e11b815260040160405180910390fd5b6014831080611739575061015e84115b1561175757604051631f0d085960e11b815260040160405180910390fd5b6014811080611767575061015e82115b1561178557604051631f0d085960e11b815260040160405180910390fd5b6117916127108561249d565b855461ffff191661ffff919091161785556117ae6127108461249d565b855461ffff91909116620100000263ffff0000199091161785556117d46127108361249d565b855461ffff919091166401000000000265ffff00000000199091161785556117fe6127108261249d565b855461ffff91909116600160301b0267ffff00000000000019909116178555604080516001600160a01b03881681526020810186905290810184905260608101839052608081018290527ff9a7f594d37202867f28057760f73a7685c973a02d6ad8a27906d7a8331f13059060a00160405180910390a1505050505050565b6118868161166c565b604051634df48c7360e11b81526001600160a01b038381166004830152821690639be918e690602401602060405180830381865afa1580156118ca573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906118ee91906123bf565b61190b57604051631f0d085960e11b815260040160405180910390fd5b6001600160a01b0382165f90815260016020819052604090912081018054909181111561194b57604051631f0d085960e11b815260040160405180910390fd5b80158015906119875750826001600160a01b0316825f81548110611971576119716122cf565b5f918252602090912001546001600160a01b0316145b156119a557604051631f0d085960e11b815260040160405180910390fd5b604051635ae6916360e01b81526001600160a01b03858116600483015260016024830181905260448301525f9190851690635ae6916390606401606060405180830381865afa1580156119fa573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611a1e91906124b0565b80519091501580611a30575080604001515b15611a4e57604051631f0d085960e11b815260040160405180910390fd5b604051635ae6916360e01b81526001600160a01b038681166004830152600160248301525f6044830152851690635ae6916390606401606060405180830381865afa158015611a9f573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611ac391906124b0565b80519091501580611ad5575080604001515b15611af357604051631f0d085960e11b815260040160405180910390fd5b82546001810184555f84815260209081902090910180546001600160a01b0319166001600160a01b03878116918217909255604080519289168352928201527fd0fbbdc73d37c26b71504158457880a132e10105178f9286bbff8eea82a3f670910160405180910390a15050505050565b5f5f5f5f611b918888608001515f81518110611b8257611b826122cf565b60200260200101518888611ca3565b915091505f5f611bc18a8a60800151600181518110611bb257611bb26122cf565b60200260200101518a8a611ca3565b91509150828015611bcf5750805b15611be4575f60029550955050505050611c9a565b8280611bed5750805b15611c17578215611c075750935060019250611c9a915050565b8360019550955050505050611c9a565b5f88611c27578960400151611c2a565b89515b61ffff1690505f89611c40578a60600151611c46565b8a602001515b61ffff1690505f611c5987868585611dbc565b90508915611c8057868510611c6e5786611c70565b845b98509650611c9a95505050505050565b868511611c8d5786611c8f565b845b985096505050505050505b94509492505050565b5f5f611cae8561166c565b604051635ae6916360e01b81526001600160a01b038781166004830152851515602483015284151560448301525f9190871690635ae6916390606401606060405180830381865afa158015611d05573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611d2991906124b0565b9050806040015115611d42575f60019250925050611c9a565b8415158160200151151514611da7575f611d6786611d61578515611e4e565b85611e4e565b1580156040850152909150611d84575f6001935093505050611c9a565b611d97825f015182846020015188611e97565b8260400151935093505050611c9a565b80516040909101519097909650945050505050565b5f838511611e175783612710611dd28488612525565b611ddc919061253c565b1015611e105783612710611df08588612525565b611dfa919061253c565b1015611e0857506002611e46565b506001611e46565b505f611e46565b84612710611e258487612525565b611e2f919061253c565b1015611e435784612710611df08587612525565b505f5b949350505050565b5f5f5f611e7173eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee6001866111f6565b909350905082158015611e845750600281105b15611e8d575060025b9193911515925050565b5f82611ed0578115611ebd57611eb68585670de0b6b3a764000061135f565b9050611e46565b611eb68585670de0b6b3a76400006116a7565b8115611ee957611eb685670de0b6b3a76400008661135f565b611efc85670de0b6b3a7640000866116a7565b95945050505050565b6001600160a01b03811681146116a4575f5ffd5b5f5f5f5f60608587031215611f2c575f5ffd5b8435611f3781611f05565b9350602085013567ffffffffffffffff811115611f52575f5ffd5b8501601f81018713611f62575f5ffd5b803567ffffffffffffffff811115611f78575f5ffd5b8760208260051b8401011115611f8c575f5ffd5b949760209190910196509394604001359392505050565b5f8151808452602084019350602083015f5b82811015611fd3578151865260209586019590910190600101611fb5565b5093949350505050565b606080825284519082018190525f9060208601906080840190835b8181101561206057835180516001600160a01b0390811685526020808301519091168186015260408083015160ff16908601526060808301511515908601526080808301519086015260a091820151918501919091529093019260c090920191600101611ff8565b505083810360208501526120748187611fa3565b92505050826040830152949350505050565b5f5f60408385031215612097575f5ffd5b82356120a281611f05565b915060208301356120b281611f05565b809150509250929050565b5f5f5f606084860312156120cf575f5ffd5b83356120da81611f05565b925060208401356120ea81611f05565b929592945050506040919091013590565b5f6020828403121561210b575f5ffd5b813561211681611f05565b9392505050565b80151581146116a4575f5ffd5b5f5f5f6060848603121561213c575f5ffd5b833561214781611f05565b925060208401356121578161211d565b915060408401356121678161211d565b809150509250925092565b5f5f5f5f5f60a08688031215612186575f5ffd5b853561219181611f05565b97602087013597506040870135966060810135965060800135945092505050565b602080825282518282018190525f918401906040840190835b818110156121f25783516001600160a01b03168352602093840193909201916001016121cb565b509095945050505050565b5f5f5f5f5f5f60c08789031215612212575f5ffd5b863561221d81611f05565b9550602087013561222d81611f05565b95989597505050506040840135936060810135936080820135935060a0909101359150565b5f5f5f5f5f5f5f60e0888a031215612268575f5ffd5b873561227381611f05565b9650602088013561228381611f05565b9550604088013561229381611f05565b969995985095966060810135965060808101359560a0820135955060c0909101359350915050565b634e487b7160e01b5f52604160045260245ffd5b634e487b7160e01b5f52603260045260245ffd5b60405160c0810167ffffffffffffffff8111828210171561231257634e487b7160e01b5f52604160045260245ffd5b60405290565b80516123238161211d565b919050565b5f60c0828403128015612339575f5ffd5b506123426122e3565b825161234d81611f05565b8152602083015161235d81611f05565b6020820152604083015160ff81168114612375575f5ffd5b604082015261238660608401612318565b60608201526080838101519082015260a0928301519281019290925250919050565b5f602082840312156123b8575f5ffd5b5051919050565b5f602082840312156123cf575f5ffd5b81516121168161211d565b5f602082840312156123ea575f5ffd5b815161211681611f05565b805169ffffffffffffffffffff81168114612323575f5ffd5b5f5f5f5f5f60a08688031215612422575f5ffd5b61242b866123f5565b60208701516040880151606089015192975090955093509150612450608087016123f5565b90509295509295909350565b634e487b7160e01b5f52601160045260245ffd5b818103818111156124835761248361245c565b92915050565b634e487b7160e01b5f52603160045260245ffd5b808201808211156124835761248361245c565b5f60608284031280156124c1575f5ffd5b506040516060810167ffffffffffffffff811182821017156124f157634e487b7160e01b5f52604160045260245ffd5b6040528251815260208301516125068161211d565b602082015260408301516125198161211d565b60408201529392505050565b80820281158282048414176124835761248361245c565b5f8261255657634e487b7160e01b5f52601260045260245ffd5b50049056fea2646970667358221220290a04e776ce97ada5d767820102edf4b9dfa7dbece0ac19525ff6987afd934464736f6c634300081c0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000001310f352f1389969ece6741671c4b919523912ff
-----Decoded View---------------
Arg [0] : cr (address): 0x1310f352f1389969Ece6741671c4B919523912fF
-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 0000000000000000000000001310f352f1389969ece6741671c4b919523912ff
Deployed Bytecode Sourcemap
133728:49770:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;160065:2231;;;;;;:::i;:::-;;:::i;:::-;;;;;;;;;:::i;:::-;;;;;;;;145333:175;;;;;;:::i;:::-;;:::i;:::-;;157444:1831;;;;;;:::i;:::-;;:::i;:::-;;;;3851:25:1;;;3907:2;3892:18;;3885:34;;;;3824:18;157444:1831:0;3677:248:1;136309:84:0;;136351:42;136309:84;;;;;-1:-1:-1;;;;;4094:32:1;;;4076:51;;4064:2;4049:18;136309:84:0;3930:203:1;149615:556:0;;;;;;:::i;:::-;;:::i;137212:60::-;;137270:2;137212:60;;;;;4284:25:1;;;4272:2;4257:18;137212:60:0;4138:177:1;147976:680:0;;;;;;:::i;:::-;;:::i;137754:59::-;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;137754:59:0;;;;;;;;;4825:6:1;4813:19;;;4795:38;;4869:19;;;4864:2;4849:18;;4842:47;4925:19;;;4905:18;;;4898:47;;;;4981:19;;;4976:2;4961:18;;4954:47;4782:3;4767:19;137754:59:0;4572:435:1;155421:1388:0;;;;;;:::i;:::-;;:::i;150370:334::-;;;;;;:::i;:::-;;:::i;152426:730::-;;;;;;:::i;:::-;;:::i;154027:102::-;;;:::i;:::-;;;6556:14:1;;6549:22;6531:41;;6519:2;6504:18;154027:102:0;6391:187:1;146520:786:0;;;;;;:::i;:::-;;:::i;137574:49::-;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;137880:42;;;;;;:::i;:::-;;;;;;;;;;;;-1:-1:-1;;;;;137880:42:0;;;147527:168;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;137316:49::-;;;;;136726;;136772:3;136726:49;;140566:882;;;;;;:::i;:::-;;:::i;153471:331::-;;;;;;:::i;:::-;;:::i;150912:279::-;;;;;;:::i;:::-;;:::i;143347:1233::-;;;;;;:::i;:::-;;:::i;148919:347::-;;;;;;:::i;:::-;;:::i;136514:47::-;;136558:3;136514:47;;160065:2231;160228:24;160263:16;160290:7;160321:19;:17;:19::i;:::-;160316:93;;160364:33;;-1:-1:-1;;;160364:33:0;;;;;;;;;;;160316:93;160441:6;160421:17;160441:6;160502:32;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;160502:32:0;;-1:-1:-1;;160502:32:0;;;;;;;;;;;;160465:69;;160545:23;160585:9;160571:24;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;160571:24:0;;160545:50;;160606:17;160636:13;160665:9;160660:1579;160680:9;160676:1;:13;160660:1579;;;160719:6;;160726:1;160719:9;;;;;;;:::i;:::-;;;;;;;;;;;;;;:::i;:::-;160758:42;;-1:-1:-1;;;160758:42:0;;-1:-1:-1;;;;;4094:32:1;;;160758:42:0;;;4076:51:1;160711:17:0;;-1:-1:-1;160758:33:0;;;;;;4049:18:1;;160758:42:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;160743:9;160753:1;160743:12;;;;;;;;:::i;:::-;;;;;;:57;;;;160821:9;160831:1;160821:12;;;;;;;;:::i;:::-;;;;;;;:25;;;160817:1044;;;161058:128;161090:9;161100:1;161090:12;;;;;;;;:::i;:::-;;;;;;;:23;;;161136:4;161163;161058:9;:128::i;:::-;161034:6;161041:1;161034:9;;;;;;;;:::i;:::-;;;;;;161033:153;;;;;;;;;161353;161400:6;161407:1;161400:9;;;;;;;;:::i;:::-;;;;;;;161440:5;-1:-1:-1;;;;;161432:27:0;;:29;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;636:4;161353:24;:153::i;:::-;161341:6;161348:1;161341:9;;;;;;;;:::i;:::-;;;;;;:165;;;;;160817:1044;;;161716:129;161748:9;161758:1;161748:12;;;;;;;;:::i;:::-;;;;;;;:23;;;161794:4;161821:5;161716:9;:129::i;:::-;161692:6;161699:1;161692:9;;;;;;;;:::i;:::-;;;;;;161691:154;;;;;;;;;160817:1044;162000:6;162007:1;162000:9;;;;;;;;:::i;:::-;;;;;;;162013:1;162000:14;:40;;;;;843:1;162018:9;:22;162000:40;161996:103;;;843:1;162061:22;;161996:103;162132:19;162119:9;:32;162115:113;;162179:33;;-1:-1:-1;;;162179:33:0;;;;;;;;;;;162115:113;160691:3;;160660:1579;;;-1:-1:-1;162259:9:0;;162270:6;;-1:-1:-1;162278:9:0;;-1:-1:-1;160065:2231:0;-1:-1:-1;;;;;;;160065:2231:0:o;145333:175::-;145420:27;:25;:27::i;:::-;145458:42;145485:5;145492:7;145458:26;:42::i;:::-;145333:175;;:::o;157444:1831::-;157609:29;157649:27;157700:19;:17;:19::i;:::-;157695:93;;157743:33;;-1:-1:-1;;;157743:33:0;;;;;;;;;;;157695:93;-1:-1:-1;;;;;157849:24:0;;;157800:17;157849:24;;;:7;:24;;;;;;157800:17;;157849:24;;157884:93;;157936:29;;-1:-1:-1;;;157936:29:0;;;;;;;;;;;157884:93;158026:83;158050:10;158075:4;158094;158026:9;:83::i;:::-;157989:120;;;;;;;;158146:150;158185:21;158229:15;-1:-1:-1;;;;;158221:44:0;;:46;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;158146:150;158122:174;-1:-1:-1;158424:26:0;;:52;;;;;843:1;158454:9;:22;158424:52;158420:107;;;843:1;158493:22;;158420:107;158556:19;158543:9;:32;158539:105;;158599:33;;-1:-1:-1;;;158599:33:0;;;;;;;;;;;158539:105;-1:-1:-1;;;;;;158669:18:0;;;;;;;:7;:18;;;;;;;;158698:93;;158750:29;;-1:-1:-1;;;158750:29:0;;;;;;;;;;;158698:93;158838:84;158862:10;158887:4;158906:5;158838:9;:84::i;:::-;158803:119;;-1:-1:-1;158803:119:0;-1:-1:-1;159050:24:0;;:50;;;;;843:1;159078:9;:22;159050:50;159046:105;;;843:1;159117:22;;159046:105;159180:19;159167:9;:32;159163:105;;159223:33;;-1:-1:-1;;;159223:33:0;;;;;;;;;;;159163:105;157684:1591;;157444:1831;;;;;;:::o;149615:556::-;149739:27;:25;:27::i;:::-;-1:-1:-1;;;;;149845:31:0;;:17;:31;;;;;;;;;;;;;149841:104;;;149900:33;;-1:-1:-1;;;149900:33:0;;;;;;;;;;;149841:104;150020:40;150044:15;150020:23;:40::i;:::-;-1:-1:-1;;;;;150080:34:0;;;:17;:34;;;;;;;;;;;150073:41;;-1:-1:-1;;150073:41:0;;;;;;150125:31;;;;;;;;;;:38;;;;;150073:41;150125:38;;;149615:556::o;147976:680::-;148041:27;:25;:27::i;:::-;148163:9;-1:-1:-1;;;;;148155:31:0;;:33;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;148406:21;148438:9;-1:-1:-1;;;;;148430:24:0;;:26;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;148471:18:0;;;148501:1;148471:18;;;:7;:18;;;;;;148406:50;;-1:-1:-1;148471:18:0;:32;;;:63;;-1:-1:-1;;;;;;148507:27:0;;;148471:63;148467:136;;;148558:33;;-1:-1:-1;;;148558:33:0;;;;;;;;;;;148467:136;-1:-1:-1;;;;;148615:18:0;;;;;;;:7;:18;;;;;:33;;-1:-1:-1;;;;;;148615:33:0;;;;;;;;147976:680::o;155421:1388::-;155536:13;155551:17;155586:19;:17;:19::i;:::-;155581:75;;-1:-1:-1;155630:1:0;;-1:-1:-1;843:1:0;155622:22;;155581:75;-1:-1:-1;;;;;155720:14:0;;;155668;155720;;;:7;:14;;;;;;155668;;155720;155802:30;;155798:116;;155886:16;155858:5;-1:-1:-1;155886:16:0;155798:116;155947:33;155957:5;155964;155971:8;155947:9;:33::i;:::-;155926:54;;-1:-1:-1;155926:54:0;-1:-1:-1;;;;;;156132:20:0;;;156128:460;;156173:8;156169:408;;;156210:150;156257:5;156293:6;-1:-1:-1;;;;;156285:28:0;;:30;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;156210:150;156202:158;;156169:408;;;156409:152;156458:5;156494:6;-1:-1:-1;;;;;156486:28:0;;:30;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;636:4;156409:26;:152::i;:::-;156401:160;;156169:408;156715:10;;:36;;;;;843:1;156729:9;:22;156715:36;156711:91;;;843:1;156768:22;;155570:1239;;155421:1388;;;;;;;:::o;150370:334::-;150440:27;:25;:27::i;:::-;-1:-1:-1;;;;;150546:31:0;;:17;:31;;;;;;;;;;;;;150542:104;;;150601:33;;-1:-1:-1;;;150601:33:0;;;;;;;;;;;150542:104;-1:-1:-1;;;;;150658:31:0;:17;:31;;;;;;;;;;:38;;-1:-1:-1;;150658:38:0;150692:4;150658:38;;;150370:334::o;152426:730::-;152651:27;:25;:27::i;:::-;-1:-1:-1;;;;;152720:25:0;;152689:28;152720:25;;;:18;:25;;;;;;;;152840:15;;;:22;152865:1;-1:-1:-1;152836:99:0;;;152890:33;;-1:-1:-1;;;152890:33:0;;;;;;;;;;;152836:99;152947:201;152981:5;153001:6;153022:17;153054:15;153084:20;153119:18;152947:19;:201::i;:::-;152640:516;152426:730;;;;;:::o;154027:102::-;154078:4;154102:19;:17;:19::i;:::-;154095:26;;154027:102;:::o;146520:786::-;146605:10;146587:17;:29;;;;;;;;;;;;;146582:69;;146520:786;:::o;146582:69::-;-1:-1:-1;;;;;146691:25:0;;146663;146691;;;:18;:25;;;;;;;;:34;;;146663:62;;;;;;;;;;;;;;;;;146691:34;;146663:62;;146691:34;146663:62;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;146663:62:0;;;;;;;;;;;;;;;;-1:-1:-1;;146758:15:0;;146663:62;;-1:-1:-1;;;146930:1:0;146916:15;;146912:331;;-1:-1:-1;146912:331:0;;146967:10;-1:-1:-1;;;;;146952:25:0;:8;146961:1;146952:11;;;;;;;;:::i;:::-;;;;;;;-1:-1:-1;;;;;146952:25:0;;;:54;;;;;146996:10;-1:-1:-1;;;;;146981:25:0;:8;146990:1;146981:11;;;;;;;;:::i;:::-;;;;;;;-1:-1:-1;;;;;146981:25:0;;;146952:54;146948:101;;;147027:7;;146520:786;:::o;146948:101::-;146912:331;;;147085:11;147100:1;147085:16;147081:63;;147122:7;;146520:786;:::o;147081:63::-;147179:10;-1:-1:-1;;;;;147164:25:0;:8;147173:1;147164:11;;;;;;;;:::i;:::-;;;;;;;-1:-1:-1;;;;;147164:25:0;;147160:72;;147210:7;;146520:786;:::o;147160:72::-;147253:45;147280:5;147287:10;147253:26;:45::i;:::-;146571:735;;146520:786;:::o;147527:168::-;-1:-1:-1;;;;;147653:25:0;;;;;;:18;:25;;;;;;;;;:34;;;147644:43;;;;;;;;;;;;;;;;;147608:23;;147644:43;;;147653:34;147644:43;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;147644:43:0;;;;;;;;;;;;;;;;;;;;;;;147527:168;;;:::o;140566:882::-;140821:27;:25;:27::i;:::-;140859:39;140883:5;140890:7;140859:23;:39::i;:::-;-1:-1:-1;;;;;141037:25:0;;141006:28;141037:25;;;:18;:25;;;;;;;;141157:15;;;:22;141037:25;;-1:-1:-1;141153:288:0;;;141200:229;141238:5;141262:6;141287:17;141323:15;141357:20;141396:18;141200:19;:229::i;:::-;140810:638;140566:882;;;;;;:::o;153471:331::-;-1:-1:-1;;;;;153579:14:0;;;153535:4;153579:14;;;:7;:14;;;;;;153535:4;;153579:14;153608:30;;153604:126;;-1:-1:-1;;;;;153662:36:0;153717:1;153662:36;;;:18;:36;;;;;;;;:45;:52;:56;;;153471:331;-1:-1:-1;;153471:331:0:o;153604:126::-;-1:-1:-1;;;;;;;153749:25:0;153793:1;153749:25;;;:18;:25;;;;;;;;:34;:41;:45;;;153471:331::o;150912:279::-;150988:27;:25;:27::i;:::-;151089:40;151113:15;151089:23;:40::i;:::-;-1:-1:-1;;;;;151149:34:0;:17;:34;;;;;;;;;;151142:41;;-1:-1:-1;;151142:41:0;;;150912:279::o;143347:1233::-;143645:27;:25;:27::i;:::-;143832:12;-1:-1:-1;;;;;143813:31:0;:15;-1:-1:-1;;;;;143813:31:0;;143809:104;;143868:33;;-1:-1:-1;;;143868:33:0;;;;;;;;;;;143809:104;143925:50;143952:5;143959:15;143925:26;:50::i;:::-;143986:44;144010:5;144017:12;143986:23;:44::i;:::-;-1:-1:-1;;;;;144169:25:0;;144138:28;144169:25;;;:18;:25;;;;;;;;144289:15;;;:22;144169:25;;-1:-1:-1;144285:288:0;;;144332:229;144370:5;144394:6;144419:17;144455:15;144489:20;144528:18;144332:19;:229::i;:::-;143634:946;143347:1233;;;;;;;:::o;148919:347::-;148992:27;:25;:27::i;:::-;-1:-1:-1;;;;;149110:23:0;;;149145:1;149110:23;;;:7;:23;;;;;;;149106:110;;149171:33;;-1:-1:-1;;;149171:33:0;;;;;;;;;;;149106:110;-1:-1:-1;;;;;149235:23:0;;;;;:7;:23;;;;;149228:30;;-1:-1:-1;;;;;;149228:30:0;;;148919:347::o;174642:787::-;174694:4;174711:27;174741:15;-1:-1:-1;;;;;174741:32:0;;:34;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;174711:64;-1:-1:-1;;;;;;174792:33:0;;;174788:610;;174845:13;174860:17;174913:19;-1:-1:-1;;;;;174902:47:0;;:49;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;174842:109;;;;;;;175144:9;175157:1;175144:14;175140:67;;175186:5;175179:12;;;;;174642:787;:::o;175140:67::-;175223:19;175245:27;175263:9;175245:15;:27;:::i;:::-;175223:49;-1:-1:-1;175291:11:0;;;;:47;;;136558:3;175306:11;:32;;175291:47;175287:100;;;175366:5;175359:12;;;;;;174642:787;:::o;175287:100::-;174827:571;;;174788:610;175417:4;175410:11;;;174642:787;:::o;163396:948::-;163514:13;;-1:-1:-1;;;;;163563:19:0;;163559:88;;163606:29;;-1:-1:-1;;;163606:29:0;;;;;;;;;;;163559:88;-1:-1:-1;;;;;163689:25:0;;163659:27;163689:25;;;:18;:25;;;;;;;;163659:55;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;163659:55:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;163689:25;;163659:55;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;163659:55:0;;;;;;;;;;;;;;;;;;;;;;;;;;;163725:19;163747:6;:15;;;:22;163725:44;;163784:11;163799:1;163784:16;163780:85;;163824:29;;-1:-1:-1;;;163824:29:0;;;;;;;;;;;163780:85;163970:1;163956:11;:15;163952:385;;;164026:52;164047:5;164054:6;164062:5;164069:8;164026:20;:52::i;:::-;163988:90;;-1:-1:-1;163988:90:0;-1:-1:-1;163952:385:0;;;164111:13;164176:64;164197:5;164204:6;:15;;;164220:1;164204:18;;;;;;;;:::i;:::-;;;;;;;164224:5;164231:8;164176:20;:64::i;:::-;164139:101;;-1:-1:-1;164139:101:0;-1:-1:-1;164255:71:0;;;;843:1;164288:22;;164255:71;164096:241;163548:796;;163396:948;;;;;;:::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;183306:189::-;183373:50;;-1:-1:-1;;;183373:50:0;;183412:10;183373:50;;;4076:51:1;183373:15:0;-1:-1:-1;;;;;183373:38:0;;;;4049:18:1;;183373:50:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;183368:120;;183447:29;;-1:-1:-1;;;183447:29:0;;;;;;;;;;;183368:120;183306:189::o;167642:1402::-;-1:-1:-1;;;;;167932:25:0;;167903:26;167932:25;;;:18;:25;;;;;;;:34;167999:15;;167932:34;;168029:16;;;168025:85;;168069:29;;-1:-1:-1;;;168069:29:0;;;;;;;;;;;168025:85;168140:1;168126:11;:15;168122:652;;;168280:7;-1:-1:-1;;;;;168265:22:0;:8;168274:1;168265:11;;;;;;;;:::i;:::-;;;;;;;;;;;-1:-1:-1;;;;;168265:11:0;:22;;;;:48;;;168306:7;-1:-1:-1;;;;;168291:22:0;:8;168300:1;168291:11;;;;;;;;:::i;:::-;;;;;;;;;;;-1:-1:-1;;;;;168291:11:0;:22;;168265:48;168261:125;;;168341:29;;-1:-1:-1;;;168341:29:0;;;;;;;;;;;168261:125;168563:7;-1:-1:-1;;;;;168548:22:0;:8;168557:1;168548:11;;;;;;;;:::i;:::-;;;;;;;;;;;-1:-1:-1;;;;;168548:11:0;:22;168544:88;;168605:8;168614:1;168605:11;;;;;;;;:::i;:::-;;;;;;;;;;168591;;-1:-1:-1;;;;;168605:11:0;;;;168591:8;;:11;;;;:::i;:::-;;;;;;;;;:25;;;;;-1:-1:-1;;;;;168591:25:0;;;;;-1:-1:-1;;;;;168591:25:0;;;;;;168544:88;168122:652;;;168683:7;-1:-1:-1;;;;;168668:22:0;:8;168677:1;168668:11;;;;;;;;:::i;:::-;;;;;;;;;;;-1:-1:-1;;;;;168668:11:0;:22;168664:99;;168718:29;;-1:-1:-1;;;168718:29:0;;;;;;;;;;;168664:99;168966:8;:14;;;;;;;:::i;:::-;;;;;;;;;;-1:-1:-1;;168966:14:0;;;;;-1:-1:-1;;;;;;168966:14:0;;;;;;168996:40;;;;;;169021:5;;169028:7;;-1:-1:-1;;;;;13183:32:1;;;13165:51;;13252:32;;13247:2;13232:18;;13225:60;13153:2;13138:18;;12991:300;168996:40:0;;;;;;;;167744:1300;;167642:1402;;:::o;183042:186::-;-1:-1:-1;;;;;183122:26:0;;:17;:26;;;;;;;;;;;;;183117:104;;183172:37;;-1:-1:-1;;;183172:37:0;;;;;;;;;;;183117:104;183042:186;:::o;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;178332:1927::-;178756:49;137270:2;178756:15;:49;:::i;:::-;178736:17;:69;178732:142;;;178829:33;;-1:-1:-1;;;178829:33:0;;;;;;;;;;;178732:142;179051:52;137270:2;179051:18;:52;:::i;:::-;179028:20;:75;179024:148;;;179127:33;;-1:-1:-1;;;179127:33:0;;;;;;;;;;;179024:148;136965:2;179275:15;:37;:93;;;;136772:3;179329:17;:39;179275:93;179257:190;;;179402:33;;-1:-1:-1;;;179402:33:0;;;;;;;;;;;179257:190;136965:2;179553:18;:40;:99;;;;136772:3;179610:20;:42;179553:99;179535:196;;;179686:33;;-1:-1:-1;;;179686:33:0;;;;;;;;;;;179535:196;179890:23;745:3;179890:17;:23;:::i;:::-;179856:58;;-1:-1:-1;;179856:58:0;;;;;;;;;179957:21;745:3;179957:15;:21;:::i;:::-;179925:54;;;;;;;;;-1:-1:-1;;179925:54:0;;;;;;180027:26;745:3;180027:20;:26;:::i;:::-;179990:64;;;;;;;;;-1:-1:-1;;179990:64:0;;;;;;180100:24;745:3;180100:18;:24;:::i;:::-;180065:60;;;;;;;-1:-1:-1;;;180065:60:0;-1:-1:-1;;180065:60:0;;;;;;180143:108;;;-1:-1:-1;;;;;13703:32:1;;13685:51;;13767:2;13752:18;;13745:34;;;13795:18;;;13788:34;;;13853:2;13838:18;;13831:34;;;13896:3;13881:19;;13874:35;;;180143:108:0;;13672:3:1;13657:19;180143:108:0;;;;;;;178332:1927;;;;;;:::o;164952:1937::-;165104:32;165128:7;165104:23;:32::i;:::-;165218:47;;-1:-1:-1;;;165218:47:0;;-1:-1:-1;;;;;4094:32:1;;;165218:47:0;;;4076:51:1;165218:40:0;;;;;4049:18:1;;165218:47:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;165213:121;;165289:33;;-1:-1:-1;;;165289:33:0;;;;;;;;;;;165213:121;-1:-1:-1;;;;;165375:25:0;;165346:26;165375:25;;;:18;:25;;;;;;;;:34;;165442:15;;165375:34;;165578:15;;165574:88;;;165617:33;;-1:-1:-1;;;165617:33:0;;;;;;;;;;;165574:88;165964:16;;;;;:42;;;165999:7;-1:-1:-1;;;;;165984:22:0;:8;165993:1;165984:11;;;;;;;;:::i;:::-;;;;;;;;;;;-1:-1:-1;;;;;165984:11:0;:22;165964:42;165960:115;;;166030:33;;-1:-1:-1;;;166030:33:0;;;;;;;;;;;165960:115;166271:65;;-1:-1:-1;;;166271:65:0;;-1:-1:-1;;;;;14128:32:1;;;166271:65:0;;;14110:51:1;166325:4:0;14177:18:1;;;14170:50;;;14236:18;;;14229:50;166226:42:0;;166271:46;;;;;;14083:18:1;;166271:65:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;166353:12;;166226:110;;-1:-1:-1;166353:17:0;;:36;;;166374:6;:15;;;166353:36;166349:109;;;166413:33;;-1:-1:-1;;;166413:33:0;;;;;;;;;;;166349:109;166619:52;;-1:-1:-1;;;166619:52:0;;-1:-1:-1;;;;;14128:32:1;;;166619:52:0;;;14110:51:1;166659:4:0;14177:18:1;;;14170:50;166665:5:0;14236:18:1;;;14229:50;166619:32:0;;;;;14083:18:1;;166619:52:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;166688:12;;166610:61;;-1:-1:-1;166688:17:0;;:36;;;166709:6;:15;;;166688:36;166684:109;;;166748:33;;-1:-1:-1;;;166748:33:0;;;;;;;;;;;166684:109;166805:22;;;;;;;-1:-1:-1;166805:22:0;;;;;;;;;;;;;-1:-1:-1;;;;;;166805:22:0;-1:-1:-1;;;;;166805:22:0;;;;;;;;;166843:38;;;13183:32:1;;;13165:51;;13232:18;;;13225:60;166843:38:0;;13138:18:1;166843:38:0;;;;;;;165026:1863;;;164952:1937;;:::o;169946:1643::-;170113:7;170122;170143:14;170159:11;170174:88;170209:5;170216:6;:15;;;170232:1;170216:18;;;;;;;;:::i;:::-;;;;;;;170236:5;170243:8;170174:20;:88::i;:::-;170142:120;;;;170274:14;170290:11;170304:88;170339:5;170346:6;:15;;;170362:1;170346:18;;;;;;;;:::i;:::-;;;;;;;170366:5;170373:8;170304:20;:88::i;:::-;170273:119;;;;170521:6;:16;;;;;170531:6;170521:16;170517:70;;;170561:1;843;170553:22;;;;;;;;;;170517:70;170706:6;:16;;;;170716:6;170706:16;170702:388;;;170971:6;170967:71;;;-1:-1:-1;171006:6:0;-1:-1:-1;952:1:0;;-1:-1:-1;170998:24:0;;-1:-1:-1;;170998:24:0;170967:71;171062:6;952:1;171054:24;;;;;;;;;;170702:388;171102:22;171127:5;:75;;171175:6;:27;;;171127:75;;;171148:24;;171127:75;171102:100;;;;171213:20;171236:5;:71;;171282:6;:25;;;171236:71;;;171257:6;:22;;;171236:71;171213:94;;;;171320:17;171353:58;171366:6;171374;171382:14;171398:12;171353;:58::i;:::-;171320:91;;171426:8;171422:94;;;171468:6;171459;:15;:33;;171486:6;171459:33;;;171477:6;171459:33;171451:53;-1:-1:-1;171494:9:0;-1:-1:-1;171451:53:0;;-1:-1:-1;;;;;;171451:53:0;171422:94;171545:6;171536;:15;:33;;171563:6;171536:33;;;171554:6;171536:33;171528:53;-1:-1:-1;171571:9:0;-1:-1:-1;;;;;;;169946:1643:0;;;;;;;;:::o;172322:1080::-;172477:7;172486:4;172503:32;172527:7;172503:23;:32::i;:::-;172593:70;;-1:-1:-1;;;172593:70:0;;-1:-1:-1;;;;;14128:32:1;;;172593:70:0;;;14110:51:1;14204:14;;14197:22;14177:18;;;14170:50;14263:14;;14256:22;14236:18;;;14229:50;172548:42:0;;172593:46;;;;;;14083:18:1;;172593:70:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;172548:115;;172756:6;:15;;;172752:64;;;172796:1;172799:4;172788:16;;;;;;;172752:64;172946:5;172930:21;;:6;:12;;;:21;;;172926:418;;172968:16;173046:43;173060:5;:28;;173080:8;173079:9;173046:13;:43::i;173060:28::-;173068:8;173046:13;:43::i;:::-;172999:90;;;173010:15;;;172999:90;;;-1:-1:-1;173104:72:0;;173152:1;173155:4;173144:16;;;;;;;;173104:72;173218:65;173236:6;:12;;;173250:8;173260:6;:12;;;173274:8;173218:17;:65::i;:::-;173302:6;:15;;;173192:140;;;;;;;;172926:418;173364:12;;173378:15;;;;;173364:12;;173378:15;;-1:-1:-1;172322:1080:0;-1:-1:-1;;;;;172322:1080:0:o;181396:1449::-;181552:7;181581:1;181576;:6;181572:679;;181711:1;745:3;181684:16;181688:12;181684:1;:16;:::i;:::-;181683:24;;;;:::i;:::-;181682:30;181678:530;;;181948:1;745:3;181919:18;181923:14;181919:1;:18;:::i;:::-;181918:26;;;;:::i;:::-;181917:32;181913:98;;;-1:-1:-1;843:1:0;181974:17;;181913:98;-1:-1:-1;952:1:0;182178:14;;181678:530;-1:-1:-1;1036:1:0;182224:15;;181572:679;182369:1;745:3;182342:16;182346:12;182342:1;:16;:::i;:::-;182341:24;;;;:::i;:::-;182340:30;182336:474;;;182574:1;745:3;182545:18;182549:14;182545:1;:18;:::i;182336:474::-;-1:-1:-1;1036:1:0;181396:1449;;;;;;;:::o;173959:569::-;174036:13;174051;174077:17;174126:33;136351:42;174144:4;174150:8;174126:9;:33::i;:::-;174105:54;;-1:-1:-1;174105:54:0;-1:-1:-1;174287:10:0;;:36;;;;;843:1;174301:9;:22;174287:36;174283:91;;;-1:-1:-1;843:1:0;174283:91;173959:569;;174499:21;;;;-1:-1:-1;;173959:569:0:o;176374:803::-;176549:7;176574:14;176569:322;;176684:8;176680:115;;;176720:59;176745:12;176759:14;636:4;176720:24;:59::i;:::-;176713:66;;;;176680:115;176818:61;176845:12;176859:14;636:4;176818:26;:61::i;176569:322::-;176978:8;176974:107;;;177010:59;177035:12;636:4;177054:14;177010:24;:59::i;176974:107::-;177108:61;177135:12;636:4;177154:14;177108:26;:61::i;:::-;177101:68;176374:803;-1:-1:-1;;;;;176374:803:0:o;14:131:1:-;-1:-1:-1;;;;;89:31:1;;79:42;;69:70;;135:1;132;125:12;150:865;254:6;262;270;278;331:2;319:9;310:7;306:23;302:32;299:52;;;347:1;344;337:12;299:52;386:9;373:23;405:31;430:5;405:31;:::i;:::-;455:5;-1:-1:-1;511:2:1;496:18;;483:32;538:18;527:30;;524:50;;;570:1;567;560:12;524:50;593:22;;646:4;638:13;;634:27;-1:-1:-1;624:55:1;;675:1;672;665:12;624:55;715:2;702:16;741:18;733:6;730:30;727:50;;;773:1;770;763:12;727:50;826:7;821:2;811:6;808:1;804:14;800:2;796:23;792:32;789:45;786:65;;;847:1;844;837:12;786:65;150:865;;878:2;870:11;;;;;-1:-1:-1;900:6:1;;979:2;964:18;951:32;;150:865;-1:-1:-1;;;150:865:1:o;1020:420::-;1073:3;1111:5;1105:12;1138:6;1133:3;1126:19;1170:4;1165:3;1161:14;1154:21;;1209:4;1202:5;1198:16;1232:1;1242:173;1256:6;1253:1;1250:13;1242:173;;;1317:13;;1305:26;;1360:4;1351:14;;;;1388:17;;;;1278:1;1271:9;1242:173;;;-1:-1:-1;1431:3:1;;1020:420;-1:-1:-1;;;;1020:420:1:o;1445:1321::-;1807:2;1819:21;;;1889:13;;1792:18;;;1911:22;;;1759:4;;2003;1991:17;;;1964:3;1949:19;;;1759:4;2036:563;2050:6;2047:1;2044:13;2036:563;;;2109:13;;2151:9;;-1:-1:-1;;;;;2147:35:1;;;2135:48;;2237:4;2229:13;;;2223:20;2219:46;;;2203:14;;;2196:70;2320:4;2312:13;;;2306:20;2328:4;2302:31;2286:14;;;2279:55;2396:2;2388:11;;;2382:18;2375:26;2368:34;2354:12;;;2347:56;2452:3;2444:12;;;2438:19;2423:13;;;2416:42;2170:3;2500:13;;;2494:20;2478:14;;;2471:44;;;;2572:17;;;;2544:4;2535:14;;;;2179:1;2065:9;2036:563;;;2040:3;;2646:9;2641:3;2637:19;2630:4;2619:9;2615:20;2608:49;2674:41;2711:3;2703:6;2674:41;:::i;:::-;2666:49;;;;2753:6;2746:4;2735:9;2731:20;2724:36;1445:1321;;;;;;:::o;2771:388::-;2839:6;2847;2900:2;2888:9;2879:7;2875:23;2871:32;2868:52;;;2916:1;2913;2906:12;2868:52;2955:9;2942:23;2974:31;2999:5;2974:31;:::i;:::-;3024:5;-1:-1:-1;3081:2:1;3066:18;;3053:32;3094:33;3053:32;3094:33;:::i;:::-;3146:7;3136:17;;;2771:388;;;;;:::o;3164:508::-;3241:6;3249;3257;3310:2;3298:9;3289:7;3285:23;3281:32;3278:52;;;3326:1;3323;3316:12;3278:52;3365:9;3352:23;3384:31;3409:5;3384:31;:::i;:::-;3434:5;-1:-1:-1;3491:2:1;3476:18;;3463:32;3504:33;3463:32;3504:33;:::i;:::-;3164:508;;3556:7;;-1:-1:-1;;;3636:2:1;3621:18;;;;3608:32;;3164:508::o;4320:247::-;4379:6;4432:2;4420:9;4411:7;4407:23;4403:32;4400:52;;;4448:1;4445;4438:12;4400:52;4487:9;4474:23;4506:31;4531:5;4506:31;:::i;:::-;4556:5;4320:247;-1:-1:-1;;;4320:247:1:o;5012:118::-;5098:5;5091:13;5084:21;5077:5;5074:32;5064:60;;5120:1;5117;5110:12;5135:517;5206:6;5214;5222;5275:2;5263:9;5254:7;5250:23;5246:32;5243:52;;;5291:1;5288;5281:12;5243:52;5330:9;5317:23;5349:31;5374:5;5349:31;:::i;:::-;5399:5;-1:-1:-1;5456:2:1;5441:18;;5428:32;5469:30;5428:32;5469:30;:::i;:::-;5518:7;-1:-1:-1;5577:2:1;5562:18;;5549:32;5590:30;5549:32;5590:30;:::i;:::-;5639:7;5629:17;;;5135:517;;;;;:::o;5657:729::-;5752:6;5760;5768;5776;5784;5837:3;5825:9;5816:7;5812:23;5808:33;5805:53;;;5854:1;5851;5844:12;5805:53;5893:9;5880:23;5912:31;5937:5;5912:31;:::i;:::-;5962:5;6040:2;6025:18;;6012:32;;-1:-1:-1;6143:2:1;6128:18;;6115:32;;6246:2;6231:18;;6218:32;;-1:-1:-1;6349:3:1;6334:19;6321:33;;-1:-1:-1;5657:729:1;-1:-1:-1;;;5657:729:1:o;6583:637::-;6773:2;6785:21;;;6855:13;;6758:18;;;6877:22;;;6725:4;;6956:15;;;6930:2;6915:18;;;6725:4;6999:195;7013:6;7010:1;7007:13;6999:195;;;7078:13;;-1:-1:-1;;;;;7074:39:1;7062:52;;7143:2;7169:15;;;;7134:12;;;;7110:1;7028:9;6999:195;;;-1:-1:-1;7211:3:1;;6583:637;-1:-1:-1;;;;;6583:637:1:o;7457:871::-;7561:6;7569;7577;7585;7593;7601;7654:3;7642:9;7633:7;7629:23;7625:33;7622:53;;;7671:1;7668;7661:12;7622:53;7710:9;7697:23;7729:31;7754:5;7729:31;:::i;:::-;7779:5;-1:-1:-1;7836:2:1;7821:18;;7808:32;7849:33;7808:32;7849:33;:::i;:::-;7457:871;;7901:7;;-1:-1:-1;;;;7981:2:1;7966:18;;7953:32;;8084:2;8069:18;;8056:32;;8187:3;8172:19;;8159:33;;-1:-1:-1;8291:3:1;8276:19;;;8263:33;;-1:-1:-1;7457:871:1:o;8333:1013::-;8446:6;8454;8462;8470;8478;8486;8494;8547:3;8535:9;8526:7;8522:23;8518:33;8515:53;;;8564:1;8561;8554:12;8515:53;8603:9;8590:23;8622:31;8647:5;8622:31;:::i;:::-;8672:5;-1:-1:-1;8729:2:1;8714:18;;8701:32;8742:33;8701:32;8742:33;:::i;:::-;8794:7;-1:-1:-1;8853:2:1;8838:18;;8825:32;8866:33;8825:32;8866:33;:::i;:::-;8333:1013;;;;-1:-1:-1;8918:7:1;;8998:2;8983:18;;8970:32;;-1:-1:-1;9101:3:1;9086:19;;9073:33;;9205:3;9190:19;;9177:33;;-1:-1:-1;9309:3:1;9294:19;;;9281:33;;-1:-1:-1;8333:1013:1;-1:-1:-1;;8333:1013:1:o;9351:127::-;9412:10;9407:3;9403:20;9400:1;9393:31;9443:4;9440:1;9433:15;9467:4;9464:1;9457:15;9483:127;9544:10;9539:3;9535:20;9532:1;9525:31;9575:4;9572:1;9565:15;9599:4;9596:1;9589:15;9615:344;9682:2;9676:9;9724:3;9712:16;;9758:18;9743:34;;9779:22;;;9740:62;9737:185;;;9844:10;9839:3;9835:20;9832:1;9825:31;9879:4;9876:1;9869:15;9907:4;9904:1;9897:15;9737:185;9938:2;9931:22;9615:344;:::o;9964:132::-;10040:13;;10062:28;10040:13;10062:28;:::i;:::-;9964:132;;;:::o;10101:987::-;10204:6;10264:3;10252:9;10243:7;10239:23;10235:33;10280:2;10277:22;;;10295:1;10292;10285:12;10277:22;-1:-1:-1;10337:17:1;;:::i;:::-;10384:9;10378:16;10403:33;10428:7;10403:33;:::i;:::-;10445:22;;10512:2;10497:18;;10491:25;10525:33;10491:25;10525:33;:::i;:::-;10585:2;10574:14;;10567:31;10643:2;10628:18;;10622:25;10691:4;10678:18;;10666:31;;10656:59;;10711:1;10708;10701:12;10656:59;10742:2;10731:14;;10724:31;10787:46;10829:2;10814:18;;10787:46;:::i;:::-;10782:2;10771:14;;10764:70;10900:3;10885:19;;;10879:26;10921:15;;;10914:32;11012:3;10997:19;;;10991:26;11033:15;;;11026:32;;;;-1:-1:-1;10775:5:1;10101:987;-1:-1:-1;10101:987:1:o;11093:230::-;11163:6;11216:2;11204:9;11195:7;11191:23;11187:32;11184:52;;;11232:1;11229;11222:12;11184:52;-1:-1:-1;11277:16:1;;11093:230;-1:-1:-1;11093:230:1:o;11328:245::-;11395:6;11448:2;11436:9;11427:7;11423:23;11419:32;11416:52;;;11464:1;11461;11454:12;11416:52;11496:9;11490:16;11515:28;11537:5;11515:28;:::i;11578:251::-;11648:6;11701:2;11689:9;11680:7;11676:23;11672:32;11669:52;;;11717:1;11714;11707:12;11669:52;11749:9;11743:16;11768:31;11793:5;11768:31;:::i;11834:179::-;11912:13;;11965:22;11954:34;;11944:45;;11934:73;;12003:1;12000;11993:12;12018:571;12121:6;12129;12137;12145;12153;12206:3;12194:9;12185:7;12181:23;12177:33;12174:53;;;12223:1;12220;12213:12;12174:53;12246:39;12275:9;12246:39;:::i;:::-;12325:2;12310:18;;12304:25;12391:2;12376:18;;12370:25;12485:2;12470:18;;12464:25;12236:49;;-1:-1:-1;12304:25:1;;-1:-1:-1;12370:25:1;-1:-1:-1;12464:25:1;-1:-1:-1;12534:49:1;12578:3;12563:19;;12534:49;:::i;:::-;12524:59;;12018:571;;;;;;;;:::o;12594:127::-;12655:10;12650:3;12646:20;12643:1;12636:31;12686:4;12683:1;12676:15;12710:4;12707:1;12700:15;12726:128;12793:9;;;12814:11;;;12811:37;;;12828:18;;:::i;:::-;12726:128;;;;:::o;12859:127::-;12920:10;12915:3;12911:20;12908:1;12901:31;12951:4;12948:1;12941:15;12975:4;12972:1;12965:15;13296:125;13361:9;;;13382:10;;;13379:36;;;13395:18;;:::i;14290:905::-;14390:6;14450:2;14438:9;14429:7;14425:23;14421:32;14465:2;14462:22;;;14480:1;14477;14470:12;14462:22;-1:-1:-1;14549:2:1;14543:9;14591:2;14579:15;;14624:18;14609:34;;14645:22;;;14606:62;14603:185;;;14710:10;14705:3;14701:20;14698:1;14691:31;14745:4;14742:1;14735:15;14773:4;14770:1;14763:15;14603:185;14804:2;14797:22;14860:16;;14885:21;;14951:2;14936:18;;14930:25;14964:30;14930:25;14964:30;:::i;:::-;15022:2;15010:15;;15003:32;15080:2;15065:18;;15059:25;15093:30;15059:25;15093:30;:::i;:::-;15151:2;15139:15;;15132:32;15143:6;14290:905;-1:-1:-1;;;14290:905:1:o;15200:168::-;15273:9;;;15304;;15321:15;;;15315:22;;15301:37;15291:71;;15342:18;;:::i;15373:217::-;15413:1;15439;15429:132;;15483:10;15478:3;15474:20;15471:1;15464:31;15518:4;15515:1;15508:15;15546:4;15543:1;15536:15;15429:132;-1:-1:-1;15575:9:1;;15373:217::o
Swarm Source
ipfs://290a04e776ce97ada5d767820102edf4b9dfa7dbece0ac19525ff6987afd9344
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.